0016 — A model that cannot be reached is not a model that declined

The decision

The decision ladder is Fable → Astra → a human, and the fall-through is automatic.

  1. A rung that CANNOT BE REACHED falls through to the next one. A capped seat, an expired bearer, a missing binary, a timeout, a non-zero exit, a reply with no json in it. These are missing evidence, and missing evidence is not a hard question.
  2. A rung that WAS REACHED AND DECLINED does not. resolvable: false, a flip between the two reversed passes, or the money/commitment class gate firing — all three are verdicts, and all three go to the human rung. Falling one through would launder a refusal into a ruling.
  3. These two must never share an exit path. This is the whole ADR. The discriminator is one pure function and it reads exactly one thing: did any pass of this rung return a parseable verdict object?
  4. The two-pass, options-reversed discipline and the class gate travel with the ladder. Whichever rung answers asks twice, concurrently, with the options in opposite order, and reports a flip as unresolved. A fallback that dropped the guard would be a cheaper answer wearing the costume of the expensive one.
  5. Every surface that carries the answer names the model that produced it. The receipt's model field is the model that answered, not the one asked first; answered_by and fallback {from, to, reason} sit beside it; the terminal prints RESOLVED via ASTRA (gpt-6-astra) with a banner; and the decision page's receipt card says which model was asked and whether the question fell through.
  6. When no model rung can answer, the tool fails fast. Exit 4 WALLED means "the ladder is down to the human — go there now". Exit 2 ERROR is reserved for the case where at least one rung failed in a way that genuinely clears, and its receipt carries retry_after so the retry is bounded.

Why — 2026-09-10, in local time (CDT)

At 14:26 a retry job armed against fable-decide began logging seat session_5h pct=101.0 every sixty seconds, with zero progress. It ran that way for about ninety minutes. Five questions on PR #7618 sat behind it reporting "pending Fable".

Nothing was broken in the retry job. It was waiting on a condition that does not clear for hours: six of seven fleet seats were at 100–101% of their weekly Fable allowance, and the seventh — the only one with weekly headroom — was session-capped until 20:40Z. The seat picker read weekly_fable and nothing else, so every call routed to the one seat in the fleet guaranteed to fail. It failed saying "You've hit your session limit · resets 3:40pm (America/Chicago)" — "hit your", not "reached your", one verb outside the wall detector — so the run fell through to exit 2, which the tool documents as "retry, do not escalate".

local-bin#107 landed at 14:48 and fixed the classification: a session cap is now exit 4 WALLED, a durable state, and a caller that sees it is told to stop retrying. That converts a spin into a stop — but it stops at "go ask a human." The ninety minutes were still spent, and they were spent while codex exec -m gpt-6-astra was up the entire time. Once a human noticed and redirected the same questions, Astra answered them in about fifteen minutes.

So the gap this ADR closes is not the classification. It is that the ladder had no rung between "Fable is unavailable" and "wake a person", and a human had to be the one to notice.

Why the reached/declined distinction is the load-bearing half

The obvious implementation — "if fable-decide exits non-zero, try Astra" — is wrong in a way that is hard to see and expensive when it fires. fable-decide exits 3 for NEEDS HUMAN, and NEEDS HUMAN is the answer the brief expressly invites:

"Saying 'a human must decide this' is a CORRECT and useful answer, not a failure."

A model saying only a person can settle a question, and a model that was never asked because its meter refused, are opposite facts. Under a single fall-through path they become the same event: 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. The class gate would still catch the money cases; nothing would catch a preference, a risk appetite, or a promise made to a person.

The distinction survived contact with a real ordering bug. fable-decide's existing code checked "did a pass fail to run?" before "did a pass refuse?" — so a pass answering resolvable: false while its twin timed out was reported ERROR. That was one wasted turn before this ADR; with a fallback behind it, ERROR falls through, and it would have been a laundered refusal. The refusal check now runs first.

Why Astra, and not another Fable seat

Fable's two meters are per-account, and the fleet shares an account pool. When the weekly allowance is spent it is spent for every seat at once — a fallback inside the same vendor is walled by the same wall. Astra is a different vendor, different weights, different meter, and it is already on this machine and already authed. It was measured answering in 7 seconds during the incident.

Why "a fallback is a cheaper answer" is a real risk, and how it is bounded

Two guards make fable-decide's verdicts worth more than a single model call: the options-reversed second pass (position bias), and the class gate that overrides agreement on money and commitments (paid for on 2026-08-07 by the unit-607 renewal rate, RESOLVED by both passes at high confidence and wrong). A fallback rung that ran one pass, or skipped the gate, would produce verdicts that look like the first rung's and are not. Both guards run on whichever rung answers, and a control asserts each — including one that asserts the two Astra passes really do get reversed briefs, using a stub that behaves like a position-biased model rather than a canned pair of answers. The canned version passed against a mutant that gave both passes the same brief; that is why it is written the way it is.

What changes for whom

Reader Before After
An Operator running fable-decide exit 4 meant "Fable's meter refused; go to a human" exit 4 means "no model rung can answer; go to a human". A question Fable cannot take is answered by Astra without anyone noticing it needed to be.
Anyone reading a verdict it was Fable's, always read answered_by. The terminal line and the receipt both name the model.
Anyone reading a decision page the card said "Fable recommends" over the raiser's own --rec, and the receipt block said "Fable was asked" in the page blocked renders: the recommendation reads "The session raising this recommends", and the receipt block names the model that answered. ⚠️ The agents-page Decisions tab is a SECOND renderer and still says itpropflowai/src/app/(workspace)/(operations)/agents/_components/DecisionsTab.tsx:548. Same false claim, different repo; named here rather than left as a fixed-everywhere implication.
A retry job armed on fable-decide exit 2 meant retry, and so did a typo in a flag exit 2 means retry and carries retry_after; a usage error is exit 64 and never retried; a durable wall is exit 4 and never retried.

What this does NOT do, stated so nobody assumes it

Alternatives considered