Skip to content

Fix vlt extglob workspace members (#1542) - #1555

Merged
Mikola Lysenko (mikolalysenko) merged 5 commits into
mainfrom
agent/fix-vlt-workspace-extglob
Oct 15, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 5 commits into
mainfrom
agent/fix-vlt-workspace-extglob

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #1542

Summary

A vlt workspace member listed through an extglob (packages/+(a|b), packages/@(a|b)) wasn't recognised as a member. Hosted and vendored runs from it wrote a stray lock or package.json that vlt never reads, exited 0, and vendored VEX attested not_affected for a pristine install. Hosted and vendored runs now refuse such a member the same way they already refused one listed by packages/* (#1134 / #1161).

Root cause

WorkspacesDialect::VLT (crates/socket-patch-core/src/utils/workspace_globs.rs) turned extglobs off and read ! patterns last-match-wins. I probed real vlt to see what it actually lists (vlt install then vlt query ':workspace') and read its bundled Monorepo#glob:

vlt 1.3.8 vlt 1.2.0
extglobs +(..), @(..), ?(..), *(..), !(..) match match
wildcards over .dir components no (packages/* skips packages/.h) no
["!packages/a","packages/*"] a excluded a listed
["packages/*","!packages/a","packages/a"] a listed (relisted) a listed
["!packages/*","packages/a"] a listed a listed
["packages/a","!packages/*"] a excluded a listed
["!!packages/a"] a listed nothing
["!(apps)/a"] nothing (a negation) packages/a (an extglob)
named groups each group globbed on its own same

vlt 1.3's splitNegatedPatterns moves a ! pattern into an ignore list, and a later positive pattern drops any ignore that its own text matches. vlt 1.2 globs every pattern as given, so a leading ! is literal. Neither reading is the old last-match-wins one, and the issue's suggested Negation::Unordered would also be wrong, because relisting works.

Fix

  • workspace_globs.rs: VLT is now extglob: true, dot: false, Negation::Relisted (1.3's rule). A new VLT_PRE_1_3 uses Negation::Literal. A new dot field on the dialect keeps every other dialect at true, so their behaviour is unchanged.
  • governing_root.rs: vlt_lists_member evaluates each vlt.json group separately. Both vlt versions write the same vlt-lock.json, so when they disagree on a directory, the root lock's workspace~<path> edge sources decide which version wrote it. vlt records an edge from every installed member that has a dependency. This is the same approach as the Bun 1.3 split (Bun 1.3.0 and 1.3.1 locks have no configVersion, so a "!"-excluded member is still refused in hosted and vendored mode after the #1492 fix (regression since #1480) #1521). An unreadable lock keeps the wider reading. It's used by the vlt.json walk (vlt_workspace_root) and by the package.json fallback (lock_lists_member), so the hosted refusal, member_stray_lock (vendored vendor_lockfile_missing, VEX discovery) and nested_npm_project all pick it up.
  • A nearer vlt.json with no lock that excludes the member no longer stops the root walk. This came from the /code-review high pass.

No wrapper (npm/, pypi/, gem/) changes: membership is decided only in core.

Tests (red → green)

Issue Test Before fix After
#1542 extglob member, hosted governing_root::tests::vlt_extglob_member_is_refused (both patterns × vlt.json / package.json fallback × with/without stray lock) FAILED ok
#1542 extglob member, vendored npm_flavor::tests::bun_and_vlt_members_with_stray_lock_are_refused (+2 extglob rows) n/a (same member_stray_lock path) ok
#1542 hosted CLI scan/get in_process_redirect_pnpm::hosted_scan_from_bun_or_vlt_member_with_stray_lock_refuses (+2 extglob rows) n/a ok
#1542 vlt grammar table (probe rows above) workspace_globs::tests::vlt_dialects_list_what_vlt_lists, negation_is_per_dialect FAILED ok
#1542 negation ordering via lock governing_root::tests::vlt_negated_member_reads_the_root_lock FAILED ok
groups / nested walk vlt_negation_stays_in_its_group, vlt_excluded_by_an_uninstalled_inner_root_walks_on guards ok

The red run used a placeholder VLT_PRE_1_3 = VLT on top of main: 4 of 5 new tests failed. The 5th (groups) guards against the new negation rule leaking across groups.

Local runs:

  • cargo fmt --all -- --check and cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --all-features --lib: 6504 passed, 4 failed. The 4 failures (copy_tree::relax_loop_must_not_traverse_symlinked_root, vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry, pypi_poetry::wire_write_failure…, pypi_requirements::wire_failure_rolls_back…) are chmod-based tests that can't fail as root in this sandbox, and they're unrelated to this change.
  • cargo test -p socket-patch-cli --all-features (--lib, in_process_redirect_pnpm, in_process_vendor, mode_migration_vlt, e2e_vlt, in_process_vendor_npm_v1_takeover): all pass.
  • I didn't run the full cargo test --workspace: building every test binary ran this container out of disk. CI runs it.

Follow-ups

  • vlt also drops a member nested inside another member (Monorepo#globOptions). That's not modelled here; it only matters for nested member layouts.

🤖 Generated with Claude Code


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
vlt expands extglobs in workspaces and reads ! patterns differently
from npm (1.3 drops excluded dirs wherever the ! sits until a later
pattern relists them; 1.2 reads a leading ! literally). These tests
pin what vlt 1.2.0 and 1.3.8 actually list (#1542).

Assisted-by: Claude Code:claude-opus-5-5
A vlt workspace member listed through an extglob such as
packages/+(a|b) was not seen as a member, so hosted and vendored runs
from it wrote a stray lock vlt never reads, exited 0, and vendored VEX
attested not_affected for a pristine install.

The vlt dialect now matches what vlt 1.2.0 and 1.3.8 list: extglobs
match, wildcards skip dot dirs, each named group globs on its own, and
! patterns follow vlt 1.3 (excluded wherever they sit until a later
pattern relists them) or vlt 1.2 (read literally). Both write the same
lock, so the root lock's member edges decide which one applies.

Fixes #1542

Assisted-by: Claude Code:claude-opus-5-5
Hosted scan/get and the vendored engine both refuse a vlt workspace
member listed through packages/+(a|b) or packages/@(a|b) that holds a
stray vlt-lock.json, as they already did for packages/* (#1542).

Assisted-by: Claude Code:claude-opus-5-5
A nearer vlt.json that excludes the member with a ! pattern and has no
lock of its own stopped the root search, so an outer root that lists
the member no longer refused the run. Only a root that the current vlt
lists the member under now ends the walk. The relist check also splits
paths on both separators, like the matcher.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 15, 2026 01:22
@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 fcfe72a. Configure here.

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

Copy link
Copy Markdown
Collaborator Author

Ready for review (burn-down agent)

  • Head: fcfe72a21faf0847ecd34caf3e6d3113a371394f
  • CI: 36/36 green, 50 path-skipped; no failures.
  • Bugbot: reviewed fcfe72a and found no new issues; no open review threads.
  • Mergeable against main; already approved by Tanmay Singla (@Tanmay182003) on this head.
  • For reviewers: the vlt 1.2-vs-1.3 negation split is decided from the root vlt-lock.json edges (governing_root.rs), and nested-member exclusion is left as a noted follow-up.

Generated by Claude Code

Merged via the queue into main with commit b1310ba Oct 15, 2026
86 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-vlt-workspace-extglob branch October 15, 2026 02:57
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