…untraced
v1.135 caught 19 Verus proofs that were DEFINED and never RAN. This is the
mirror image, and it had been true the whole time: 22 Kani harnesses that RAN
on every push, and no artifact recorded them.
THE ASYMMETRY. VGATE-P01 gave the gate a cross-check in ONE direction — an
artifact citing `cargo kani -p <crate>` for a crate outside kani.yml's matrix
is an ORPHANED PROOF, because CI never runs it. That catches evidence claimed
but not executed (the MIX-P05..P08 pattern, unenforced for ~40 releases).
It cannot catch the reverse, and a one-directional check is satisfied by citing
NOTHING: the fewer proofs an artifact claims, the less can be orphaned. The
incentive runs the wrong way and the failure is invisible — nothing goes red,
an assessor simply reads a hole in the trace.
MEASURED.
kani.yml matrix engines 45
cited by >= 1 artifact step 35
cited by NOTHING 10 <- untraced
relay-hk 2 verify_collect_bounded, verify_no_panic
relay-cs 3 verify_crc_deterministic, verify_check_bounded, verify_no_panic
relay-ds 3 verify_decision_bounded, verify_disabled_no_decision, verify_no_panic
relay-fm 2 verify_empty_path_rejected, verify_no_panic
relay-ci 2 verify_valid_header_accepted, verify_no_panic
relay-to 2 verify_subscribe_unsubscribe, verify_no_panic
relay-md 2 verify_sample_bounded, verify_no_panic
relay-mm 2 verify_out_of_range_rejected, verify_no_panic
relay-tbl 2 verify_register_bounded, verify_no_panic
relay-ccsds 2 verify_encode_decode_roundtrip, verify_no_panic
TOTAL 22
CONFIRMED BY AN INDEPENDENT QUERY over different data. For every requirement at
implemented/verified/accepted, collect its `verifies` edges and flag those whose
verifiers ALL have zero steps. That returns exactly SWREQ-{HK,CS,DS,FM,CI,TO,MD,
MM,TBL,CCSDS}-P01 — the same ten, reached without reading kani.yml at all. Their
only `verifies` edge came from a stepless roll-up (SV-RELAY-*), so the trace said
"no executable evidence" for requirements whose proofs were green in CI that
same minute. Two queries converging is what makes this a finding rather than an
artefact of one script.
THE FIX IS FILTER-INDEPENDENT BY CONSTRUCTION, which is the part that matters.
`kani_cited_crates()` scans the artifact tree from DISK, not the filtered set the
run is executing. Coverage is a property of the graph, not of one run's scope.
Computed from the filtered set, `Verify-Filter: (has-tag "oci")` (6 of 213
artifacts) would have reported 39 engines untraced — a spurious failure that
would have got the check deleted inside a week. Verified: under that filter it
still reports exactly the real set. A filter can shrink what is EXECUTED; it
cannot shrink what is CHECKED FOR COVERAGE.
Fail-closed on an empty matrix, mirroring the verus.yml empty-set guard: an
unreadable kani.yml would otherwise make coverage vacuously pass at "0 uncovered".
NEGATIVE CASE OBSERVED, not assumed. Injecting `- relay-fake-untraced` into the
matrix makes the gate print it and exit 1; reverting restores exit 0. The first
injection attempt silently changed nothing (the matrix is a YAML block list, not
the inline-quoted form assumed) and the run then "passed" — so the substitution
count is asserted before the result is believed. A negative test that did not
inject is a passing test proving the opposite of its claim.
GAP CLOSED, NOT JUST DETECTED. FV-RELAY-KANICI-001 — whose stated scope is
already "cFS engines' Kani harnesses model-checked in CI" — goes from 6 engines
to 16 (30 -> 52 harnesses) and gains `verifies` edges to the ten SWREQ-*-P01.
The requirement-side query goes 11 -> 1.
WHAT THIS DOES NOT CLAIM. Citing the proofs makes the evidence visible; it does
not argue the evidence is sufficient. Ten of the 22 are `verify_no_panic`, a
totality property rather than a functional one, so the ten requirements stay at
`implemented` — not promoted on the strength of a link that did not exist
yesterday.
THE ONE REMAINING CASE IS NAMED, NOT PAPERED OVER. SWREQ-FALCON-SIM-P04's eight
verifiers (FV-FALCON-SIM-006..013) are stepless gz-sim bench artifacts. A step
asserting the recorded bench-evidence CSVs still exist would zero the query and
verify almost nothing — it would check that a May-2026 record is still on disk,
not that the software still produces it. That is optimising the metric instead
of the property, which is the failure this gate exists to prevent.
Two-commit rule: this PR carries code, so nothing goes past `implemented`.
rivet validate: exit 0. Full unfiltered dry-run: exit 0, 0 FAIL, 0 UNTRACED.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HvusAXYbHLyv3uTzfBcMbG
No
Verify-Filteron this PR, deliberately. It changes the gate itself; itsevidence should be the unscoped default sweep.
The finding
v1.135 caught 19 Verus proofs that were defined and never ran. This is the
mirror image, and it had been true the whole time: 22 Kani harnesses that ran
on every push, recorded by nothing.
VGATE-P01cross-checks in ONE direction — an artifact citingcargo kani -p Xfor a crate outside
kani.yml's matrix is an orphaned proof, because CI neverruns it. That catches evidence claimed but not executed.
It cannot catch the reverse. And a one-directional check is satisfied by citing
nothing: the fewer proofs an artifact claims, the less can be orphaned. The
incentive runs the wrong way, and the failure is invisible — nothing goes red, an
assessor just reads a hole in the trace that the CI log has been filling all along.
Measured
relay-hkrelay-csrelay-dsrelay-fmrelay-cirelay-torelay-mdrelay-mmrelay-tblrelay-ccsdsConfirmed by an independent query over different data. For every requirement
at
implemented/verified/accepted, collect itsverifiesedges and flagthose whose verifiers all have zero steps. That returns exactly
SWREQ-{HK,CS,DS,FM,CI,TO,MD,MM,TBL,CCSDS}-P01— the same ten, reachedwithout reading
kani.ymlat all. Their onlyverifiesedge came from a steplessroll-up (
SV-RELAY-*), so the trace said "no executable evidence" forrequirements whose proofs were green in CI that same minute.
Two queries over different data converging is what makes this a finding rather
than an artefact of one script.
The design decision that matters: filter-independence
kani_cited_crates()scans the artifact tree from disk, not the filtered setthe run is executing. Coverage is a property of the graph, not of one run's
scope.
Computed from the filtered set,
Verify-Filter: (has-tag "oci")(6 of 213artifacts) would have reported 39 engines untraced — a spurious failure that
would have got the check deleted inside a week. Verified: under that filter it
still reports exactly the real set.
Fail-closed on an empty matrix, mirroring the
verus.ymlempty-set guard: anunreadable
kani.ymlwould otherwise make coverage vacuously pass at "0 uncovered".Negative case — observed, not assumed
Reverted → exit 0.
The first injection attempt silently changed nothing (the matrix is a YAML
block list, not the inline-quoted form I assumed) and the run then "passed". So
the substitution count is now asserted before the result is believed — a negative
test that did not actually inject is a passing test proving the opposite of its
claim.
Gap closed, not just detected
FV-RELAY-KANICI-001— whose stated scope is already "cFS engines' Kaniharnesses model-checked in CI" — goes 6 → 16 engines (30 → 52 harnesses) and
gains
verifiesedges to the tenSWREQ-*-P01.Requirement-side query: 11 → 1.
What this does NOT claim
Citing the proofs makes the evidence visible; it does not argue the evidence
is sufficient. Ten of the 22 are
verify_no_panic— a totality property, nota functional one — so the ten requirements stay at
implemented, not promoted onthe strength of a link that did not exist yesterday.
The one remaining case is named, not papered over
SWREQ-FALCON-SIM-P04's eight verifiers (FV-FALCON-SIM-006..013) are steplessgz-sim bench artifacts. A step asserting the recorded bench-evidence CSVs still
exist would zero the query and verify almost nothing — it would check that a
May-2026 record is still on disk, not that the software still produces it. That is
optimising the metric instead of the property, which is the failure this gate
exists to prevent.
Evidence
Note for the merge order
This touches
scripts/run-falcon-verification.py, as does #342. Expect to rebasethis onto #342 once that lands — #342 goes first (it fixes a gate that can pass
having verified nothing, and everything after it should be validated under the
fixed gate).
Two-commit rule: this PR carries code, so nothing goes past
implemented.Refs #6
🤖 Generated with Claude Code
https://claude.ai/code/session_01HvusAXYbHLyv3uTzfBcMbG