Repository navigation
Plan pnpm rewires with one core for both modes (lock-model 2b) - #2029
Draft
Mikola Lysenko (mikolalysenko) wants to merge 7 commits into
Draft
Mikola Lysenko (mikolalysenko) wants to merge 7 commits into
Mikola Lysenko (mikolalysenko) wants to merge 7 commits into
Conversation
Add formats/pnpm/plan.rs, the planning core hosted and vendored mode share. They now differ only in where a rewired entry points: * Target::check_lock: one lock-version table. Hosted takes every lock but pnpm 1's early shrinkwrap. Vendored takes 5.4 / 6.0 / 9.0 and routes each dialect from it. This replaces unsupported_early_shrinkwrap, check_v9_lock_version and the legacy check_lock_version. * match_key: one lookup of how a key names name@version, used by the hosted lookup, the hosted "vendored?" hint, and both vendored dialects' target, split-entry and rekey checks. It finds the registry entry with its peer suffix, or a vendored rekey read with origin::vendor_ref plus the artifact leaf. * Target::repoints: the all-or-nothing gate's per-instance predicate. Hosted splices any parsable peer context; vendored rekeys the plain entry only. Within the vendored planner, the v9 and legacy dialects now share the dep-pair revert (DepPair), the block revert (revert_block, re-sorting legacy's bare file: rekey), target_blocks, and dep_entries. dep_entries also serves the importer edit, the 6.0 root-dep edit, the ref gate and the lock index. The ref gate's index and scan paths run one set of predicates. Behavior changes, each pinned by a test: * N15: the vendored planner and reverter edit a CRLF pnpm-lock.yaml or pnpm-workspace.yaml like its LF twin and write it back CRLF. Only a file mixing CRLF and LF is still refused (vendor_lockfile_crlf_unsupported). * N5 (vendored planner): a sibling checkout's ../.socket/vendor rekey is no longer taken for this project's entry. * The hosted "vendored" hint now judges a rekey by its artifact leaf, as the vendored planner does, instead of the entry's version: line. N16 is kept as a target-specific refusal: no lock version beyond 5.4 / 6.0 / 9.0 has a captured fixture that proves the vendored rekey. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
N5's vendored-planner part and N15 are resolved in PR 2b. N16 stays target-specific for pnpm vendored mode. scripts/loc-budget.py --lower: lock-readers 31207 -> 31201, lock-writers 88314 -> 88093. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner decision on divergence N11: pnpm never reads a pnpm <= 2 shrinkwrap.yaml it has a pnpm-lock.yaml for, so that file is shadowed. The planning core's planned_locks leaves it out, so hosted mode never rewrites it and it no longer takes part in the all-or-nothing gate. Before, an entry the splice cannot repoint, or pnpm 1's early-shrinkwrap head, refused the dependency in every lock. Discovery keeps sweeping it for stale Socket identities, and vendored mode never reads it. A shrinkwrap.yaml that is the only pnpm lock (nested ones are shadowed only by their own sibling) is rewritten as before. No redirect golden changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Read every vendored pnpm text file through one reader, read_pnpm_text. It normalizes CRLF and rejects mixed endings. The revert now reads a CRLF two-document lock: it used to fail on `---\r`. A lock or workspace file that mixes CRLF and LF now fails the revert before any write, as vendoring refuses it; the revert used to rewrite it all-LF. - N11: a project that pins pnpm 1 / 2 (install record or package.json packageManager) reads only shrinkwrap.yaml, so there the stray pnpm-lock.yaml is the shadowed one. Hosted (planned_locks) and discovery share governing_pnpm_lock. The pin reader moves to utils::pnpm_workspace::pinned_pnpm_major, which pnpm_major_from reuses. - sniff_lock_grammar: an unparseable lockfileVersion major keeps the update-socket-patch remedy. - Perf: SectionIndex::build no longer formats a string per block. dep_entries is lazy and borrowed, so the non-index ref gate stops at the first refusal. matching_blocks classifies each block once, and target_block returns it with its rekey flag. - Target::check_lock is split into hosted_refuses_lock and the vendored dialect's sniff_lock_grammar check, with no dead default. Target::repoints is an explicit match per target. Budget, against the base: lock-readers 31206 (base 31207), lock-writers 88115 (base 88314). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vendored mode now reads the same plan::governing_pnpm_lock decision as hosted mode and discovery. When the project pins pnpm 1 or 2 (install record, else package.json packageManager), pnpm installs from shrinkwrap.yaml and ignores pnpm-lock.yaml. Vendored mode does not write the shrinkwrap grammar, so it now refuses with vendor_lockfile_version_unsupported before any write, instead of wiring the stray pnpm-lock.yaml. With no pin, nothing changes. Documented in CLI_CONTRACT.md and the N11 divergence row. The mixed-ending read error is now an io::ErrorKind::Unsupported error instead of a custom type, which keeps lock-writers within budget (88113). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Nov 6, 2026
Clears the conflicts left when the base took the 2026-11-05 owner decisions and the loc-budget counter fix. - lock-model-divergences.md: keep this PR's "Resolved in PR 2a" detail for N4, N5, N12 and N14, tagged with #2009, plus the base's PR links (#2025, #2029). N11 takes the base's owner decision (shadowed), which replaces "pending owner decision". - loc-budget.json: the base re-measured lock-readers with the fixed counter (30259). This PR grows the group, so the max is raised by hand to its measured count under the new counter (30482). Co-Authored-By: Claude <noreply@anthropic.com>
Clears the conflicts left when the base merged lock-model/1-origin. - lock-model-divergences.md: keep this PR's PR 2b resolutions (N5, N11, N15, N16) and tag them #2029, take the base's #2009 tags for the PR 2a rows, its #2025 note on N5, and its P4 note on out-of-root includes. - loc-budget.json: set both groups to their measured counts under the base's fixed counter (this PR shrinks both). Co-Authored-By: Claude <noreply@anthropic.com>
Collaborator
Author
|
Burn-down agent: merged
Generated by Claude Code |
Brings in #2002's review fixes and #2001's later counter fixes through 2a. Restores crates/socket-patch-core/src/origin.rs to the lock-readers group (lost in the earlier 1-origin merge). Budget at this branch's counts: lock-readers 30766, lock-writers 88114, both below 2a's 30767 and 88315. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack: PR 2b of the lock-model stack, based on #2009.
Hosted and vendored pnpm mode now plan with one core. They differ only in where a rewired entry points: a Socket URL, where hosted splices the instance's
resolution:, or a committed.socket/vendor/path, where vendored rekeys the entry and mirrors the override. The code is 202 implementation lines smaller than the base.The shared core:
formats/pnpm/plan.rs(pure)hosted_refuses_lockholds hosted's only refusal: pnpm 1's early shrinkwrap.sniff_lock_grammar: 5.4, 6.0, 9.0), andPnpmDialect::check_lockroutes each dialect from it.grammar::unsupported_early_shrinkwrap,formats::pnpm::check_v9_lock_versionand the legacycheck_lock_version.match_key: one rule for how a key namesname@version.name@file:or legacy's barefile:, read withorigin::vendor_refplus the artifact leaf.vendored_packagesis deleted), and in both vendored dialectstarget_key,lock_has_target_package,target_block(with the split-entry refusal) and the rekey edits.Target::repoints: the per-instance check of the all-or-nothing gate. Hosted splices any peer context it can parse; vendored rekeys only the plain entry.governing_pnpm_lock/planned_locks: which of a directory'spnpm-lock.yamlandshrinkwrap.yamlpnpm reads (N11, below). Hosted and discovery both use it.The vendored v9 and legacy dialects now share more code:
DepPair);revert_block, which re-sorts legacy's barefile:rekey);dep_entries), used by the importer edit, the 6.0 root-dep edit, both ref gates andLockIndex::build;read_pnpm_text).The refusal codes are unchanged. The 2a architecture test's writer allowlist shrinks from 6 to 4 walks for
vendor/pnpm_lock_legacy.rsand stays at 3 forvendor/pnpm_lock.rs.Behavior changes (each pinned by a test that fails before this PR)
pnpm-lock.yamlorpnpm-workspace.yaml(a Windows autocrlf checkout) like its LF twin and writes it back CRLF, in both vendoring and the revert. This includes pnpm 11's two-document lock. Before, it refused these files withvendor_lockfile_crlf_unsupported.crlf_lock_is_wired_like_its_lf_twin_and_stays_crlfmixed_line_ending_lock_refuses_naming_line_endingscrlf_workspace_file_gains_the_override_in_its_own_sectioncrlf_checkout_of_a_vendored_project_reverts_cleanlycrlf_two_document_lock_revertsmixed_line_ending_revert_fails_before_any_writecrlf_is_wired_and_foreign_versions_refuseonly_a_mixed_line_ending_hosted_pnpm_lock_is_refused(takeover preview)scan_vendored_over_hosted_pnpm_crlf_lock_takes_over_and_stays_crlfpreflight_agrees_with_the_loop…now use a mixed-ending lock.../.socket/vendor/…rekey as this project's entry. Before,parse_vendor_pathfound the anchor anywhere in the path. Test:a_sibling_checkouts_rekey_is_not_a_target. The reverter still finds its wiring withparse_vendor_path, because values such as pnpm 7/8's absolute specifier need it.version:line.version:line now getsredirect_pnpm_entry_vendored.version:line now getsredirect_pnpm_entry_not_found.pnpm_vendored_diagnosis_reads_the_rekeyed_entry_through_origin.lockfileVersionnow reads "has no lockfileVersion in its head" and gets the re-lock remedy. An unparseable major (for example'v10') keeps the update-socket-patch remedy. The error codes are unchanged.shrinkwrap.yaml(owner decision: shadowed). Of a directory'spnpm-lock.yamland pnpm <= 2shrinkwrap.yaml, the planner rewrites only the one pnpm reads; the other is shadowed (governing_pnpm_lock).pnpm-lock.yaml. pnpm 1 / 2 read onlyshrinkwrap.yaml, so when the project pins pnpm 1 / 2 (node_modules/.modules.yaml, else package.jsonpackageManager), the straypnpm-lock.yamlis the shadowed one.pnpm-lock.yamlgoverns.recognize_ignored.shrinkwrap.yamlgovern, it refuses withvendor_lockfile_version_unsupported(it does not write the shrinkwrap grammar) instead of wiring the straypnpm-lock.yaml. With no pin it is unchanged. Test:a_pnpm_2_pin_beside_a_shrinkwrap_refuses, which fails without the gate.shrinkwrap.yamlis rewritten as before. A nested shrinkwrap is shadowed only by its own sibling.formats/registry.rskeeps itsHOSTEDread role, which a lone shrinkwrap needs. The hosted engine's candidate list is unchanged; the planner drops the shadowed file. The hosted unwind can still restore an older run's pin in it.pnpm_shrinkwrap_beside_a_pnpm_lock_is_shadowed: a plain entry, an unparseable key, an early-shrinkwrap head, the nested case, a pnpm 2 pin and a lone shrinkwrap.the_pinned_pnpm_major_picks_the_governing_lock: no evidence, pnpm >= 3, pnpm 2, and the install record outranking package.json.pnpm_shrinkwrap_only_without_pnpm_lock, now with a pnpm 2 pin.CLI_CONTRACT.md(pnpm hosted paragraph),docs/ecosystems.md, and divergences rows N11, now "Resolved (owner: shadowed) in PR 2b".N16: kept as target-specific. Hosted reads every pnpm lock version except early shrinkwrap. Vendored keeps refusing versions other than 5.4, 6.0 and 9.0, because no captured pnpm
file:override fixture proves the rekey for 5.3, 5.x≤5.2, 6.1 or 7.0. This is pinned bylock_versions_each_target_rewrites.Unchanged: N14 (
lockfile=falsestays target-specific).Review findings (
/code-review high)---\rfailed every revert of a CRLF two-document lockcrlf_two_document_lock_revertsfailed)read_pnpm_textfirst.mixed_line_ending_revert_fails_before_any_writefailed)read_pnpm_text(root, file)serves the vendoring reads and the revert pre-read of the lock and the workspace file.is_mixedandread_refusalmap its errors.shrinkwrap.yamlgoverning_pnpm_lockreads the pin (utils::pnpm_workspace::pinned_pnpm_major, whichpnpm_major_fromnow reuses), and hosted and discovery share it. There are tests for all three cases.'v10'lost the update-socket-patch remedylock_version_remedy_is_version_aware.SectionIndex::buildallocatedformat!("@{key}")per blockstarts_with("file:")andmatch_indices("@file:")on the key directly.dep_entriesandimporter_refsare lazy and borrowed; the gate stops at the first refusal.matching_blocksclassifies once;target_blockreturns the block and its rekey flag; the curried closure is gone.Target::check_lock'sOptionforced a dead.unwrap_or(V9)hosted_refuses_lockand the vendored dialect'ssniff_lock_grammarcheck; no dead default.Target::repointsearly return was hard to readBack-ports to hosted
I found no pnpm lock shape that vendored rewires and hosted does not. One vendored-only behavior is deferred: the warning about an unpatched
file:copy of the same release (vendor_copy_unpatched, #935). It needs project I/O (discovery'spnpm_lock_file_copies) and belongs in the hosted engine, not the pure planner.Golden diffs
None.
committed_fixture_corpus_matches_goldenpasses unchanged, and no file undertests/fixtures/redirect/npm/pnpmchanges.Restack (2026-11-06)
Merge 1fec27a brings in #2002's review fixes and #2001's later counter fixes, through #2009. Nothing in this PR's code needed changing.
The
formatsarchitecture guard now bans the host policy (OriginPolicy,hosted_uuid(,SOCKET_PATCH_SERVER_HOST). It still allowscrate::origin::vendor_ref, whichplan::match_keyuses: that function is path grammar and applies no host policy.The merge also restores
crates/socket-patch-core/src/origin.rsto thelock-readersgroup. The earlier routine merge had dropped it. Counted with the fixed counter:That is 202 lines net below the base. The table in the Size budget section below is from the old counter.
Tests after the restack:
cargo test -p socket-patch-core --lib -- origin:: vex:: formats:: vendor::lock_inventory:: vendor::pnpm patch::redirect:: hosted::: 2,537 passed. That includes the golden test.--test in_process_redirect_pnpm: 41 passed.--test in_process_vendor_pnpm_takeover: 16 passed.test_loc_budget.py: OK.Size budget (
scripts/loc-budget.py --lower, then--check)Fixing the review findings and adding the N11 pin evidence grew the counts past this PR's first push (31,201 / 88,093), so I set the maxima to the new counts by hand in
scripts/loc-budget.json, then ran--lower. Both stay below the base's maxima.Tests
cargo test -p socket-patch-core --lib -- formats::pnpm vendor::pnpm vendor::lock_inventory:: vex::discover:: patch::redirect:: hosted:: vendor::pnpm_takeover utils::pnpm_workspace: 1,974 passed.vex::discover::testing::golden::tests::committed_fixture_corpus_matches_golden: passed.in_process_vendor_pnpm_takeover: 16 passedin_process_redirect_pnpm: 41 passedin_process_vendor_pnpm_parent_child: 8 passedin_process_vendor: 148 passedin_process_rollback_vendored: 23 passedscan: 248 passedhosted_memory_parity: 42 passedcargo clippy --locked --workspace --all-features -- -D warningsandcargo fmt --all -- --check: clean.e2e_vendor_pnpm_build,e2e_redirect_pnpm_build).Generated by Claude Code