Add the prove-the-test-fails skill - #13
Conversation
Encodes a rule from a real session: a test you just wrote is not verified until you have watched it fail for the right reason. The test that prompted it asserted that two retrieval strategies returned the same set of result types, which two empty lists satisfy. It was the only test guarding the project's central design invariant, it could not fail for the reason it existed, and it had been green in CI for weeks. Breaking the implementation on purpose was what found it. The skill covers when to reach for the loop, how to pick a mutation that is the smallest change at the seam the test claims to guard, what counts as confirmation including the blast radius across a parametrised suite, and reverting. It names the anti-patterns that make the exercise worthless, mutating too broadly or at the wrong layer or leaving the mutation behind, and the case where a surviving test is correct rather than decorative. Packaged as a top-level skills/ directory with its own marketplace entry using source "./" and a skills path, per the marketplace docs' pattern for several entries sharing one skills folder. The entry carries no version so Claude Code resolves it from the commit SHA and installed copies refresh without a manual bump. Two checks, both per-skill through paths filters. make check validates the frontmatter and the marketplace entry, then proves the eval fixture is still a trap by applying the mutation an agent is meant to find and asserting the exact shape of the run that follows. make evals gives a headless Claude Code run the fixture and grades on behaviour: the verdict is only reachable by breaking a strategy, the tracked files must match the starting commit, and the suite must be green again. A --control flag runs the same task without the skill. In the runs on record the control also passes, so this is a regression guard on the guidance rather than evidence of uplift, and the eval README says so.
Everything committed here is meant to be reusable on any project, and this skill's practice already was. Its illustrations were not: every one came from the Python retrieval codebase that prompted it, so a reader working in Go, TypeScript, Swift or Rust met a skill whose examples were all one search engine. State up front that no step depends on a language or a runner, and spread the examples. "Two strategies agree" becomes two implementations of one interface. The blast-radius step now names the shape it needs in three ecosystems, since table-driven subtests in Go, one describe per implementation in Jest and a parametrised pytest case report their cases the same way. The reporting example moves to a cache contract under Vitest and keeps what made it good: a named mutation, exact counts on both sides, and a confirmed revert. The empty-result survivor stays, restated without a search function. Recast the eval fixture as two route matchers, a compiled-regex one and a segment walk, rather than the origin project's two search strategies. The defect is unchanged: a contract test comparing sets of result types on an input that matches nothing, which reduces to set() == set() whichever implementation is broken. One fixture in one language stays the right trade, so this is a recast rather than a fixture per ecosystem. check_fixture.sh follows the rename and still asserts the exact run shape. It was verified against three mutations it must catch: a contract test made non-vacuous, a blast radius leaked into the second implementation, and drift in the line it anchors on. Each turned it red with the message that explains why, and reverting turned it green. The eval and its control both pass on the recast fixture, so the README's admission is unchanged and still accurate: with the skill absent the model reaches the same answer here, which makes this a regression guard on the guidance rather than evidence of uplift.
Generalised past the codebase that prompted itAnything in this repo should be reusable on any project. The practice this skill states is What went. The two-strategies framing, the What the examples span now. A sentence up front says no step depends on a language or a Length is roughly unchanged. This was substitution, not addition, and there is deliberately The fixture. Recast from two search strategies to two route matchers, a compiled-regex Confirming the checks still bite.
Eval results. Both runs pass on the recast fixture, verdict The honest negative stands. The control still passes, so this remains a regression guard Untouched shared files. |
The skill read as a procedure manual: a mutation catalogue, a five-item anti-pattern list, a section on legitimate survivors, and a runner inventory in the opening. Each piece was defensible and the whole was minutiae, which is not what a skill is for. Lead with the principle that a test is not evidence until observed failing for the reason it exists, keep the loop as the workflow it is, and cut the elaboration. What survives is what changes behaviour the principle alone would not settle: mutate at the seam the test claims to guard, check that the right cases failed and the wrong ones did not, and always revert. One anti-pattern and one gold standard remain, compressed. Body drops from 84 lines to 47.
Rewritten as principle and workflowThe file read as a procedure manual. It is now the principle, the workflow that principle Cut
Kept, and why each earns it
One line was added rather than cut: the loop takes one mutation at a time, so independent Overfitting No project names, session references, issue numbers, ports, or component names. No Wiring check No retargeting needed. Verification
|
Adds
skills/prove-the-test-fails, a skill encoding one rule: a test you just wrote is not verified until you have watched it fail for the right reason.Why
From a real session. A Python repo had two lexical retrieval strategies expected to satisfy one shared contract, and the test asserting it read:
Two empty lists satisfy that. The single test guarding the project's central design invariant could not fail for the reason it existed, and it had been green in CI for weeks. It was found only by deliberately breaking the implementation and noticing that nothing went red.
What the skill says
Pick the smallest mutation at the seam the test claims to guard, run the suite, confirm the right test fails and the message names the right thing, confirm the blast radius (breaking implementation A fails A's cases and leaves B's passing), then revert. It names the anti-patterns that make the exercise worthless, mutating too broadly or at the wrong layer or forgetting to revert, and the case where a surviving test is correct rather than decorative: an always-empty implementation legitimately satisfies "an empty query returns nothing".
Packaging
A top-level
skills/directory with its own marketplace entry,source: "./"plus askillspath, which is the documented pattern for several entries sharing one skills folder at the marketplace root.strict: falsebecause the repository root has noplugin.jsonto be the authority. Noversion, so Claude Code resolves it from the commit SHA and installed copies refresh without a manual bump.Verified end to end by installing from a local clone of this branch into a throwaway
CLAUDE_CONFIG_DIR: the plugin installs, reports version7aa20b2e69d9, and the skill lands atplugins/cache/walkerhughes/prove-the-test-fails/<sha>/skills/prove-the-test-fails/SKILL.md.Evals
One fixture, a small retrieval library whose suite is green and whose contract test cannot fail, reproducing the defect above.
make checkneeds no credentials and runs in CI. It validates the frontmatter and the marketplace entry, then proves the fixture is still a trap: it applies the mutation an agent is meant to find and asserts the exact shape of the run that follows, including that the contract test survives, that only the[lexical]cases die, and that the empty-query case survives legitimately. Repairing the fixture's assertion turns it red.make evalsgives the fixture to a headless Claude Code run with the skill installed as a project skill, and grades on behaviour rather than prose: the verdict is only reachable by breaking a strategy, the tracked files must match the starting commit so any mutation was reverted, and the suite must be green again. The skill is never named in the prompt, so an automatic load also tests thedescription.Honest result.
--controlruns the same task with the skill absent, and in the runs on record it passes too. So this is a regression guard on the guidance, not evidence of uplift, andevals/README.mdsays exactly that rather than implying otherwise.Not a Harbor task, unlike the MCP plugins here. Those need a server exercised as a server against a live hub. A skill is a markdown file that has to sit in the agent's own skill directory, and the version under test is the one in the branch, which the existing tasks cannot reach because they install their subject from GitHub's default branch.
Checks run
make checkinskills/prove-the-test-fails, green.claude plugin validate . --strict, passes.make evalswith--model sonnet, passes. The transcript shows the loop: two mutations, blast radius read correctly, reverted.strict: falsefrom the marketplace entry fails exactly one wiring check. Stub agents that leave the mutation, give the wrong verdict, or write nothing each fail exactly the corresponding grader check and no others.🤖 Generated with Claude Code