Skip to content

Carry scan's lockfile-only and vendored-ledger candidates without a fabricated node_modules path #1113

Description

[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.

Kind: refactor. Source: Part 6.2 ("fabricated CrawledPackages"); register E36, child 1 of #1112.

Problem

scan turns lock-inventory entries and vendor-ledger entries into fake installed packages:

  • scan/discovery.rs#L111-L133 crawled_from_purl sets path: cwd.join("node_modules").join(name_part) for every ecosystem. A lockfile-only pkg:cargo/serde@1.0.0 or pkg:pypi/six@1.16.0 gets <cwd>/node_modules/serde or <cwd>/node_modules/six.
  • It is called by lockfile_supplement (#L88) and vendored_ledger_supplement (#L215).``

Because the paths are fake, the caller keeps parallel sets that say which entries to distrust:

  • supplement_purls (scan/mod.rs#L1807-L1835),`` which exists only so the PATH-scope filter (#L1926-L1962) can skip them;
  • lockfile_only.purls, consulted through lockfile_only_contains at scan/mod.rs 801, 2821 and 3121 and at discovery.rs 299.

Every new consumer of all_crawled that reads .path (for example gradle_cache::installed_copies(&pkg.path, …) in preverify_vendor_baselines, or is_gradle_version_dir(&p.path) at scan/mod.rs 1206) has to remember that some paths are placeholders. Today these happen to degrade safely, because Maven and Gradle never reach the inventory.

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.

Dependencies


Backlog review — 2026-10-08

Consolidated into #1112. The retained tracker(s) preserve this issue’s implementation scope and acceptance criteria. Closing this separate scheduling item as not planned, not as completed.

Explicit candidate-type child of the unified inventory tracker; one parent issue is enough to schedule it.

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