GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Compare purls through one PurlKey type by mikolalysenko · Pull Request #1045 · SocketDev/socket-patch

Conversation

@mikolalysenko

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

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Collaborator

Problem

Architecture audit §3.B (purl equality). At least six relations answered "do these two purls name the same package release", and they disagreed:

  • purl_eq folded percent-encoding and composer only;
  • purl_identity_key stripped qualifiers and did composer only;
  • two different functions were both named canonical_base_purl (one in vex::discover and one in rollout);
  • policy::canon and package_spec_matches each had their own folding;
  • the ledger had five ownership matchers with different canonicalization (covers_purl, purl_keys_cover, lookup_entry, apply's Go --check set, the hosted_pin_of / hosted_vendored_overlap keys);
  • there were several local normalize_purl(strip_purl_qualifiers(..)) closures used as keys.

The canonical_purl doc comment also claimed an identity it doesn't provide.

User-visible effects:

  • B20: scan --prune / --sync dropped a live manifest entry, and GC'd its blobs, when the API spelled the purl pkg:nuget/[email protected] and the NuGet global-cache crawl reported pkg:nuget/[email protected]. Update detection and redirect-candidate matching missed the same entry. docker_e2e_nuget.rs worked around this by serving a lowercase purl from the fixture. A PEP 503 spelling (typing_extensions vs typing-extensions) was pruned the same way.
  • B73: remove / rollback pkg:pypi/[email protected] found nothing when the recorded key was typing-extensions. The same happened for a NuGet case variant.

Related: #553 (the takeover ledger lookup now uses the same key, but there's no e2e for it yet), #748 / C20 (this is the identity half; the builders are untouched), #484 (Go + vs %2B is folded by the key).

Change

  • New utils::purl_key
    • PurlKey is the release identity. It strips qualifiers and subpath, percent-decodes, lowercases the type, PEP 503-folds PyPI names, case-folds NuGet names and versions, case-folds Composer names, and keys Composer versions by release identity (3.0.2 = v3.0.2 = 3.0.2.0).
    • PurlKey::qualified keeps release variants apart.
    • canonical_base_purl moved here. It is the display spelling the key is built from, and VEX product purls still use it.
  • Call sites. Every purl identity comparison in core and the CLI now builds PurlKeys (the exceptions are listed under Deferred):
    • ledger ownership;
    • prune GC;
    • update detection;
    • redirect candidates;
    • lockfile-only checks (one predicate; the duplicate notInstalled check now calls it);
    • takeover ledger drop;
    • hosted pins;
    • VEX source matching;
    • rollout budget;
    • policy reports;
    • get presence;
    • Go-patches orphan prune;
    • vlt heal targets;
    • Gradle pin rows;
    • the hosted memory engine's batch-search owner map, lock_inventory::lookup, the vendored blob harvest, apply's mismatch-blob record filter, rollback's superseded_by_hosted, and the rollout RecordedIndex (review round, see below).
  • Vendored key sets are now HashSet<PurlKey>, so the compiler routes every construction through the key.
  • package_spec_matches compares the folded key case-insensitively. User filter specs stay as lenient as before, and a versioned Composer spec still matches by exact release identity.
  • canonical_purl keeps only its display role. Its doc no longer claims identity.
  • Docker e2e: docker_e2e_nuget.rs now serves the API's real mixed-case spelling for the patch, and scan --sync must keep that entry.

Duplicate copies deleted

Purl equality relations went from 11 to 1 (PurlKey, with canonical_base_purl as its display spelling). Deleted:

  • utils::purl::purl_eq
  • composer_version::{purl_identity_key, composer_purl_identity, composer_purls_equivalent, composer_bases_equivalent}
  • rollout::canonical_base_purl
  • policy::canon
  • vex::discover::{canonical_base_purl, same_package}
  • rollout::stage::qualified_key (a copy of PurlKey::qualified)
  • lock_inventory::lookup's own PEP 503 / exact-version matcher
  • vex_sources::same_package
  • policy's canonical_pypi_purl

The ledger matchers (covers_purl, purl_keys_cover, lookup_entry_kv) are now one-line PurlKey comparisons. The ad-hoc key closures in scan/mod.rs, ledgers.rs, list.rs, hosted.rs, get.rs and apply.rs are gone.

Behavior notes

  • Policy filtered[] / retained[] purls and rollout base_purls are the PurlKey spelling, so PyPI and NuGet names there now appear folded. Composer already showed its identity form.
  • VEX output is unchanged except for one case: a Composer dev- branch name keeps its case in canonical_base_purl. Before this PR it was lowercased.

Review round (rebased onto main @ 431b818)

  • Rebased onto 14 new main commits (Fix VEX attesting beside an unpatched same-lock copy (#935, #938, #939) #940, Fix gem takeover un-hosting a grouped gem (#775) #776, Fix hosted yarn classic pins missing berry warning (#907) #917, Fix gem crawler missing Bundler .bundle root (#967) #968, Fix pnpm lock/workspace readers missing a BOM (#903, #904, #905) #909, Fix rollback/remove of an agent record superseded by a hosted pin (#933) #934, Honor HTTP-date Retry-After on vendor-service retries through api::retry (#677) #889, then Fix composer e2e flake on packagist connect timeouts #1037, Fix yarn berry project gates drifting between modes (#628, #629) #657, Fix Hatch environments being invisible to stale-install checks and VEX (#335) #700, Fix .bundle/config values keeping a trailing # comment (#951) #953, Scan every vendored-write file for vendored references (#832, #958) #1015, Fix remove/rollback missing PyPI name spellings (#1024) #1025, Fix stale docs and comments, and the npm wrapper's schema and exit code #1022).
  • Fix remove/rollback missing PyPI name spellings (#1024) #1025 (fixes remove and rollback don't PEP 503-normalise PyPI purl identifiers, so remove pkg:pypi/[email protected] exits 1 "No patch found" while get accepts the same identifier #1024, the PyPI half of B73) had brought back utils::purl::purl_eq with a PEP 503 rule. This branch deletes it again: patch_matches already folds PEP 503 through PurlKey. Fix remove/rollback missing PyPI name spellings (#1024) #1025's unit test now checks equality with PurlKey::qualified, and its remove/pypi_name_spellings.rs CLI tests pass unchanged. The get.rs conflict was resolved so Fix VEX attesting beside an unpatched same-lock copy (#935, #938, #939) #940's hosted-claim set is a HashSet<PurlKey> (not canonical_purl strings). The new gem-takeover pin lookup in vendor.rs uses PurlKey::same, and the new rollback::superseded_by_hosted uses PurlKey instead of the deleted helpers.
  • scan --prune --dry-run now shares the wet vendor GC's manifest-key drop (vendor::unused_vendored_manifest_keys). Before this, the preview used a qualifier-strip relation, so NuGet case, PEP 503 and composer padding variants were pruned for real but missing from the preview.
  • hosted::memory::discover::batch_search matches response packages to their asking roots by PurlKey. Before this, a respelled answer (such as Newtonsoft.Json) was credited to every root in the chunk.
  • lock_inventory::lookup matches by PurlKey, so a composer API @3.0.2.0 finds the lock's 3.0.2.
  • LockfileSupplement.purls is a HashSet<PurlKey> built once. The lockfile-only check is now one hash lookup, not an O(n) re-key on every miss.
  • hosted_vendored_overlap deduplicates by PurlKey, so one release spelled two ways gives one takeover warning.
  • Composer: PurlKey keeps the sentinel-free composer_version_key so its string stays printable in policy and rollout reports. A new test over the vector file checks that a rejected spelling can never key the same as an accepted one: every accepted key is itself accepted, bare and behind a v. The module docs now say so.

Core API break (for the release notes; CHANGELOG untouched)

The following socket-patch-core public items were removed or moved:

  • utils::purl::purl_eq
  • vex::canonical_base_purl (re-export) and rollout::canonical_base_purl; use utils::purl_key::canonical_base_purl
  • composer_version::{composer_purl_identity, purl_identity_key, composer_purls_equivalent}
  • rollout::stage::qualified_key

These signatures changed from HashSet<String> to HashSet<PurlKey>:

  • vendor::vendored_purl_keys
  • VendorState::purl_keys
  • vendor::purl_keys_cover

lock_inventory::lookup now also matches composer padding and NuGet/composer name case. Nothing else in the workspace references the removed items.

Testing

Failing first: on main plus only the new tests, all three regression tests failed. On this branch they pass.

  • cargo test -p socket-patch-core --lib -- folds_pep503_and_nuget_case nuget_case_spellings_are_one_vendored_package: 2 failed.
  • cargo test -p socket-patch-cli --lib -- detect_prunable_keeps_case_and_pep503: failed. It pruned both Newtonsoft.Json and typing_extensions.

New tests:

  • purl_key property-style table tests (hand-written loops, not proptest):
    • every spelling variant of a release shares one key, and no other release does;
    • the Composer key equals release equivalence over the whole composer-version-vectors.json;
    • qualified keys keep variants apart;
    • NuGet and PEP 503 cases.
  • B20 prune test (gc.rs).
  • B73 identifier test (purl.rs).
  • NuGet scan --mode vendored over a hosted pin skips the takeover (purl case mismatch), keeps the hosted feed wired, writes no vendor ledger and still reports success #553-shape ledger test (state.rs).

Commands run on this branch (macOS):

  • cargo test -p socket-patch-core -p socket-patch-cli --lib
    • CLI: 862 passed.
    • Core: 5580 passed. 1 failed, digest::production_digests_go_through_the_helpers, which was already red on main and is fixed by Fix main CI red on stale digest pending-list entries #1016 (now merged; I rebased onto it after the run).
  • cargo test -p socket-patch-core --tests --no-fail-fast: all 36 integration suites pass. The lib failure is the same pre-existing one.
  • cargo test -p socket-patch-cli with these integration tests: scan, remove, rollback, apply, get, vendor, cli, e2e_scan, e2e_nuget, e2e_composer, e2e_composer_version_identity, e2e_socket_yml_policy, scan_rollout_e2e, hosted_memory_{rollout,engine,parity}, covgap_commands_{scan_mod,scan_hosted,rollback,get,vendor,vex}, global_scope_project_state, in_process_{remove_repair_lifecycle,rollback_vendored,vendor}, e2e_vex, e2e_vex_vendor, e2e_vex_redirect, e2e_embedded_vex, coverage_fix_scan_hosted_dryrun_vendored. All passed.
  • cargo clippy -p socket-patch-core -p socket-patch-cli --all-targets -- -D warnings: no findings in any touched file.
    • The local clippy 1.93 reports pre-existing lints in untouched files, such as jvm_jar.rs, prebuilt_common/mod.rs and a macOS-only unused variable in python_crawler.rs.
    • I rustfmt'd only the changed hunks. Files that were already unformatted on main keep their old formatting.
  • After the rebase: focused unit tests for purl, gc, state, policy and rollout pass.
  • After the review-round rebase and fixes (macOS):
    • cargo build -p socket-patch-core -p socket-patch-cli --all-targets
    • cargo clippy -p socket-patch-core -p socket-patch-cli --all-targets: 0 findings in touched files. The pre-existing lints in untouched files listed above remain.
    • cargo test -p socket-patch-core --lib: 5641 passed (the digest failure is gone now that Fix main CI red on stale digest pending-list entries #1016 is on main).
    • cargo test -p socket-patch-cli --lib --test scan --test vendor --test rollback --test apply --test get --test remove --test gradle_agent_cli --test in_process_rollback_vendored --test in_process_vendor: all passed (lib 872, scan 118, vendor 91, rollback 38, apply 106, get 81, remove 94 (incl. Fix remove/rollback missing PyPI name spellings (#1024) #1025's PyPI spelling tests), gradle_agent_cli 34, in_process_rollback_vendored 16, in_process_vendor 121).
    • New regression tests: batch_search_credits_a_respelled_response_only_to_its_asker, lookup_matches_by_purl_identity, overlap_reports_one_entry_per_release_across_spellings, covers_every_spelling_of_the_release (unused_vendored_manifest_keys), and sentinel_free_key_keeps_rejected_spellings_apart. The first three fail against the pre-fix code: a spelling-keyed owner falls back to every chunk root, exact-version lookup misses 3.0.2.0, and spelling dedup gives 4 entries.
  • Not run locally: docker_e2e_nuget (Linux/Docker). It is the end-to-end proof for B20 (mixed-case manifest key against the lowercase global-cache crawl, through scan --sync, GC, apply and agent VEX). It must pass in CI before this lands.

Deferred

  • Name-level PyPI comparisons inside lock parsers (canonicalize_pypi_name(a) == canonicalize_pypi_name(b)) are left alone. They compare names, not purls.
  • Same-source qualifier grouping in vendor.rs / apply.rs (variant_groups, vendored_bases over manifest keys) is left as-is, since both sides already share one spelling.
  • Moving Ecosystem and canonicalize_pypi_name to core (E39 / Move canonicalize_pypi_name and the PEP 508 name scanner out of crawlers and vendor into one PyPI name module #883) is a separate refactor.
  • The four target grammars (scan --package, get fuzzy, remove/rollback, UUID shortcut) are untouched.
  • Left as literal spelling comparisons, deliberately:
    • get.rs's failure dedup on normalize_purl is display-only.
    • ecosystem_dispatch::merge_qualified matches a crawler's echo of the exact base purl it was asked for, so both sides are the same string.
    • The Gradle/Maven scan keys use canonical_base_purl. Maven coordinates are case-sensitive, so the canonical spelling is the identity, and the lock-file GAVs they are checked against are built as strings.
  • The vendored blob harvest matches PurlKey::new(base_purl), not lookup_entry. It keeps the old qualifier-insensitive match for manifest keys, whereas lookup_entry is qualifier-sensitive.
  • No maintainer decision was needed.

🤖 Generated with Claude Code


Note

Medium Risk
Wide refactor of identity comparisons across apply, scan, GC, rollback, and policy paths; behavior changes are intentional but any missed call site could still mis-match or over-prune patches.

Overview
Introduces PurlKey as the single release-identity for package URLs (encoding, qualifiers, NuGet/PyPI/Composer spelling variants) and routes prune GC, lockfile-only detection, vendor ownership, rollout, policy, VEX, and hosted batch search through it instead of a dozen overlapping helpers (purl_eq, policy::canon, duplicate canonical_base_purl, composer purl identity helpers, etc.).

User-visible fixes: scan --prune/--sync no longer drops live manifest entries when the API uses mixed-case NuGet or alternate PyPI spellings vs the crawl; remove/rollback identifiers now match those recorded keys. Vendored key sets become HashSet<PurlKey>; dry-run prune preview shares wet vendor GC manifest-key logic via unused_vendored_manifest_keys; hosted memory batch search credits respelled API purls only to the asking root.

Several removed/moved socket-patch-core public APIs (purl_eq, old canonical_base_purl locations, composer identity exports); vendored helpers now take HashSet<PurlKey>.

Reviewed by Cursor Bugbot for commit daa5ef8. Configure here.


Generated by Claude Code

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mikolalysenko Mikola Lysenko (mikolalysenko) added the arch-refactor PR opened by the scheduled architecture refactor routine label Oct 7, 2026
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 7, 2026
@mikolalysenko @claude
Route the remaining purl relations through PurlKey
0c13e9e
Review of #1045 found purl equality checks that still bypassed the key:

- hosted memory batch_search matched response packages to their asking
  roots by spelling, so a `Newtonsoft.Json` / `typing_extensions` /
  composer `@3.0.2.0` answer fell back to every root in the chunk;
- lock_inventory::lookup had its own matcher (PEP 503 only, exact
  version), so a composer API purl `@3.0.2.0` missed the lock's `3.0.2`;
- the vendored blob harvest and apply's mismatch-blob record filter
  compared qualifier-stripped strings;
- rollback's superseded_by_hosted (new on main) used the deleted
  canonical_base_purl / composer_purls_equivalent pair;
- rollout::stage::qualified_key duplicated PurlKey::qualified (deleted);
  RecordedIndex now keys by PurlKey;
- Gradle scan keys use canonical_base_purl (Maven is case-sensitive, so
  the canonical spelling is the identity there).

Regression tests: a mixed-case NuGet batch answer is credited only to
its asker; lookup matches composer padding and PEP 503 spellings.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko
Mikola Lysenko (mikolalysenko) force-pushed the arch-fix/purl-key branch from 583e93c to af4a4ed Compare October 7, 2026 16:47
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 7, 2026 16:47
Mikola Lysenko (mikolalysenko) and others added 5 commits October 7, 2026 12:48
@mikolalysenko @claude
Add PurlKey, the one purl identity type
fea57af
One type answers "do these two purls name the same package release":
qualifiers and subpath stripped, components percent-decoded, the type
lowercased, PyPI names PEP 503-folded, NuGet names and versions
case-folded, Composer names case-folded and Composer versions keyed by
release identity (3.0.2 = v3.0.2 = 3.0.2.0). PurlKey::qualified keeps
release variants apart. canonical_base_purl (moved here from
vex::discover) stays the display spelling the key is built from.

Property tests check that every spelling variant of a release shares
one key, that no other release does, and that the Composer half equals
release equivalence over the whole shared vector file.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko @claude
Route every purl comparison through PurlKey and delete the copies
b572514
Six "same package" relations disagreed, so a NuGet or PyPI spelling
difference between the API purl, the crawl and the ledger could prune a
live manifest entry, skip a takeover or miss a remove target. Every one
now compares PurlKeys, and the copies are gone:

- deleted utils::purl::purl_eq, composer_version::{purl_identity_key,
  composer_purl_identity, composer_purls_equivalent,
  composer_bases_equivalent}, rollout::canonical_base_purl,
  policy::canon, vex::discover::{canonical_base_purl, same_package},
  vex_sources::same_package and policy's canonical_pypi_purl;
- the ledger matchers (covers_purl, purl_keys/purl_keys_cover,
  lookup_entry_kv), the hosted/vendored overlap, the hosted pin lookup,
  apply --check's Go set, the takeover ledger drop and every local
  normalize_purl(strip_purl_qualifiers(..)) closure used as a key now
  build PurlKeys; vendored key sets are HashSet<PurlKey>.

Fixes B20: scan --prune no longer GCs a NuGet entry the API spelled
Newtonsoft.Json while the global-cache crawl reports newtonsoft.json
(update detection and redirect candidates use the same key). Fixes B73:
remove/rollback identifiers fold PEP 503 and NuGet case. canonical_purl
keeps only its display role and its doc no longer claims identity.

Policy filter specs stay case-insensitive (they compare the folded key
lowercased), and policy/rollout report purls are the PurlKey spelling,
so PyPI/NuGet names there appear folded.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko @claude
Drop the NuGet casing workaround from the docker e2e
9d0f2ce
The wiremock fixture had to serve the crawler's lowercase purl so scan's
GC pass would not prune the manifest entry. Serve the API's real
mixed-case Newtonsoft.Json spelling for the patch instead; scan --sync
must now keep it, and agent VEX names the manifest key's spelling.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko @claude
Route the remaining purl relations through PurlKey
97416b5
Review of #1045 found purl equality checks that still bypassed the key:

- hosted memory batch_search matched response packages to their asking
  roots by spelling, so a `Newtonsoft.Json` / `typing_extensions` /
  composer `@3.0.2.0` answer fell back to every root in the chunk;
- lock_inventory::lookup had its own matcher (PEP 503 only, exact
  version), so a composer API purl `@3.0.2.0` missed the lock's `3.0.2`;
- the vendored blob harvest and apply's mismatch-blob record filter
  compared qualifier-stripped strings;
- rollback's superseded_by_hosted (new on main) used the deleted
  canonical_base_purl / composer_purls_equivalent pair;
- rollout::stage::qualified_key duplicated PurlKey::qualified (deleted);
  RecordedIndex now keys by PurlKey;
- Gradle scan keys use canonical_base_purl (Maven is case-sensitive, so
  the canonical spelling is the identity there).

Regression tests: a mixed-case NuGet batch answer is credited only to
its asker; lookup matches composer padding and PEP 503 spellings.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko @claude
Key scan GC, lockfile-only and overlap sets by PurlKey
5953eb1
- `scan --prune --dry-run` previewed the vendor GC's manifest drop with a
  qualifier-strip relation while the wet pass used PurlKey, so NuGet case,
  PEP 503 and composer padding variants were pruned for real but not in
  the preview. Both now call vendor::unused_vendored_manifest_keys.
- LockfileSupplement.purls is a HashSet<PurlKey> built once, so the
  lockfile-only predicate is one hash lookup instead of re-keying the
  whole set on every miss.
- Ledgers::hosted_vendored_overlap deduplicates by PurlKey, so two
  spellings of one release give one takeover warning.
- get's hosted-claim set (rebased onto #940's new code) is a
  HashSet<PurlKey>; the new gem takeover pin lookup uses PurlKey::same.
- composer_version: pin that the sentinel-free key PurlKey uses never
  lets a rejected spelling collide with an accepted one, and document it.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko
Mikola Lysenko (mikolalysenko) force-pushed the arch-fix/purl-key branch from af4a4ed to 5953eb1 Compare October 7, 2026 17:01
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cursor[bot]
cursor Bot reviewed Oct 7, 2026
View reviewed changes

@cursor cursor Bot left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Lockfile-only skips installed spelling variants
    • Changed lockfile_supplement to use PurlKey normalization for exclusion checks, matching the membership check behavior and preventing spelling variants from being incorrectly classified as not installed.

Create PR

Or push these changes by commenting:

@cursor push aae44b9bf5
Preview (aae44b9bf5)
diff --git a/crates/socket-patch-cli/src/commands/scan/discovery.rs b/crates/socket-patch-cli/src/commands/scan/discovery.rs
--- a/crates/socket-patch-cli/src/commands/scan/discovery.rs
+++ b/crates/socket-patch-cli/src/commands/scan/discovery.rs
@@ -75,7 +75,7 @@
     if entries.is_empty() {
         return out;
     }
-    let crawled_purls: HashSet<&str> = crawled.iter().map(|p| p.purl.as_str()).collect();
+    let crawled_purls: HashSet<PurlKey> = crawled.iter().map(|p| PurlKey::new(&p.purl)).collect();
     let in_scope = |purl: &str| {
         only.is_none_or(|list| {
             socket_patch_core::crawlers::Ecosystem::from_purl(purl)
@@ -83,7 +83,7 @@
         })
     };
     for entry in entries {
-        if crawled_purls.contains(entry.purl.as_str()) || !in_scope(&entry.purl) {
+        if crawled_purls.contains(&PurlKey::new(&entry.purl)) || !in_scope(&entry.purl) {
             continue;
         }
         let Some(pkg) = crawled_from_purl(&entry.purl, &common.cwd) else {

You can send follow-ups to the cloud agent here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread crates/socket-patch-cli/src/commands/scan/discovery.rs Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread crates/socket-patch-cli/src/commands/vendor.rs Resolved

Uh oh!

There was an error while loading. Please reload this page.

Tanmay182003
Tanmay Singla (Tanmay182003) approved these changes Oct 7, 2026
View reviewed changes
@claude
Match crawled lock entries and golang base purls by identity
daa5ef8
lockfile_supplement excluded installed packages by literal purl but
keyed the remainder by PurlKey, so a lock spelling that differed from
the crawl only in NuGet case, PEP 503 form or composer padding was
recorded as lockfile-only and lockfile_only_contains then flagged the
live install package_not_installed (agent apply skip, vendor baseline
pre-verify, [NOT INSTALLED] marker). Exclude crawled packages by
PurlKey, the same relation the lookup uses, via a testable
lockfile_only_packages helper.

unused_vendored_manifest_keys only keyed the ledger key, but a golang
ledger key can keep the module proxy's !x case encoding while the
manifest holds the decoded spelling, which PurlKey does not bridge. The
earlier wet GC also matched entry.base_purl; restore that through
VendorEntry::covers_purl in both the wet GC and the scan --prune
--dry-run preview so a reverted !burnt!sushi entry no longer leaves its
BurntSushi manifest record and blobs behind.

Co-Authored-By: Claude <[email protected]>
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

cursor[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cursor[bot]
cursor Bot reviewed Oct 7, 2026
View reviewed changes

@cursor cursor Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

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 daa5ef8. Configure here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 7, 2026
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator Author

[agent] Ready for review at daa5ef8bfba15b90700b40b8680235601206098f.

  • CI: required ci-ok green. 527 success / 6 skipped / 0 failing; 30 non-required macOS/Windows legs still queued or running. yarn-berry 4.1.0 (ubuntu) failed on attempt 1 with a corepack [email protected] unavailable fetch race (a sibling [email protected] test passed 0.6s later) and passed on re-run.
  • Bugbot reviewed daa5ef8: no unresolved findings. No open review threads.
  • Mergeable, no conflicts.
  • Reviewer focus: PurlKey equality and normalization, which now backs every purl comparison.

Generated by Claude Code

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) added this pull request to the merge queue Oct 7, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 8, 2026
@mikolalysenko @claude
Merge origin/main into arch-fix/purl-key
f7c4188
Resolve conflicts against main's rustfmt pass and the containment-helper
refactor (#1042): keep main's formatting, drop the removed `canon` /
composer-identity helpers in favour of PurlKey, and route main's new
apply-failure purl matching in get.rs (#955) through PurlKey::qualified /
PurlKey::same so it agrees with the rest of the purl identity.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko Mikola Lysenko (mikolalysenko) closed this Oct 8, 2026
@mikolalysenko Mikola Lysenko (mikolalysenko) reopened this Oct 8, 2026
@mikolalysenko Mikola Lysenko (mikolalysenko) closed this Oct 8, 2026
@mikolalysenko Mikola Lysenko (mikolalysenko) reopened this Oct 8, 2026
@mikolalysenko @claude
Merge origin/main into arch-fix/purl-key
5ceeae4
Pick up #1093 so PR CI runs without the macOS legs.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko
Mikola Lysenko (mikolalysenko) added this pull request to the merge queue Oct 8, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 8, 2026
@mikolalysenko @claude
Merge origin/main into arch-fix/purl-key
450f7f0
Resolve conflicts with #1035 (supersede lifecycle), #1038 (shared repo-root
walk), and #1033 (unwired VEX copies):

- #1035 added `vex::discover::same_release` and a second
  `canonical_base_purl` there. `PurlKey::same` already treats composer
  version spellings as one release, so every `same_release` call
  (vex_sources, rollback, discover, and `ledgers::hosted_pins_matching`)
  now uses `PurlKey::same`, and the duplicate helpers are dropped.
- Both sides' new ledgers tests are kept.
- The repo-root lookup in `policy` takes main's `utils::repo_root` version.
  `canonical_pypi_purl` stays deleted (nothing calls it now).
- `vex` re-exports main's `UnattestedKind`. `UnwiredCopy::covers` compares
  purls with `PurlKey::same` rather than raw string equality.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko
Mikola Lysenko (mikolalysenko) added this pull request to the merge queue Oct 8, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 8, 2026
@mikolalysenko @claude
Merge origin/main into arch-fix/purl-key
c9cd86d
Resolve the apply `--check` conflict with #1029. Main hoisted the vendored
key set into `run_check`'s outer scope (`vendored_purl_keys`, already a
`PurlKey` set via `purl_keys_cover`). The Go redirect check now reuses that
set instead of loading the vendor ledger a second time.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 8, 2026
Vendored uv repair pairs a hashless pure wheel with another wheel's hash, because ledger recovery re-parses uv.lock with its own scanner #1079
Closed
4 tasks
@mikolalysenko
Mikola Lysenko (mikolalysenko) enabled auto-merge October 8, 2026 09:02
@mikolalysenko @claude
Label the setup-php pin in ci.yml with its real tag
5525c18
Upstream moved setup-php's `v2` tag to d52fc211, so the `# v2` comment on
the f3e473d1 pin no longer matches. zizmor's ref-version-mismatch now
fails the org-required "Audit GitHub Actions" check on every PR. f3e473d1
is tag 2.37.2, the label composer-compatibility.yml already uses. This is
the same one-line change as #1118, carried here so this PR can merge;
whichever lands first, the other merges cleanly.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 8, 2026
Read recovered uv/pdm wheel pins through the shared lock model (#1079) #1121
Merged
@mikolalysenko
Mikola Lysenko (mikolalysenko) added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit 628542d Oct 8, 2026
456 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the arch-fix/purl-key branch October 8, 2026 10:30
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 8, 2026
@mikolalysenko @claude
Merge origin/main into arch-fix/jvm-layout
db21ba8
Resolve conflicts with #1038 (shared repo-root walk, Option m2_repo) and
#1045; route #1035's superseded-checksum path and the hosted engine's
Gradle root files through vendor::jvm::layout.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 8, 2026
@mikolalysenko @claude
Merge origin/main into arch-fix/takeover-atomic
172a25f
Resolve the hosted.rs conflict with #1045: this branch moved the
takeover out of hosted.rs into hosted/takeover.rs, so keep that layout
and port #1045's change there. The takeover's ledger drop now compares
PurlKeys and the local canonical_purl key helper is gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 8, 2026
@mikolalysenko @claude
Merge origin/main into agent/fix-pnpm-open-issues
be89ccc
Resolve get.rs and scan/vendor_flow.rs against #1045's PurlKey: the
hosted takeover set is now a HashSet<PurlKey> shared by the fetch gate
and the dry-run preview.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 8, 2026
@mikolalysenko @claude
Merge main into arch-fix/ui-text-cycles
fbf3104
get.rs: keep this branch's split (the download engine lives in
agent_download.rs, short_uuid tests in ui/text.rs) and carry main's
changes to the moved code over to agent_download.rs: store_verified_blob
in write_blob_entry (#726), PurlKey comparisons in lock_text_refusals_for
/ apply_key_covers / fold_apply_failures (#1045), and the base64 engine.
main's new get.rs tests (verified blob writes, linked blob dirs, base64
tolerance, the pnpm-lock FIFO guard) are kept.
list.rs: keep ui::sentence_case (main only reformatted the line).
scan/hosted.rs: add main's yarn_classic_outer closure (#1083).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 8, 2026
@mikolalysenko @claude
Merge origin/main into agent/fix-npm-open-issues
800e2f7
Conflicts resolved:
- vex discover: main's UnattestedKind (#1033) replaces this branch's
  parallel UnattestedWhy; the #899 shrinkwrap case becomes
  UnattestedKind::NpmShrinkwrapOnly, mapped through vex_sources'
  unattested_note like the other kinds.
- scan/policy.rs: the #812 shared-copy keys use PurlKey (#1045) instead
  of the removed canon().
- CLI_CONTRACT.md: main's contested/unattested bullets, plus this
  branch's #828 withheld-ref sentence, #899 shrinkwrap bullet and npm
  warning rows.
- redirect npm.rs / scan mod.rs: imports and key types from both sides.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 8, 2026
@mikolalysenko @claude
Merge remote-tracking branch 'origin/main' into prfix3/1058
abc90c3
Conflicts:
- ruby_crawler.rs: keep the branch's bundler_config_files (the read-set
  paths of the snapshot probe) alongside main's BundlerEnv /
  BUNDLE_LOCKFILE; main's new gems.rb stat in
  bundler_loaded_manifest_with_env is added to those paths so a reused
  discovery re-checks it.
- vex/discover/mod.rs: DiscoverCtx keeps both the branch's view-based
  constructor and hosted_hosts memo and main's per-ecosystem read log;
  Discovery keeps vlt_bundled_copies plus main's read and withheld.
- testing/golden.rs: ignore all three bookkeeping fields.

canonical_base_purl moved to utils::purl_key on main (#1045); the
branch's three call sites now use it from there.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Mikola Lysenko (mikolalysenko) pushed a commit that referenced this pull request Oct 8, 2026
@claude
Merge main into agent/fix-bun-open-issues
e647108
Resolve the conflicts with main's move of vendored in-use detection
into discovery (#1050) and its PurlKey rename (#1045):

- npm_flavor.rs: drop the branch's vendored_entry_in_use, now that
  Discovery::vendor_entry_in_use replaces it. Bun discovery already
  picks the live lock through bun_text_lock_drives, so the #735
  regression test now runs through the shared in_use helper with a
  minimist entry.
- lock_inventory/tests.rs: keep both sides' new tests.
- vendor.rs: key the Bun reinstall dedupe on PurlKey.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 8, 2026
Fix open bun issues (#992, #861, #784, #764, #735, #635, #599, #578, #497, #443, #371) #1009
Merged
Mikola Lysenko (mikolalysenko) pushed a commit that referenced this pull request Oct 8, 2026
@claude
Drop the unused canonical_purl import from agent_download
82bb4e1
The merge of main (#1045) moved lock_text_refusals_for onto PurlKey, so
canonical_purl is no longer referenced in agent_download.rs and the
workspace clippy job fails on -D unused-imports.

Co-Authored-By: Claude <[email protected]>
This was referenced Oct 9, 2026
remove, rollback and get treat case-distinct packages as one: remove pkg:npm/jsonstream also removes JSONStream's patch #1292
Closed
Tracking: build and classify purls through one validated utils::purl API #748
Open
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 28, 2026
NuGet scan --mode vendored over a hosted pin skips the takeover (purl case mismatch), keeps the hosted feed wired, writes no vendor ledger and still reports success #553
Closed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@cursor cursor[bot] cursor[bot] left review comments
@Tanmay182003 Tanmay Singla (Tanmay182003) Tanmay182003 approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

arch-refactor PR opened by the scheduled architecture refactor routine Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

remove and rollback don't PEP 503-normalise PyPI purl identifiers, so remove pkg:pypi/[email protected] exits 1 "No patch found" while get accepts the same identifier

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@mikolalysenko @Tanmay182003 @claude
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.