chore(routing): retire haiku from delivery-lifecycle roles (#680)

Haiku can't reliably emit the structured envelopes the lifecycle now
runs on — pass_review's per-AC criteria_verified, delegate's
covers_parent_criteria, the findings ledger. A haiku QA/PM claims, gets
validation-rejected, idles, respawns, and loops without advancing a task
(2026-07-24 live: fe-qa on haiku looped four awaiting_qa tasks to zero
progress). The per-token savings (~2x under the Sonnet-5 promo, 3x after)
are dwarfed by the cost of a review that never completes.

Three coordinated changes: ROLE_MODEL_MAP's qa/documenter defaults move
haiku -> sonnet (the actual source of the live incident); the cost_tiered
developer:low -> haiku seed retires to empty (the floor would upgrade it
anyway); and a structured-verb capability floor upgrades any below-floor
Anthropic assignment to sonnet at resolution — from a pin, a ROLE row,
or a future map edit — in both the assignment and legacy paths.
Non-Anthropic providers are untouched (an Anthropic-tier floor, not a
provider policy). pr_reviewer/auditor stay on opus.

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
Renzo F
2026-07-24 12:14:13 +02:00
committed by GitHub
co-authored by Renn F
parent e1ae58489c
commit a3f84f3165
5 changed files with 132 additions and 26 deletions
+6 -6
View File
@@ -956,8 +956,10 @@ async def test_apply_mode_cost_tiered_seeds_day1_rows(
"/api/providers/complexity-overrides", headers=_HDR_PM
)
rows = {(r["role"], r["complexity"]): r["model_name"] for r in listing.json()}
# cell_pm is deliberately excluded (a coordinator role) — only developer.
assert rows == {("developer", "low"): "haiku"}
# Seed retired (2026-07-24): its only entry was developer:low -> haiku,
# which the structured-verb capability floor would upgrade to sonnet
# anyway. cost_tiered mode stays wired but seeds nothing now.
assert rows == {}
@pytest.mark.asyncio
@@ -979,11 +981,9 @@ async def test_apply_mode_cost_tiered_is_additive_preserves_global(
assert response.status_code == HTTPStatus.OK
assignments = response.json()["assignments"]
scopes = {(a["scope"], a["scope_value"]) for a in assignments}
# The pre-existing GLOBAL row from 'ollama' mode survives untouched.
# The pre-existing GLOBAL row from 'ollama' mode survives untouched — the
# non-wiping contract holds even with the seed retired to empty.
assert ("global", None) in scopes
assert ("role", "developer:low") in scopes
# cell_pm is deliberately excluded from cost_tiered — a coordinator role.
assert ("role", "cell_pm:low") not in scopes
# =============================================================================