Skip to content

Scan every vendored-write file for vendored references (#832, #958) - #1015

Merged
Mikola Lysenko (mikolalysenko) merged 6 commits into
mainfrom
arch-refactor/832-vendored-reference-scan
Oct 7, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 6 commits into
mainfrom
arch-refactor/832-vendored-reference-scan

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #832
Fixes #958

Summary

The vendored-reference scan (scan_vendor_references) is what keeps a .socket/vendor/<eco>/<uuid>/ unit with no ledger entry from being deleted while a project file still points at it. Every caller goes through it: repair (vendor_ledger_missing), the orphan sweeps (vendor --revert, the vendored gc), the vendor stranded-reference gate, and rollback's ledger-less gate. It missed NuGet, Maven and Hatch wiring for two reasons:

  1. Two notions of "a file a vendored run writes". The scan read registry::paths_with(VENDORED). nuget.config (all three spellings), packages.lock.json, pom.xml, .mvn/maven.config, hatch.toml and pnpm-workspace.yaml sat in a second list, VENDORED_WRITES_UNMARKED, that only the vendored dry run's symlink check (wiring_paths) read.
  2. The grammar. NuGet's feed (value=".socket/vendor/nuget/<uuid>") and Maven's repository (<url>file://${project.basedir}/.socket/vendor/maven/<uuid></url>) name the uuid directory itself, while parse_vendor_path requires a leaf. The scanner also had no < terminator.

Why (leverage)

B 2 (#832, #958: same root cause, per the fixer's "Shares root cause" comments), U 0, D ≈1 (two registry notions collapse to one role, and the second list is deleted), R M. Score ≈5, the best eligible candidate this run: every higher-ranked queue row is blocked by open PRs on commands/vendor.rs or by claims. Register rows E61 and E67 (register); living document doc/05-vendored.md, new findings E61/E67.

What changed

  • formats/registry.rs: the eight rows get the VENDORED role, and VENDORED_WRITES_UNMARKED is deleted. wiring_paths(eco) is now just ecosystem && VENDORED, and its output is unchanged for every ecosystem.
  • vendor/path.rs: new parse_vendor_reference, which is parse_vendor_path's grammar but also accepts an empty leaf (the bare uuid dir). parse_vendor_path is now parse_vendor_reference(..).filter(leaf non-empty), so there is one grammar and every existing caller is unchanged.
  • vendored_backend/repair.rs: the scan reads through parse_vendor_reference, and < ends a reference. A directory-wired unit reports the uuid dir as its path, with any trailing / trimmed.
  • utils/digest.rs (separate commit): ports the base-red fix that Honor HTTP-date Retry-After on vendor-service retries through api::retry (#677) #889 and Fix uv dry run missing inline [tool.uv] refusal (#979) #980 carry. main fails production_digests_go_through_the_helpers because sbt, Mill and scala-cli support in agent, hosted and vendored modes #690 migrated gradle_cache.rs, jvm_jar.rs and sidecars/maven.rs while the pending list still names them. It is the same three-line removal, and it no-ops once main carries it.

Deleted

git diff --stat origin/main, split at #[cfg(test)]:

  • production: +41 / −41 (VENDORED_WRITES_UNMARKED and its filter are gone; the grammar is shared)
  • tests: +255 / −0 (plus −3 in the digest ratchet list)

Behavior

These are the intended fixes:

  • With a missing ledger entry, a unit wired by nuget.config, pom.xml, hatch.toml, packages.lock.json, .mvn/maven.config or pnpm-workspace.yaml is now kept by the orphan sweeps (stillWired) instead of being deleted.
  • repair now reports such a unit as vendor_ledger_missing (exit 1) instead of finding no vendored traces.
  • The vendor stranded-reference gate and rollback's ledger-less refusal now see the same references.

Nothing else changes: wiring_paths returns the same files, and parse_vendor_path callers see the same results. Not done here: the dead eco == "maven2" arm of the stranded-reference gate in commands/vendor.rs, which is unreachable. That file is changed by #776 and #978, so the arm is left for a follow-up.

Test evidence

  • New tests:
    • repair_vendor_e2e::repair_reports_missing_ledger_for_nuget_maven_and_hatch_wiring (CLI, built binary): on main it fails with left: [] (no events); on this branch it passes with 3 vendor_ledger_missing events (maven, nuget, pypi).
    • vendored_backend::repair::tests::scan_recovers_unit_dir_and_hatch_toml_references: covers the NuGet dir with a trailing /, the backslashed NuGet.Config, Maven <url>…</url> and hatch.toml. It also checks that a bare maven/, the v5 maven2 tree and a non-uuid dir are still not references.
    • vendor::path::tests::parse_vendor_reference_accepts_the_uuid_dir_itself: parse_vendor_path still rejects the bare dir.
    • formats::registry::tests::the_reference_scan_and_the_symlink_check_read_the_same_files: paths_with(VENDORED) equals the union of wiring_paths over every ecosystem, and the NuGet and PyPI lists are pinned.
  • cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --lib: 5,559 passed. The 4 failures are the known root-only ones (copy_tree::relax_loop…, vlt_heal::an_unremovable…, pypi_poetry::wire_write_failure…, pypi_requirements::wire_failure…). The digest ratchet passes after the port.
  • cargo test -p socket-patch-cli --all-features --test <suite>:
    • passing: repair (125 + 1 new), in_process_vendor (120), in_process_remove_repair_lifecycle (23), remove (91), rollback (38), scan (118), vendor_crash_safety_e2e (6), vendor_jvm_cli (29), e2e_sbt_vendor (18), mode_migration_npm (19), mode_migration_cargo (9), apply (106), cli (92);
    • root-only failures in the sandbox: repair's 2 known chmod tests, and covgap_commands_vendor's 3 *_state_write_failure_* tests, which chmod 0o555 the vendor dir and are ineffective as root (51 others pass).

Risk

M. Where a project file references a unit, the orphan sweep now keeps it rather than deleting it, so the risk is that something is kept, not that something is lost. The new < terminator and the bare-dir form only add matches, and a match still needs a known ecosystem dir and a canonical uuid.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RcjbNmuocdNawny89vudHV


Note

Medium Risk
Changes which vendor units are considered “still wired” across repair, revert/prune, vendor, and rollback—generally retaining more dirs rather than deleting them; matching logic is additive (more files scanned, dir-level paths, < terminator) with uuid/ecosystem validation unchanged.

Overview
Fixes #832 and #958 by making the shared vendored-reference scan see NuGet, Maven, and Hatch wiring that was previously ignored.

Registry: NuGet configs, packages.lock.json, pom.xml, .mvn/maven.config, hatch.toml, and pnpm-workspace.yaml now carry the VENDORED role; the separate VENDORED_WRITES_UNMARKED list is removed so paths_with(VENDORED) and wiring_paths use one definition of “files a vendored run writes.”

Path parsing: New parse_vendor_reference accepts references to the uuid directory (no leaf), which NuGet feeds and Maven <url> use; parse_vendor_path still requires a leaf. scan_vendor_references uses the new parser, treats < as an XML terminator, and normalizes trailing slashes.

Behavior: Orphan sweeps, repair’s vendor_ledger_missing path, vendor stranded-reference checks, and rollback’s ledger-less gate now detect these wires instead of treating projects as unwired or deleting still-referenced vendor dirs.

Reviewed by Cursor Bugbot for commit ecfc1e7. Configure here.

Assisted-by: Claude Code:claude-opus-5-5
The vendored-reference scan behind repair, the orphan sweeps
(vendor --revert, the vendored gc), the vendor stranded-reference
gate and rollback's ledger-less gate read only the registry's
VENDORED rows, while the files NuGet, Maven, Hatch and pnpm vendoring
also write sat in a second list, VENDORED_WRITES_UNMARKED, that only
the dry run's symlink check used. NuGet's feed and Maven's repository
also name the uuid directory itself, which parse_vendor_path rejects.

So with a missing ledger entry, a NuGet or Maven unit, or a wheel a
hatch.toml environment installs, was deleted by the orphan sweep and
never reported by repair while the project still pointed at it.

The eight rows now carry the VENDORED role and the second list is
gone, so the scan and wiring_paths read one notion of "a file a
vendored run writes". parse_vendor_reference is parse_vendor_path's
grammar plus the bare uuid dir, and the scan reads through it, with
`<` ending a reference inside XML text. Fixes #832 and #958.

Assisted-by: Claude Code:claude-opus-5-5
main is red on production_digests_go_through_the_helpers: #690
moved gradle_cache.rs, jvm_jar.rs and sidecars/maven.rs onto the
utils::digest helpers, but PENDING_INLINE_DIGESTS still lists them,
and the ratchet fails on a stale entry. Same three-line change as
#889 and #980; it no-ops once main carries it.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 7, 2026 13:19
@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-cli/src/commands/vendored_backend/repair.rs
nuget.config and NuGet.Config are one file on a case-insensitive
file system (Windows, default macOS), so the second fixture write
replaced the first and the scan test could not see both uuids. The
backslashed NuGet.Config case now runs in its own temp project.

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

bugbot run

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

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] Ready for review at ecfc1e7.

  • CI on head: 421 passed, 6 skipped, 0 failed. Four vlt compatibility jobs failed on infra and passed when re-run once:
    • three install-proof (ubuntu-latest, …) jobs never got a runner ("failed to be acquired (5 attempts)");
    • native (macos-latest, 1.0.0-rc.14) hit transient vlt install exited 1: Request Error: Request failed network errors.
  • Conflicts: none. Fix main CI red on stale digest pending-list entries #1016 merged, so I merged origin/main in (fabe99a). The merge was clean, and the digest ratchet removal in this PR is now identical to main's, so digest.rs no longer shows in the diff. Another main merge then landed (ecfc1e7). The branch is still conflict-free against the latest main, and the merge doesn't touch the files this PR changes.
  • Fixes made: none needed.
  • Local validation after the merge:
    • production_digests_go_through_the_helpers and the registry / vendor::path tests pass;
    • vendored_backend::repair unit tests pass (10/10);
    • the repair integration suite passes (127/127);
    • cargo clippy --workspace --all-features -D warnings: the only error is an unused_variables in python_crawler.rs that only shows on macOS. It is already on main and outside this PR; CI's clippy job passes.
  • Bugbot: the earlier finding (case-insensitive NuGet.Config/nuget.config fixture) was fixed in 82185b8 and its thread is resolved. A re-run on ecfc1e7 found no issues.
  • Note for reviewers: the PR deliberately makes the orphan sweeps keep uuid dirs that are still referenced from nuget.config / pom.xml / hatch.toml / packages.lock.json / .mvn/maven.config / pnpm-workspace.yaml. wiring_paths output is unchanged for every ecosystem.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-refactor PR opened by the scheduled architecture refactor routine refactor Structural change: duplicated code or logic, missing abstraction, layering, dead code

Projects

None yet

3 participants