COSI_CORPUS_REQUIRE=1 has a floor of one, not of nine — 8 of 9 repos can skip and the run passes green #108
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
h-dv/code-index#108
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found by the #80-blocker audit and verified first-hand in source before filing.
The defect
crates/indexer/tests/corpus/mod.rs:911:tests/corpus/corpus.tomlpins 9 repos:rust-ripgrep,python-flask,ts-zod,js-express,php-guzzle,ruby-sinatra,cs-dapper,rust-analyzer,py-django.The guard fires only when the executed set is completely empty. A run in which 8 of the 9 skip — one repo at the wrong sha, a tracked file an antivirus scanner removed, a partial clone — executes one repo, prints
executed=1 skipped=8, and passes. The panic message even says "A corpus run that grades nothing must fail", which is precisely the narrower property it enforces: it defends against nothing, not against less than everything.corpus/mod.rs:106-140turns both a sha mismatch and a missing tracked file into a plain SKIP, so the two most likely real-world causes both land in the silent path.Why this matters more than a missing assert
This is the same class as the I035 finding this guard was written for — "five RPC arms deletable with CI green" — and the same class as the anti-vacuity guards elsewhere in this suite. The
ctl.len() > 0positive-control check immediately above it is the pattern done right: it proves the setup took effect. TheREQUIREcheck below it does not prove the universe was intact.The consequence is that the corpus suites — which are the only gates that see real-world scale, the sticky-resolution class of bug, and cross-language recall — can silently shrink to a single repo while reporting green. A ratchet over a shrunken universe is not a ratchet.
It is also the shape this project has already paid for repeatedly: a check that was green while the thing it checked was false, and a one-sided bound blind to the failure it is most likely to have. Every way this harness goes wrong in practice reduces the executed set; the guard only triggers at zero.
The fix
skippedis already tracked and already printed, so the data is in hand. But the naive form —require && !self.skipped.is_empty()— is wrong, because not every suite grades every repo (tier-1 vs tier-3, language-specific suites). The honest form is an expected set per suite:COSI_CORPUS_REQUIRE=1, every repo in that set must appear inexecuted;Three-state discipline applies to the log line too:
executed=1 skipped=8should not read as a healthy run. Underrequire, "skipped" is a failure, not an observation.The mutation that must go red
Point one pinned repo at a wrong sha (or remove one tracked file), run with
COSI_CORPUS_REQUIRE=1, and the suite must fail naming that repo. Today it passes. That mutation is also the anti-vacuity check for the fix itself: a test that only ever runs with all 9 present cannot tell the new guard from the old one.Related
Found while auditing #45. Adjacent to #44 (positive controls), and to the corpus suites tracked in #42/#41/#45. The nightly-cron finding is separate and worse in its own way:
event=schedulereturns 0 runs of 574, so the nightly leg that carries these suites has never fired — a guard with a floor of one is moot if the job never runs at all.github.event.scheduleis empty on this Forgejo, so every cron-gated job — including tier-1 corpus — skipped on all 36 scheduled runs #109Fixed — and the generic form found a third suite nobody had mentioned.
The fix
Coverage::finishnow fails underrequireon anySkipClass::Unavailablerepo. The discriminator is structural —repo_path(spec)returningErr— so all 12 call sites across 6 suites are unedited, and content-determined skips ("no cross-file refs to mutate") stay legal. That distinction is the whole design: a repo that could not be fetched is a broken universe; a repo with nothing to grade is a measurement.Log line is three-state:
executed=N unavailable=U not_applicable=A.The mutation, verbatim
And its control — same wrong sha, old floor restored:
test result: ok. 2 passed. So the old guard demonstrably passed on a shrunken corpus, on real data, today. Plus 3 unit mutations, all RED.The third instance, and the answer to a question I asked
I had asked whether this fix would automatically cover the #84 axis-C case (
ruby_package_parityin no CI job, grading zero, passing). The answer is no, and the reason matters: the floor is opt-in by env var — deliberately, sincecargo test --workspacemust not demand a 9-repo cache — so a suite that noCOSI_CORPUS_REQUIRE=1job names has a floor of zero. The two changes compose; neither alone suffices.So the generic form was built:
every_corpus_suite_runs_where_the_require_floor_applies— anycrates/indexer/tests/*.rsconstructing aCoveragemust be named by a job that sets the floor.It found a third suite nobody had raised:
upgrade_equivalence's corpus half, not#[ignore]d, which had never graded a repo. All three are now wired; measured--releaseunder contention:ruby_package_parity8.4 s (executed=1),ruby_package_cost27.5 s (executed=1— 1 is their recorded universe, so the floor is satisfied),upgrade_equivalence47.4 s (executed=7). 4 mutations RED.The gate caught itself twice before it caught anything else — first matching its own prose, then its own
containsargument. Fixed by stripping comments and assembling the needle from parts. That is the third time today a guard's first version matched its own source.Verification note
corpus_ratchetwithREQUIRE=1:executed=7 unavailable=0,baseline.jsonmd5 unmoved at534084b856c22566c48e386bc41ed67e, never blessed.One process finding recorded against the lane's own work: its first workspace-test summary was vacuous — it read the wrapper's
echoexit code rather than cargo's, and cargo had exited 101. Caught by reading the output file verbatim, which is why the final report quotes exit codes instead of summaries. That is the same failure I made on this issue's sibling (#109) with a vacuous API filter, twice.