type: meta

slug: failure-routing-and-escalation

base_branch: origin/main

gate0_mode: strict

preset: codex

land_mode: merge-to-main


type: goal

text: Make seat bindings arrays so every role escalates model-by-model on repeated failure, route every v2 failure class deliberately, and add the deterministic tier-0 auto-fix seam ahead of any LLM dispatch.


type: methodology

text: Extend the deployed v2 engine (modules/harness/v2/**, lib/gates.sh) only. Never touch modules/harness/src/ — untracked, undeployed, absent from every bundle. Loop mechanics are proven on the free offline canary preset; add canary arms, never alter an existing one.


type: intent

text: Repeated fixer failure today burns identical dispatches on the same model. Escalating to a stronger model on each retry, and spending zero dispatches on mechanical slop a deterministic pass can fix, is what turns the harness into a usable software factory.


type: direction

verbatim: roles: fixer=[luna/xhigh,terra/medium,terra/high] - so the array will be: First go to luna/xhigh, if luna failed, terra/medium, if terra/medium failed, go to terra/high , and if there is only 1 model: no escalation possible. if there is more models, more escalation. array can be as long as i want. i can put 5 models there if i want to. it will not override maximum budget for retry. if a setting says that max retries is 3, having 5 models in the fixer array will not be useful, should emit a warning, not crash.


verbatim: every role can have an array. lets just put it this way. it should be a primitive for all roles, and escalation should be a primitive for all roles that are relevant.


verbatim: if we allow a gate to be red and continue, it's not a gate at all. the exception i was talking about is 'gate is wrong, gate needs fixing'. i dont want a good red gate to pass just because 'it's baseline red'.


verbatim: docs create a diff. no-op verification is no verification. verification = op. it may be no-write verification, but not no-op.


verbatim: needs full observability about what the resolver decided and why


verbatim: If agent is failed, so its failed.


type: deferred

text: The tier-0 auto-fix CATALOGUE — which concrete deterministic fixes ship.

reason: Operator directed a separate brainstorm: mine ~/.claude/projects transcripts for recurring agentic mistakes with the ca.sh composer, then triage each category safe/unsafe. This plan ships only the registry seam.


note: lib/gates.sh resolves from the bundle and run-tests.sh unsets HARNESS_ENGINE_DEV, so any acceptance command that shells out to gates.sh or runplan MUST export HARNESS_ENGINE_DEV=1 scoped to that subprocess or it tests bundle 0.1.120 and fails on the missing summary.


note: This worktree has no .claude/scripts/ship.sh (gitignored, machine-local). meta.land_mode is stamped merge-to-main, matching the main checkout's frozen wrapper, so run-plan rung 2 regenerates it non-interactively.


note: Landing does NOT deploy. modules/harness/v2/** and lib/gates.sh ship only via bin/harness-release.sh bump then release. Do that AFTER the run returns, never as a plan task — flipping CURRENT mid-run swaps the engine underneath runplan.


note: presets/adapters.json has no -xhigh model ids; gpt-5.6-{sol,terra,luna}-{low,medium,high} only. A luna/xhigh rung is unbindable until that family is registered.


type: anchor

what: engine orientation — bundle resolution, canary preset, reply markers


type: task

seat: coder

tier: medium

desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 1 (Gate red-check summary) for the full contract — it is authoritative for every signature, literal string, and journal record shape. lib/gates.sh writes a machine-readable green/red/checks JSON summary when HARNESS_GATE_SUMMARY names a path, and behaves byte-identically when it does not. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

verify: cd modules/harness && bash test/gate-summary.sh

acceptance: test/gate-summary.sh exits 0 and prints gate-summary: ok

acceptance: gate0 run with HARNESS_GATE_SUMMARY unset creates no summary file and keeps its current exit codes


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 2 (Array seat value in schema and validator) for the full contract — it is authoritative for every signature, literal string, and journal record shape. Add a bindingChain seat form (minItems 1, maxItems 8) to the preset schema and validate every chain element like a standalone seat, naming the element index in errors. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

verify: cd modules/harness && node presets/_validate.mjs --self-test

acceptance: a 9-element chain is rejected naming maxItems

acceptance: a chain element with an unregistered model is rejected naming seats.fixer[1]

acceptance: every shipped preset in presets/*.json still validates unchanged


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 3 (Array-aware seat resolution and the fix ladder) for the full contract — it is authoritative for every signature, literal string, and journal record shape. resolveSeat accepts an array seat with an optional rungIndex; add buildFixLadder and resolveIndependentFixBinding with exact back-compat for a bare fixer plus stronger-fixer. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

verify: cd modules/harness && node --test v2/test/seats.test.js

acceptance: buildFixLadder on a bare fixer plus stronger-fixer preset returns rung ids dependency-repair, fixer#1, fixer#2

acceptance: resolveSeat with an out-of-range rungIndex throws naming the rung

acceptance: resolveIndependentFixBinding returns null when the resolver binding matches a burned binding


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 4 (Tier-0 auto-fix registry seam) for the full contract — it is authoritative for every signature, literal string, and journal record shape. New v2/autofix.js holding the AutoFix registry and runAutoFix: only safe entries run, only inside the task file claims, and registration rejects entries touching gate config, test files, or .warnignore. The registry ships EMPTY. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

verify: cd modules/harness && node --test v2/test/autofix.test.js v2/test/suite-manifest.test.js

acceptance: an empty registry returns applied and changed both empty

acceptance: a fixture safe entry runs and reports its changed files

acceptance: an entry is passed only the subset of files inside allowedFiles

acceptance: registering an entry declaring .warnignore throws naming the entry id

acceptance: suite-manifest sees autofix.test.js registered in v2/test/index.js


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 5 (Surface red checks from the gate) for the full contract — it is authoritative for every signature, literal string, and journal record shape. runRealGate passes HARNESS_GATE_SUMMARY and returns green plus redChecks, where null means attribution unavailable and never crashes on a version-skewed bundle. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

verify: cd modules/harness && node --test v2/test/gate.test.js

acceptance: a green real gate returns green true and redChecks empty array

acceptance: a red real gate returns the failing check name in redChecks

acceptance: a gates.sh that ignores HARNESS_GATE_SUMMARY yields redChecks null with the run still completing

acceptance: a corrupt summary file yields redChecks null and no throw


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 6 (Verify-fixer loop walks the chain) for the full contract — it is authoritative for every signature, literal string, and journal record shape. verifyWithFixerRetries resolves attempt N from fixer rung N of the ladder, stays capped by MAX_VERIFY_FIXER_ATTEMPTS, and writes no fix.rung records. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

verify: cd modules/harness && node --test v2/test/run-quality.test.js

acceptance: a 2-element fixer chain failing verify twice journals verify.retry with rung fixer#1 then fixer#2 and dispatches two different bindings

acceptance: a 1-element chain journals fixer#1 twice

acceptance: a 3-element chain still makes at most 2 verify attempts

acceptance: no fix.rung record is written by this loop


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 7 (Gate-fix ladder walk, stamp, and resume) for the full contract — it is authoritative for every signature, literal string, and journal record shape. Replace the RUNGS constant with a per-task ladder, stamp it as fix.ladder before the first fix.rung, resume from the stamp rather than the current preset, and pass reviseAfterReviewFail its binding so exactly one walker owns the chain. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

verify: cd modules/harness && node --test v2/test/quality.test.js

acceptance: a 4-rung ladder all-red produces exactly 4 gate-fix dispatches with of:4

acceptance: killing after fixer#2 and resuming returns fixer#3

acceptance: resuming after the preset chain was replaced still returns fixer#3 from the stamp with no quarantine

acceptance: a legacy history whose fix.rung records lack of resumes without quarantine

acceptance: a 5-rung chain under a 3-attempt budget warns once, journals preset.chain-truncated, and the run proceeds

acceptance: reviseAfterReviewFail writes no fix.rung record


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 8 (Keep-vs-revert and scope-violation routing) for the full contract — it is authoritative for every signature, literal string, and journal record shape. Hoist a pre-rung-1 workspace snapshot, apply the first-match keep-vs-revert precedence table on red-set divergence, and route a second file-claim escape to the dependency-repair seat before quarantine. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

acceptance: a grown red set journals fix.tree action revert

acceptance: the reverted tree equals the pre-rung-1 snapshot and not the task base

acceptance: redChecks null on either side journals keep

acceptance: a second file-claim escape journals fix.scope-routed and dispatches the resolver seat before any quarantine


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 9 (Run-level escalation ceiling and defective-gate halt) for the full contract — it is authoritative for every signature, literal string, and journal record shape. Count escalated dispatches across the run and halt between tasks at ceil(taskCount/2); run gate0 on the untouched base before wave 1 and halt with the verbatim two-cause message when it is red. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

verify: cd modules/harness && node --test v2/test/run.test.js

acceptance: a 4-task run with a forced ceiling of 1 halts after the task that crossed it with that task ladder complete and run.escalation-ceiling journaled

acceptance: a run whose base gate is red halts before wave 1 with the two-cause message and gate.defective journaled

acceptance: a run whose base goes red mid-run halts naming the poisoning task


desc: Read docs/plans/2026-08-07-failure-routing-and-escalation.md Task 10 (Tier-0 invocation before the ladder) for the full contract — it is authoritative for every signature, literal string, and journal record shape. Call runAutoFix before every rung when redChecks is a non-empty array, re-run only those checks, and contain any autofix error so tier 0 can never fail a task. Touch ONLY the files listed in files_modify. NEVER edit modules/harness/src/ — it is untracked, undeployed, and absent from every engine bundle.

acceptance: with a fixture safe entry that turns the red check green the quality phase completes with zero fix.rung records and one autofix.applied

acceptance: with an empty registry the ladder runs exactly as before

acceptance: redChecks null produces no autofix record at all

acceptance: a throwing entry journals autofix.failed and the ladder still runs