Repository navigation
Nothing consumes removed_by: no T-0 expiry check, no slips counter, no two-slip andon — refusals will carry deadlines nothing enforces #3615
Description
removed_by is about to have a shape and a validator (#3613) and still no consumer that acts on it. A refusal carrying removed_by: v0.70 will sit past 0.70 with nothing noticing.
Measured on origin/main 2026-09-20:
$ git grep -c removed_by origin/main -- scripts/ crates/
(no files)
Zero. #3613 lands the contract, the closed sentinel set (v<major>.<minor> | never | unscheduled) and pv refusing malformed or absent values — that is the shape obligation and it is satisfied. What nothing implements is the semantic one, which is the reason the field exists at all.
The doctrine this is supposed to enforce
Refusals carry
removed_byand never block a cut. At T-0 an expired refusal auto-bumps one train and incrementsslips; two slips raises a non-blocking andon naming the ticket. A refusal is the safe state and is never auto-reverted.
Every clause after the first is unimplemented. There is no T-0 step that reads removed_by, no slips counter, no two-slip andon.
Why the shape validator does not cover it
A validator that checks "is this a well-formed version string" and a checker that asks "has this train passed" are different obligations. The first is satisfied by a refusal that says v0.70 forever; the second is what makes a refusal a deadline rather than a permanent exemption with good syntax.
This matters more than usual here because refusals are about to be minted in bulk: #3597 classifies 111 registry verbs into V / V2 / REFUSED, and every refusal in that third bucket carries a removed_by. Without an expiry consumer, the verb table becomes a list of permanent exemptions that each look time-boxed. That is the strictly worse outcome than having no field — an unenforced deadline reads as an enforced one.
done_when
- A T-0 step reads every refusal's
removed_byand compares it to the train being cut. - An expired refusal auto-bumps one train and increments
slipson that refusal. It is never auto-reverted — a refusal is the safe state. - Two slips raises a non-blocking andon naming the ticket. Non-blocking: an expired refusal must not refuse a cut, or the safe state becomes the one that stops the train.
- The
slipscounter is written where the next reader finds it — beside the refusal, not in a log. - Falsifier, both arms: a refusal with
removed_byin the past must bump and increment; one with a future train must not be touched. A checker that only fires is as wrong as one that never does. neverandunscheduledare exempt by construction, not by a special case in the comparator — they are declared sentinels meaning "no deadline", and the expiry check must not treat an absent deadline as an expired one.
Scope
Not #3613's. That row lands the shape and correctly stops there; bundling an expiry checker into a schema PR would make it unreviewable, and the contract is what makes this row possible rather than the same work. Sequence: #3613 lands, refusals get minted by #3597, this consumes them.
Exists because #3613's author checked their own done_when item by item rather than assuming, which surfaced that item 3's "until a consumer reads the field, it is decoration" was satisfied for shape and unsatisfied for meaning.
Activity
noahgift commentedon Sep 25, 2026
Parked by APR-EPIC-001: over S1 budget (rank 35/163). Reopen = pull. Applied by aprender-d1: claude+agy both said close, apr shadow row recorded (handoff/close-quorum-2026-09-25.json).