What is missing
The failure taxonomy names WHAT went wrong but never WHO it went wrong on. FAILURE_CLASSES is a flat list of 25-plus classes — sandbox_failure, timeout, budget_exceeded, missing_credentials, and so on — and FailureClassification carries failureClass, reason, and two trigger ids. There is no blame axis, so a consumer cannot separate "the machine never reached a model" from "the agent's own budget ran out", and every comparison silently charges infrastructure outages to the agent under test.
Three related capabilities, one axis:
- A blame axis on every class.
machine — the run never reached a model: the bridge refused, its lane was full, the box never provisioned. An agent cannot route around this, so a run that recorded nothing behind only machine failures is not evidence about the agent and must be voided, not counted as a loss. provider — the model was reached and the turn did not complete: an empty completion, a torn stream, a killed process. Every arm faces the same provider on the same day, so this stays charged. agent — the agent's own budgeting or scheduling ran out. Charged.
- Outage detection. From a series of runs, the trailing streak of consecutive
machine/provider deaths per arm, and a per-credential verdict on whether the recent record reads as an outage.
- A time-expiring hold. A stateless verb that answers "should this credential be used right now" from the run record alone, with no ledger, no probe rows, and no per-arm state — so there is nothing to latch and nothing to unwedge by hand.
Where it lives today
discovery-lab/tools/failure-classes.mjs 180 lines — the ordered taxonomy carrying the three blames, with the note that ordering is load-bearing because one reason string carries two signals: a seat killed by SIGKILL while the bridge refuses connections is a bridge failure, not a process failure.
discovery-lab/tools/line-health.mjs 763 lines — the read-only report and the one enforced verb, --hold <seat>.
Where it belongs
src/failure-taxonomy.ts:450 — export function classifyFailure(, and the FailureClassification interface at :23. Add blame beside failureClass.
src/trace/schema.ts:234 — export const FAILURE_CLASSES, which today has no blame mapping. blame appears 0 times in either file.
Measured motive
All six director cells in one round settled with the runtime journal's own infra flag reading FALSE, because the runtime cannot see why the bridge stopped answering. Their real reason was host-executor: acquire timeout after 900000ms (in_flight=10/10) — the bridge's host lane had saturated. Read on the runtime's flag alone, six machine outages would have been charged to the agent profile as six failures to produce science (failure-classes.mjs:33-40).
Separately, measured 2026-08-22: 8 arms burned 236 runs at 83% no-winner, and the audit read most of those deaths as sandbox or bridge deaths — the machine, not the question. The attempt cap forgives a zero-spend death, so each question was retried against a machine that was down, and every retry was one more zero-token run directory. No reader of the fleet could tell "this arm's bridge is dead" from "this arm's questions are hard" (line-health.mjs:11-16).
Acceptance
Both files can be deleted when classifyFailure returns a blame for every class, a test asserts that an ordered rule set charges a SIGKILL-during-bridge-refusal to machine rather than agent, and an exported reader turns a run series into a per-credential outage verdict plus a stateless time-expiring hold.
What is missing
The failure taxonomy names WHAT went wrong but never WHO it went wrong on.
FAILURE_CLASSESis a flat list of 25-plus classes —sandbox_failure,timeout,budget_exceeded,missing_credentials, and so on — andFailureClassificationcarriesfailureClass,reason, and two trigger ids. There is no blame axis, so a consumer cannot separate "the machine never reached a model" from "the agent's own budget ran out", and every comparison silently charges infrastructure outages to the agent under test.Three related capabilities, one axis:
machine— the run never reached a model: the bridge refused, its lane was full, the box never provisioned. An agent cannot route around this, so a run that recorded nothing behind only machine failures is not evidence about the agent and must be voided, not counted as a loss.provider— the model was reached and the turn did not complete: an empty completion, a torn stream, a killed process. Every arm faces the same provider on the same day, so this stays charged.agent— the agent's own budgeting or scheduling ran out. Charged.machine/providerdeaths per arm, and a per-credential verdict on whether the recent record reads as an outage.Where it lives today
discovery-lab/tools/failure-classes.mjs180 lines — the ordered taxonomy carrying the three blames, with the note that ordering is load-bearing because one reason string carries two signals: a seat killed by SIGKILL while the bridge refuses connections is a bridge failure, not a process failure.discovery-lab/tools/line-health.mjs763 lines — the read-only report and the one enforced verb,--hold <seat>.Where it belongs
src/failure-taxonomy.ts:450—export function classifyFailure(, and theFailureClassificationinterface at:23. AddblamebesidefailureClass.src/trace/schema.ts:234—export const FAILURE_CLASSES, which today has no blame mapping.blameappears 0 times in either file.Measured motive
All six director cells in one round settled with the runtime journal's own
infraflag reading FALSE, because the runtime cannot see why the bridge stopped answering. Their real reason washost-executor: acquire timeout after 900000ms (in_flight=10/10)— the bridge's host lane had saturated. Read on the runtime's flag alone, six machine outages would have been charged to the agent profile as six failures to produce science (failure-classes.mjs:33-40).Separately, measured 2026-08-22: 8 arms burned 236 runs at 83% no-winner, and the audit read most of those deaths as sandbox or bridge deaths — the machine, not the question. The attempt cap forgives a zero-spend death, so each question was retried against a machine that was down, and every retry was one more zero-token run directory. No reader of the fleet could tell "this arm's bridge is dead" from "this arm's questions are hard" (
line-health.mjs:11-16).Acceptance
Both files can be deleted when
classifyFailurereturns a blame for every class, a test asserts that an ordered rule set charges a SIGKILL-during-bridge-refusal tomachinerather thanagent, and an exported reader turns a run series into a per-credential outage verdict plus a stateless time-expiring hold.