Skip to content

Fix pnpm 7/8 vendored specifier YAML quoting (#754) - #755

Merged
Mikola Lysenko (mikolalysenko) merged 5 commits into
mainfrom
agent/fix-pnpm-legacy-specifier-yaml-quote
Oct 5, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 5 commits into
mainfrom
agent/fix-pnpm-legacy-specifier-yaml-quote

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #754

Summary

Vendoring a pnpm 7/8 project (lockfile 5.4 / 6.0) writes the project's
absolute path into pnpm-lock.yaml as the root dependency's
specifier. When that path contained # or : (e.g.
~/src/My Project #2), the value was written unquoted, so YAML cut it
short at # or rejected the line at : . Every
pnpm install --frozen-lockfile then failed at the very path the
lock was written for, while vendor reported success. The specifier
is now written the way pnpm itself writes it: plain when safe,
single-quoted otherwise (double-quoted with escapes for characters
single quotes can't carry).

Root cause

vendor/pnpm_lock_legacy.rs spliced file:<abs root>/<tgz> into the
specifiers: line (5.4) and the nested specifier: line (6.0) with
format!, never encoding it as a YAML scalar. The in-sync checks
compared that same raw text, so a re-run agreed with the broken write.

Changes

  • formats/pnpm/lines.rs: new yaml_value, which spells a mapping
    value the way pnpm's writer (js-yaml dump) does.
  • vendor/pnpm_lock_legacy.rs: both specifier writers and their
    in-sync checks use the encoded spelling. Ownership checks read the
    unquoted value. Revert recognizes our own value in quoted form too.
  • A lock that an older release left broken (the unquoted spelling) is
    not treated as in sync. Re-running vendor rewrites it to the
    quoted spelling, records no "original" for our own stale value, and
    the first ledger entry still reverts byte-for-byte.

Test evidence

Issue Test Without fix With fix
#754 (5.4 + 6.0, # and : ) pnpm_lock_legacy::tests::absolute_specifier_is_yaml_quoted_under_indicator_paths FAIL (specifier written unquoted) pass
#754 (heal a lock broken by an older release) pnpm_lock_legacy::tests::unquoted_absolute_specifier_from_an_older_release_is_healed FAIL (broken lock treated as in sync) pass
#754 (real pnpm 7.33.5) e2e_vendor_pnpm_build::pnpm7_real_lifecycle_under_yaml_indicator_paths FAIL ERR_PNPM_OUTDATED_LOCKFILE pass
#754 (real pnpm 8.15.9) e2e_vendor_pnpm_build::pnpm8_real_lifecycle_under_yaml_indicator_paths FAIL ERR_PNPM_OUTDATED_LOCKFILE pass
encoder formats::pnpm::lines::tests::yaml_value_* (plain-safe cells from the issue's matrix stay plain) n/a pass

The e2e legs run the existing legacy capstone (vendor, same-path
--frozen-lockfile --offline install of the patched bytes, moved
checkout, idempotent re-vendor, byte-exact revert) in hash #x and
colon: x project dirs (colon: x on unix only: Windows forbids : in a
path component). The red runs used this branch's tests with
origin/main's writer.

Commands run locally (Linux):

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo test -p socket-patch-core --lib -- pnpm_lock_legacy formats::pnpm: 80 passed
  • cargo test -p socket-patch-cli --test e2e_vendor_pnpm_build -- real_lifecycle: 4 passed
  • cargo test --workspace --all-features --no-fail-fast: the only failures are
    the permission and self-update tests that fail when run as root in this
    sandbox (chmod-0555 / unremovable-file write-failure cases, self-update
    lock/state-dir legs). None touch pnpm; CI runs them as non-root.

No wrapper changes: this is Rust-only lock surgery, and the npm, pypi
and gem wrappers only dispatch to the binary.

Notes

🤖 Generated with Claude Code

https://claude.ai/code/session_01WrJKfSVrc5xqCq2bHEQsUA


Note

Medium Risk
Changes how pnpm 7/8 lockfiles are rewritten and reconciled; mistakes could corrupt locks or mis-detect drift, but scope is limited to legacy vendoring and is heavily tested.

Overview
Fixes #754: vendoring on pnpm 7/8 (lockfile 5.4 / 6.0) used to splice the machine-absolute file: root specifier into pnpm-lock.yaml as a plain scalar. Paths containing YAML trouble spots ( #, : ) then broke the lock (ERR_PNPM_OUTDATED_LOCKFILE / broken lockfile) even though vendor reported success.

Adds yaml_value in formats/pnpm/lines.rs to spell mapping values like pnpm’s js-yaml writer (plain when safe, single-quoted for indicators, double-quoted for non-printables). The legacy lock writer uses it for 5.4 specifiers and 6.0 root specifier: lines, compares in-sync state against the encoded form, and teaches revert/drift to treat quoted spellings as ours. Re-vendor heals locks an older release left unquoted (not “in sync”) without recording our stale value as the user’s original.

Tests: unit tests for the encoder; pnpm_lock_legacy fixtures under hash #x / colon: x dirs; e2e legacy capstone runs with a configurable project dir name (unix-only for : paths on Windows).

Reviewed by Cursor Bugbot for commit ca37b7e. Configure here.


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
Vendoring on a pnpm 7/8 lock writes the project's absolute path into
pnpm-lock.yaml. When that path contained " #" or ": " (for example
"My Project #2"), it was written unquoted, so YAML cut it short or
rejected the line and every frozen install failed while vendor
reported success.

The specifier is now spelled the way pnpm itself writes it: plain
when safe, single-quoted otherwise. Re-running vendor heals a lock an
older release left broken, and revert still restores the original
bytes.

Fixes #754

Assisted-by: Claude Code:claude-opus-5-5
Adds end-to-end legs that vendor with real pnpm 7.33.5 and 8.15.9 in
project directories named "hash #x" and "colon: x", then require the
same-path frozen offline install to land the patched bytes. Without
the quoting fix both fail with ERR_PNPM_OUTDATED_LOCKFILE.

Refs #754

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 4, 2026 07:06
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

1 similar comment
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread crates/socket-patch-core/src/vendor/pnpm_lock_legacy.rs Outdated
Windows does not allow ":" in a directory name, so the #754 tests
that create a "colon: x" project dir would fail there before testing
anything. Those cases now run on Linux and macOS only; the " #" case
still runs everywhere.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

The quoting commit reformatted 130 files outside the fix, which buries
the real change and conflicts with every other open PR touching those
files. Restore them to main; the fix itself (pnpm_lock_legacy.rs,
formats/pnpm/lines.rs, e2e_vendor_pnpm_build.rs) is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ca37b7e. Configure here.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] e2e (ubuntu-latest, e2e_vendor_jvm_build, 8.14.3, 17, --ignored gradle_multi_project) failed on ca37b7e before the test itself ran. Setup could not seed the Maven repo because Maven Central (repo.maven.apache.org) returned 403 Forbidden for maven-dependency-plugin:3.6.1.pom. This PR changes only pnpm 5.4/6.0 lock writing (formats/pnpm/lines.rs, vendor/pnpm_lock_legacy.rs, the pnpm e2e file), and that check passed on this PR's previous head (2595524). No fix exists to port: the failure comes from Maven Central, not the repo. I'll re-run the job once when the current workflow run finishes.


Generated by Claude Code

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 4, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Ready for review at ca37b7e.

  • CI: 408/408 green. One gradle_multi_project e2e leg (ubuntu, Gradle 8.14.3) failed on the first run. It's unrelated to this diff, which touches only pnpm files, and it passed on re-run.
  • Bugbot: reviewed ca37b7e, no findings. The one earlier thread is resolved and outdated.
  • What changed in this pass: commit 85a2a38 had run cargo fmt --all, which reformatted 130 files that have nothing to do with the fix. I restored those files to main in ca37b7e, so the PR now touches just 3 files: vendor/pnpm_lock_legacy.rs, formats/pnpm/lines.rs (new yaml_value helper) and tests/e2e_vendor_pnpm_build.rs. Locally, the core pnpm unit tests (303) and e2e_vendor_pnpm_build pass.
  • Reviewer focus: check that yaml_value / is_plain_safe match js-yaml's plain-scalar rules. That decides whether a vendored file: specifier is written plain or single-quoted.

Generated by Claude Code

@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit 809561c into main Oct 5, 2026
608 of 609 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-pnpm-legacy-specifier-yaml-quote branch October 5, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

3 participants