Skip to content

Withhold a vendored Cargo copy a member's other source bypasses - #2024

Merged
Mikola Lysenko (mikolalysenko) merged 13 commits into
fix/cargo-members-liveness-originfrom
fix/cargo-vendored-twins-and-split-patches
Nov 9, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 13 commits into
fix/cargo-members-liveness-originfrom
fix/cargo-vendored-twins-and-split-patches

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #2019 (fix/cargo-mixed-member-pins). It closes the vendored-mode Cargo false-attestation gap the #2019 author found.

The second gap, a root pinning a crate to one Socket patch while a member pins it to another, is now handled by #2019 itself (beside_the_pin emits the other patch's Cargo.toml ref, so the CLI gates it as wiring_conflict). This PR no longer touches it. I ran my earlier split-patch tests against #2019's code alone and they pass, so there was nothing left to keep.

Vendored copy bypassed by another source

vendor wires a crate through the root's [patch.crates-io], and cargo applies that only to crates.io declarations. A workspace member (or the root) can declare the crate from another registry, a registry-index or a repository URL, at a requirement that may select the patched version. That declaration resolves its own unpatched copy. The vendored ref still attested beside it, because the lock copy claim (vendored_copy_claim) only reads sourceless entries.

  • The ref now stays (rollback, remove and the ledgers still see the wiring), but it's marked unattested with a new UnattestedKind::CargoPatchBypassed. The detail names the declaration.
  • A Cargo.lock entry at exactly the patched version from any registry or repository source, beside the copy, is marked the same way. The detail names that lock entry.
  • Declarations are read through Stop attesting a Cargo pin a workspace member resolves from crates.io #2019's DeclSource classification:
    • Only live declarations count, so a [workspace.dependencies] template no manifest inherits doesn't.
    • A registry dependency is covered when a [patch.<registry>] table pointing at the same copy redirects it (Decl::patched_by). A git dependency is covered by a [patch."<repository URL>"] table pointing at the copy (see the follow-ups below).
    • A path declaration (the user's own fork) is still ignored, as a_same_version_fork_beside_the_tagged_copy_is_ignored already specifies.
    • A socket-patch-* registry dependency is hosted wiring, handled by Stop attesting a Cargo pin a workspace member resolves from crates.io #2019.
  • The CLI omits the ref as vex_cargo_patch_bypassed. It's documented in CLI_CONTRACT.md (Unattested references paragraph and the notes table).

I added a new variant rather than reusing CargoUnpinnedDeclaration. That variant's note tells the user to re-run scan, which is the wrong fix for vendored wiring.

Member gate. #2019 reads workspace members only when the lock holds a Socket-sourced package (or, with no lock, a manifest names a socket-patch- registry). A vendored copy's lock entry has no source, so the members are now also read whenever the root manifest or the project config wires a Socket copy through [patch], whatever the lock's state.

Cargo follow-ups (second commit)

  1. Lockless pins use the same classification (unresolved_manifest_pins, UnlockedPin, only_this_patch).
    • A socket-patch-<uuid> registry beside path, git or registry-index is no pin, matching the rewriter's pinned check. It no longer feeds an UnlockedPin; it counts as an unpinned declaration that excludes the versions it accepts (all of them, without a requirement).
    • A [workspace.dependencies] template no manifest inherits is no declaration.
    • A non-Socket [patch] registry entry no longer counts as an unpinned declaration (it redirects, it declares nothing).
  2. DeclSource::Git keeps its URL. Decl::patched_by matches it against a [patch."<repository URL>"] table (a trailing / or .git ignored). A git declaration whose repository table points at the same vendored copy no longer withholds it, while one from another repository still does. Hosted routing gets the same match for a Socket registry pin in such a table.
  3. The no-pin conflict branch checks the requirement. When no declaration pins the lock's patch, a pin to another patch makes the conflict pair only when it is live and cargo_req_selects says it may select the locked version. Otherwise the stale lock entry is diagnosed and dropped like any unrouted one.

Tests

  • New tests that fail when the check is disabled:
    • a_member_from_another_source_bypasses_the_vendored_copy (another registry, a renamed =1.0.4, a repository URL, a registry-index)
    • a_same_version_lock_entry_from_any_source_bypasses_the_vendored_copy
    • a_member_from_git_bypasses_the_config_wired_copy
    • members_are_read_for_a_vendored_copy_without_a_socket_lock_entry (with and without a lock)
  • Guard that stays attested: declarations_the_patch_redirects_keep_the_vendored_copy_attested. It covers crates.io members in every spelling, including registry = "crates-io" and a rename; an excluding requirement; [patch.my-corp] coverage; a path fork; and an un-inherited workspace template.
  • CLI: a_vendored_cargo_copy_beside_a_bypassing_source_is_gated.
  • Follow-up tests. Each one fails when only its own fix is switched off:
    • lockless_path_or_git_beside_a_socket_registry_is_no_pin (path / git / registry-index member beside the root's pin, and alone)
    • lockless_uninherited_template_is_not_a_declaration (Socket-pinned template uninherited vs inherited; an uninherited crates.io template beside the root's pin)
    • a_git_patch_table_for_the_copy_covers_that_repository_only (covered with a .git/ spelling and a branch; another repository still bypasses)
    • another_patch_pin_excluding_the_locked_version_is_no_conflict
  • Results:
    • cargo test -p socket-patch-core --lib -- vex::discover:: vendor::cargo patch::redirect:: utils::cargo_workspace (includes the golden corpus test): 1564 passed.
    • -p socket-patch-cli --lib vex_sources: 16 passed.
    • --test in_process_redirect cargo, --test in_process_cargo_apply cargo, --test mode_migration_cargo: 6 / 3 / 30 passed.
  • cargo clippy --locked --workspace --all-features -- -D warnings and cargo fmt --all -- --check are clean.

Review findings (/code-review high, third commit)

Each of findings 1–6 was confirmed first by a test that fails on the previous commit and passes now.

  1. False attestation from a shadowed [patch] entry: confirmed and fixed. The bypass check counted a manifest entry cargo ignores (the config redefines its crates.io key with a git fork) as redirecting crates.io declarations, so the copy's honored [patch.my-corp] entry was attested beside the fork. Only honored entries count now. Test: a_shadowed_manifest_entry_covers_no_declaration.

  2. registry-index coverage: confirmed and fixed. A [patch."<index URL>"] table now covers a declaration of the same index (a registry+ prefix, host case and a trailing / ignored). A registry-index naming the crates.io git index is crates.io. Test: a_registry_index_patch_table_covers_that_index.

    • Partly declined: the sparse crates.io index (sparse+https://index.crates.io/) is not treated as crates.io. Cargo.lock records it as a distinct source string from the git crates.io index, and the files don't show that [patch.crates-io] reaches it. Treating it as covered could attest a copy cargo doesn't build, so it stays withheld. The cost is a missed attestation on a rare hand-written shape.
    • Not done: a registry = "<name>" declaration is still matched only by a [patch.<name>] table, not by its index URL (the registry's URL may live in $CARGO_HOME).
  3. Remedy per evidence: confirmed and fixed. The detail now ends with the remedy for its evidence:

    • a declaration: re-running vendor doesn't help;
    • a crates.io lock entry beside a [patch.crates-io] copy: stale, so re-lock (re-run vendor or cargo update -p <crate>);
    • another lock entry: cargo tree -i <crate>@<version> names the dependency that declares it.

    The CLI note's fixed suffix no longer makes that claim. Test: the_bypass_remedy_follows_its_evidence.

  4. Canonical git URLs: confirmed and fixed. URLs are compared as cargo's CanonicalUrl spells them: one trailing / and .git dropped, a GitHub URL lowercased whole, any host lowercased. Test: a_git_patch_table_matches_cargos_canonical_url.

  5. Unreflected pin to another patch lost its diagnostic: confirmed and fixed. Once the lock held any Socket entry of the crate, unresolved_manifest_pins skipped it, so such a pin got no ref and no diagnostic. It now gets patched_ref_unattributable unless the lock resolves the crate from that patch or a ref already carries it. Test: another_patch_pin_excluding_the_locked_version_is_no_conflict (extended).

  6. Ineffective Socket registry gets no diagnostic: confirmed and fixed. A well-formed socket-patch-<uuid> beside path / git / registry-index, or on a [workspace.dependencies] entry no manifest inherits, is now diagnosed patched_ref_invalid ("pins nothing there"). Test: an_ineffective_socket_registry_is_diagnosed.

    • This changes one committed golden. The redirect/cargo/cargo/workspace-member/expected tree omits the unchanged inheriting member a/, so its pinned template reads as uninherited there and now carries that diagnostic. I regenerated the golden; no other corpus project changed.
  7. socket_copies computed twice: fixed. It's computed once, before the root manifest moves; vendored = !wired_all.is_empty().

  8. Shared helpers: done. Decl::describe and same_version_foreign_entry are used by both beside_the_pin and patch_bypassed.

  9. One classifier: done without widening route. route already takes (table, uuid) pins, so the vendored check calls it with the copy's honored [patch] tables as the pins and the lock's other versions of the crate. That is the same classifier hosted pins use, with no new parameter. The only vendored-specific rule left is that a path declaration (the user's own fork) is ignored, an existing documented rule.

Not done

  • The sparse crates.io index isn't treated as crates.io (see review finding 2). It can only cause a missed attestation.
  • No vendored planner warning. vendor::cargo already refuses the lock-twin state: locked_multi_source_conflict covers a same-version entry from two sources, and vendor_source_unsupported covers a non-crates.io entry. A member declaration whose other-source copy isn't locked yet is invisible to the planner without re-resolving.

Cloud routine: T1 verified, brought current, one more fix

  • The T1 review-fix round (6592bf2) landed before this run. All 9 findings are addressed (see the section above). I re-ran the full T1 test set on 6592bf2: discovery, vendor::cargo, patch::redirect, utils::cargo_workspace, the golden corpus, CLI vex_sources, --test in_process_redirect cargo, --test mode_migration_cargo, clippy and fmt. Everything passes except vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry, a chmod test that fails only because the container runs as root.
  • Merged the updated Stop attesting a Cargo pin a workspace member resolves from crates.io #2019 in as 1021784. Three conflicts in vex/discover/cargo.rs::read_members / extract. I resolved them by combining Cargo VEX: read member manifests, match liveness by origin, withhold mixed and vendored bypasses #2012's rule (parse members whenever a socket-patch- name appears anywhere) with this PR's vendored rule (a [patch]-wired copy always reads members).
  • New false-attestation fix, found reviewing Stop attesting a Cargo pin a workspace member resolves from crates.io #2019. A root [patch.crates-io] Socket registry pin that cargo ignores is replaced either by a [patch."<crates.io URL>"] table or by a config that redefines the key. That pin still counted for hosted route, so a member's crates.io declaration was taken as pinned. Such an entry now stays a declaration, so the ref stays, but it isn't live. route weighs only live [patch] pins, matching what the vendored bypass check already does. Test: a_shadowed_patch_pin_pins_no_declaration. It fails without the fix.

Tests after the merge and fix: cargo test -p socket-patch-core --lib -- vex::discover:: vendor::cargo patch::redirect:: utils::cargo_workspace gives 1570 passed (the 1 failure is the root-only chmod test). CLI vex_sources, in_process_redirect cargo and mode_migration_cargo pass. clippy and fmt are clean.

Round 4: merged #2019, /code-review high

Merged fix/cargo-mixed-member-pins at 0c83105, bringing #2012's fail-closed liveness and #2019's round-3 fixes. The only conflict was in beside_the_pin's declaration text. I kept this branch's Decl::describe and moved #2019's "which overrides its registry" clause into it, so every caller now says it. Core and CLI vex tests pass on the merge.

Fixed:

  1. Misleading "only from other Socket patches" diagnostic. It fired when beside_the_pin had returned early over a same-version crates.io twin. It now fires only when the lock has no non-Socket entry of the crate. Test: another_patch_pin_beside_a_foreign_twin_is_not_called_socket_only.
  2. A named [patch.<registry>] table and a [patch."<its index>"] table didn't compare as one source. Shadow now resolves registry names through the config's [registries] index URLs. Without this, a config git fork under the URL table left the manifest's vendored copy counted as honored. Test: config_items_shadow_pathless_and_named_source_entries (extended).
  3. The gated closure didn't match the CLI's conflict gate. It now drops a ref from the gate only for a file-scoped mark on the ref's own file, exactly as the CLI's bypassed_ref does.
  4. Two URL canonicalizations. patched_by (registry-index) and same_patch_source now share patch_source_key, with CanonicalUrl rules (.git, GitHub path case) on both.
  5. An identical Socket registry [patch] pin in the manifest and the config was treated as shadowed. That raised a spurious patched_ref_invalid. The same registry is now the same wiring, as the same path already was for copies. Test: extended as in 2.
  6. is_crates_io_lock_source duplicated patch::redirect::is_crates_io_source. It's removed, and the redirect helper is now pub(crate).
  7. patch_bypassed ran route twice per declaration. It's now one pass.
  8. The bypass detail dropped the other-patch declarations when a bypass or twin was also present. It now names them too. A git lock entry that a [patch."<repo>"] table pointing at the copy redirects now gets the stale/re-lock remedy instead of cargo tree -i.
  9. A comment above wired_all described manifests. Moved.

Declined:

  • "The golden's patched_ref_invalid for workspace-member encodes wrong behavior." By the redirect-fixture convention, expected/ holds only the files the rewriter changed, and the golden snapshots discovery over that tree as committed. a/Cargo.toml, the inheriting member, isn't there, so the diagnostic is correct for that tree. Adding the file breaks redirect_golden's changed-file-set check, and overlaying input/ would re-snapshot every redirect family. The live-template behavior is pinned by the unit test on templates (… only for a manifest that inherits it).
  • "Decide the conflict gate in one place." Finding 3 aligns the copy with the CLI's rule. Moving the gate is a larger refactor than this PR.

Tests: core vex:: origin cargo hosted:: patch::redirect:: vendor:: and redirect_golden, plus CLI --lib, e2e_vex_lockfile, e2e_vex_redirect, in_process_redirect and mode_migration_cargo. All pass. clippy and fmt are clean.


Note

Medium Risk
Changes Cargo discovery and VEX attestation for vendored patches across workspaces; incorrect routing could false-negative or false-positive attestations, though coverage is heavy in tests.

Overview
Adds vex_cargo_patch_bypassed so vendored Cargo wiring is not attested when Cargo can still build the same crate/version from a source the [patch] table does not redirect—e.g. a workspace member on another registry, git, or registry-index, or a foreign Cargo.lock entry at the patched version. The ref stays discoverable for rollback/list; only vex omits it.

Discovery now reads workspace members whenever a Socket copy is wired via [patch] (not only Socket-sourced locks), classifies declarations/[patch] shadowing more like Cargo (honored vs ignored entries, git/index URL canonicalization, ineffective socket-patch-* beside path/git), and tightens lockless pin handling.

CLI contract documents the new unattested case and lockless Cargo pin rules.

Reviewed by Cursor Bugbot for commit bc39a27. Configure here.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Burn-down agent: resolved the merge conflicts with fix/cargo-mixed-member-pins (merge cdf9d61, no force-push).

  • The base branch was rewritten (06d306c became 77a4d2d, plus 650143e and b2e171b), so I replayed 684c5fb on the new base. Decl keeps this PR's DepSource and describe() on top of the base's socket_shaped() (which replaces this PR's identical socket_pinned()) and its pinned-version Decl::new.
  • Behavior change to review: 650143e walks member manifests only when the lock has a Socket-sourced package, so a_member_from_another_source_bypasses_the_vendored_copy and a_member_from_git_bypasses_the_config_wired_copy failed (they found no member declarations). read_members now also walks the members when the root manifest or the config wires a vendored Socket copy through [patch].
  • Local: cargo check -p socket-patch-core -p socket-patch-cli --all-targets passes, and cargo test -p socket-patch-core --lib vex::discover passes 466/466. Waiting on CI.

Generated by Claude Code

`vendor` wires a crate through the root's `[patch.crates-io]`, which
cargo applies only to declarations from crates.io. A workspace member
(or the root) that declares the crate from another registry, a
`registry-index` or git, at a requirement that may select the patched
version, resolves its own unpatched copy. The vendored ref stayed
attested beside it because the lock copy claim only reads sourceless
entries.

The ref now stays (rollback, remove and the ledgers still see the
wiring) but is marked unattested with the new
`UnattestedKind::CargoPatchBypassed`, naming the declaration. A
same-version Cargo.lock entry from any registry or git source beside the
copy is marked the same way, naming the lock entry. The check reads the
declarations through #2019's classification: live declarations only, a
registry dependency counts as covered when a `[patch.<registry>]` table
pointing at the same copy redirects it (`Decl::patched_by`), a path
declaration (the user's own fork) keeps the existing "ignored" rule, and
a `socket-patch-*` registry dependency is hosted wiring. The CLI omits
the ref as `vex_cargo_patch_bypassed`; documented in CLI_CONTRACT.md.

The workspace member walk ran only when the lock held a Socket-sourced
package (or, with no lock, a manifest named a `socket-patch-` registry).
A vendored copy's lock entry has no source and it has no such pin, so
the walk now also runs whenever the root manifest or the project config
wires a Socket copy through `[patch]`, whatever the lock's state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mikolalysenko
Mikola Lysenko (mikolalysenko) force-pushed the fix/cargo-vendored-twins-and-split-patches branch from 5b08b24 to 64d73a6 Compare November 6, 2026 05:27
@mikolalysenko Mikola Lysenko (mikolalysenko) changed the title Withhold Cargo pins a member's other source or other patch bypasses Withhold a vendored Cargo copy a member's other source bypasses Nov 6, 2026
Three Cargo follow-ups to the declaration classification:

Lockless pins read declarations like locked ones. A
`socket-patch-<uuid>` registry beside `path`, `git` or `registry-index`
is no pin (cargo builds that source, and the rewriter's own pinned check
agrees), so it no longer adds its requirement to an `UnlockedPin` or
makes one on its own. It counts as an unpinned declaration instead,
excluding the versions it accepts (every version, without a
requirement). A `[workspace.dependencies]` template no manifest
inherits is no declaration: a Socket-pinned one makes no lockless pin,
and an unpinned one excludes nothing from the root's pin. A non-Socket
`[patch]` registry entry no longer counts as an unpinned declaration
either (it redirects declarations, it adds none).

`DeclSource::Git` keeps its URL, and `Decl::patched_by` matches a
`[patch."<repository URL>"]` table against it (a trailing `/` or `.git`
ignored). So a git declaration whose repository table points at the
same vendored copy no longer withholds that copy, while one from
another repository still does. Hosted routing gains the same match for
a Socket registry pin in such a table.

When no declaration pins the lock's patch, a pin to another patch now
makes the conflict pair only when it is live and its requirement may
select the locked version (`cargo_req_selects`). One that excludes it is
about another version; the stale lock entry is then diagnosed and
dropped like any unrouted one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
False attestation: the vendored bypass check counted a declaration as
redirected by any root or config `[patch]` entry pointing at the copy,
including a manifest entry cargo ignores (the project config redefines
its crates.io key, or a crates.io URL table replaces `[patch.crates-io]`).
Cargo then builds whatever replaced it for those declarations, while the
copy's other, honored entry was attested. Only honored entries count now:
the root's `[patch]` entries are collected once with their shadow reason
(a `Shadow` built from the root manifest and the config), and the bypass
check sees only the unshadowed ones. `vendored` (the member gate) is
derived from the same list instead of re-reading every `[patch]` table.

One classifier: the bypass check runs each declaration through `route`
with the copy's honored `[patch]` tables as the pins, as hosted pins do,
passing the lock's other versions of the crate. A path declaration (the
user's own fork) is still left alone.

`patched_by` now covers a `registry-index` declaration with a
`[patch."<index URL>"]` table for the same index (a `registry+` prefix,
host case and a trailing `/` ignored; `sparse+` is another source), and
treats a `registry-index` naming the crates.io git index as crates.io.
The sparse crates.io index stays a separate source. Git URLs compare as
cargo's `CanonicalUrl` spells them (one trailing `/` and a `.git` suffix
dropped, a GitHub URL lowercased whole, any host lowercased).

The bypass detail ends with the remedy for its evidence: a declaration
(re-running `vendor` does not help), a crates.io lock entry beside a
`[patch.crates-io]` copy (stale: re-lock), or another lock entry
(`cargo tree -i` names its declarer). The CLI note no longer claims
re-vendoring never helps.

Diagnostics: a Socket pin to another patch that the lock does not
reflect (its requirement excludes every locked version) used to vanish
once any Socket entry of the crate was locked; it is now diagnosed
`patched_ref_unattributable`. A well-formed `socket-patch-<uuid>`
registry that pins nothing (beside `path` / `git` / `registry-index`, or
on a `[workspace.dependencies]` entry no manifest inherits) is diagnosed
`patched_ref_invalid`. The committed `workspace-member` redirect golden
gains that diagnostic: its `expected/` tree omits the unchanged
inheriting member, so the pinned template reads as uninherited there.

`Decl::describe` and `same_version_foreign_entry` are shared by the
hosted and vendored checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o fix/cargo-vendored-twins-and-split-patches

# Conflicts:
#	crates/socket-patch-core/src/vex/discover/cargo.rs
FALSE ATTESTATION (found reviewing #2019; fixed here, where `Shadow`
lives): a root `[patch.crates-io]` Socket registry pin cargo ignores
(a `[patch."<crates.io URL>"]` table replaces it, or the config
redefines the key) still counted as pinning every crates.io
declaration of the crate, so a member's plain declaration was taken as
routed to the patch and the hosted ref attested while cargo builds
crates.io. Such an entry stays a declaration (Socket's wiring is
present, the ref stays) but is not live, and `route` only weighs live
`[patch]` pins, as the vendored bypass check already weighs only
honored entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

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 3 potential issues.

Autofix Details

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

  • ✅ Fixed: Pathless config patch still counts as live
    • Changed the shadowing detection logic from '*p != own' to '!(p.is_some() && *p == own)' so that path-less config patches properly shadow path-less manifest patches while preserving the same-path exception.

Create PR

Or push these changes by commenting:

@cursor push 93a51234a1
Preview (93a51234a1)
diff --git a/crates/socket-patch-core/src/vex/discover/cargo.rs b/crates/socket-patch-core/src/vex/discover/cargo.rs
--- a/crates/socket-patch-core/src/vex/discover/cargo.rs
+++ b/crates/socket-patch-core/src/vex/discover/cargo.rs
@@ -1435,7 +1435,7 @@
         let own = path.map(same_path_key);
         self.config_keys
             .iter()
-            .find(|(_, k, p)| k == key && *p != own)
+            .find(|(_, k, p)| k == key && !(p.is_some() && *p == own))
             .map(|(file, k, _)| {
                 format!("{file} redefines `[patch]` key `{k}`, which replaces it in cargo")
             })

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

Cargo replaces a manifest [patch] item with a project-config item of the
same source and key, whatever the source table and whether either wires a
path. Shadow only looked at crates.io tables and treated two path-less
items (a registry pin and a git fork) as the same wiring, so a config fork
left the manifest's Socket pin live and its stale lock row could be
attested. Only an identical path is now the same wiring, and named and
URL tables are compared too (URLs as an index key).

The ineffective-registry diagnostic also called a shadowed [patch] pin an
uninherited [workspace.dependencies] template; it now says cargo ignores
the [patch] entry.

Addresses Bugbot 4501098254, 4501098256 and 4501098258.

Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Shadow compared a config's [patch."<url>"] table with the manifest's
through index_key, which keeps a trailing .git and a GitHub path's case.
Cargo canonicalizes both, so a config item under a canonical-equivalent
git URL replaced the manifest's Socket copy while discovery still counted
it. Non-sparse URL tables now compare through git_key; sparse+ ones stay
index keys (another source).

Addresses Bugbot 4501313607.

Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

…plit-patches

The base picked up #2012's main merge, which added the npm-family,
sbt, NuGet and Go UnattestedKind variants and their vex notes. This
branch adds CargoPatchBypassed. The two sides only add entries, so
the merge keeps both:
- vex/discover/mod.rs: CargoPatchBypassed comes after
  CargoUnpinnedDeclaration, then the base's variants and file_scoped().
  Cargo stays non-file-scoped.
- vex_sources.rs: keeps both sides' note constants and
  unattested_note() arms.
- CLI_CONTRACT.md: keeps the base's paragraph, appends this branch's
  vendored-Cargo case, and changes the case count from "Nine" to
  "Ten". The reasons table keeps both sides' rows.

Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

…plit-patches

Resolve the patched_by conflict: keep this branch's per-source match
(registry, registry-index, git) and apply the base's fix that reads an
explicit registry = "crates-io" as crates.io in the Registry arm.

Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

patch_bypassed only withheld the vendored ref for declarations route()
finds Unpinned. A member declaring the crate from another socket-patch
registry routes to Pin(other) and was skipped. When the lock resolves the
crate from that patch, its hosted ref sits beside the vendored one and the
CLI's wiring_conflict gate refuses both. When the lock is stale and holds
no entry from that patch, only a patched_ref_unattributable diagnostic was
left, and patch A was attested even though the member re-resolves to
patch B. Mark the vendored copy CargoPatchBypassed in that case instead.

Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

The exemption for a member pinned to another Socket patch trusted any
lock line from that patch. hosted_from_lock drops a line whose project
registry definition disagrees, and a line at another version is no ref
for this package, so wiring_conflicts never fired and the vendored copy
stayed attested. Exempt only when the hosted pass emitted a ref for that
patch at this very purl that is not itself withheld.

Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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

…plit-patches

Brings #2012's fail-closed liveness and #2019's round-3 review fixes.
Conflict in beside_the_pin's declaration text: kept this branch's
Decl::describe and moved #2019's 'which overrides its registry' clause
into it, so every caller says it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review on #2024 (/code-review high), round 4:

- The "resolves it only from other Socket patches" diagnostic fired
  beside a same-version crates.io twin; it now needs a lock with no
  non-Socket entry of the crate.
- Shadow resolves a [patch.<registry>] table through the config's
  [registries] index, so a config [patch."<index>"] item shadows it.
- An identical path-less Socket registry [patch] pin in the manifest and
  the config is the same wiring, not a shadow.
- patched_by (registry-index) and same_patch_source share
  patch_source_key, with CanonicalUrl rules on both.
- patch_bypassed's conflict-gate check matches the CLI's bypassed_ref
  (file-scoped marks only); it routes each declaration once; its detail
  also names other-patch declarations; a git lock entry a git [patch]
  table redirects gets the stale/re-lock remedy.
- Reuse patch::redirect::is_crates_io_source for lock sources.
- Move the manifests comment back above its vector.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review November 9, 2026 21:01
Base automatically changed from fix/cargo-mixed-member-pins to fix/cargo-members-liveness-origin November 9, 2026 21:15
@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit f87fc9f into fix/cargo-members-liveness-origin Nov 9, 2026
80 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the fix/cargo-vendored-twins-and-split-patches branch November 9, 2026 21:15
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Not merged to main. GitHub marked this merged because the stack was folded: fix/cargo-members-liveness-origin was fast-forwarded to this PR's head. The whole Cargo stack is now reviewed and landed as #2012.

Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Nov 9, 2026
Behavior-preserving cleanup of #2012 after #2019 and #2024 were folded in:

- One `distinct<T>` replaces four hand-written order-preserving dedups;
  `describe_all` and one `other_declared` replace repeated describe/join
  chains.
- `DeclSource::patched_by` is the one redirect rule; the bypass check's
  stale-entry test maps the lock source to a `DeclSource` instead of
  re-deriving crates.io and git matching. `index_key` is folded into
  `patch_source_key`.
- `beside_the_pin` collects the lock's Socket uuids once; the manifests
  are serialized for the rewriter's dry planner once per discovery
  (`ManifestTexts`), not per crate. `vendored_from_patches` takes the lock
  from `Bypass`; the two `decls` passes in `extract` are one.
- `foreign_hosted_uuid` moves to `origin::hosted_shape_uuid`, so
  `normalized_hosted_url` is private again; the cheap accepted-origin
  check runs first in `foreign_hosted_url_in_files`.
- Comments and docs no longer narrate review history; the cargo module
  doc points at `beside_the_pin` / `patch_bypassed` instead of restating
  them; CLI_CONTRACT.md states the registry-index rule once and the
  `apply` sentence parses.
- Tests share `workspace_root`, `member`, `one_mark` and `shadow` instead
  of respelling manifests and config parsing; the e2e fail-closed comments
  point at CLI_CONTRACT.md.

Review of the simplify diff (/code-review high): the stale-lock remedy
named `[patch.crates-io]` and `socket-patch vendor` for a git entry too;
it now names the table that redirects the entry and offers `vendor` only
for crates.io. CLI_CONTRACT.md keeps the member-walk and uninherited-
template rules the trim had dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants