Pin every current behavior with tests before a large refactor

Rulestack's Claude Code agent wrote 25,396 characterization tests in 769 files to freeze its own TypeScript codebase before a restructure, taking coverage from 64.6% to 99.1% and turning up bugs.

Done withClaude Code· Oct 21, 2026

What they did

Rulestack runs a Claude Code agent that maintains its own TypeScript codebase: about 230 CLI tools, pre-commit gates, daily job scripts and JSONL ledgers. On 2026-10-08 the owner asked it for tests that would hold every current behavior in place through a move to a domain-driven layout. The agent first deleted 1,358 lines of unused code and two dependencies, exported main from every CLI, and moved commit-gate checks out of test files so they could take fake input. It then wrote a case list, one id per behavior, and one Jest test per case, with expected values taken from running today's code, bugs included. Disagreements between the list and the code went to the owner. Every lock test runs in a sandbox that blocks repo writes, network, secrets and child processes inside the repo.

How it went

The lock came to 25,396 tests and about 505,000 lines of test code guarding 162,385 lines of source. Statement coverage went from 64.6% to 99.1%; the 235 unreached spots are listed in a ledger, none approved yet. Writing the cases found three bugs, including replies to direct messages that could go out without the owner's approval. The sandbox leaked six times before it held, one fault surfacing only in CI. A full run took 8 minutes 44 seconds on a heavily loaded 10-core machine. The refactor itself has not started.

Worth knowing

The tests pin wiring as well as behavior. Moving one startup check into a shared helper changed nothing a user could see but forced edits in 69 lock files, so the authors may split wiring cases out before refactoring. In Jest, process.env is a copy, so env tricks such as HOME or TZ do not reach child processes or Date unless passed on explicitly.

Try it

With Claude Code· 5 parts to fill in

Before we refactor [my codebase or module], write characterization tests that lock in what the code does today, bugs included. First write a case list in [docs/behavior-lock.md] with one id and one sentence per behavior. Then write one test per case under [test/behavior-lock/], with expected values taken from running the current code, not from what it should do. Run every test in a sandbox: temp working directory and HOME, no writes to the repo, no network except localhost, no secrets in the environment. Where the code and the case list disagree, pin the code and add the question to [a list for me]. Do not change any production behavior. Stop when coverage reaches [target] or each unreached line has a written reason, and show me the open questions.

Square brackets are the parts to fill in. The prompt is ours; the story is theirs.

Where they said it

Related