a promise is a claim about what the program does for whoever uses it.
what
a story is the sequence of whats somebody really performs.
what
a test is the file on disk that runs a story.
how
the code holds the promise, and the test measures that it still holds in time.
The promise and its measure
A test asserts a promise
rule
a story names the promises it asserts.
why: everything else a test could check is a measure of a promise the program
makes.
rule: a story with no promise to name is deleted rather than filed.
rule
the promise is written down, and the test only measures it.
why: a promise legible only as a test name is unreadable to the one it was made to.
why: the writing states the promise, the test holds it to time.
rule
the promise and its test stand or fall together, in both directions.
why: a promise held makes its test green, so a red names the promise that broke.
why: the other direction must be proved — a green means the promise holds only if
breaking the promise would redden the test.
The promise decides what is measured
rule
a test tries the inputs the promise covers, not every input the code accepts.
why: an input the interface never presents measures a promise nobody made.
rule
the promise says when the work is done, never the coverage number.
A reasoning links the stories to the promise
rule
what links a promise and its stories is a reasoning, written beside the
promise — these stories passing entails this promise held.
why: a red test then traces back to the promise that broke.
why: if unwritten, the next reader guesses the link, and a gap looks like a choice.
Stories are what matter
rule
we tell the stories, never the feature.
why: a use comes in whole stories — triaging a morning’s photos, running the
cabinet frame, picking a few shots to send — and those stories are the
promises the program makes.
why: a test written per feature asserts a promise nobody holds, since
nobody opens a program in order to exercise one feature.
what
when described in text, the desired behaviour is a what
what
when described in text, the chosen technical approach is a how
rule
stories describe whats in the order the person performs
them, carrying state from step to step.
why: a chain of gestures on one open program is what using it looks like, and
an isolated one-gesture run is a path no human takes.
rule
every story is one somebody really lives.
how: the user tells the stories and the writer never invents one.
how: the writer writes the what, the how and the tests, and assembles them
into the stories it was told.
why: there are very few of them, because a story is a whole real use rather
than a feature.
rule
between them the stories reach every promise the program makes — that reach is
the semantic coverage.
why: a promise no story reaches goes unmeasured.
how: the writer finds the gap and must propose it; the user decides.
how: a what that fits no story is that signal — either one is missing from
the set, or nobody does that thing, and which it is is the user’s call.
rule
ground walked twice is cut.
why: overlapping stories cost CPU, RAM, time and money
how: the writer suggests the stretch to cut and the user cuts it.
scope: stories overlap a little whatever happens, each one opening the program
and loading the same first screen, and that much is irreducible.
scope: the user may bend a story so that it stops short of showing the whole
thing, when the reasoning shows the trimmed part is measured elsewhere.
why: what is protected is semantic coverage, not the walking of every path.
rule: the reasoning linking promises to stories capture the cut and
indicate how a set of stories is fulfilling a given promise
The surface and the data
The promise is made at the seam the user touches
rule
whoever uses the work decides where the seam is — the end user of an
application, the programmer calling a library.
why: the promise is made at that interface; below it is the how.
rule
assertions probe the observable surface — visible text, public API,
exported artifact, ARIA role — not internals like private stores, test-only hooks
or implementation-selector classes.
why: an internal is the how, no user should care about the fact that
how works, but people care that the promise is fulfilled.
example: in web dev, the suite reaches for get_by_role, get_by_label and
get_by_placeholder rather than CSS selectors that encode the current DOM.
rule
the code carries nothing that exists solely for the test.
why: an affordance that exists only so a test can reach something serves no one
who uses the program.
example: in web dev, a data-testid or an attribute added for the suite — the
final user never reads a test id.
how: when the program turns out hard to test at the seam the user touches, the
difficulty is real information, and the fix belongs in the design.
why: usually the interface is just as unclear to the user.
A test seeds the world it reads
rule
the test world must be as close as possible to the real life
why: the product ends being used in real life, promises tested in a
different env but that don’t work in real life are worth nothing.
rule
when possible, the real world is duplicated for the test purpose
example: if possible a pg_dump of the production database gives a good
sandbox to check the promises.
rule
but a test creates the fixtures it depends on
why: it helps reproducible result by contrast to using the real world.
why: tests must assert there promises while not being disturbed by the changes of the real world
rule
the user decides the properties of the test world, not the writer
why: the writer is tempted to create a dummy world that has nothing to do with real life to make tests pass
When it goes wrong
Test, don’t patch
what
a bug is a promise found broken.
rule
every fix starts from a red, added to an existing story or by writing a
new story. Observed red, then made green by the smallest change that
satisfies it.
A flake is a diagnosis, not a knob
rule
an intermittent red is measured before any limit is touched.
why: widening a timeout is hiding the symptom, not fixing the problem
why: the expected time usually sits far under the ceiling, so the
failure is a transient — a CDN stall, a resource race — to remove (e.g. by
a fixture) or isolate.
rule
a timeout is raised only when the measurement shows the expected time
nearing it.
rule: the new number is justified in a comment.
rule
any limit change must be validated by the user
rule
flakiness that is not obvious to fix gets meaningful logging.
why: it helps investigate the next time the flakiness occurs.
rule
moving on a flaky test is the choice of the user, never the one of the writer.
The cycle
rule
the cycle is the unit of change.
why: each step exists because the previous one is provably insufficient.
why: skipping a step leaves a gap the next regression will fall into.
rule
the baseline run covers THE WHOLE SUITE, not a subset.
why: a subset baseline says nothing about pre-existing reds of the whole baseline.
rule
the baseline run is gated like any other action.
rule
a codebase that is red and not flaky has its tests fixed before the task at
hand resumes, unless the user explicitly asks otherwise.
rule
a promise is measured by the suite the cycle runs, and by nothing else.
why: a measure taken anywhere else is one no cycle can cite.
rule
the cycle is the succession of the following sub headings
1. focus on one promise at a time
rule
only one promise is fulfilled during a cycle
why: focusing on several creates a mess hard to untangle
rule
the other known promises are still taken into account when writing one
why: sometimes, we know that what we are doing is going to be put into
question or factorized by a future promise
why: there are several minimal ways to fulfil a promise, choosing the
one of least future friction is preferable
2. Red proves the test
rule
every test must be observed RED for the good reason at least once
rule
a test that passes for the wrong reason is worse than one that fails for
the wrong reason.
why: a wrong-failure test still points at a real fault to hunt; a wrong-pass
test sits green and hides a gap the suite reports covered, and its green is
indistinguishable from outside, so it survives every whole-suite run.
rule
the test is written first and observed red before any production code
changes.
why: that failure is what establishes that the test measures the promise it names.
rule
the failure mode and message are part of the test’s value.
rule
provided a given code, a test either always fails or always succeeds always for the same reasons
why: a flaky test cannot be trusted
rule
a test that was restructured rather than written is observed red again, by
breaking the promise it names.
why: a restructuring starts and ends green, so the moment that would have shown
the test still bites never arrives (see the wrong-pass rule above).
why: the failure names which test catches the break, so one that has drifted to
where an earlier test already covers it is visible as well.
how: break one behaviour at a time, in the production code, and require the
named test to be the one that fails; a break nothing catches is a test that
claims a promise it does not read, and a break something else catches first is a
promise measured elsewhere.
rule
a promise that cannot be broken from where the suite stands is recorded as
such, in writing, with the reason NEVER without the user gating the decision.
why: otherwise it is indistinguishable from one nobody has got round to
breaking, and the next reader spends the effort again.
why: the reason is itself a finding — it usually names a boundary the suite
cannot reach past, which is worth knowing before trusting what lies beyond it.
3. Minimum to green, then a test before the next line of code
rule
new behaviour appears under a failing test, and the next line of code waits
for the next test.
why: code beyond what the failing test demands is untested by definition and therefore unwanted.
why: the coupling keeps the suite a faithful description of the system, every
branch tracing back to a test that was once red.
scope: a refactor pass adds structure no single test motivates.
rule: an anticipated edge case is written as the next failing test, not as a
preemptive guard in the current change.
4. The whole suite measures the whole contract
what
the contract is every promise the program makes to whoever uses it.
rule
a change is verified only when the whole suite is green.
why: the new test going green proves its own promise realised, and says nothing
about which of the others the change broke.
why: implicit dependencies between modules — shared state, cached values,
ordering assumptions — surface only when every test runs.
why: the test you left out is the one most likely to catch the regression you
did not predict.
why: a green-to-green refactor can still flip a subtle ordering, a fixture, or
a shared helper.
why: what each run guards against is unknown ahead of time, which is what makes
it a regression rather than an anticipated case.
5. Refactor lives under green
rule
structural change runs under a green suite.
rule
behaviour is held fixed by the tests, and structure is the only thing
allowed to move.
why: mixing behaviour change with structure change loses the bisect signal — a
test going red mid-refactor no longer tells you whether it caught a regression or
reacted to an in-progress edit.
rule
the tests are refactored with the same discipline.
why: tests are code, and they drift.
why: the refactor-tests step is the only place in the cycle where test debt can
be paid without losing signal, the suite being green on both sides of the edit.
why: a suite that takes too long stops being run.
why: a suite full of duplicated assertions gives false confidence that semantic
coverage is broader than it is.