Skip to main content

Two failed attempts now stops the orchestrator, not just the model

· 3 min read
Anchor maintainers

Mythos-core rule 6 has always told a model to stop after two failed fix attempts and hand the problem up. That only works if the model is still counting straight — and a resumed or re-invoked task starts a fresh context with no memory of the attempts a prior run already burned. The orchestrator now keeps that count itself.

What was missing

Rule 6 is prompt discipline: "if the same error survives two distinct fix attempts, stop." It works inside one continuous conversation. It does not survive a process boundary — a fleet worker picking the same task back up, or orchestrate.py --plan-file re-run after an interruption, starts counting from zero every time, because nothing outside the model's own context remembered the earlier failures.

A persistent count, not an in-memory one

scripts/fleet_metrics.py already writes a claimed-vs-actual row to var/fleet-metrics/outcomes.jsonl for every finished task. should_stop reads that ledger instead of trusting a counter that resets with the process:

should_stop(task_id, model, ledger, tier="mid")
# → continue | escalate-tier | human-report

Counting is per (task, model). A scope-gate rejection counts as a failure — it is one, per rule 7 — even though it never runs --verify. A handoff does not count, because a handoff never reaches the ledger in the first place; the orchestrator returns before recording one. Fewer than two recorded failures for that pair, and the answer is always continue.

Refuse the third dispatch, escalate a tier

execute_task consults should_stop before every (re)dispatch. Two recorded failures at the current tier means the model that already failed twice does not get a third try — the orchestrator picks an endpoint at the fleet's next configured tier (available_fit_tiers, pick_escalation_endpoint) and dispatches there instead, with both failures' evidence attached to the escalated spec's prompt so the stronger tier knows what already didn't work.

Nowhere left to escalate

Two failures already at the top tier this fleet has configured is not "reasoner still open, keep trying" — it is exhaustion. The orchestrator generates a structured report itself, in rule 6's own shape (tried / observed / hypothesis / what a stronger model or human should look at), and writes it to var/human-reports/ before the task ever needs a third dispatch anywhere. The ledger is metadata-only by design — no prompts, no output — so the report says so plainly rather than inventing a diagnosis it cannot support.

Using it

Nothing new to configure — pass --metrics-ledger (or take the default var/fleet-metrics/outcomes.jsonl) the way you already do for claimed-vs-actual tracking, and orchestrate.py handles the rest:

python scripts/orchestrate.py --plan-file .plans/bugs/flaky-import.md \
--verify "pytest -q"

Because failures are only persisted on a task's final attempt, this backstop stays invisible inside one continuous run — the two-attempts-then-stop behavior you already know is unchanged. It only bites when a task comes back around, which is exactly the case a model's own attempt-counting can't cover.