routing: route every role to opus, keep model as the escape hatch #75

Closed
opened 2026-07-28 18:54:38 +00:00 by crenshawdev · 1 comment
crenshawdev commented 2026-07-28 18:54:38 +00:00 (Migrated from github.com)

Extracted from #63 as part of the 1.5.0 / 2.0.0 split. No config key changes, so no user has to do anything on upgrade. See the objection section below, because #63 explicitly argues this piece should not be extracted, and that deserves an answer rather than a quiet override.

What you want Cadence to do

Route every role to opus in cadence-core/route-table.json. Keep model as a field so it stays an escape hatch, keep model.overrides.<role> working, and keep fable reachable only through an explicit override.

Why

The current placement is a cost decision wearing capability clothes. Under the shipped balanced default, route-table.json puts cad-executor at tier standard and cad-plan-checker at tier light, which map to sonnet and haiku. No role needs to be haiku or sonnet for any reason except latency.

The evidence already exists informally and should be made formal. Moving an executor to Opus 5 produced fewer loops and fewer bugs in observed use. That is the argument, and it stands without any reframe: a looping executor burns more than the model it saved, so the cheap placement was never actually cheap. The question that matters is not spend per dispatch, it is how many dispatches it takes to get the answer right.

It removes a live inconsistency. While roles are split across model tiers, one effort value in an agent file has to be simultaneously correct for haiku, sonnet and opus. Opus-5-specific guidance cannot be applied to roles that are not routed to opus, which today includes the executor and the plan checker. Collapsing the model axis makes per-role effort meaningful.

The objection from #63, stated fairly

#63 argues this cannot be extracted, in these words:

the model collapse cannot be argued on its own: "put the executor on opus" reads as a spending increase, while "the executor's work is consequential, so it runs at hardened rigor" reads as what it is.

That objection is about framing, not dependency. Technically this change has no relationship to the enum rename: it is a different file, it breaks nothing, and it can be reverted in one commit. And the loop-count evidence is a standalone empirical case that does not need the rigor vocabulary to make sense.

If the framing concern turns out to be the deciding one, the correct response is to close this and fold it back into #63, not to ship it half-argued. Flagging it explicitly so that stays an open choice.

What it costs

This is a behaviour and cost change, and it must not ship silently. No config key changes, which is what makes it minor-release-eligible, but users will see different latency and different consumption. It needs a changelog entry that says so plainly.

Not a cost optimization, and it should not be sold as one. Cadence targets Max subscribers rather than API metering, where the allowance is a ceiling and not a budget. Measured usage on a heavy day (2026-07-27) was 44M billed-equivalent tokens across 11.8 active hours with no weekly cap hit.

Half the burn is out of reach regardless. The orchestrator is the user's own session and Cadence cannot configure it. That was 50.9% of measured burn, so no routing change here touches half the spend, and any claim about totals has to say so.

The measurement that would validate this

Executor loop and retry counts by model. This is the one with an informal result already behind it and it deserves a recorded one.

Files this touches

cadence-core/route-table.json, cadence-core/bin/route.mjs and route.test.mjs, CHANGELOG.md.

  • #63, which contains the full argument and the objection above.
  • #54, which wants per-role tier and effort user-configurable; the tier half of it is what this starts dismantling.
