Chapter 21
Wednesday morning
Trace one batch by state and begin the software model with an outer test.
On this page
On Wednesday morning, July 15th, 2026, I lifted the lid on the brass tumbler and poured its output into a tray. I expected clean 5.56 brass. That was most of what I had loaded the night before.
Mostly.
Clean 5.56 cases came out with some 9mm, a few .50 caliber cases, and a stripper clip. The 9mm had slipped in unnoticed. The .50 caliber cases had been included deliberately. The stripper clip was not a case at all.
Nothing about the tumbler looked broken. Every object was cleaner than when it entered. The machine had done its one job, including on the things the next part of the system could not use.
That tray is where the tutorial's drawing begins to move. Up to now we have looked at parts, connections, rejections, swaps, and decisions. Now one batch has to travel through them. A drawing that cannot explain what happens to the stripper clip is incomplete. A drawing that loses the 9mm is dishonest. A drawing that cannot say what is known about the 5.56 at each step is only a floor plan.
Follow state, not activity
It is easy to describe the morning as a list of work:
- Clean.
- Sort.
- Decap.
- Prepare the primer pocket.
- Size and trim.
- Inspect.
- Load.
That list tells us what the operator does. It does not tell us what the system knows.
Take one 5.56 case from the tray. Before cleaning it was a candidate: recovered
material, dirty, mixed with whatever the range bag collected. After the first
cleaning, one fact changed. The case was free of range dirt. Its caliber had
not been admitted into this process. Its primer pocket had not been checked.
Its length had not been measured. Nobody had established that it was safe to
load. Later production would show why calling that one fact simply clean
was too broad.
Activity is not state. Passing through a machine is not proof that every fact the next machine needs now holds.
The trace below makes that distinction explicit. It preserves the first working model and records the later physical evidence without upgrading the live-ammunition line.
| Point in the journey | State established here | Decision owner | Possible exit | Evidence status |
|---|---|---|---|---|
| Range bag | identity not yet trusted | none; still a candidate | none yet | observed |
| Loading block | expected caliber and case-like shape | classification boundary | wrong-context bin or foreign-material exit | observed |
| Dillon preparation pass | primer removed and full-length sizing performed | configured station owns the transformations | calibration scrap or work continues to measurement | observed |
| Headspace inspection | measured acceptance after sizing | operator with gauge and acceptance policy | rework | observed and measured |
| Readiness line | current required facts hold together | readiness gate | rejection with every failed reason | evolving working model; not crossed by the fifty-case set |
| Progressive live-ammunition line | primed, charged, seated, crimped, position by position | production line | held plate on fault | designed, not yet live-proven |
Five more stations run the same five questions; the full station-by-station trace lives on The Lab Ledger, with current counts and open obligations.
Read the table across, not only down. Every row answers five questions:
- What changed?
- What became knowable?
- Who owns the decision at this point?
- Where can the material leave the main flow?
- What kind of evidence supports the claim?
Those questions stop a common substitution. We stop saying, "it was processed," when what we mean is, "we hope the facts downstream needs are true."
Start with the body walking
Before designing a classifier, a readiness gate, or a press, write the smallest test that makes the whole intended behavior visible. In this lab that is a system-level acceptance test around one production entry point. It uses the real objects we own and substitutes only the station that produces the fault we need to observe.
The test starts with four inputs:
- one ready 5.56 case;
- one 5.56 case whose
sizedfact is false; - one 9mm case;
- one stripper clip.
It also starts with the provenance a completed batch will need: load specification, brass lot, and component lots. Mid-run, the powder station faults once.
This was the first assertion:
it "stops at the first station fault instead of silently retrying" do
result
expect(charge.attempts).to eq(1)
end
The first run was red because the production orchestrator kept cycling. The fake station failed once and then succeeded, which exposed the dangerous behavior precisely: the system could make a fault disappear by trying again. On a progressive press, advancing after a station failed can turn a located problem into an ambiguous cartridge farther around the plate.
So the outer test asks for more than a stopped loop. It asks the system to return the partial truth:
it "returns a halted result with the fault and a derived recovery plan" do
expect(result).to have_attributes(
halted?: true,
faults: contain_exactly(
have_attributes(
station: "charge", status: :faulted, fault: :powder_hopper_empty
)
),
recovery_plan: contain_exactly(
have_attributes(
station: "charge", disposition: :resume, missing: []
)
)
)
end
And it refuses to let the earlier exits vanish merely because a later stage failed:
it "preserves every exit decided before the production fault" do
expect(result.rejected.map { |kase, _| kase }).to eq([unsized])
expect(result.rejected.first.last.reasons).to eq([:unsized])
expect(result.wrong_context).to eq([nine_millimeter])
expect(result.foreign).to eq([stripper_clip])
end
The complete test is in
spec/reloading_lab_spec.rb.
It is green now. That does not convert the modeled production event into an
observed garage event. It proves that the Ruby body walks according to the
contract we wrote. The first live batch is still a different kind of proof.
Why this test comes before the parts
The test does not yet tell us how many classes to write. It tells us what must enter the system, what must remain visible, where control returns, and what shape the answer must have. Those are body-plan claims.
If we began with a CaseClassifier, we could produce excellent DNA for one
part while missing the fact that a production fault must preserve
classification exits. If we began with the press, we could make its cycle
beautiful while forgetting provenance. If we began with the batch record, we
could record completed work and have no honest representation of a halted
run.
The outer test forces all of those parts to belong to the same creature before we perfect any of them.
It also gives the inner tests a court of appeal. Later, a unit test may claim a collaborator protocol works because its mock returned the expected shape. The outer test runs the owned objects together. If the unit tests pass and this test fails, the doubles told a convincing lie.
This is the walking skeleton: the smallest end-to-end behavior that exercises the load-bearing path. It need not be complete. It must be complete enough to fail on behavior, not on missing plumbing. A useful red says, "the run retried the fault." A useless red says, "constant not found."
Make your own trace
Choose one thing that moves through a system you know: an invoice, a support case, a deployment, a new employee, a shipment.
Do not list the screens it visits. Trace its state.
| Point | State established | Decision owner | Possible exit | Evidence |
|---|---|---|---|---|
Then write one outer test in ordinary language before you name the classes:
Given ________, when ________ happens, the system returns ________, preserves ________, and refuses to ________.
Make the test carry at least one successful path, one expected refusal, and one interrupted path. Include the identity or provenance a future operator would need. If the sentence forces you to invent several unrelated entry points, your body plan may still be hidden.
What this trace cannot prove
A state trace records the model we currently believe. It does not make the model true.
The magnifier has already improved what can be seen at the inspection point.
The quarantine bag has already received damaged cases. The six-fact readiness
line is a working synthesis, corrected once when sized was missing. The
halt-and-recover path is executable in Ruby. None of that is evidence that a
full production run will reveal no seventh readiness fact, no unexpected
station interaction, and no new exit.
That is why the evidence column stays in the artifact. Without it, a clean diagram quietly turns designed behavior into remembered history.
The next chapter returns to the Wednesday tray. Before the expected 5.56 can move forward, the other material needs honest destinations.