Plumb
Reading stable · switch to edge
Explanation

Testing depth, and the roles it serves

For QA, engineers and programmers deciding what depth to claim.

"Done" in Plumb is a vector over testing depth, not a single green bit (see Plumb's own gold spec, spec/chapter_01_proof.pych1-3). Each rung proves a different thing, assumes the rung below it, and hands its assumption up to be discharged by a rung above — so a run stays fast and non-redundant, and a story proven only at the bottom reads as only that deep. The same rungs map to who does the work in an organization: each is written by a role and assures another.

A rung is not a layer. Layer means a spec's architectural strata — the ladder of packages a system is decomposed into, where an edge may only point down. That is a different axis and a different kind of spec, proved by inspecting structure rather than by running anything. Depth is how far up the proof pyramid a test reached; layering is how the code is arranged. Nothing here refers to the latter.

Two rules frame the whole stack:

Where a depth is written

Everything on this page is about one argument in the citation you already write — depth:

@pytest.mark.proves("ORD-1", depth="wiring")
def test_an_order_gets_a_queue():
    assert run("A-1")["queue"] == "standard"

The same claim in Java:

@Test
@Proves(value = "ORD-1", depth = "wiring")
void anOrderGetsAQueue() {
    assertEquals("standard", api.handle("A-1").queue());
}

depth is a claim about how far that test reached, not a label for how it is filed. The run either supports the claim or refutes it. The rest of this page is what the values mean and how to choose between them.

Two things worth knowing before you read the table:

Choosing a depth honestly

There is a real pull toward claiming deep, and it is worth naming rather than pretending it away.

A behavioural story reaches PROVEN only when its test grounds — when execution passes through a declared production entry point. unit and component claim isolation, so they do not ground, so a story cited only at those rungs stays UNPROVEN however good the test is. That is by design, and it means the board rewards depth. Anyone reading a board as a score will feel it.

Claiming a rung you did not reach does not work, and the tool says so. Write depth="wiring" on a test that calls a function directly and grounding refutes it — depth.unsupported, with the citation named. This is the check doing its job, and it is not the thing to guard against.

The thing to guard against is entry_points. That list is the one input Plumb cannot verify: it takes your word for where the system begins. Declare the unit under test as an entry point and a direct unit test grounds, comes out PROVEN [wiring], and raises no condition at all — because every mechanical check passed. The claim became true by moving the front door, and nothing in the tool can tell that from a system whose front door was always there.

So the discipline lives in one place:

And the pressure releases entirely once one thing is accepted: UNPROVEN is not a failing grade. A story proven at unit is proven at unit, and the achieved vector says so precisely. A board full of honest unit is worth more than a board of wiring bought by widening a list, because only one of them still tells you something the day it goes red.

The rungs

Rung What it proves Mocks Assumes → discharged by Written by Assures
unit a unit's input→output in isolation no its collaborators work → component / wiring programmer the logic itself is correct
component branching, looping, error paths — how the unit behaves yes (spies) the doubles mirror the real collaborators → wiring / standards-integration programmer the engineer: the code does what the story says
wiring the code is actually integrated, not orphaned yes component is already proven — ordered, because you cannot check the wiring of wrong code programmer + engineer that "done" is real, not dead or unwired code
standards-integration it works against the real resource technology through a standard interface no — a real resource, embedded & fresh standard conformance; the platform choice is ops' → smoke/e2e programmer / engineer portability, and that it works against the resource
smoke / e2e everything real, assembled artifact, end-to-end no nothing — the floor programmers, to a QA + devops plan QA: works as specified · devops: packaging introduced no bug

Grounding underlies wiring and standards-integration: in the test's own call tree — a language-native per-test trace, never a coverage tool — execution must run under a declared production entry point, proof it drove the real system and not an isolated method. A test claiming wiring or standards-integration whose execution never grounds is a lie the tool catches.

These rungs are the pyramid for behavioral proof. A structural story — dependency direction, containment, format — is proved by inspecting the artifact rather than running it, so its test executes no production code at all and grounding is the wrong question to ask of it; the gate asks the mirror question instead (Plumb's own gold spec, ch1-7, ch1-2-3). Which rung such a test sits on is genuinely unsettled — see ch1-U2.

Read the artifact; do not import it. A structural test must reach its subject as data — open the file, parse the bytecode, walk the tree. Importing the module to inspect it does not work, and it fails in the direction that wastes a day: the first import runs module-level code, so the test looks like it executed production code, while a later run finds the module already imported and touches nothing at all. Same test, same assertions, and what the board says depends on whether some other test imported it first. Plumb refuses both — a structural claim is proved only by a test that read the artifact — so an import-based one is simply never provable, whichever order the suite runs in. Note that non-functional requirements are not a third kind:

they are behavioral, proven at smoke/e2e against the assembled artifact, exactly as the two-track section below describes.

Three things that cost people time when missed

Two tracks, one implementer

All test code is code, written by the programmers — every rung, including smoke/e2e. QA and devops do not write tests; they write the plan. Requirements arrive on two parallel tracks:

So "written by" always means the programmers; what changes hands is the rung's plan — a functional story for the lower rungs, a QA/devops non-functional plan for smoke/e2e.

How the rungs close the loop across roles

The rungs are the vertical proof; the roles are a horizontal loop around them:

Everything Plumb enforces is objective correctness — ran + passed · grounded · wired. Mutation is reported beside that and never enforced: a surviving mutant may be a weak test or may be semantically identical to the original, and nothing can tell those apart. Which rungs a story must reach — the required depth — is policy, set per team, and is never imposed by the framework.