Let tests say "I did not verify this" - #113
Merged
b-macker merged 2 commits intoAug 1, 2026
Merged
Conversation
Five times this session an assertion passed while the property it named was
untrue, and none were caught by review — only by running the degraded case.
Four accidental discoveries is a poor sampling method, so this audits the set:
360 assertion sites in the example's run.sh, 2294 across 235 shell suites.
Most of it is already disciplined. Absence checks generally pair with a positive
existence check, a fail-safe default (${X:-1}, where unset means fail), or a
named control — TR-01 is labelled "the anti-regression", PU-01 fails outright if
its scenario produced fewer than six samples, C-02 is guarded by C-01 asserting
presence. Those were left alone.
The systematic finding is seven security suites that define only ok() and fail() and
no skip(). Unable to say "inconclusive", they were forced to record every
"executor not available" branch as a PASS. test_gov_comment_styles_gov002.sh
reported "Results: 4/4 passed" while verifying nothing at all — every check
unverifiable in this environment, the Python polyglot block evaluating to null
so the probe never satisfies. It now reports 0/4 passed, 4 skipped. Nineteen
sites across seven files, plus a SKIP count in each summary.
H01 is the sharpest single case. The living script prints its health verdict as
its very last act, so the line is absent exactly when a run died early — and the
fallback then inferred a verdict from stderr containing the string "governance",
which every governed run prints. A gk_fail-severity health check passed on a
substring match, and passed hardest in the case that matters most. IMPAIRED in
stderr is still real evidence and still fails; absence is now inconclusive.
Four smaller ones of the same shape: L24-03 was trivially true at zero
attestations and non-vacuous only because a neighbouring assertion stayed strict
(now self-guarding); DB-01/DB-03 could not distinguish "no false positives" from
"the compliant scenario never ran" (initialiser 0 -> sentinel -1); DB-04's
"1.00 0 0" fallback made a missing result file read as a confirmed known
negative; E04 asserted a line was absent from a dashboard that a failed run
never produced.
Every fix verified by degraded case. H01 three ways: a died-early run now skips
where it used to pass "healthy", a genuinely healthy run still passes, IMPAIRED
still fails.
The rule is narrower than "write better assertions": an assertion about an
absence needs the thing it is absent from to exist. A missing line in a document
nobody wrote, a zero from a counter nobody incremented, and a clean result are
the same observation until something distinguishes them.
Full suite: 441 tests, 0 unexpected failures. Leak check: 874/0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ELUfjXZvx8kzXo1UJjrAhC
NAAb Governance Report
All governance checks passed! Generated by NAAb Governance Engine v4.0 |
Reviewing the previous commit's diff before merge found six more inconclusive-as-PASS sites, in three files that commit was already editing. 19 of 25 had been caught. The filter searched for "not available" and "may be". The survivors read "may not be available", "depth may not have been reached", and "(acceptable)" — none of which match. A keyword filter over prose is itself an assertion that can be satisfied without the property holding: it finds the phrasings you thought of and reports clean on the ones you did not. Reading the changed files end to end is what caught the rest, which is the same lesson the rest of this branch is about, applied to its own detection method. test_js_marshal_depth_rt006.sh moves from 2/3 passed to 1/3 passed, 2 skipped — one more check that was reporting success while verifying nothing. The other two files are unchanged in this environment; their inconclusive branches simply do not trigger here, and are now correct if they ever do. Count corrected 19 -> 25 in the findings doc, with the miss recorded rather than the number quietly bumped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ELUfjXZvx8kzXo1UJjrAhC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Five times recently an assertion passed while the property it named was untrue —
grep '"key_fingerprint":"'matching an empty value, an attestation-count equality against a counter incremented on non-attesting paths, a taint total asserted on the wrong scope, a baseline inflated 2x by a telemetry defect, and a test-phase split that ran 19 fewer tests while printing clean summaries. None were caught by review; all were caught by running the degraded case.Four accidental discoveries is a poor sampling method, so this audits the set: 360 assertion sites in the example's
run.shand 2294 across 235 shell suites.Most of it is already disciplined
Worth saying first, because it shaped the scope. Absence checks generally pair with a positive existence check, a fail-safe default (
${X:-1}, where unset means fail), or a named control —TR-01is labelled "the anti-regression",PU-01fails outright if its scenario produced fewer than six samples,C-02is guarded byC-01asserting presence. 43 ofgovernance_v4's 69 candidates already pair with a positive check. Those were left alone.The systematic finding
Seven security suites define only
ok()andfail()— noskip(). Unable to say "inconclusive", they were forced to record every "executor not available" branch as a PASS:That suite verified nothing at all — every check unverifiable in this environment, the Python polyglot block evaluating to
nullso the probe never satisfies — while reporting four passes. 19 sites across 7 files, plus a SKIP count in each summary.Five individual findings
H01"governance", which every governed run prints. The living script emits its verdict as its last act, so the line is absent exactly when a run died early — agk_fail-severity check passing hardest in the case that matters most. IMPAIRED still fails; absence is now inconclusive.L24-03DB-01,DB-030indistinguishable from "the compliant scenario never ran" → sentinel-1DB-04"1.00 0 0"made a missing result file read as a confirmed known-negativeE04Deliberately unchanged
T9greps stable source;A05genuinely tests config acceptance;B02requires the value present;FM-01/FM-02treat a missing result file as uncaught → fail.tests/gorilla(62 candidates) is out of scope — older scenario tests, weakest claims.Test Plan
bash run-all-tests.shwith no new failures — 441 tests, 0 unexpected failuresbash tests/security/test_error_msg_leaks.sh— 874 checks, 0 failuresEvery fix verified by degraded case.
H01three ways:IMPAIREDin stderrDB-01/DB-04likewise skip on absent measurements while the real run still passes 4/4.Note
test_r24_fixes.shfails 2/10 locally (exit 127—naab-scanner/naab-govnot built in this container). Pre-existing and identical before this change, andrun-all-tests.shdoes not invoke it.Related Issues
Follow-up to #109–#112.
docs/governance-campaign-findings.mdrecords the audit and the rule it produced: an assertion about an absence needs the thing it is absent from to exist. A missing line in a document nobody wrote, a zero from a counter nobody incremented, and a clean result are the same observation until something distinguishes them.Generated by Claude Code