You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tracking: derive scan candidates, lock entries and hosted refs from one project inventory instead of four discovery systems #1112
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.
Kind: tracking. Source: §2.1, Part 6.2 and 6.7 of the October 2026 review; register E36.
Problem
On main @ ea09714, "which packages does this project have" is still answered by four discovery systems. Each has its own record type, and they are joined in the CLI by converting everything to CrawledPackage:
CrawledPackage (installed copies, plus whole machine caches: #595)
B. Lock inventory
inventory_project*,`` with two modes Instances::Collapsed / `Instances::Every`
LockfileEntry (ecosystem: &'static str)
C. Wiring discovery
discover_with_ctx,`` with 15 extractors and three contest passes
Discovery { refs: Vec<PatchedRef>, elsewhere, … }
D. Vendor-ledger supplement
vendored_ledger_supplement
fabricated CrawledPackages
How they are joined:
B and D are turned into fake installed packages.crawled_from_purl sets path: cwd.join("node_modules").join(name_part) for every ecosystem, including cargo, pypi, gem and golang.
Consumers have to know which paths are fake.scan/mod.rs#L1807-L1835 builds a side set, supplement_purls, only so that the PATH-scope filter (#L1926-L1962) can skip them. The "not installed" partition is a third set, lockfile_only.purls, consulted through lockfile_only_contains in four places (scan/mod.rs 801, 2821, 3121; discovery.rs 299). apply.rs computes its own set through lockfile_resolved (apply.rs 2018) and threads it through 1022-1417.
Liveness reads B a third time from disk.vex/discover/mod.rs#L1896-L1898 calls inventory_project_every_lock(root) rather than the run's ProjectView.
vex::discover is really the hosted-state store. It is imported by 42 files outside vex/, including formats/{composer,pnpm,gem,cargo,registry,mod}.rs (a formats → vex edge), patch/redirect/*, vendor/*, rollout.rs, ledgers.rs, and the scan, get, apply, vendor and rollback commands.
Target design
There is one core inventory module that owns a single instance model. Every other view is derived from it:
structInstance{purl:CanonicalPurl,declared_in:Option<Rel>,// which lock/manifestresolution:Registry{url, integrity, source_kind }
| Hosted{ uuid, url, integrity, required }
| Vendored{ uuid, artifact_rel, integrity }
| Other,
installed_at:Vec<PathBuf>,// filled by locators (ex-crawlers); empty = not installed}
LockfileEntry becomes the Registry instances after precedence and dedup. PatchedRef/HostedPin become the Hosted and Vendored instances. ResolvedElsewhere becomes Registry plus Other.
Scan candidates are instances. "Not installed" is installed_at.is_empty(), so no fabricated path and no side sets are needed.
The PATH-scope warning path_scope_excluded_supplements exists only because the supplement's paths are fake.
Impact
This is the root of the discovery overlap described in Part 6.2. Each new consumer must remember the side sets, and each new ecosystem must be taught to all four systems. Total size is large, so it lands as the children above.
Acceptance criteria
Each checklist item lands as its own PR that deletes the code it replaces.
cargo test -p socket-patch-core --lib and the CLI scan, vex and vendor e2e suites stay green at every step.
Blocks the E32 single hosted pipeline, which needs one instance source.
Consolidated work — backlog review, 2026-10-08
The following standalone issues are now tracked here. Their closure consolidates scheduling; it does not mean their implementation is complete. Original reports and discussion remain linked below.
#1113: Carry scan's lockfile-only and vendored-ledger candidates without a fabricated node_modules path
Alternatively, keep CrawledPackage for crawler output only and carry the supplement as purl-only records beside it.
The PATH-scope filter matches Installed only. "Not installed" is matches!(c, Candidate::LockOnly { .. }).
Delete:crawled_from_purl, supplement_purls and the LockfileSupplement::packages / LedgerSupplement::packages vectors of fabricated packages.
Keep lockfile_only.purls only where API-spelled purls are matched (lockfile_only_contains bridges the percent-encoding and composer padding). Where the candidate itself is at hand, derive the answer from the candidate.
No behavior change: same JSON (lockfileOnlyPackages, notInstalled, the [NOT INSTALLED] marker, path_scope_excluded_supplements), same exit codes.
Size and scope
crates/socket-patch-cli/src/commands/scan/{mod.rs,discovery.rs}, plus any scan helper typed on &[CrawledPackage] that receives supplements. Estimate about 150–300 changed production lines.
Out of scope: the core inventory model (later children of the tracking issue), apply.rs's own lockfile_resolved set, and crawler changes.
Acceptance criteria
crawled_from_purl and supplement_purls are deleted, and no CrawledPackage is constructed in commands/scan/ outside tests.
The existing scan/discovery.rs unit tests (ledger_supplement_*, corrupt_ledger_*) are ported and green.
The CLI scan e2e suites stay green, including scan_paths_e2e (path scope and the path_scope_excluded_supplements warning), the lockfile-only/notInstalled tests, and the vendored-ledger fresh-clone tests.
A regression test: a path-scoped scan over a project with a lockfile-only cargo or pypi package excludes it with the counted warning, and never treats <cwd>/node_modules/<name> as its location, even when such a directory exists.
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.
Kind: tracking. Source: §2.1, Part 6.2 and 6.7 of the October 2026 review; register E36.
Problem
On main @
ea09714, "which packages does this project have" is still answered by four discovery systems. Each has its own record type, and they are joined in the CLI by converting everything toCrawledPackage:crawl_every_ecosystemCrawledPackage(installed copies, plus whole machine caches: #595)inventory_project*,`` with two modesInstances::Collapsed/ `Instances::Every`LockfileEntry(ecosystem: &'static str)discover_with_ctx,`` with 15 extractors and three contest passesDiscovery { refs: Vec<PatchedRef>, elsewhere, … }vendored_ledger_supplementCrawledPackagesHow they are joined:
crawled_from_purlsetspath: cwd.join("node_modules").join(name_part)for every ecosystem, including cargo, pypi, gem and golang.scan/mod.rs#L1807-L1835builds a side set,supplement_purls, only so that the PATH-scope filter (#L1926-L1962) can skip them. The "not installed" partition is a third set,lockfile_only.purls, consulted throughlockfile_only_containsin four places (scan/mod.rs801, 2821, 3121;discovery.rs299).apply.rscomputes its own set throughlockfile_resolved(apply.rs2018) and threads it through 1022-1417.vex/discover/mod.rs#L1896-L1898callsinventory_project_every_lock(root)rather than the run'sProjectView.vex::discoveris really the hosted-state store. It is imported by 42 files outsidevex/, includingformats/{composer,pnpm,gem,cargo,registry,mod}.rs(aformats→vexedge),patch/redirect/*,vendor/*,rollout.rs,ledgers.rs, and the scan, get, apply, vendor and rollback commands.Target design
There is one core
inventorymodule that owns a single instance model. Every other view is derived from it:LockfileEntrybecomes the Registry instances after precedence and dedup.PatchedRef/HostedPinbecome the Hosted and Vendored instances.ResolvedElsewherebecomes Registry plus Other.installed_at.is_empty(), so no fabricated path and no side sets are needed.--globaland lockless projects; the project-scoping half is Tracking: scope project-mode cache crawls to what the project resolves #595.Ordered checklist
crawled_from_purlandsupplement_purls(CLI only).ProjectView/DiskSnapshotinstead of re-reading every lock from disk withinventory_project_every_lock(root). This waits on Decide vendored-entry liveness through one discovery verdict #1050, which rewrites liveness.Instances::{Collapsed, Every}into one every-instance walk plus acollapse()pass, so each format has one walk.LockfileEntryand the neutral lock types toformats/inventory(Move LockfileEntry, LockIntegrity, SourceKind and http_url from vendor::lock_inventory into formats::entry #834, child of Tracking: move the pure lock codecs and neutral lock types into formats/ so formats imports nothing from vendor or redirect #833).vex::discoverto the hosted-state store (hosted::stateorinventory::wiring). This is a mechanical move with re-exports, done after the redirect split (Tracking: split patch/redirect/mod.rs into per-ecosystem modules and sibling test files #1010) and the open campaign PRs that touch it land.Instanceand deriveLockfileEntry,PatchedRefandResolvedElsewherefrom one per-formatentries()walk, one format family per PR (npm family first, after Walk package-lock entries once for inventory, vendored, hosted and restore #663).Symptoms
~/.m2) #265, Project-mode NuGet agent scan patches, and VEX attests, packages the project doesn't depend on (the crawler lists the whole ~/.nuget/packages) #427: whole-cache crawls (Tracking: scope project-mode cache crawls to what the project resolves #595).path_scope_excluded_supplementsexists only because the supplement's paths are fake.Impact
This is the root of the discovery overlap described in Part 6.2. Each new consumer must remember the side sets, and each new ecosystem must be taught to all four systems. Total size is large, so it lands as the children above.
Acceptance criteria
cargo test -p socket-patch-core --liband the CLIscan,vexandvendore2e suites stay green at every step.Dependencies
Consolidated work — backlog review, 2026-10-08
The following standalone issues are now tracked here. Their closure consolidates scheduling; it does not mean their implementation is complete. Original reports and discussion remain linked below.
#1113: Carry scan's lockfile-only and vendored-ledger candidates without a fabricated node_modules path
Preserved scope and acceptance criteria from #1113
Proposed change
CrawledPackagefor crawler output only and carry the supplement aspurl-only records beside it.Installedonly. "Not installed" ismatches!(c, Candidate::LockOnly { .. }).crawled_from_purl,supplement_purlsand theLockfileSupplement::packages/LedgerSupplement::packagesvectors of fabricated packages.lockfile_only.purlsonly where API-spelled purls are matched (lockfile_only_containsbridges the percent-encoding and composer padding). Where the candidate itself is at hand, derive the answer from the candidate.lockfileOnlyPackages,notInstalled, the[NOT INSTALLED]marker,path_scope_excluded_supplements), same exit codes.Size and scope
crates/socket-patch-cli/src/commands/scan/{mod.rs,discovery.rs}, plus any scan helper typed on&[CrawledPackage]that receives supplements. Estimate about 150–300 changed production lines.apply.rs's ownlockfile_resolvedset, and crawler changes.Acceptance criteria
crawled_from_purlandsupplement_purlsare deleted, and noCrawledPackageis constructed incommands/scan/outside tests.scan/discovery.rsunit tests (ledger_supplement_*,corrupt_ledger_*) are ported and green.scan_paths_e2e(path scope and thepath_scope_excluded_supplementswarning), the lockfile-only/notInstalledtests, and the vendored-ledger fresh-clone tests.<cwd>/node_modules/<name>as its location, even when such a directory exists.