Skip to content

Tracking: derive scan candidates, lock entries and hosted refs from one project inventory instead of four discovery systems #1112

Description

[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:

System Entry point Returns
A. Crawlers crawl_every_ecosystem 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:

struct Instance {
    purl: CanonicalPurl,
    declared_in: Option<Rel>,            // which lock/manifest
    resolution: 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.
  • Crawlers become locators for project mode. Enumeration remains for agent mode, --global and lockless projects; the project-scoping half is Tracking: scope project-mode cache crawls to what the project resolves #595.

Ordered checklist

Symptoms

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.

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

  • Add a scan-local candidate type, for example:
    enum Candidate { Installed(CrawledPackage), LockOnly { purl, eco }, Vendored { purl, eco } }
    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.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)priority:p3refactorStructural change: duplicated code or logic, missing abstraction, layering, dead code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions