0019 — Two rungs are asked on one snapshot, and agreement drives
- Status: Accepted (the rule). Supersedes ADR-0016's ladder (its
Statusshould readSuperseded-by-0019for the ordering clause only — see What dies and what carries). The mechanism is largely shipped in~/.local/bin/fable-decide(--only-astra) and~/.local/bin/puller(the concurrence rule,local-bin#117); the gaps where this rule outruns that code are inventoried below. This ADR does not wait on any merge, because ADR-0004 puts the record at decision time. ⚠️ VOCABULARY: the role this ADR calls the Operator is the Driver since 2026-09-10 —operatoris the product's word for a PM company. Decision text below is unchanged; ids, binaries, trigger phrases and theOperatorTaskWorkflowtype that still sayoperatorare live invocations and deliberately lag. See ADR-0021. (Appended toStatuson purpose: this adds NO line, so every line-number citation into this file stays true.) - Date: 2026-09-10
- Deciders: Gera, 2026-09-10 at 22:33 local (CDT), session
ab6d89b8, verbatim: "if you have a decider like something's blocking it would it should surface to fable or Astra If they agree, drive, that's the decision. They disagree, maybe ask Fable again and then go with Fable. Like, there is no reason for us to be blocked about anything." Mechanics specified by a third reviewer (Astra,gpt-6-astra, high effort). Written at decision time by the Worker in the room, because ADR-0004 says a decision that changes how systems relate is not done until it is written here.
The decision
The founder's ladder governs. Two rungs are asked independently on one evidence snapshot; agreement is the decision; a disagreement is settled by Fable, once. It supersedes ADR-0016's Fable → Astra → human ordering and overrides the operator task criterion in ~/.claude/jobs/tasks/sess-propflow-b1/task.json.
Fable and Astra are asked independently, concurrently, on the SAME evidence snapshot, with stable option IDs. Neither sees the other's answer. Concurrency is the mechanism; the claim is independence plus a frozen snapshot — sequential consultation lets the first answer anchor the second and turns a second opinion into an echo, and two calls that straddle a new commit or comment are not answering the same question. Options carry stable IDs so "they agree" is a string identity on a validated
rec, never a prose comparison.Agreement drives. That is the decision. No human step, no confirmation, no queue entry.
A disagreement gives Fable exactly ONE reconsideration, and its ACTIONABLE verdict wins. One reconsideration, not a loop. Actionable is load-bearing: a reconsideration that returns
NEEDS HUMAN, flips under the options-reversed guard, or trips the class gate is not a ruling and goes to the human queue. A tie may end at a human; a coin-flip dressed as a ruling may not.Two seats answered by ONE model is a single-rung answer, and never reads as agreement. If Fable is unreachable, ADR-0016's fall-through means the first call is answered by Astra — comparing that to the
--only-astracall would be Astra corroborating Astra, guaranteed self-agreement wearing the clothes of concurrence. It is ledgeredsingle_rungand the raiser is told Fable never ran. (Already enforced:~/.local/bin/puller:1439.)Three outcomes are NOT ordinary votes and are separated from a substantive answer, because each has a different remedy:
Non-vote What it means What happens Unavailable no model rung could be reached — a capped seat, an expired bearer, a timeout, a reply with no json exit 2 → bounded retry, honour retry_after. exit 4 → durable; the decision link enters the human queue immediately. Never a refusal, never a dissent, and a missing second opinion never re-blocks a lane.Insufficient evidence a rung was reached and says it cannot settle this on what it was given human queue, with the receipt naming the gap. The raiser may raise a new question with the evidence attached; the original is never silently re-asked (ADR-0017 rule 7). Outside authority the question asks for an act no agent may take — posting as him, a production write, spending money, a promise to a person human queue, terminal. Checked before any spend. Authority restrictions cannot be overruled by model agreement. Two models agreeing that someone else's credentials should be used does not authorize it. Agreement is evidence about a choice; it is never a grant of permission.
fable-decide's money/commitment class gate survives this ADR unchanged and fires regardless of agreement — it is the second layer behind the authority check, and it is broader than "authority": it overrides concurrence on money and commitments even when both rungs are clean and aligned. It was paid for on 2026-08-07 by the unit-607 renewal rate, RESOLVED by both passes at high confidence and wrong.A rung REACHED AND DECLINED is terminal, from either seat. Astra's clean answer never overturns Fable's refusal, and Fable's ruling never overturns Astra's. This is ADR-0016 rule 2 applied to both seats rather than to one, and it is the half of ADR-0016 this ADR most depends on.
Exit codes are honoured as they already read. exit 0 RESOLVED, read
answered_by; exit 2 ERROR — bounded retry, honourretry_after; exit 3 NEEDS HUMAN — terminal, never re-asked; exit 4 WALLED — durable, do NOT burn repeated paid calls against it; exit 64 USAGE — a typo, never retried.A decision link may enter the human queue IMMEDIATELY without waking the founder immediately. Entering the queue and waking a person are two acts, not one. Wake urgency keys off deadline or consequence — never off a provider outage. A weekly Fable wall must not deliver every question raised during it to a sleeping founder at once, each one looking exactly like a question a model considered and declined.
What dies and what carries
ADR-0004 requires a superseding record to carry three parts. This is part 1.
Superseded in ADR-0016 — these lines no longer state the rule:
⚠️ Every line number below is ADR-0016's own numbering, and the Status amendment in the same commit deliberately adds NO line so they stay true. The first draft of that amendment added a bullet and silently shifted lines 9, 57 and 70 by one — which would have made every citation here, and in PR #135 and ADR-0017, point one line off. Anything editing ADR-0016's header must preserve its line count or re-derive these citations.
Line 9: "The decision ladder is Fable → Astra → a human, and the fall-through is automatic." Accurate as the ordering rule it was; the ordering is now both rungs asked, concurrently. The fall-through survives inside the first call (rule 4 above depends on it) but is no longer the whole ladder.
Line 57: "It does not make the two rungs equivalent. Fable is asked first because it is the better model on these questions; Astra answers only when Fable could not." Astra is now asked always. Fable's primacy survives in one narrower place only — it wins a disagreement (decision 3).
Line 70, and this is the line a hostile reader will pull: "Ask BOTH models always and compare. Rejected: it doubles the cost of the common case to buy a cross-vendor agreement check nobody asked for, and a disagreement between two vendors has no defined meaning here — the reversal guard is a claim about one model's stability under reframing, not a vote."
ADR-0016 rejected this exact decision nine hours before it was made, and the rejection is answered, not ignored. Both halves of it have since failed:
- "nobody asked for" — the founder asked for it, at 22:33 the same day, in the words quoted above.
- "a disagreement has no defined meaning here" — this was the real objection, and it was correct at the time. The founder defined the meaning: "maybe ask Fable again and then go with Fable." A tie-break rule's job is to be stated in advance so nobody negotiates it per-question. It is now stated.
What ADR-0016 got right and this ADR preserves: agreement across two vendors is not the same claim as stability under reframing, and it is not proof of correctness. It is a second, independent, cheap check. Both run.
Carried forward from ADR-0016, unchanged and load-bearing here:
- Rules 1–3 (lines 11–13) — "reached" and "declined" must never share an exit path. This is the foundation of decision 5 and decision 7. Nothing here weakens it.
- ⚠️ The exit-3 qualifier (lines 30–34), which a one-line summary of this ADR will get wrong:
fable-decideexits 3 for NEEDS HUMAN, and per line 30 NEEDS HUMAN "is the answer the brief expressly invites" — quotingfable-brief.mdat line 32: "Saying 'a human must decide this' is a CORRECT and useful answer, not a failure." Exit 3 is TERMINAL. It does not fall through to Astra; only unreachability does. Line 34 states the cost of collapsing them: "a question Fable declined to settle would be handed to Astra, could come back RESOLVED, and would be acted on — with nothing on the page saying a refusal had been overruled by a second model." Both halves of ADR-0016 matter: a summary that quotes only line 9 is wrong, and so is one that says "Astra is never consulted." - Rule 4 (line 14) — the two-pass, options-reversed discipline and the class gate travel with the ladder. Every rung in this ADR is a
fable-deciderun, so all three calls carry both guards. - Rule 5 (line 15) — every surface names the model that produced the answer.
answered_by, and a receipt carrying neitheranswered_bynormodelrendersprovenance UNKNOWN, never "Fable". - Rule 6 (line 16) and the exit table — decision 8 is ADR-0016's table, not a new one.
- The
decision-ladder-canary(line 61, launchdco.propflow.decision-ladder-canary, 300s) — it reads both rungs' reachability and calls no model. It is more load-bearing now, not less: under this ADR a rung being down changes the shape of every answer, not just the unlucky ones.
Overridden — the operator task criterion. ~/.claude/jobs/tasks/sess-propflow-b1/task.json:3, verbatim: "You are gonna be the operator Right, you're gonna be driving all the sub-agents. You're gonna be driving the astras … and if something needs true help it should do the fable decision and if it still can't then you can raise a decision link".
⚠️ Read exactly, this is not a third consultation ladder at all, and it should stop being cited as one. The Astras in that sentence are workers being driven, not a rung being consulted; the only consultation named is "the fable decision"; and "if it still can't" is ambiguous between cannot be reached and was reached and declined — the one distinction ADR-0016 exists to keep apart. Under this ADR the Operator asks both rungs and raises a decision link only on a non-vote or a refusal. The task file is the Operator's live artifact and is not edited by this ADR; the override is recorded here and should be appended there by its owner.
Inventory of the superseded surface
ADR-0004 part 2. The inventory is what was missing when tmux "was deleted intentionally" yet drive-send.sh, a skill mode, and an authorizing memory entry all survived.
| Surface | State under this ADR | Action |
|---|---|---|
~/.local/bin/fable-decide — THE LADDER block (lines 47–60) |
Still accurate as the first call's internal behaviour. Its ordering is no longer the whole rule. | Fence: the header must point at the CONCURRENCE block as the governing rule, not read as complete on its own. |
~/.local/bin/fable-decide — CONCURRENCE block (lines 94–118), --only-astra |
Shipped and correct. Same two-pass reversal, same class gate, no fabricated fallback block, answered_by: astra. |
None. This is the mechanism. |
~/.local/bin/puller:1295–1344 — the concurrence rule |
Shipped and substantially this ADR. Ladder → --only-astra → --no-astra tie-break. |
See the two divergences below. |
~/.local/bin/puller:1439 — answered_by != "fable" → astra-only |
Shipped; it is decision 4. Closes the Astra-vs-Astra self-corroboration hole. | None. Keep a control on it. |
~/.local/bin/puller:1486–1512 — the tie-break |
Diverges from decision 3 (below). | Reconcile. |
ADR-0016 Status line |
Says Accepted with no pointer forward. |
Amend to Superseded-by-0019 for the ordering clause; the reached/declined rule stays Accepted. A reader who opens 0016 alone must not act on line 9. |
PR #135 / origin/decider-adr |
As written it recorded the same 22:33 statement without superseding ADR-0016 — its line 34: "ADR-0016's ladder is correct and it is not this." Merging both ladder statements would have made three live ladders four. | ✅ Reconciled in this effort. #135 is re-scoped to the delivery rung and renumbered docs/adr/0020-a-ruling-goes-back-to-whoever-is-blocked.md. Its ladder adjudication is deleted — this ADR owns it, and 0020 restates none of it. What survives is the half this ADR does not cover: the last hop, delivering a ruling back to the parked raiser, and the measured zero-wake bug behind it. |
PR #132 / origin/astra-relaunch-catalog |
Carried a file numbered 0018 while its heading and PR title both said ADR-0017, which origin/main already took. |
✅ Reconciled in this effort. #132 holds 0018 — filename, heading and PR title now agree. The number line is settled: 0018 the Astra lane, 0019 this ADR, 0020 the delivery rung. Nothing is claimed twice. |
docs/the-four-roles.md — "The Fable decider", the THERE ARE TWO MODEL RUNGS NOW block |
Stated the fall-through as the rule a reader should act on — a live restatement of superseded line 9. | ✅ Fenced in this commit. The block now reads as the first call's internal behaviour and points here for the governing rule; the reached/declined half beside it is untouched, because this ADR rests on it. |
SYSTEMS.md — the decision-ladder entry (job string, docs[]) |
job described the fall-through as the whole rule, and docs[] cited only ADR-0016 — so a reader who followed the catalog landed on superseded line 9 with no pointer forward. |
✅ Fixed in this commit. job names the concurrence rule; docs[] carries this ADR alongside 0016. |
SYSTEMS.md — the puller entry's "Ladder routing" paragraph |
Read "goes to fable-decide (Fable → Astra → a human)" — a fourth live statement of the superseded ordering, in the catalog rather than an ADR. |
✅ Fixed in this commit. |
Memory reference_fable_decide_flags_and_session_cap_exit2 |
Flag and exit-code pointers; unaffected by the ordering change. | None. |
Where this rule outruns the shipped code
Named rather than left as an implication, because the value of this ADR is that it is the one place the mechanics are right.
The tie-break is asked FRESH, not shown both rationales. ⚠️ Decision 3 does not settle this either way, and this ADR does not settle it here. Decision 3 says only that a disagreement gives Fable one reconsideration whose actionable verdict wins; it is silent on what Fable is shown. "Shown both rationales" is the mechanics reviewer's specification (Astra,
gpt-6-astra, named in Deciders), not the founder's words and not a numbered decision — an earlier draft of this paragraph attributed it to Decision 3, which does not contain it. It is recorded as an open mechanism question rather than a decided rule, because the two readings are different questions and the difference is not cosmetic. The shipped tie-break isfable-decide --no-astra— Fable asked again, cold (puller:1487, viaRUNGS["fable"]atpuller:1344).fable-decideis built around exactly this hazard, quoting Gera on 2026-08-02 (fable-decide:129): "If we tell them 'this is what we think, what do you think?' then it's just going to be 'oh yeah, I can see this and this.'" — and the file's own conclusion at line 132, "A model handed your conclusion agrees with it. A model handed ONE SIDE's evidence reaches that side's conclusion and sounds independent doing it — which is worse, because you now have false corroboration."The reconciliation, and it is the whole reason the reversal guard survives the tie-break: showing both rationales is admissible only because the reconsideration is still two concurrent options-reversed passes whose flip is reported as
NEEDS HUMAN. Anchoring that a reordering can flip is caught. Anchoring that survives reordering is what the founder asked for — Fable ruling with the dissent in front of it rather than re-rolling the same dice. A reconsideration shown both rationales but run as a single pass would be the false-corroboration failure with none of the guard, and must not ship.The three non-votes have no structured taxonomy on the receipt.
needs_human_why(fable-decide:401) is free text, and the class gate returns a reason string (fable-decide:902). Insufficient evidence and outside authority are therefore distinguishable by a reader but not by a caller. Decision 5 gives them different remedies, so this gap is real: until a field carries it, the separation is enforced by the human-only ACTION pattern list running before any spend, and by nothing else.Wake urgency is not yet keyed to deadline or consequence. Decision 9 is a rule about a queue that currently has one urgency. Entering the queue is shipped; the urgency split is not.
The cost, stated plainly
This ladder is more expensive than either thing it supersedes, and that is a deliberate trade, not an oversight.
| Model calls | Passes (each call is two, options reversed) | |
|---|---|---|
| ADR-0016's ladder, healthy day | 1 | 2 |
| This ADR, agreement | 2 | 4 |
| This ADR, disagreement | 3 | 6 |
Count passes, not consultations — fable-decide runs every call twice with the options in opposite order, so the headline "two consultations" is four model runs, and three is six. Bounded twice on disk: a per-tick question cap (PULLER_CONCUR_CAP, default 1) and a per-day invocation cap in an append-only ledger, and an unreadable spend ledger holds routing for the day — a job that cannot account for its spending does not get to spend.
The justification is that the founder is the scarce resource, not the tokens. On 2026-09-10 the fleet spent ninety minutes with five questions parked reporting "pending Fable" while a healthy Astra sat unasked, and a human had to be the one to notice. Twice that evening Gera noticed a problem before the Operator did. Doubling a model bill to stop doing that is not a close call. Said here rather than left for someone to discover from an invoice — and the honest version of the trade is that the third call, the tie-break, is the one that could grow without anyone watching, which is why the caps are per-tick and per-day rather than per-question.
Alternatives considered
- Leave the three ladders live and add a fourth document. This is the defect being fixed. Three records disagreeing about when a human is woken is worse than any one of them being wrong, because each reader acts on whichever they opened.
- Keep ADR-0016 and treat concurrence as a
pullerimplementation detail (what PR #135 did as written). Rejected: the ordering of model consultations is the rule, not a composition detail, and leaving line 9 standing means a reader offable-decidealone still believes Astra is a fallback. It also leaves line 70 — an explicit rejection of this decision — live in an Accepted ADR. - Astra wins a disagreement, or a third model breaks the tie. Rejected: the founder stated the tie-break, and a third rung invents a model nobody chose and makes the outcome depend on which vendor happens to be up.
- Ask both rungs sequentially and let the second see the first. Rejected: that is the echo. It buys a cheaper-looking second opinion that is worth nothing, and it is the exact failure
fable-decidewas built around. - Wake the founder whenever a rung is down. Rejected explicitly by decision 9 — it converts a provider outage into a pager, at the hour a weekly wall is most likely.
Related
- ADR-0016 — a model that cannot be reached is not a model that declined. Superseded in part by this ADR (lines 9, 57, 70); its reached/declined distinction, reversal guard, class gate, provenance rule and exit table all carry forward and this ADR rests on them.
- ADR-0020 — a ruling goes back to whoever is blocked (PR #135, re-scoped). The other half of the same night: this ADR says how a block is decided; 0020 says how the decision reaches the session parked on it, and why the path that was supposed to carry it woke the raiser zero times. It restates no part of this ladder and defers here for it.
- ADR-0017 — the Operator is fed, it does not poll. Rule 7 (a rung reached and declined is never re-asked, by the puller either) is the scheduled-job form of decision 7 here.
- ADR-0004 — a decision that changes how systems relate is written at decision time, by whoever is in the room; and the three parts a superseding record must carry.
- ADR-0003 — the supervision ladder: rungs integrate by signals, never calls. This remains a decision ladder, not a supervision one.
SYSTEMS.md— thedecision-ladderentry and its canary.