Repository navigation
Vendored-reference scan never sees NuGet or Maven wiring, so the orphan sweep deletes a still-wired unit #832
Description
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.
Kind: bug. Source: new finding, register E61 (related to the backend-trait tracking row E21).
Problem
scan_vendor_references is the one check that keeps a .socket/vendor/<eco>/<uuid>/ directory with no ledger entry from being deleted while a project file still points at it. It is used by the orphan sweeps (vendor --revert, the vendored gc pass), by repair (vendor_ledger_missing), by vendor (vendor_ledger_entry_missing) and by rollback. It recognizes NuGet and Maven wiring in neither of the two ways it would need to:
-
The file list. It reads
registry::paths_with(VENDORED)(repair.rs#L100-L104).`` The threenuget.configspellings and `pom.xml` are `HOSTED | PROBE`, without `VENDORED` (`registry.rs#L123-L125`, `#L142`). Yet those are exactly the files the NuGet and Maven vendored backends rewire. -
The reference grammar. Even if the files were read, both backends point at the uuid directory, not at a leaf inside it:
- NuGet:
<add key="…" value=".socket/vendor/nuget/<uuid>" />(nuget_feed.rs#L950); - Maven:
<url>file://${project.basedir}/.socket/vendor/maven/<uuid></url>(maven_repo.rs#L1644).
parse_vendor_pathrequires a non-empty leaf after the uuid (path.rs#L102-L108), and the scanner's terminator set has no<(repair.rs#L73-L77),`` so…/maven/<uuid></url>doesn't parse either. - NuGet:
Meanwhile sweep_vendor_dirs does enumerate nuget/ and maven/ (ECOSYSTEM_DIRS), and sweep_orphan_vendor_dirs deletes every unrecorded unit the scan didn't report (vendor.rs#L294-L333). Its doc comment states the invariant this breaks: "Deleting such a dir would break the next install, so every candidate is checked against the wiring-bearing files first".
Also dead: the vendor stranded-reference gate matches eco == "maven2" (vendor.rs#L2134-L2139), but parse_vendor_path only ever yields maven.
Proof by execution (a throwaway #[tokio::test] in commands/vendor.rs, run twice on 045d7ec, then removed). It uses an empty VendorState, one artifact file in the uuid dir, and the backend's own wiring text:
PROBE nuget: refs=[] still_wired=0 removed=1 artifact_exists=false
PROBE maven: refs=[] still_wired=0 removed=1 artifact_exists=false
PROBE npm: refs=[("npm", "1a2b…", ".socket/vendor/npm/1a2b…/left-pad-1.3.0.tgz")] still_wired=1 removed=0 artifact_exists=true
The npm control is kept as still wired; the NuGet and Maven units are deleted while nuget.config / pom.xml still name them.
Symptoms
None filed. When a NuGet or Maven ledger entry is missing (state.json lost, a partial commit, or a merge that drops a row: the case the sweep guards against for every other ecosystem):
vendor --revertand the vendored gc delete the feed or repository, and the nextdotnet restore/mvnfails with a missing source;repairreports nothing (novendor_ledger_missing);vendorre-vendors without thevendor_ledger_entry_missingrefusal.
Impact: destructive, but it needs a missing ledger entry first. Small fix.
Proposed change
- Give the NuGet config spellings and
pom.xmltheVENDOREDrole (check every reader ofpaths_with(VENDORED)/has(VENDORED)first). The Maven reactor's module poms live below the root, so add them the waywiring_filesalready adds the dynamic sets (vlt importers, requirements includes), or from the ledger's recorded wiring files. - Recognize a uuid-directory reference: a
parse_vendor_dir_ref(or an optional leaf inparse_vendor_path) that yields(eco, uuid)for.socket/vendor/<eco>/<uuid>terminated by",<or end of value, and add<to the scanner's terminators. Repair can fall back to the uuid dir as the path for these. - Delete the dead
eco == "maven2"arm. - Longer term, E21 (the
VendorBackendtrait) should own "which files carry my references and how they are spelled", so that this table can't drift from the writers again.
Size and scope
formats/registry.rs, vendor/path.rs, commands/vendored_backend/repair.rs, commands/vendor.rs; under ~80 production lines. The Gradle tree (.socket/vendor/gradle/) is outside ECOSYSTEM_DIRS and out of scope. The registry role change must not widen hosted reads (HOSTED is unchanged).
Acceptance criteria
-
scan_vendor_referencesreports(nuget, uuid)for a vendorednuget.config(all three spellings) and(maven, uuid)for a vendored rootpom.xmland a reactor module pom. -
sweep_orphan_vendor_dirswith an empty ledger keeps such units instill_wired(regression test mirroringorphan_sweep_keeps_include_referenced_dir), and still removes them once the reference is gone. -
repairreportsvendor_ledger_missingfor a NuGet/Maven reference with no ledger entry. -
scan_ignores_non_vendor_socket_mentionsand the existing repair/orphan tests stay green, and the vendored NuGet/Maven e2e suites pass.
Dependencies
None. It touches nuget_feed.rs and maven_repo.rs only for tests. Coordinate with #597 (hosted NuGet) only if it changes registry.rs.
Activity
audit-ecosystems: file E20 (#833, #834), E18 (#835), new E61 (#832)
mikolalysenko commentedon Oct 5, 2026
[agent] Triaged as priority:p3 (NuGet/Maven). Not a duplicate, and no open PR covers it.
Generated by Claude Code
mikolalysenko commentedon Oct 6, 2026
[agent] Related: #958 is the same file-list gap for
hatch.toml. It is listed inregistry::VENDORED_WRITES_UNMARKEDbut has noVENDOREDrole, so the orphan sweep deletes a wheel that ahatch.tomlenvironment still names (executed twice on9c43dfc). If this fix makesscan_vendor_referencesreadwiring_paths(every file a vendored run writes) instead ofpaths_with(VENDORED), it closes #958's half too. Re-checked on9c43dfc: the file list and the uuid-directory grammar gap described above are unchanged.Generated by Claude Code
mikolalysenko commentedon Oct 6, 2026
[agent] Shares root cause with #958:
scan_vendor_referencesreads onlyregistry::paths_with(VENDORED), not every file a vendored run writes (wiring_paths). Will be fixed together (this issue additionally needs the NuGet/Maven uuid-directory grammar).Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Claiming this issue for the architecture refactor routine (highest leverage: one registry notion of "a file a vendored run writes" plus one uuid-unit grammar closes #832 and #958 together and deletes
VENDORED_WRITES_UNMARKED). Branch: arch-refactor/832-vendored-reference-scan. Claim-ID: 2026-10-07T12:56:20Z-90d5b6Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
[agent] Draft PR: #1015 (fixes this and #958).
Generated by Claude Code
Scan every vendored-write file for references
refactor: record #886, open #1015 (#832, #958)