Skip to content

test(guard): the sibling check reads manifests; the lockfile disagrees - #2484

Open
noahgift wants to merge 2 commits into
mainfrom
fix/lockfile-sibling-guard
Open

test(guard): the sibling check reads manifests; the lockfile disagrees#2484
noahgift wants to merge 2 commits into
mainfrom
fix/lockfile-sibling-guard

Conversation

@noahgift

Copy link
Copy Markdown
Contributor

check_workspace_siblings_pathed.sh proves no Cargo.toml DECLARES an in-tree
crate from crates.io. It passes, and its own header names the class it cannot
see: a dependency we legitimately take from the registry can drag an in-tree
name in TRANSITIVELY, and no manifest in this repo mentions it.

Currently resolved from crates.io despite being in-tree (7 names):

aprender 0.27.8   <- whisper-apr 0.2.8 <- {apr-cli, aprender-orchestrate,
trueno 0.17.5                              aprender-rag}
realizar 0.8.6
trueno-quant, renacer-core, provable-contracts-macros
batuta-common     <- bashrs <- aprender-compute-xtask (NOT optional)

aprender 0.27.8 is this monorepo depending on a published copy of ITSELF, 36
minors behind the workspace's 0.63.0 — the exact self-referential cycle APR-MONO
was meant to remove. #2471 closed 24 of 32 such collisions by fixing declarations
(lock 1493 -> 1402 packages); these 7 survive because they are transitive.

NOT implemented as cargo tree --duplicates, which is the instrument the
existing guard's header recommends and is structurally blind here. --duplicates
reports ONE PACKAGE resolved at two versions, but trueno, realizar and
batuta-common are [lib] names — the packages are aprender-compute,
aprender-serve, aprender-common. The lockfile holds exactly one trueno
package, the registry one, so it is not a duplicate and never will be. Measured:
0 of 8 caught under default features, 2 of 8 under --all-features, which no
workflow passes.

The lockfile is also the only feature-independent surface. Cargo.lock records
optional dependencies regardless of feature selection, which is why it sees the
six that cargo tree cannot reach without --all-features.

Severity note, against the audit that raised this as CRITICAL: 6 of 7 are
lockfile-only at HEAD. cargo tree -i aprender@0.27.8 exits 101 under default
features, so the tree does NOT currently compile two mutually-incompatible
truenos. Only batuta-common is actually built, via a non-optional bashrs in
aprender-compute-xtask. The live harms are the published-crate cycle and
lockfile/supply-chain pollution, not a broken build. Ratcheted rather than
failing outright, because closing them needs the transitive source cut (vendor
whisper-apr per APR-MONO, or drop its published aprender dep) and that is a
separate change.

Reuses the existing guard's own name extractor (workspace_sibling_names.awk),
so the two cannot disagree about what "in-tree" means — independently produces
the same 272 names the manifest guard prints.

Mutation-verified, each RED then restored GREEN:

  • a new registry package colliding with an in-tree name -> "grew 7 -> 8, NEW: aprender-core"
  • name extractor pointed at a missing dir -> vacuity RED (103 < 200)
  • lockfile parser matching the wrong source prefix -> vacuity RED (0 < 500)

4-row case table covers the parsing traps: path-sourced packages excluded, git
sources are not registry sources, and a source line must not leak onto the
PRECEDING package block.

Refs #2481, #2471

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

noahgift and others added 2 commits August 15, 2026 11:44
`check_workspace_siblings_pathed.sh` proves no Cargo.toml DECLARES an in-tree
crate from crates.io. It passes, and its own header names the class it cannot
see: a dependency we legitimately take from the registry can drag an in-tree
name in TRANSITIVELY, and no manifest in this repo mentions it.

Currently resolved from crates.io despite being in-tree (7 names):

    aprender 0.27.8   <- whisper-apr 0.2.8 <- {apr-cli, aprender-orchestrate,
    trueno 0.17.5                              aprender-rag}
    realizar 0.8.6
    trueno-quant, renacer-core, provable-contracts-macros
    batuta-common     <- bashrs <- aprender-compute-xtask (NOT optional)

`aprender 0.27.8` is this monorepo depending on a published copy of ITSELF, 36
minors behind the workspace's 0.63.0 — the exact self-referential cycle APR-MONO
was meant to remove. #2471 closed 24 of 32 such collisions by fixing declarations
(lock 1493 -> 1402 packages); these 7 survive because they are transitive.

NOT implemented as `cargo tree --duplicates`, which is the instrument the
existing guard's header recommends and is structurally blind here. `--duplicates`
reports ONE PACKAGE resolved at two versions, but `trueno`, `realizar` and
`batuta-common` are `[lib]` names — the packages are `aprender-compute`,
`aprender-serve`, `aprender-common`. The lockfile holds exactly one `trueno`
package, the registry one, so it is not a duplicate and never will be. Measured:
0 of 8 caught under default features, 2 of 8 under `--all-features`, which no
workflow passes.

The lockfile is also the only feature-independent surface. Cargo.lock records
optional dependencies regardless of feature selection, which is why it sees the
six that `cargo tree` cannot reach without `--all-features`.

Severity note, against the audit that raised this as CRITICAL: 6 of 7 are
lockfile-only at HEAD. `cargo tree -i aprender@0.27.8` exits 101 under default
features, so the tree does NOT currently compile two mutually-incompatible
`trueno`s. Only `batuta-common` is actually built, via a non-optional `bashrs` in
`aprender-compute-xtask`. The live harms are the published-crate cycle and
lockfile/supply-chain pollution, not a broken build. Ratcheted rather than
failing outright, because closing them needs the transitive source cut (vendor
whisper-apr per APR-MONO, or drop its published `aprender` dep) and that is a
separate change.

Reuses the existing guard's own name extractor (`workspace_sibling_names.awk`),
so the two cannot disagree about what "in-tree" means — independently produces
the same 272 names the manifest guard prints.

Mutation-verified, each RED then restored GREEN:
  * a new registry package colliding with an in-tree name -> "grew 7 -> 8, NEW: aprender-core"
  * name extractor pointed at a missing dir -> vacuity RED (103 < 200)
  * lockfile parser matching the wrong source prefix -> vacuity RED (0 < 500)

4-row case table covers the parsing traps: path-sourced packages excluded, git
sources are not registry sources, and a `source` line must not leak onto the
PRECEDING package block.

Refs #2481, #2471

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bashrs parses an embedded heredoc as shell, so the TOML fixtures read as 21
SC1007 "space after =" errors, and the word "in-tree" inside printf strings
reads as the shell `in` keyword (5 SC1035). Fixtures moved to
scripts/lib/lockfile_cases/; report text says "workspace-local", which is also
the vocabulary the manifest guard already uses.

Self-test 4/4 and the collision mutation re-verified after the refactor —
extending a guard is not proof the old verification still holds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@noahgift
noahgift force-pushed the fix/lockfile-sibling-guard branch from bcc4c7f to 5f5b387 Compare August 15, 2026 09:44
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.

1 participant