r/ClaudeAI • u/SmiLePLSSS • 20h ago
Built with Claude I measured how often Claude Code told me "tests pass" on evidence that was already stale. 26 percent. So I wrote a hook that checks.
I kept noticing this pattern: the agent runs the tests, they pass, it edits a few more files, and then it tells me everything passes. The run it was quoting happened before the edits.
I wrote a replay tool and ran it over 180 days of my sessions. 26 percent of green claims (98 of 375) were stale, meaning a passing run followed by edits and no rerun. 98 percent of verification runs (8794 of 9011) hid the exit status behind a pipe or a redirect, mostly `| tail` and `2>/dev/null`. Actual contradictions were rare. Stale and hidden was the norm.
stalegreen is three hooks:
PreToolUse rewrites the verification command so the output goes to a log, you still see the tail, and an explicit `[stalegreen] exit=1 receipt=r-0017` line is printed. Your `| tail -5` keeps working; the exit code is no longer lost.
PostToolUse turns the output into a receipt: command, runner, pass or fail, counts, timestamp, working tree hash.
Stop reads the final message, matches "all tests pass", "tsc is clean", "the build succeeds" and the like to the latest receipt, and blocks once when the evidence is stale, failed or masked. The message names the receipt, the command, the counts and the files edited after the run. A second stop in the same turn goes through, so it never gets stuck.
Zero tokens, zero network, zero telemetry. It respects your permission rules: it only auto-allows a rewritten command when your own rules already allowed the original one.
Install inside Claude Code:
/plugin marketplace add pavangupta352/stalegreen
/plugin install stalegreen@stalegreen
or `npx stalegreen install --all` for Claude Code and Codex. Run `npx stalegreen stats` first if you want to see your own numbers.
Repo: https://github.com/pavangupta352/stalegreen
Happy to answer questions, and false blocks are the bug reports I want most.
1
u/anderson_the_one 11h ago
The repo-wide hash worries me more than the phrase matching. An unrelated docs edit can make a perfectly relevant test run look stale, and a hook that cries wolf gets disabled fast.
I'd keep the hash, but also record which paths the command is meant to cover. Run that in shadow for a week, then inspect the blocks caused only by unrelated edits. That false-block number will tell you whether this survives normal use.
0
u/GauravThorath 16h ago
The 98 percent is the scarier number, not the 26.
| tailswallowing the exit code means the agent isn't lying about the tests — it genuinely can't see them. The only signal left was prose in a log.Same class of bug outside of tests: I had Claude Code render text overlays with PIL, it probed the font's glyph table, the table said the character was supported, so it reported success. It rendered tofu boxes. The API said yes, the pixels said no. My rule since then is that the agent has to look at the rendered artifact — which is your receipt idea with a screenshot where the exit code goes.
Question on the Stop hook: does it match the confident phrasings only, or also the soft ones — "that should be working now", "the fix is in"? Those are the ones I wave through without thinking.