fix(verify): the runner shall not report success having executed zero commands (#403) - #440
fix(verify): the runner shall not report success having executed zero commands (#403)#440avrabe wants to merge 1 commit into
Conversation
… commands (#403) `tools/run_verification.py` skipped an artifact with no `fields.steps[].run` and counted the skip toward exit 0. Its terminal decision was `return 0 if failed_count == 0 else 1`, so a run that matched artifacts and executed ZERO commands returned 0 — and `Verification Gate (rivet-driven)` is a REQUIRED context, so it reported green having verified nothing. Measured: `--filter '(and (= type "feature") (has-field "test-name"))'` matched 64 artifacts, ran nothing, exit 0. The sibling `if not ids: return 1` had already closed "the filter matched nothing"; "matched, and nothing ran" sat open one branch below. REQ-GUARD-GATE-EVIDENCE-003 (check_evidence_steps.py) guards the artifact PLANE via a ratchet that deliberately does NOT hard-fail the skip backlog. This is the sibling RUNNER half it named as still open: a pure `decide_exit(total, passed, failed, skipped)` reds a run that verified nothing and names the cause, while a mixed run that ran something still passes — so it does not re-introduce the "fail all 85 at once" posture the ratchet avoids. - decide_exit + `--self-test` (no rivet, no shell); the load-bearing "all skipped -> 1" case pins both the exit code and the "verified nothing" reason. Mutating the guard to never fire reds the self-test. - ci.yml: Verification-runner guardrail self-test in the rivet-validate job. - check_self_test_potency.py: `rv-zero-executed-lenient` mutant (CAUGHT). - REQ-GUARD-GATE-EVIDENCE-005 + TEST-GUARD-EVIDENCE-RUNNER (release v0.43.0), tracing to -003. Blast radius: the Verification Gate default filter (v093/v0100) selects 20 type:feature artifacts, all with runnable steps, so the default gate cannot red. Evidence-step floor unchanged (78). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rivet verification gate✅ 20/20 passed
Filter: Failed artifacts(none) Updated automatically by |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Clippy came back red — diagnosed as a transient runner flake, not this PR'sThe This diff touches zero Rust. The change is It does not reproduce under the exact CI conditions. Locally I ran, on this branch's checkout:
The failure signature is transient, not a lint. The job log shows I could not re-run it myself: Ask: a maintainer re-running the The remaining required checks (Mutation ~2h, Lean ~90m, etc.) are still running. Generated by Claude Code |
Correction: this is NOT a flake — it's a real, repo-wide nightly-clippy regression. My previous comment was wrong.I have to correct my earlier comment. I diagnosed the Clippy failure against stable 1.98.0 and called it a transient flake. That was a mistake: the Reproduced on the actual toolchain — Root cause:
|
|
Standing down this run — the CI red here is a base-branch clippy break, not this PR. State of the head ( This PR's diff is five files — Root cause is the toolchain: the job installs Reproduce on the base: I'm not widening this no-Rust PR with an unrelated, repo-wide clippy fix. The base needs a fix (or a nightly-clippy pin) first; once that lands, this PR should go green on a re-run with no change here. Not merging. Autonomous issue-hunt run: 4 PRs open (#440–#443), so the overlap guard held and no new work was started this run. Generated by Claude Code |
|
CI red on this PR is a repo-wide nightly-clippy drift, not this change. Standing down rather than widening a Python-only PR — this needs a maintainer decision (see below). What is failingOnly the required The Evidence it is toolchain drift and repo-wide, not this PR:
The 3 hits (all pre-existing, none touched here)All three are symmetric 2D-matrix accesses that use both indices, so clippy's Why I did not just fix it here
This blocks all four currently-open PRs (#440, #441, #442, #443). Once a fix or pin lands on Generated by Claude Code |
Closes the remaining live half of #403 — the issue's reported title.
The defect
tools/run_verification.pyskips an artifact with nofields.steps[].runand counts the skip toward exit 0. Its terminal decision wasreturn 0 if failed_count == 0 else 1, so a run that matched artifacts and executed zero commands returned 0 — andVerification Gate (rivet-driven)is a REQUIRED context, so it reported green having verified nothing.Measured on the live plane:
The sibling
if not ids: return 1had already closed "the filter matched nothing"; "the filter matched, and nothing ran" sat open one branch below.Scope — the runner half, ratchet-bounded
REQ-GUARD-GATE-EVIDENCE-003 (
check_evidence_steps.py) already guards the artifact plane via a ratchet that deliberately does not hard-fail the skip backlog (failing all 85 claiming-but-stepless artifacts at once is "a gate that gets disabled"). It named the runner's exit logic as a separate, still-open question. This PR is that half, and it stays compatible with the ratchet:decide_exit(total, passed, failed, skipped)reds a run where nothing executed (every match skipped) and names the cause.REQ-GUARD-GATE-EVIDENCE-003(taggedhuman-scoped) is untouched.What's here
run_verification.py:decide_exit()+--self-test(no rivet, no shell). The load-bearing caseall skipped -> exit 1pins both the exit code and theverified nothingreason text. Mutating the guard to never fire reds the self-test.ci.yml:Verification-runner guardrail self-teststep in the rivet-validate job, beside its siblings.check_self_test_potency.py:rv-zero-executed-lenientmutant — CAUGHT (5/5 declared mutants caught).REQ-GUARD-GATE-EVIDENCE-005+TEST-GUARD-EVIDENCE-RUNNER(releasev0.43.0), tracing to-003.Blast radius
The Verification Gate default filter (
v093/v0100) selects 20type: featureartifacts, all with runnable steps, so the default gate cannot red on this change. Evidence-step floor unchanged (78).Verification (local)
run_verification.py --self-test→ 9/9; proven non-vacuous by the mutation above.check_self_test_potency.py→ 5/5 CAUGHT;--self-test12/12.check_evidence_steps.py --max-stepless 78→ green (floor held).rivet validateruns in CI (no local rivet, as expected).Not claimed
check_verification_filters.py's and the per-step cargo exit's question.-003's job.🤖 Generated with Claude Code
Generated by Claude Code