fix(pacquet): persist the synthesized runtime package.json into the store index#12829
Conversation
…tore index Runtime archives (Node.js / Bun / Deno) ship no `package.json`, so pacquet synthesizes one carrying `name`, `version`, and `bin`. That synthesized manifest was only ever added to the *in-memory* `cas_paths` in `fetch_binary_resolution_to_cas`, after the download had already queued the store-index row. The persisted `PackageFilesIndex` therefore recorded no `package.json` and no bundled `manifest`. A cold fetch masks this — the current install's slot still gets the manifest from `cas_paths`. But a later *warm* install materializes the runtime straight from the store-index row (via the warm-batch prefetch, which never calls `fetch_binary_resolution_to_cas`), so the slot lands without a `package.json` and the warm-batch bin linker finds no bin. That is exactly the CI failure on #12811, where the root install cold-fetches `node@runtime:26.4.0` and the later `pnpm dlx node@runtime:26.4.0` warm-reads the manifest-less row and dies in `getBinName` with `dlx_read_manifest`. Thread the synthesized manifest into the two binary download paths as `append_manifest`, mirroring pnpm's `appendManifest`: fold it into the extracted output's `cas_paths`, the row's `files` map, and its bundled `manifest` before the row is persisted, so warm and cold installs land the same slot. This brings pacquet in line with the TypeScript stack, which already bakes `appendManifest` into the files index via `addManifestToCafs`.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds Changesappend_manifest feature
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant InstallPackageBySnapshot
participant DownloadTarballToStore
participant apply_append_manifest
participant CAS
InstallPackageBySnapshot->>InstallPackageBySnapshot: synthesize_runtime_manifest_bytes()
InstallPackageBySnapshot->>DownloadTarballToStore: run(append_manifest: Some(bytes))
DownloadTarballToStore->>DownloadTarballToStore: extract archive
alt package.json missing
DownloadTarballToStore->>apply_append_manifest: apply(cas_paths, pkg_files_idx, bytes)
apply_append_manifest->>CAS: write synthesized package.json
end
DownloadTarballToStore-->>InstallPackageBySnapshot: extraction result
Suggested labels: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Summary by QodoPersist synthesized runtime package.json into the pacquet store index
AI Description
Diagram
High-Level Assessment
Files changed (9)
|
Code Review by Qodo
1.
|
Micro-Benchmark ResultsLinux |
PR Code Suggestions ✨Latest suggestions up to 8f354b9 Warning
Previous suggestionsSuggestions up to commit 301e8fb
|
||||||||||||||||||||
|
Code review by qodo was updated up to the latest commit 301e8fb |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #12829 +/- ##
==========================================
+ Coverage 86.33% 86.42% +0.09%
==========================================
Files 438 438
Lines 68355 68395 +40
==========================================
+ Hits 59013 59110 +97
+ Misses 9342 9285 -57 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Port the core of `installing/deps-installer/test/install/nodeRuntime.ts:209` (`installing Node.js runtime` — cold install, then rimraf `node_modules` + offline reinstall) as a network-free integration test. `installing_a_runtime_persists_the_synthesized_manifest_into_the_store_index_row` drives `InstallPackageBySnapshot` on a `Binary` resolution pointing at a local `file:` runtime-archive fixture (a tarball with a `bin/node` and no `package.json`), backed by a real `StoreIndexWriter`. It asserts the cold install's `cas_paths` carries the synthesized `package.json`, the persisted store-index row records it in both `files` and the bundled `manifest`, and a warm/offline reinstall — with the fixture deleted so only the store can serve — re-materializes it from that row. Verified to fail when the `apply_append_manifest` fold is neutered. The real-download lockfile-shape / musl-variant / npm+corepack-filter assertions of nodeRuntime.ts remain unported; TEST_PORTING.md notes the split.
|
Code review by qodo was updated up to the latest commit 0a4b3fb |
PR Code Suggestions ✨Warning
No code suggestions found for the PR.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pacquet/crates/package-manager/src/install_package_by_snapshot/tests.rs (1)
763-769: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winStrengthen the warm-reinstall assertion to check manifest content, not just key presence.
The regression this test guards against (
dlx_read_manifestfailing to resolvebin) is specifically about manifest content, not just apackage.jsonkey existing incas_paths. The cold-path/row checks (lines 722-728) verify thebinfield content, but the final warm assertion only checkscontains_key. Reading the file atwarm_cas_paths.get("package.json")and asserting itsbin.nodevalue would tie the test more directly to the actual failure mode being fixed.Based on path instructions ("Test expectation: add a regression test that ... asserts persisted results (warm reinstall) rather than only executing nearby code paths"), this closes the loop on end-to-end proof.
♻️ Suggested strengthening
assert!( warm_cas_paths.contains_key("package.json"), "the warm reinstall re-materializes the manifest from the persisted row", ); + let warm_manifest_path = warm_cas_paths.get("package.json").expect("warm package.json slot"); + let warm_manifest_bytes = + std::fs::read(warm_manifest_path).expect("read the warm-materialized package.json"); + let warm_manifest: serde_json::Value = + serde_json::from_slice(&warm_manifest_bytes).expect("parse the warm manifest"); + assert_eq!( + warm_manifest.get("bin").and_then(|bin| bin.get("node")).and_then(serde_json::Value::as_str), + Some("bin/node"), + "the warm-materialized manifest carries the runtime bin", + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pacquet/crates/package-manager/src/install_package_by_snapshot/tests.rs` around lines 763 - 769, The warm-reinstall check in install_package_by_snapshot/tests.rs only verifies that warm_cas_paths contains the "package.json" key, which is too weak for the regression being guarded. Update the final assertion in the warm reinstall test to read the manifest from the path returned by warm_cas_paths.get("package.json") and assert its persisted content, especially the bin.node value, using the existing test setup around warm_cas_paths and the manifest checks already used earlier in the test.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@pacquet/crates/package-manager/src/install_package_by_snapshot/tests.rs`:
- Around line 763-769: The warm-reinstall check in
install_package_by_snapshot/tests.rs only verifies that warm_cas_paths contains
the "package.json" key, which is too weak for the regression being guarded.
Update the final assertion in the warm reinstall test to read the manifest from
the path returned by warm_cas_paths.get("package.json") and assert its persisted
content, especially the bin.node value, using the existing test setup around
warm_cas_paths and the manifest checks already used earlier in the test.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: c8874f3c-6f6f-468e-b135-1071e7c00a16
📒 Files selected for processing (2)
pacquet/crates/package-manager/src/install_package_by_snapshot/tests.rspacquet/plans/TEST_PORTING.md
✅ Files skipped from review due to trivial changes (1)
- pacquet/plans/TEST_PORTING.md
|
Code review by qodo was updated up to the latest commit 0a4b3fb |
1 similar comment
|
Code review by qodo was updated up to the latest commit 0a4b3fb |
Integrated-Benchmark Report (Linux)Commit: Each scenario reports direct installs and pnpr installs. Bencher consumes pacquet@HEAD and pnpr@HEAD. Scenario: Isolated linker: fresh restore, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 4.173935280259999,
"stddev": 0.09894761655879349,
"median": 4.148459878060001,
"user": 3.9257931799999994,
"system": 3.5129288800000005,
"min": 4.04716913406,
"max": 4.36894455806,
"times": [
4.18638028606,
4.16510428606,
4.04716913406,
4.10665670606,
4.30872109006,
4.10902718006,
4.10990811806,
4.13181547006,
4.36894455806,
4.20562597406
]
},
{
"command": "pacquet@main",
"mean": 4.1858937448599995,
"stddev": 0.18908684613689147,
"median": 4.11542221256,
"user": 4.009833179999999,
"system": 3.4952954800000002,
"min": 3.94485242306,
"max": 4.53074795606,
"times": [
4.47007072506,
4.12658826006,
4.53074795606,
4.18992386306,
4.08733223306,
4.10345901506,
4.10425616506,
4.01887038906,
3.94485242306,
4.28283641906
]
},
{
"command": "pnpr@HEAD",
"mean": 2.2000479337599996,
"stddev": 0.13299909429167123,
"median": 2.18821468006,
"user": 2.67983268,
"system": 2.99306288,
"min": 2.03044966006,
"max": 2.36988872606,
"times": [
2.20535418706,
2.36988872606,
2.36455656306,
2.17107517306,
2.03234770806,
2.30483448406,
2.03044966006,
2.10810769906,
2.32096613006,
2.0928990070599998
]
},
{
"command": "pnpr@main",
"mean": 2.19097449736,
"stddev": 0.13919796285879676,
"median": 2.20224733506,
"user": 2.70270958,
"system": 2.9960678799999996,
"min": 1.99917724706,
"max": 2.39325740806,
"times": [
2.39325740806,
2.05852217906,
2.19035710506,
2.01020977206,
2.3296133600599997,
1.99917724706,
2.33899323006,
2.13888949506,
2.23658761206,
2.21413756506
]
}
]
}Scenario: Isolated linker: fresh restore, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.62958809812,
"stddev": 0.015559793481111785,
"median": 0.62321097372,
"user": 0.3753712,
"system": 1.31446828,
"min": 0.61244227472,
"max": 0.65648563772,
"times": [
0.65259464572,
0.6233674207200001,
0.6230545267200001,
0.61450749472,
0.61244227472,
0.6402938797200001,
0.6329468957200001,
0.65648563772,
0.6230292577200001,
0.61715894772
]
},
{
"command": "pacquet@main",
"mean": 0.6412436668200001,
"stddev": 0.03404476802622841,
"median": 0.63010650622,
"user": 0.38286619999999993,
"system": 1.30848498,
"min": 0.61624433372,
"max": 0.7342318267200001,
"times": [
0.6371178687200001,
0.64368483172,
0.61812445772,
0.62757207072,
0.62926973172,
0.63094103572,
0.62927197672,
0.61624433372,
0.64597853472,
0.7342318267200001
]
},
{
"command": "pnpr@HEAD",
"mean": 0.72270306012,
"stddev": 0.08538198032723325,
"median": 0.6941586177200001,
"user": 0.4022145999999999,
"system": 1.35515098,
"min": 0.6716637977200001,
"max": 0.9598287737200001,
"times": [
0.6885827307200001,
0.6885371237200001,
0.70604258872,
0.6919536967200001,
0.69739149272,
0.6840716437200001,
0.6716637977200001,
0.69636353872,
0.9598287737200001,
0.74259521472
]
},
{
"command": "pnpr@main",
"mean": 0.68864831692,
"stddev": 0.022315034912533963,
"median": 0.68940236272,
"user": 0.393498,
"system": 1.33862518,
"min": 0.66359455272,
"max": 0.71677238672,
"times": [
0.71677238672,
0.69350132972,
0.66359455272,
0.6664922077200001,
0.71210046072,
0.66525207172,
0.68530339572,
0.70953969072,
0.70930011472,
0.66462695872
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 4.3021786766800005,
"stddev": 0.03204609886918103,
"median": 4.30247912638,
"user": 3.80175232,
"system": 3.3792206800000004,
"min": 4.24699210388,
"max": 4.35220199888,
"times": [
4.29224277188,
4.32367427288,
4.3143695088800005,
4.28354990488,
4.24699210388,
4.308669123880001,
4.29628912888,
4.35220199888,
4.33768502088,
4.26611293188
]
},
{
"command": "pacquet@main",
"mean": 4.330174649480001,
"stddev": 0.024664189826323343,
"median": 4.33478822338,
"user": 3.8606682199999995,
"system": 3.3785789800000003,
"min": 4.2922285458800005,
"max": 4.37161517888,
"times": [
4.31703763388,
4.3422901318800005,
4.350350675880001,
4.32728631488,
4.34415692788,
4.37161517888,
4.2922285458800005,
4.31032622088,
4.34440411288,
4.30205075188
]
},
{
"command": "pnpr@HEAD",
"mean": 2.21849782738,
"stddev": 0.10247230462494226,
"median": 2.21076678588,
"user": 2.47464662,
"system": 2.91602348,
"min": 2.0770734328800002,
"max": 2.4309955958800002,
"times": [
2.29556629688,
2.2516857648800004,
2.0770734328800002,
2.12200578888,
2.16277534488,
2.4309955958800002,
2.17207284988,
2.15385637388,
2.2494607218800002,
2.2694861038800003
]
},
{
"command": "pnpr@main",
"mean": 2.15180636908,
"stddev": 0.08251844632885226,
"median": 2.13100990138,
"user": 2.5508194200000003,
"system": 2.90647198,
"min": 2.04472352888,
"max": 2.32119135688,
"times": [
2.07798417588,
2.12288867588,
2.04472352888,
2.18186692688,
2.32119135688,
2.11808966288,
2.15048350088,
2.25484386288,
2.13913112688,
2.10686087288
]
}
]
}Scenario: Isolated linker: fresh install, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.3914230145400004,
"stddev": 0.03139862735862692,
"median": 1.38231866974,
"user": 1.3819592600000001,
"system": 1.6899987600000004,
"min": 1.3520253212400002,
"max": 1.45064904424,
"times": [
1.3520253212400002,
1.36414322224,
1.3652866972400002,
1.37760987724,
1.38646390724,
1.3961950252400002,
1.45064904424,
1.37817343224,
1.41405258424,
1.42963103424
]
},
{
"command": "pacquet@main",
"mean": 1.45415458544,
"stddev": 0.03112258488877874,
"median": 1.44943978274,
"user": 1.4030273600000003,
"system": 1.74878046,
"min": 1.42086434324,
"max": 1.52947684524,
"times": [
1.4630600332400001,
1.52947684524,
1.46681096724,
1.45352630424,
1.43483275324,
1.4453532612400002,
1.42086434324,
1.4660804872400002,
1.4329277092400001,
1.4286131502400001
]
},
{
"command": "pnpr@HEAD",
"mean": 0.6904455739400001,
"stddev": 0.009259955300931167,
"median": 0.6885430272399999,
"user": 0.3529992599999999,
"system": 1.30561536,
"min": 0.67802888724,
"max": 0.70817020524,
"times": [
0.68579873924,
0.68512531224,
0.67802888724,
0.68448961724,
0.6978778302399999,
0.69994422024,
0.69167441524,
0.69128731524,
0.68205919724,
0.70817020524
]
},
{
"command": "pnpr@main",
"mean": 0.65149413614,
"stddev": 0.010110676623414376,
"median": 0.64985430474,
"user": 0.34277546,
"system": 1.26874726,
"min": 0.63698661024,
"max": 0.6706468182399999,
"times": [
0.64263518324,
0.65086596324,
0.63698661024,
0.65857203924,
0.64884264624,
0.6422107432399999,
0.64778498024,
0.66110575424,
0.6706468182399999,
0.65529062324
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 3.0783491412000004,
"stddev": 0.024409643189211974,
"median": 3.0777611548,
"user": 1.82576598,
"system": 1.96220258,
"min": 3.0270212223,
"max": 3.1107102653000003,
"times": [
3.0615962553,
3.0994440143000004,
3.1037903963000004,
3.0649783623,
3.0780386263,
3.0270212223,
3.0724300963,
3.1107102653000003,
3.0774836833,
3.0879984903000004
]
},
{
"command": "pacquet@main",
"mean": 3.0938588105,
"stddev": 0.05736638448600275,
"median": 3.0793888198,
"user": 1.8120485800000001,
"system": 1.9813251800000002,
"min": 3.0337160693,
"max": 3.2318721683000002,
"times": [
3.0802294063000004,
3.0951661283000003,
3.0645919313000003,
3.0568147023,
3.0558012653000004,
3.0945693463,
3.0785482333000003,
3.2318721683000002,
3.1472788543,
3.0337160693
]
},
{
"command": "pnpr@HEAD",
"mean": 0.6807052692,
"stddev": 0.02185712790728542,
"median": 0.6844368053000001,
"user": 0.35568137999999994,
"system": 1.31312158,
"min": 0.6511292183,
"max": 0.7082645353,
"times": [
0.7082645353,
0.6965842283,
0.6549160513,
0.6581504983,
0.6511292183,
0.6661308193000001,
0.7014063793,
0.6926261053,
0.6762475053,
0.7015973513
]
},
{
"command": "pnpr@main",
"mean": 0.6785474401999999,
"stddev": 0.06206193510144619,
"median": 0.6596263173,
"user": 0.34857678000000003,
"system": 1.27948388,
"min": 0.6481863093,
"max": 0.8534806323,
"times": [
0.6631950273,
0.6619058863,
0.6789321073,
0.6565138483,
0.6547570733,
0.6583650673,
0.6492508833,
0.8534806323,
0.6481863093,
0.6608875673
]
}
]
}Scenario: Isolated linker: fresh resolve, hot cache, offline
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.6432087567,
"stddev": 0.013803467473562684,
"median": 0.6427539226000001,
"user": 0.61673108,
"system": 0.14296468,
"min": 0.6203966066000001,
"max": 0.6608094086,
"times": [
0.6460172436000001,
0.6589421526000001,
0.6503488146,
0.6350483316000001,
0.6394906016,
0.6353529356000001,
0.6203966066000001,
0.6280787156000001,
0.6576027566000001,
0.6608094086
]
},
{
"command": "pacquet@main",
"mean": 0.6515351220000001,
"stddev": 0.019165730171763276,
"median": 0.6445344351,
"user": 0.61691198,
"system": 0.15079798000000003,
"min": 0.6302664366,
"max": 0.6906403466000001,
"times": [
0.6683116346000001,
0.6722952466000001,
0.6906403466000001,
0.6367022406,
0.6485898066000001,
0.6388049556000001,
0.6429317406,
0.6302664366,
0.6461371296,
0.6406716826000001
]
},
{
"command": "pnpr@HEAD",
"mean": 0.10734784498461539,
"stddev": 0.0017581356303845524,
"median": 0.10764191560000001,
"user": 0.02825574153846154,
"system": 0.017632949230769225,
"min": 0.10310700260000001,
"max": 0.11039210160000001,
"times": [
0.10549400860000001,
0.10858093660000001,
0.11039210160000001,
0.10448921260000002,
0.10821970260000001,
0.10761365760000001,
0.10310700260000001,
0.10836973660000002,
0.10734223460000002,
0.10875039460000001,
0.10754830560000002,
0.10859229760000001,
0.10767017360000002,
0.10400812760000001,
0.10774475260000001,
0.1086208356,
0.10776012860000002,
0.10705877160000002,
0.10509048060000001,
0.10663070660000001,
0.10863874360000002,
0.10895507960000002,
0.10659530760000001,
0.10998179260000002,
0.10644735660000001,
0.1073421216
]
},
{
"command": "pnpr@main",
"mean": 0.10767193504,
"stddev": 0.0015712166711778926,
"median": 0.10781522260000001,
"user": 0.027233039999999997,
"system": 0.018387140000000003,
"min": 0.10341579060000002,
"max": 0.11122959360000001,
"times": [
0.10727469260000001,
0.10341579060000002,
0.10808400560000002,
0.10819892560000001,
0.10884346360000001,
0.10779934460000001,
0.10717525860000002,
0.10922588860000002,
0.10781105360000001,
0.10844196260000001,
0.10781522260000001,
0.10758921760000001,
0.10817483060000001,
0.11122959360000001,
0.10599937260000002,
0.10871174260000001,
0.10636376960000002,
0.10858840360000001,
0.10650571360000001,
0.10441087560000001,
0.10800003460000002,
0.10734082660000001,
0.10838335560000001,
0.10947400760000002,
0.10694102360000002
]
}
]
}Scenario: Isolated linker: fresh restore, cold cache + cold store + cold pnpr
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 7.11789809446,
"stddev": 0.1646630452021146,
"median": 7.08629922906,
"user": 4.034726579999999,
"system": 3.7680026,
"min": 6.90643040256,
"max": 7.3756622925599995,
"times": [
7.16018167156,
7.09441777056,
6.96993181856,
6.97134111256,
7.00593848856,
7.29394180456,
6.90643040256,
7.3756622925599995,
7.32295489556,
7.07818068756
]
},
{
"command": "pacquet@main",
"mean": 6.932774202659999,
"stddev": 0.1657298364231341,
"median": 6.89252501306,
"user": 4.134476179999999,
"system": 3.7663245000000005,
"min": 6.79658032456,
"max": 7.36415234256,
"times": [
7.36415234256,
6.9496213955599995,
6.79797111856,
6.9761669265599995,
6.88611269556,
6.8723906455599995,
6.79658032456,
6.89893733056,
6.81520218656,
6.97060706056
]
},
{
"command": "pnpr@HEAD",
"mean": 5.028276466459999,
"stddev": 0.08522231013630473,
"median": 5.0036208780599996,
"user": 2.78660838,
"system": 3.212686,
"min": 4.94153486656,
"max": 5.23542521256,
"times": [
4.94153486656,
5.04648567556,
5.037335522559999,
4.97762397456,
4.98915734856,
5.23542521256,
4.9825403035599996,
5.09141208456,
5.01808440756,
4.96316526856
]
},
{
"command": "pnpr@main",
"mean": 4.97496787456,
"stddev": 0.12847601659055446,
"median": 4.93579070806,
"user": 2.8197990799999997,
"system": 3.1793126999999997,
"min": 4.78337353356,
"max": 5.23593133556,
"times": [
4.95860358656,
5.15625170756,
4.94029366856,
4.78337353356,
4.92090482256,
4.93128774756,
4.93096292856,
5.23593133556,
4.92402238356,
4.968047031559999
]
}
]
} |
|
| Branch | pr/12829 |
| Testbed | pnpr |
⚠️ WARNING: No Threshold found!Without a Threshold, no Alerts will ever be generated.
Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the--ci-only-thresholdsflag.
Click to view all benchmark results
| Benchmark | Latency | milliseconds (ms) |
|---|---|---|
| isolated-linker.fresh-install.cold-cache.cold-store | 📈 view plot | 2,218.50 ms |
| isolated-linker.fresh-install.cold-cache.hot-store | 📈 view plot | 680.71 ms |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot | 690.45 ms |
| isolated-linker.fresh-resolve.hot-cache.offline | 📈 view plot | 107.35 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot | 2,200.05 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store.cold-pnpr | 📈 view plot | 5,028.28 ms |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot | 722.70 ms |
…riant Rephrase the store-index-row test's comments to state the current contract — a warm install materializes straight from the persisted row, so the row must carry the synthesized package.json and bundled manifest — instead of narrating pre-fix behavior in source, per the repo's comment convention.
|
Code review by qodo was updated up to the latest commit 8f354b9 |
1 similar comment
|
Code review by qodo was updated up to the latest commit 8f354b9 |
|
Code review by qodo was updated up to the latest commit 8f354b9 |
Summary
Fixes the
TS CI / Compile & Lintfailure seen after bumping the repo to theRust pnpm alpha (Related to #12811). The
compile-onlyscript runspnpm dlx node@runtime:26.4.0 …, which died with:Root cause. Runtime archives (Node.js / Bun / Deno) ship no
package.json,so pacquet synthesizes one (
name,version,bin). That synthesizedmanifest was only added to the in-memory
cas_pathsinfetch_binary_resolution_to_cas, after the download had already queued thestore-index row. The persisted
PackageFilesIndextherefore recorded nopackage.jsonand no bundledmanifest.A cold fetch masks this — the current install's slot still gets the
manifest from
cas_paths. But a later warm install materializes theruntime straight from the store-index row (via the warm-batch prefetch, which
never calls
fetch_binary_resolution_to_cas), so the slot lands without apackage.jsonand the warm-batch bin linker finds no bin. That is exactly theCI sequence: the root install cold-fetches
node@runtime:26.4.0, then thelater
pnpm dlx node@runtime:26.4.0warm-reads the manifest-less row and diesin
getBinName.Fix. Thread the synthesized manifest into the two binary download paths as
append_manifest, mirroring pnpm'sappendManifest: fold it into theextracted output's
cas_paths, the row'sfilesmap, and its bundledmanifestbefore the row is persisted. Warm and cold installs now land thesame slot. This brings pacquet in line with the TypeScript stack, which already
bakes
appendManifestinto the files index viaaddManifestToCafs— noTypeScript change is needed.
Verified end-to-end by reproducing the CI two-step (
installthen warmdlx node@runtime:26.4.0 --version) against an isolated store: it fails on thepre-fix binary with
dlx_read_manifestand succeeds (v26.4.0) on the fixedbinary.
Regression test.
installing_a_runtime_persists_the_synthesized_manifest_into_the_store_index_row(
install_package_by_snapshot/tests.rs) ports the core ofinstalling/deps-installer/test/install/nodeRuntime.ts:209(cold install →rimraf node_modules→ offline reinstall) network-free: it drivesInstallPackageBySnapshoton aBinaryresolution pointing at a localfile:runtime-archive fixture, asserts the persisted store-index row carries the
synthesized
package.jsonin bothfilesand the bundledmanifest, and thata warm/offline reinstall (fixture deleted) re-materializes it. Confirmed to fail
when the fix is neutered. Plus unit tests for
apply_append_manifest. Thereal-download lockfile-shape / musl-variant assertions of
nodeRuntime.tsremain unported — tracked in
pacquet/plans/TEST_PORTING.md.Squash Commit Body
Checklist
pacquet/port, or the description notes what still needs porting. (pacquetonly — the TypeScript stack already has this behavior via
appendManifest.)nodeRuntime.ts:209's cold→wipe→offline-reinstall core, plus unit tests forapply_append_manifest; verified against the pre-fix/fixed binaries and byneutering the fix.)
Written by an agent (Claude Code, claude-opus-4-8).
Summary by CodeRabbit
Bug Fixes
package.json: pacquet now persists the synthesizedpackage.jsonand bundled runtime manifest into the stored index during import, enabling correct warm reinstalls and offline use.package.json, existing behavior remains unchanged to avoid duplicate/incorrect metadata.Tests
Documentation