Skip to content

Fix untagged Bun 1.3.0/1.3.1 lock dialect (#1521) - #1523

Merged
Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-bun-untagged-lock-dialect
Oct 14, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-bun-untagged-lock-dialect

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #1521

Summary

Bun 1.3.0 and 1.3.1 honour ! workspace exclusions, but socket-patch read their locks as pre-1.3 Bun. A project excluded from a Bun workspace with ! therefore couldn't be patched from either directory. The hosted scan was refused, the vendored scan failed, and the suggested root run reported success with nothing pinned. This PR makes the untagged lock's own workspace list decide which Bun wrote it.

Root cause

lock_dialect in crates/socket-patch-core/src/hosted/governing_root.rs works out whether a Bun root lock honours ! from a version tag alone: a top-level configVersion in bun.lock, or the cNfGvRsN trailer in bun.lockb (#1496). Bun 1.3.0 and 1.3.1 write neither tag (1.3.2 is the first release that does), so their locks read as pre-1.3, and package_json_workspace_root counted the excluded member as governed by the root lock. Both the hosted refusal (redirect_workspace_lockfile_elsewhere) and the vendored stray-lock check (member_stray_lock → vendor_lockfile_missing) go through that function.

Fix

New lock_lists_member helper. Only a directory that a ! pattern excludes reads differently between the two Bun dialects, and only an untagged lock is ambiguous. For that case:

  • If the lock lists the member, or any other !-excluded directory, it was written by Bun before 1.3, which lists every member it matched. The member is governed.
  • If it lists none of them, it is a 1.3.0/1.3.1 lock and the member is a standalone project.
  • If the list can't be read (unparseable or missing section), today's wider pre-1.3 reading is kept.

Workspace keys are normalized (./ prefix, \\ separators) before comparing. Real bun.lockb files written by Bun 1.2.23, 1.3.0 and 1.3.1 for the same ["packages/*","!packages/b"] root are added under tests/fixtures/bun-lockb/negated-workspace. They were generated with the official @oven/bun-linux-x64 builds; the text-lock outputs are inlined in the test.

Accepted trade-off: suppose a stale Bun 1.2 lock was last written before every !-excluded directory existed. Then it lists none of them and is read as 1.3.0/1.3.1, so the member is not refused. Nothing in such a lock tells it apart from a 1.3.0 lock. This matches 5.0.0, before #1480. The fix keeps the refusal whenever the lock lists any excluded directory.

Test evidence

  • untagged_bun_lock_reads_its_workspace_list (new). Covers 1.2.23 / 1.3.0 text locks and 1.2.23 / 1.3.0 / 1.3.1 binary locks: the hosted refusal, member_stray_lock (the vendored path), the unexcluded member packages/a (still refused), and that each verdict comes from a parsed list. Red without the fix: bun.lock of 219 bytes: left: Some("redirect_workspace_lockfile_elsewhere") right: None. Green with it.
  • untagged_bun_lock_listing_any_excluded_dir_is_pre_1_3 (new): the per-lock decision and ./ key normalization.
  • bun_lockb_with_a_config_version_tag_honours_negated_workspaces: the untagged 1.2.23 row now uses the real 1.2.23 lock for this workspace (it lists packages/b; still refused). The old fixture was a non-workspace project lock.
  • bun_config_version_is_read_at_the_top_level_only: its pre-1.3 lock now lists packages/b, as a real one does, so the test still checks only that a nested configVersion isn't read as the tag.
  • VEX discovery golden regenerated for the new fixture directory (empty entries).

Commands run locally:

  • cargo fmt --all -- --check and cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --all-features --lib: 6473 passed. The 5 failures were the 4 chmod-based tests that don't hold under root in this sandbox (copy_tree, vlt_heal, pypi_poetry, pypi_requirements) plus the golden corpus, now regenerated.
  • in_process_redirect_pnpm (38), in_process_vendor_bun_takeover (40), mode_migration_bun (35): all pass.
  • e2e_bun_lockb: 23/24. binary_shared_bundled_record_hosted_pin_is_managed needs patches-api.socket.dev, which the sandbox can't reach; it doesn't touch this code path.
  • A full cargo test --workspace ran out of the sandbox's disk, so CI covers the rest.

No wrapper (npm/, pypi/, gem/) changes: they only dispatch to the binary.

Per-issue checklist

/code-review high

Fixed: per-lock version decision, key normalization, the shared read_regular_to_bytes helper, and the stale WorkspacesDialect docs. Not fixed: (1) the stale-1.2-lock case above, which can't be told apart from the lock bytes; (2) the repeated lock reads. They happen only for a !-excluded member under an untagged Bun lock, so caching isn't worth the extra code.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FEZwdsnHoJB8vCKkMFipaY


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
Bun 1.3.0 and 1.3.1 already skip workspace members excluded with a `!`
pattern, but their bun.lock / bun.lockb carry no config-version tag, so
socket-patch read them as older Bun and still counted the excluded
member as part of the root workspace. Hosted scans from that member
were refused (redirect_workspace_lockfile_elsewhere), vendored scans
failed with vendor_lockfile_missing, and the suggested root run pinned
nothing.

For an untagged Bun lock, an excluded directory now counts as a member
only when the root lock actually lists it: Bun before 1.3 lists every
member it matched, while 1.3.0/1.3.1 leave an excluded one out. An
unreadable lock keeps the old, wider reading. Adds real 1.2.23, 1.3.0
and 1.3.1 binary locks as fixtures.

Fixes #1521

Assisted-by: Claude Code:claude-opus-5-5
Asserts the verdict comes from the members each real lock lists rather
than from a lock that failed to read, and records the new
negated-workspace fixture in the VEX discovery golden corpus.

Refs #1521

Assisted-by: Claude Code:claude-opus-5-5
An untagged Bun lock that lists any `!`-excluded directory comes from
Bun before 1.3, so every excluded directory under it now counts as a
member, including one added since the last install. Workspace keys
spelled with a `./` prefix or backslashes are normalized before the
comparison, the binary lock is read through the shared file helper,
and the dialect docs describe the 1.3.0/1.3.1 case.

Refs #1521

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

✅ 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 ea8578d. Configure here.

Merged via the queue into main with commit b4b8e4b Oct 14, 2026
86 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-bun-untagged-lock-dialect branch October 14, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants