Skip to content

Fix yarn berry hosted pin of catalog deps (#632) - #763

Merged
Mikola Lysenko (mikolalysenko) merged 7 commits into
mainfrom
agent/fix-yarn-berry-catalog-resolutions
Oct 5, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 7 commits into
mainfrom
agent/fix-yarn-berry-catalog-resolutions

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 #632

Summary

scan --mode hosted now pins yarn berry dependencies declared through a yarn catalog ("left-pad": "catalog:"). Before this, the scan reported redirected: 1, but the next yarn install --immutable failed with YN0028 and a plain yarn install silently installed the unpatched release. This was a regression from #465.

Root cause

Since #465 the hosted yarn berry pin routes the lock entry's descriptors to the hosted tarball through root package.json resolutions, keyed name@npm:<range>. Those keys come from the lock key's expanded ranges in berry_resolutions_pin. Yarn matches resolutions against the manifest descriptor before it expands the catalog, so left-pad@npm:^1.3.0 never matches a dependency declared catalog: or catalog:<named>.

Fix

  • berry_resolutions_pin reads the .yarnrc.yml catalog: / catalogs: tables through the new berry_catalog_selectors (serde-saphyr). Some catalogs give the package a range that, normalized to yarn's npm: form, is one of the pinned ranges. For each of those, the pin also routes name@catalog: or name@catalog:<named> to the hosted tarball.
  • The catalog tables are read as string tables, so an unquoted range keeps its exact text (1.10 stays 1.10), the way yarn's failsafe schema reads .yarnrc.yml.
  • The npm: selectors stay: transitive dependents still ask for the expanded range, and rollback rebuilds the lock key from them.
  • Catalog selectors are derived from the final selector list. So a re-run over a pin written before this fix (lock already keyed by URL, only the npm: selector) adds the missing catalog selector and leaves the lock alone.
  • Rollback needs no change. It already drops every selector routed to the hosted URL and rebuilds the lock key from the npm: ones; a new test covers this.
  • A user-authored name@catalog: resolution still refuses with redirect_yarn_berry_resolutions_conflict.
  • docs/ecosystems.md: the yarn berry hosted notes now describe catalog pins.
  • The npm, PyPI and gem wrappers only dispatch to the binary, so they need no change.

Checked by hand with real yarn 4.12.0:

  • {"left-pad@npm:^1.3.0": X, "left-pad@catalog:": X} installs the patched bytes for a catalog: dependency, and --immutable passes.
  • On a project that defines the catalog but declares a plain range, the unused catalog: selector is harmless: the install gets the patched bytes and --immutable passes.

Per-issue checklist

Test evidence

  • Red to green: with the catalog lookup disabled, the new core tests fail, and so does the real-yarn e2e (no left-pad@catalog: selector). With the fix, all pass: cargo test -p socket-patch-core --lib -- yarn_berry gives 102 passed on 9abb2d9.
  • cargo test -p socket-patch-cli --test in_process_redirect -- yarn_berry: 7 passed.
  • SOCKET_PATCH_YARN_E2E_REQUIRED=1 cargo test -p socket-patch-cli --test e2e_redirect_yarn_berry_build: 15 passed against real yarn 4.12.0.
  • cargo test -p socket-patch-cli --lib: 840 passed on 454b068.
  • New code is rustfmt-formatted (cargo fmt --all -- --check also flags pre-existing code on main). cargo clippy --workspace --all-features -- -D warnings is clean.
  • An earlier full local cargo test --workspace --all-features --no-fail-fast run had 14 failures, all from the sandbox. 12 were chmod-based write-failure tests, which can't fail when running as root. 2 were mode_migration_npm fixtures whose registry download rejects the sandbox proxy's TLS certificate. CI runs these for real.

History

🤖 Generated with Claude Code

https://claude.ai/code/session_01DPHxnE5P1rkfCpHFFCwzFR


Note

Medium Risk
Changes hosted Yarn Berry lock/manifest rewrite and resolution selector planning; wrong catalog matching could break immutable installs or leave deps unpatched, but behavior is heavily tested and user pins are refused rather than overwritten.

Overview
Fixes #632: Yarn Berry hosted redirects now route catalog: dependencies to the patch tarball, not only the lock’s expanded npm: descriptors.

Yarn Berry hosted pin reads .yarnrc.yml catalog / catalogs tables and adds matching name@catalog: / name@catalog:<named> entries to root package.json resolutions alongside the existing npm: selectors (needed for transitive deps and rollback). Catalog ranges are matched as string source text (e.g. 1.10 ≠ 1.1). Re-runs are stable; older pins that only had npm: selectors get the catalog selector added without touching yarn.lock. User-authored catalog resolutions still fail closed.

Tests & docs: unit tests in redirect/mod.rs, in-process pin/rollback, and a real-yarn e2e for fresh yarn install --immutable with catalog deps; docs/ecosystems.md updated. vex_consumed npm alias tests are adjusted so alias expansion is still exercised after the name-keyed resolver (#605) returns fuller copy sets.

Reviewed by Cursor Bugbot for commit 454b068. Configure here.


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
A dependency declared "catalog:" in package.json was never patched
by scan --mode hosted: the resolutions entry was keyed by the lock's
expanded npm: range, but yarn matches resolutions before it expands
the catalog. The scan reported success, then yarn install --immutable
failed (YN0028) and a plain yarn install kept the unpatched release.

Also route name@catalog: / name@catalog:<named> for every
.yarnrc.yml catalog that maps the package to a pinned range. A re-run
adds the selector to a pin written by an earlier release.

Fixes #632

Assisted-by: Claude Code:claude-opus-5-5
Add a real-yarn check that a fresh checkout of a hosted-pinned
catalog dependency installs the patched bytes under --immutable,
an in-process scan + rollback round trip, and document catalog
pins in the yarn berry hosted notes.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 4, 2026 08:03
@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.

cargo fmt --all also reformatted 127 files this fix doesn't touch
(main isn't rustfmt-clean). Restore them and the untouched hunks of
the edited files to main, so the PR only carries the catalog fix,
its tests and the docs note.

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.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

One CI check failed on 55dc0cb: native (ubuntu-latest, 2.8.2), the PDM backtest. Only the optional hosted cell failed, on rescanIdempotent. The other 35 PDM cells passed, and so did the other 481 checks.

I don't think this PR caused it:

  • The PR only changes yarn berry code: berry_resolutions_pin and berry_catalog_selectors in patch/redirect/mod.rs, plus yarn tests and docs. The PDM pdm.lock path never calls that code.
  • The same job passed on f3f8ca1. That commit has the same fix code; 55dc0cb only reverts formatting in unrelated files.

I don't have a fix to port, because I haven't found a root cause in the PDM path. I've re-run the failed job once. If it fails again, I'll treat it as a real failure and dig in.


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 55dc0cb.

  • CI: 482/482 checks green on the current head. The earlier PDM rescanIdempotent failure did not come back on re-run.
  • Bugbot: reviewed 55dc0cb and found no issues. There are no unresolved review threads.
  • Mergeable: yes, no conflicts with main.
  • For the reviewer: the core change is berry_catalog_selectors / berry_resolutions_pin in patch/redirect/mod.rs. Catalog selectors are added next to the existing npm: selectors, and rollback is unchanged.

Generated by Claude Code

Resolve the docs/ecosystems.md conflict by keeping both changes: the
yarn catalog routing note from this branch and main's note on how the
re-keyed entry and its bin map are written. Also move the "#404 upgrade
path" doc line back onto its own test; the new catalog test had been
inserted in the middle of that comment.

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

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

One check failed on 2ab819a, the merge of main: composer 2.2.30 / php 8.3 / windows-latest.

This failure isn't caused by this PR. composer_vendor_v_tagged_fresh_checkout_install failed while setting up its fixture, before the test itself ran. The fixture's composer update call timed out reaching packagist:

curl error 28 while downloading https://repo.packagist.org/packages.json: Connection timed out after 10002 milliseconds

The PR's diff against main only touches yarn berry code, and the composer path never calls it. There's no code fix to port, because the problem was reaching the network. I'll re-run the failed job once when the rest of the workflow finishes; GitHub won't allow a re-run while the run is still going.


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/patch/redirect/mod.rs
berry_catalog_selectors parsed .yarnrc.yml catalogs into serde_json
Values, so an unquoted range like `1.10` became the number 1.1 and
never matched the lock's `npm:1.10`: the `catalog:` selector was
dropped while the pin was still confirmed. Yarn reads .yarnrc.yml with
the failsafe schema, so deserialize the catalog tables as string
tables instead, which keeps each scalar's source text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPHxnE5P1rkfCpHFFCwzFR
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

main fails commands::vex_consumed::tests::hosted_expands_alias_only_copies
and hosted_reuses_expanded_npm_copies_and_merges_alias_variants since
#605 landed alongside #738; #851 fixes the tests. Carry the same change
so this PR's CI (coverage, test-release) is green; it no-ops once main
has it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPHxnE5P1rkfCpHFFCwzFR
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

On 2ab819a, coverage and test-release both failed on the same two tests, which this PR doesn't touch:

  • commands::vex_consumed::tests::hosted_expands_alias_only_copies
  • commands::vex_consumed::tests::hosted_reuses_expanded_npm_copies_and_merges_alias_variants

main fails them too: I reproduced both failures locally on main at 6811b4e. They broke when #605 and #738 both landed on main. #851 fixes them, so I copied the same test change into this PR as 454b068, and all 840 socket-patch-cli lib tests now pass locally. That commit becomes a no-op once #851 merges.

454b068 sits on top of 9abb2d9, which fixes Bugbot's YAML-number finding. The composer … windows-latest packagist timeout on 2ab819a will be re-tested by this push's CI.


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.

@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 454b068. Configure here.

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

Copy link
Copy Markdown
Collaborator Author

Burn-down agent: labeled Ready for review at 454b068.

  • CI: 482 success + 6 skipped, 0 failing; mergeable clean against main.
  • Bugbot: Cursor Bugbot check passed on 454b068; 0 unresolved review threads.
  • Linked issue(s) still open and not fixed on main.

Generated by Claude Code

@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit 02d13c9 into main Oct 5, 2026
489 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-yarn-berry-catalog-resolutions branch October 5, 2026 17:26
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