This article is part of a set of free Claude skills
These rules are packaged as Claude skills: small files you drop into Claude Code so your own assistant works this way too. The published set is at blonderoofrat/agent-skills. They are public domain: copy them, change them, no attribution and no permission needed. How to install them is at the end of this article.
There was an animal in the colony that did not exist.
It had a name in the house style, a date of birth, a cage. It looked like all the others. It was sitting in the active list, being counted, making the total read 312 when the true number was 311. It had been created by a test – a script proving that the “add an animal” form worked – and the test had proved it by adding one, to the real database, and then not cleaning up after itself.
Then I looked for its siblings. There were thousands.
Not thousands of visible animals: the great majority were soft-deleted, invisible on every screen, harmless in every practical sense. But they were in the same table as the real ones, and they had been arriving for months, and the only reason anybody noticed was that one of them failed to delete itself and pushed a number on a dashboard up by one.
That is the part I keep coming back to. The system was not silent because it was well-designed. It was silent because the bug was tidy. A messier version of the same bug would have been found in a day.
What I tried first, and why it was not enough
The obvious fix is to point the tests somewhere else. So I built that: a staging copy, and a redirect that every test calls at startup to aim itself at the copy instead of production.
It worked, and then it leaked, and the way it leaked is the interesting part.
The redirect installed itself by overriding a setting on an imported module. Two files imported that module by two different names – one as a submodule of a package, one as a bare top-level import. Python treats those as two separate module objects. The redirect overrode one of them. Writes that went through the other went to production, while the test printed a cheerful line saying it had been redirected.
Every check I had confirmed the redirect had been called. None confirmed it had worked. So the machinery printed reassurance at exactly the moment it was failing.
Making the test suite refuse to touch production
I had built six checks around the redirect. A reviewer looked at them and said something that reorganised the problem for me: not one of the six had caught a single real defect, three of them contained the very bug they were policing, and all six verified a call was made rather than an effect was achieved.
The advice was to stop asking tests to behave and start making misbehaviour impossible:
Withhold the credentials. Membership is location, not intention.
Any script whose entry point lives in a test directory is denied production credentials from its first line – whether or not it redirects, whether or not it remembers to, whether or not it was written yesterday by someone who has never read this. There is no opt-in to get right, so there is nothing to forget. A new test cannot reach production by accident, only by being deliberately named in a short list that a human maintains.
The difference is that the old design failed open for anyone who forgot, and the new one fails closed for everyone who does not ask.
And a ground-truth check, because guards lie
The second thing that reviewer said was that all the static checks in the world are proxies, and the one check actually worth having was missing: audit the real database around every test run.
Snapshot it before, compare after, report every row added, removed or changed. It knows nothing about which tests exist, what a fixture looks like, or what the naming conventions are – that ignorance is the point, because every piece of knowledge is somewhere my assumptions could hide. It would have caught the two-module leak on day one without anyone having imagined two-module leaks.
The postscript that makes the point better than the story does
That audit was written, tested, and declared correct. It then sat inert for a day.
The seal I had built an hour later denied it credentials too – it lived in the test directory, so it was treated like a test – and so the one instrument whose entire job was to prove the database had not changed was silently unable to look at the database. Its own self-test passed the whole time. That self-test only ever asked whether the seal blocks things. It never asked what it was blocking.
It is now in an explicit read-only list, its self-test has a case for that path, and a separate check enumerates what the seal denies rather than only what it permits.
I do not offer that as a tidy ending. I offer it as the actual lesson: the guard you just wrote is the least-tested code in your system, and it will fail in the direction that looks like success.
The rules
- Isolate by construction, not by convention. Withhold credentials by location. Do not ask tests to redirect themselves.
- Verify the effect, not the call. “The redirect ran” and “the write went to the copy” are different claims, and only one of them is the one you care about.
- Keep one dumb ground-truth check that knows nothing about your test suite and only compares the real data to itself.
- Run your new guard inside the real pipeline before trusting it. A self-test proves the guard fires. It says nothing about what else it broke.
Get the skills
Everything above is generic. None of it is about rats, and none of it is specific to this site. So these rules are also published on their own as Claude skills: small Markdown files that an AI coding assistant reads and applies when the situation comes up.
The set: blonderoofrat/agent-skills
git clone https://github.com/blonderoofrat/agent-skills
Installing them in Claude Code. Copy any skill’s folder into one of these, so the file ends up at .../skills/<skill-name>/SKILL.md:
~/.claude/skills/(available in every project on your machine)your-project/.claude/skills/(that one project only)
Claude reads them at the start of the next session and applies one when what you are doing matches the description at the top of that file. You can also ask for one by name.
Using a different assistant? They are plain Markdown with a two-line header. Paste the body into whatever system prompt, rules file or instructions file your tool uses. Nothing in the rules themselves is Claude-specific.
Licence: CC0, public domain. Copy them, adapt them, ship them in commercial work, no attribution required. These are deliberately frozen snapshots rather than a maintained project, so if one is wrong for your situation, change it. That is easier than asking us to.
The particular rule in this article is being added to that set; it is not up there yet.
Part of Notes from building this site: articles about working practices that exist because something here went wrong first. Most of these rules are also published on their own, as free public-domain instruction files for AI coding assistants, at blonderoofrat/agent-skills on GitHub. This one is not up there yet.
Filed under News about this site