Extracted from #63 as part of the 1.5.0 / 2.0.0 split. No config key changes, so no user has to do anything on upgrade. See the objection section below, because #63 explicitly argues this piece should *not* be extracted, and that deserves an answer rather than a quiet override. ## What you want Cadence to do Route every role to opus in `cadence-core/route-table.json`. Keep `model` as a field so it stays an escape hatch, keep `model.overrides.<role>` working, and keep `fable` reachable only through an explicit override. ## Why **The current placement is a cost decision wearing capability clothes.** Under the shipped `balanced` default, `route-table.json` puts `cad-executor` at tier `standard` and `cad-plan-checker` at tier `light`, which map to **sonnet** and **haiku**. No role needs to be haiku or sonnet for any reason except latency. **The evidence already exists informally and should be made formal.** Moving an executor to Opus 5 produced fewer loops and fewer bugs in observed use. That is the argument, and it stands without any reframe: a looping executor burns more than the model it saved, so the cheap placement was never actually cheap. The question that matters is not spend per dispatch, it is how many dispatches it takes to get the answer right. **It removes a live inconsistency.** While roles are split across model tiers, one `effort` value in an agent file has to be simultaneously correct for haiku, sonnet and opus. Opus-5-specific guidance cannot be applied to roles that are not routed to opus, which today includes the executor and the plan checker. Collapsing the model axis makes per-role effort meaningful. ## The objection from #63, stated fairly #63 argues this cannot be extracted, in these words: > the model collapse cannot be argued on its own: "put the executor on opus" reads as a spending increase, while "the executor's work is consequential, so it runs at hardened rigor" reads as what it is. That objection is about **framing, not dependency**. Technically this change has no relationship to the enum rename: it is a different file, it breaks nothing, and it can be reverted in one commit. And the loop-count evidence is a standalone empirical case that does not need the rigor vocabulary to make sense. If the framing concern turns out to be the deciding one, the correct response is to close this and fold it back into #63, not to ship it half-argued. Flagging it explicitly so that stays an open choice. ## What it costs **This is a behaviour and cost change, and it must not ship silently.** No config key changes, which is what makes it minor-release-eligible, but users will see different latency and different consumption. It needs a changelog entry that says so plainly. **Not a cost optimization, and it should not be sold as one.** Cadence targets Max subscribers rather than API metering, where the allowance is a ceiling and not a budget. Measured usage on a heavy day (2026-07-27) was 44M billed-equivalent tokens across 11.8 active hours with no weekly cap hit. **Half the burn is out of reach regardless.** The orchestrator is the user's own session and Cadence cannot configure it. That was 50.9% of measured burn, so no routing change here touches half the spend, and any claim about totals has to say so. ## The measurement that would validate this Executor loop and retry counts by model. This is the one with an informal result already behind it and it deserves a recorded one. ## Files this touches `cadence-core/route-table.json`, `cadence-core/bin/route.mjs` and `route.test.mjs`, `CHANGELOG.md`. ## Related - #63, which contains the full argument and the objection above. - #54, which wants per-role tier and effort user-configurable; the tier half of it is what this starts dismantling.
crenshawdev commented 2026-07-28 19:51:29 +00:00 (Migrated from github.com)

Superseded by #81

Closing because the change this issue describes stops existing under #81, rather than because the underlying observation was wrong.

What survives. The seed observation holds: flipping the conventional heavy-plans/cheap-executes assignment and putting the heavier model on the executor produced fewer iterative cycles of bug-finding in adversarial review. That is carried into #81 with a mechanism behind it (Anthropic's Opus 5 guidance: strongest on difficult multi-file work, "completes tasks rather than leaving stubs or placeholders," with a smaller gap on easy single-turn edits) and with the falsifiable prediction that follows from it, namely that the effect should concentrate on heavy phases and nearly vanish on trivial ones.

What does not survive. This issue was scoped as "route every role to opus," which was my reading of #63's wording rather than the actual intent. That framing is wrong twice over:

  1. It is not what was being proposed. The proposal is to invert the assignment at one role, not to collapse the model axis everywhere.
  2. Collapsing every cell of the profile matrix to opus has no clean form. Rewriting all nine cells makes model.profile a key that is read, resolved, escalated, and has no effect, which is precisely the defect #64 fixed and #78 tracks; deleting the matrix instead is the v2.0.0 breaking change by definition. There is no third option.

And the narrow version is not a standalone change either. Moving one role is technically trivial (cad-executor from tier: standard to tier: heavy lands it on opus under balanced with the matrix untouched), but under #81 the executor's model stops being a pinned value and becomes a derived one. Pinning it now would be work undone later.

The framing objection this issue reproduced from #63 is therefore moot: the question was never whether "put the executor on opus" could be argued on its own, but whether the model should be pinned at all.

## Superseded by #81 Closing because the change this issue describes stops existing under #81, rather than because the underlying observation was wrong. **What survives.** The seed observation holds: flipping the conventional heavy-plans/cheap-executes assignment and putting the heavier model on the *executor* produced fewer iterative cycles of bug-finding in adversarial review. That is carried into #81 with a mechanism behind it (Anthropic's Opus 5 guidance: strongest on difficult multi-file work, "completes tasks rather than leaving stubs or placeholders," with a smaller gap on easy single-turn edits) and with the falsifiable prediction that follows from it, namely that the effect should concentrate on heavy phases and nearly vanish on trivial ones. **What does not survive.** This issue was scoped as "route every role to opus," which was my reading of #63's wording rather than the actual intent. That framing is wrong twice over: 1. It is not what was being proposed. The proposal is to invert the assignment at one role, not to collapse the model axis everywhere. 2. Collapsing every cell of the profile matrix to opus has no clean form. Rewriting all nine cells makes `model.profile` a key that is read, resolved, escalated, and has no effect, which is precisely the defect #64 fixed and #78 tracks; deleting the matrix instead is the v2.0.0 breaking change by definition. There is no third option. **And the narrow version is not a standalone change either.** Moving one role is technically trivial (`cad-executor` from `tier: standard` to `tier: heavy` lands it on opus under `balanced` with the matrix untouched), but under #81 the executor's model stops being a pinned value and becomes a derived one. Pinning it now would be work undone later. The framing objection this issue reproduced from #63 is therefore moot: the question was never whether "put the executor on opus" could be argued on its own, but whether the model should be pinned at all.
Sign in to join this conversation.
No description provided.