Layer: verification. Proof: make prove LEVEL=verification.
Claude cannot finish on a red gate, and every fixed bug has a test that fails without the fix.
Three bugs hide in this app. "Kindergarten" falls through to the wrong band because the parser only matched digits. The page drops the assistant's question from the history, so the agent asks it again. The preview overflows a 375 px phone. Happy-path tests pass on all three.
Reintroduce one fix by hand and ask Claude to finish. It stops, says done, and the bug ships.
.claude/hooks/posttooluse-typecheck.mjsruns after each edit and returns type errors to Claude at once..claude/hooks/stop-gate.mjsruns lint, types and tests when Claude tries to stop. Exit 2 sends the failure back as its next task. It honoursstop_hook_activeso it never loops.tests/structure/bands.test.tswalks every band and alias.web/src/lib/history.test.tsandlayout.test.tspin the other two bugs.
Break the code and let Claude try to stop. The gate refuses and prints the failure.
- Open
shared/src/bands.tsand breakparseBand. Ask Claude to stop. Expect the stop to be refused. - Fix it. Expect the stop to go through.
- Type
make prove LEVEL=verification.
The proof undoes each fix in turn, runs the named test, expects it to fail, then restores the file. It also checks both hooks are wired in .claude/settings.json. Expect 3 bugs bite, hooks wired.
The layout test reads the page source. A browser replay with Playwright and axe is the next step and is part of the take-home.
Track A: add a fourth bug and its biting test. Track B: replace the layout test with a Playwright check at 375 px.
A hook that fails the turn is a check you cannot forget. The design-reviewer agent adds eyes: it builds the app, opens it at 375 and 1280 px and reports sideways scroll, low contrast and print clipping. Run it after changing a font size and compare its verdict with tests/e2e/layout.e2e.ts, which asserts no sideways scroll, no serious accessibility violation and no clipped print page.
REVIEW.md tells the reviewer what failure looks like here: the count first, file:line evidence, at most three nits. The pretooluse-test-lock.mjs hook blocks edits to test files while FACTORY_PHASE=fix, so a fix cannot pass by changing the test. Set the variable in a shell and try to edit a test to see it refuse.
How many of your bug fixes would still pass their test with the fix removed?
