Fail closed when a gauntlet layer never runs - #16
Merged
Conversation
Scenario 5 placed `2>&1` outside the command substitution, so the subshell's stderr leaked to the terminal instead of being captured — unlike the four controls above it. It asserts only stdout, so nothing was wrong today, but a regression that printed the all-green message while also emitting a missing- or failed-layer complaint on stderr would have passed this scenario on its own. The other controls still catch that; this restores the layer of depth they were written to have. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Source state is now `42528d9` / `5aa96ec5487c957c`. The 50-test randomized suite was rerun 10/10 at this state rather than inherited, and the orchestration control was re-verified at 13/13 with the fail-open mutation battery still turning it red. Records that scenario 5 was found shallow by review rather than by the control, and that the REVISION 7 contract is unchanged — this is a rebind, not a new revision, because `tools/` is inside the hashed scope. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Closes #13.
The defect
tools/gauntlet.shprinted a layer heading and ran that layer's command on two separate lines. Delete the command, keep the heading, commit, and on a clean tree the entry point printed the heading, did no work for the layer, exited zero and announcedall layers green. Reproduced by deleting the committed mutation invocation: no mutant ran, and the gauntlet still reported success. Becauseevidence.mdis written by hand, the previous run's22/22would then be copied forward.This is the failure class the repo exists to eliminate — a mechanism reporting success while doing nothing — sitting in the orchestration layer that every other layer's result is reported through. Nothing guarded it: of the six scripts in
tools/, four already carried negative controls and one is a six-line wrapper.gauntlet.shwas the one with none.The repair
tools/gauntlet_layers.shholds a fixed expected-layer manifest, an execution wrapper and a final audit:run_layerprints the heading and runs the command in one call, so the two cannot be separated by deleting a line.all layers greenis emitted only by the final audit, after every expected layer completed exactly once.The manifest and the invocations live in different files, so an accidental one-file deletion is caught. A coordinated edit to both is still possible; that residual is stated in
evidence.mdrather than papered over.Assurance boundary
Recorded in
spec.mdREVISION 7 and generalised intoskills/old-coder/references/gauntlet.md:Coverage and mutation were deliberately not extended to
tools/. The decisive argument is inevidence.md: the shallow-history defect fixed in REVISION 6 would have survived 100% coverage and a full mutation run, because it was a missing scenario, not an unkilled mutant. The control that found it was a negative control.Controls
tools/test_gauntlet_orchestration.sh, five scenarios / 13 expectations, run as the gauntlet's first layer and therefore accounted for by the mechanism it tests:set -ethrough a conditional contextThe RED step was performed against a deliberately fail-open helper: 8 of 13 expectations failed, including an omitted
mutationlayer returning zero and printing green.Verification
rc=1,FAIL: missing layer 'mutation',all layers greenabsent.gauntlet_layers.sh(always-zero audit, skip the missing check, record failed layers as complete, drop the duplicate guard, drop the unknown guard, swallow the exit status): 6/6 turn the control red.42528d9; binding42528d9/5aa96ec5487c957creproduces from a clean clone.Commits
905e9895b8dc1b9f4fae342528d95c9d48aTwo hardening items found in review and deliberately deferred are in #15: unprefixed shell globals in
gauntlet_layers.sh(verified unreachable today), and the absence of a control for the plural half of "names every missing layer".