0020 — A ruling goes back to whoever is blocked

The decision

Obtaining an answer is not delivering one. A rung that can rule on a block and cannot reach the session waiting on that block has not unblocked anything. The ruling is delivered, once, to the raiser — and delivering is a distinct act with its own failure mode, its own signal, and its own place in puller's contract.

  1. The ruling goes back to the raiser, and that is not optional. One message, once, to the one session parked on that question, naming the choice, the receipt id, and the model that ruled. A ruling that lands in routed.json and nowhere else is not a ruling anybody received.
  2. It decides and returns; it never resolves. It writes no state on a block, answers no decision page, executes nothing. Applying a ruling remains the raiser's act — which is also why the raiser has to be told.
  3. Provenance travels with the ruling, and is never Gera's by default. A matched option with an invented answeredBy is a forged decision. Every message names the rung, the model and the receipt id; a single-rung ruling (ADR-0019 decision 4) says on its face that it was not corroborated.
  4. The message says in as many words that it is not Gera's answer, and tells the raiser to apply it or to say on the block why it will not. A raiser that mistakes a model's ruling for the founder's has been handed a forged decision by a well-meaning courier.
  5. Delivery is a carve-out from puller's contract 5, taken explicitly. One message, once, to one session, about one question that session is parked on. It is not a delta ping, it never reaches the Operator, and §1's ~30-firings cap on Operator judgement is untouched.
  6. The last hop gets its own signal, because every other signal stays green through its failure. puller DELIVERED, on a three-day window. puller OK is true of a puller that reads the whole fleet, asks the ladder, obtains a ruling and hands it to nobody — which was the live state of this rung.
  7. What this ADR does NOT decide: which rungs are asked, what their agreement means, who settles a disagreement, what happens when a rung is walled or refuses, and when a human is woken. All of that is ADR-0019. If this document and ADR-0019 ever appear to disagree about the ladder, ADR-0019 is the record and this one is wrong.

Why

The rung existed and answered into the void

puller already routed un-ruled blocks to the ladder, ledgered them, and rendered the rulings in a digest. What it never did was tell the session that had stopped working. A ruling landed in routed.json and the blocked lane learned nothing — it was still parked, still waiting, still counted as "waiting on Gera" by anyone reading the decisions surface.

And the path that was supposed to carry it is measured broken. Answering by clicking an option on the /agents Decisions tab resolves the ledger row atomically, so SmithDecisionBlockWorkflow polls, sees RESOLVED, and early-returns before the wake. Measured live on three of Gera's real decisions: zero wakes in the raiser's transcript. Not misrouted — never sent.

So the fleet had a decider that could obtain an answer and no way for the answer to reach the thing that needed it. That is a system in the shape of a system, and the last hop is the part that makes it one.

⚠️ This is the fact that justifies a separate ADR at all. ADR-0019 can be entirely correct — both rungs asked, agreement observed, a ruling produced — and the lane stays parked, because the defect is downstream of every rule ADR-0019 states. A reader who takes ADR-0019 as the whole of that night's decision will build a decider that answers into the same void.

Why extend puller rather than build a decider daemon

Two scheduled jobs on one decision queue double-spend and double-answer, and the queue has no lock of its own. Everything that makes routing safe already lives in puller — the ledger's terminality rules, the retry_after windows, the block↔receipt join that stops a ruled question reading as "never asked", one launchd label. A rival binary would have had to reimplement all of it and then race it.

The cost is honest and is recorded here: puller's contract 5 said it was not a wake source, and now it sends one message. That contract was written against a puller that pinged on every delta and rebuilt the 1,064-stop polling failure one layer up. The carve-out is decision 5 above — the decisions wake the blocked contract always promised. The amendment is written into the contract rather than taken silently, which is the point of ADR-0004.

Why it is not a subagent

A subagent dies with its pane. On the night this was designed that happened three times: a Fable weekly wall killed four lanes at 02:5x, and two ccswitch respawns killed every child process. A decider that dies when the Operator dies is worth nothing, because the entire point is that it keeps working while Gera sleeps. It is a launchd job in the shape of puller and astra-relaunch (ADR-0003: rungs integrate by signals, never by calls).

Why the delivery signal is three days and not fifteen minutes

Deciding is demand-driven. A quiet week raises no blocks and delivers nothing, and a signal that went red for a quiet week would train everyone to ignore it — ADR-0009 cuts both ways, and a signal that fails while the system is fine is as useless as one that cannot fail. Three days is long enough that silence is unusual and short enough that a return hop broken on Monday is visible by Thursday.

Consequences