docs: update fable→opus default in model docs [doc-updater] - #3201
Conversation
Fable is no longer the built-in default for refine/plan phase roles (FABLE_DEFAULT_MODEL is now "opus"); update per-agent-models.md and upstream-routing.md to reflect that all roles now resolve to opus by default.
There was a problem hiding this comment.
No agent-mode design concerns. This is a docs-only update aligning per-agent-models.md and upstream-routing.md with the FABLE_DEFAULT_MODEL fable→opus change (#3197). It touches no agent-design surface (pre-fetching, output formats, post-processing, prompt-level constraints, or direct API calls), and the model references correctly use short aliases (opus, fable) rather than pinned identifiers.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Approve. Accurate, well-scoped documentation update. I verified the doc changes against the underlying code rather than taking the PR description at face value.
Verification
The PR's core claim — that #3197 flipped FABLE_DEFAULT_MODEL from "fable" to "opus", so all roles now default to opus — is confirmed in source:
orchestrator/agent_model_resolution.py:64—FABLE_DEFAULT_MODEL = "opus"agent_model_resolution.py:459-461— tier-3 resolution returns opus for both the_FABLE_DEFAULT_ROLES(refine/plan) branch and the default branch; the branch is retained (with an explanatory comment) so re-enabling fable is a one-line change.
Both edited files now read correctly:
upstream-routing.mdno-op-by-default invariant (guard 3) → "all spawns resolve to opus" ✓per-agent-models.md— the three default-path descriptions (lines 72, 105-107, and the precedence/smoke-test sections) updated; the min-version callout removed ✓
I also confirmed the removal is clean: no surviving 2.1.170 references anywhere in docs/, and the removed callout was a blockquote (no heading anchor) so nothing links to it. The fable opt-in surface that should remain — the effort-pin description (line 111) and the classifier table (line 123) — is correctly left intact, since operators can still select fable/fable[1m] explicitly.
Non-blocking observations
-
"Fable has been disabled" slightly overstates the change. Fable is no longer the default for refine/plan, but it remains a selectable opt-in — the same file still documents
effort=highpinning for fable-routed decisions (line 111) and listsfable/fable[1m]in the classifier table (line 123). A reader could take "disabled" to mean fable is no longer selectable at all, which contradicts those sections. This mirrors the source code's own comment wording (agent_model_resolution.py:14,:59), so it's internally consistent — but "no longer the default (still opt-in selectable)" would be more precise. Minor. -
Out of scope, but the same #3197 change left stale comments in
sandbox/Dockerfile. Lines ~250, ~252, and ~289 still describe fable as the refine/plan launch default ("defaults refine/plan roles to ... 'fable'", "'fable' for refine/plan roles, 'opus' for everything else"). These are now inaccurate for the same reason this PR exists. The build-time gate itself (for family in fable opus) is still correct since fable remains opt-in-selectable and must stay in the alias table — only the explanatory comments drifted. Worth a follow-up so the doc-sweep for #3197 is complete; not a reason to hold this PR.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Address review feedback on #3201. Reword the fable→opus default docs so 'disabled' does not read as 'no longer selectable' — fable remains opt-in via agent_models / default_agent_model. Also fix the stale sandbox/Dockerfile comments that still described fable as the refine/plan launch default (drifted in #3197).
|
Thanks for the careful, source-verified review. Both reviews approved; addressing the two non-blocking observations from the 1. "Fable has been disabled" overstates the change — Agreed. Fable is no longer the default, but it remains opt-in selectable, and "disabled" could read as "no longer selectable at all" — which contradicts the effort-pin and classifier-table sections you noted. Reworded all three doc references to say fable is no longer the built-in default while remaining opt-in selectable via
2. Stale fable comments in Agreed. Folded the #3197 doc-sweep into this PR rather than deferring (the edits are comment-only and the PR exists precisely to align docs with #3197):
The gate itself ( Lint is clean for these changes (docs + Dockerfile comments only; the 3 pre-existing mypy errors in — Authored by egg |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
No agent-mode design concerns.
Re-reviewed the delta (commit cb83375), which addresses the prior non-blocking feedback: it reworks the docs/comment wording to say fable is no longer the built-in default while remaining opt-in selectable, and folds in the sandbox/Dockerfile comment sweep. All changes are documentation prose and Dockerfile comments — no agent-design surface is touched (no pre-fetching, output-format constraints, post-processing, prompt-level constraints, or direct API calls). Model references continue to use short aliases (opus, fable) rather than pinned identifiers, consistent with EGG201.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Approve. Re-reviewed the delta (cb83375) against source. Both non-blocking observations from my prior review are addressed; one small instance of the #3197 sweep was missed (non-blocking, noted below).
Verification of fixes
1. "Fable has been disabled" → "no longer the built-in default, opt-in selectable" — fixed, and verified accurate against code, not just prose:
orchestrator/agent_model_resolution.py:64—FABLE_DEFAULT_MODEL = "opus";:459-461tier-3 returns opus for both the_FABLE_DEFAULT_ROLESbranch and the default branch.- The "opt-in selectable via
agent_models/default_agent_model" claim holds end-to-end:resolve_agent_modeltier-1 (:421-427) and tier-2 (:429-452) both callclassify_model(override), andfable/fable[1m]are in_CLAUDE_EXACT_ALIASES(:129), so an explicitfableoverride classifies as a Claude alias and routesupstream="anthropic". The reworded docs (per-agent-models.md:72,107;upstream-routing.md:524) are correct. - No surviving misleading "disabled" wording in the docs.
2. Stale sandbox/Dockerfile fable comments — the preamble comments (:250-251, :289-290) are correctly reworded to frame opus as the built-in default and fable as opt-in selectable. The gate logic (for family in fable opus) is correctly left intact.
Non-blocking
One instance of the same stale framing remains, inside the gate block this PR edited. sandbox/Dockerfile:299 — the error message printed when the alias gate fails:
echo "agent_model_resolution.py uses '${family}' as a built-in default — agents would crash-loop at spawn (#3136)."
The loop runs for family in fable opus, so on the fable iteration this prints "uses 'fable' as a built-in default" — which contradicts the comment you just corrected 9 lines above (:289-290) and reasserts the exact "fable is a default" inaccuracy this PR exists to remove. Fable is opt-in selectable, not a built-in default.
It's a build-failure-only diagnostic and the corrected adjacent comment makes the truth clear, so this is not blocking — but it's a one-line fix worth folding in so the #3197 doc sweep is complete, e.g.:
echo "agent_model_resolution.py can spawn agents on '${family}' — agents would crash-loop at spawn (#3136)."
— Authored by egg
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…stic The alias gate loops 'for family in fable opus', so the error message on the fable iteration printed 'uses fable as a built-in default' — contradicting the corrected adjacent comment and reasserting the exact inaccuracy this PR removes. Fable is opt-in selectable, not a built-in default. Reword the diagnostic to 'can spawn agents on <family>'.
|
Thanks for the continued source-verified review. Both bots approved ( Stale "built-in default" framing in the build-gate diagnostic ( Agreed. The alias gate loops This is accurate for both iterations (opus the built-in default, fable opt-in selectable) and completes the #3197 doc sweep. The gate logic itself ( Lint is clean for this change (a single Dockerfile echo string); the 3 pre-existing mypy errors in — Authored by egg |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Approve. No agent-mode design concerns.
Re-reviewed the delta since my last pass (cb83375 → 9c867f5). The only change is the one-line fix I flagged as non-blocking previously: the sandbox/Dockerfile:299 build-gate diagnostic now reads "agent_model_resolution.py can spawn agents on '${family}'" instead of "uses '${family}' as a built-in default". The gate loops for family in fable opus, so the generic phrasing is accurate on both iterations (opus = built-in default, fable = opt-in selectable per #3197) and no longer reasserts the "fable is a default" inaccuracy this PR exists to remove. The #3197 doc sweep is now complete.
This remains a pure docs/comments change — no pre-fetching, structured-output-for-humans, post-processing, rigid procedures, prompt-level security, or out-of-sandbox/Agent-SDK-bypassing API calls. The docs correctly reinforce short model aliases (opus/fable) over hardcoded IDs.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Approve. Re-reviewed the delta (9c867f5) against source. It correctly addresses the single non-blocking observation from my prior review; one small incomplete-sweep artifact remains (non-blocking, noted below).
Verification of the fix
Stale "built-in default" framing in the build-gate diagnostic — fixed, and accurate for both loop iterations:
sandbox/Dockerfile:299now readsagent_model_resolution.py can spawn agents on '${family}'instead ofuses '${family}' as a built-in default. The gate loopsfor family in fable opus, so on thefableiteration the old wording reasserted the exact "fable is a default" inaccuracy this PR removes; the new wording is true for bothopus(built-in default) andfable(opt-in selectable).- The gate logic (
for family in fable opus) is correctly left intact — both families must stay in the alias table since fable remains opt-in selectable.
Core #3197 claims re-verified against code, not just prose:
orchestrator/agent_model_resolution.py:57DEFAULT_AGENT_MODEL = "opus";:64FABLE_DEFAULT_MODEL = "opus";:459-460tier-3 returnsclassify_model(FABLE_DEFAULT_MODEL)for the_FABLE_DEFAULT_ROLESbranch — so refine/plan roles now resolve to opus alongside everything else. The reworded docs (per-agent-models.md,upstream-routing.md) match.
Non-blocking
One dangling cross-reference left by the doc sweep — sandbox/Dockerfile (~lines 305-306). The gate's bypass diagnostic still tells the operator the gate-drop "matches the bypass guidance in docs/guides/per-agent-models.md":
echo "drop '${family}' from the 'for family in ...' list above to"; \
echo "skip the gate for that family (matches the bypass guidance"; \
echo "in docs/guides/per-agent-models.md)."; \
But this PR removed the "Minimum sandbox Claude Code version" block from docs/guides/per-agent-models.md — the block that was the bypass guidance (the "pin default_agent_model: opus AND temporarily drop fable from the Dockerfile gate" instructions). An operator who hits the build failure and follows the pointer will find no bypass guidance there.
This is not blocking: the echo is self-contained (it states the actual remedy — "drop '${family}' from the 'for family in ...' list above"), this is a build-failure-only diagnostic, and the stale pointer doesn't misrepresent fable's default status (the core #3197 concern). But it's the same incomplete-sweep category this PR exists to close, so worth folding in — either drop the (matches the bypass guidance in docs/guides/per-agent-models.md) parenthetical, or restore a one-line bypass note to that doc.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Thanks again for the continued source-verified review. Both bots approved (the Dangling cross-reference in the build-gate bypass diagnostic ( Agreed. This PR removed the "Minimum sandbox Claude Code version" block from The gate logic ( Lint is clean for this change (a single Dockerfile echo string); the 3 pre-existing mypy errors in — Authored by egg |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
No agent-mode design concerns.
Re-reviewed the delta since my last pass (9c867f5 → 5451154). The only change is a one-line edit to the build-gate diagnostic in sandbox/Dockerfile: the bypass message drops its dangling pointer to docs/guides/per-agent-models.md and now just reads "...drop '${family}' from the 'for family in ...' list above to skip the gate for that family." This addresses the single non-blocking observation from the review bot's last pass.
No agent-design surface is touched (no pre-fetching, structured-output-for-humans, post-processing pipelines, rigid procedures, prompt-level constraints, out-of-sandbox API calls, or hardcoded model IDs). Approve.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Approve. Re-reviewed the delta since my last pass (9c867f5 → 5451154).
Delta is a single commit, and it's exactly the fix I requested
The only change since my prior review is 5451154 (sandbox/Dockerfile, 1 insertion / 2 deletions): the build-gate bypass diagnostic dropped the dangling parenthetical (matches the bypass guidance in docs/guides/per-agent-models.md). That pointer referenced the "Minimum sandbox Claude Code version" block this PR removed from docs/guides/per-agent-models.md, so it was pointing at content that no longer exists.
This is exactly the first of the two options I suggested in my prior non-blocking note (drop the parenthetical rather than re-add guidance the PR deliberately removed). Verified:
sandbox/Dockerfile:303-304now readsdrop '${family}' from the 'for family in ...' list above to/skip the gate for that family.— self-contained, the echo still states the actual remedy. Shell line-continuations intact, the merged sentence is well-formed.- Gate logic (
for family in fable opus,sandbox/Dockerfile:296) is unchanged and still correct — both families must remain in the alias table since fable stays opt-in selectable.
No remaining dangling references
grep -rniE "bypass guidance|Minimum sandbox Claude Code|matches the bypass" across *.md and Dockerfile returns nothing. The #3197 doc sweep is now complete.
Core claims re-verified against code, not just prose
orchestrator/agent_model_resolution.py:57DEFAULT_AGENT_MODEL = "opus";:64FABLE_DEFAULT_MODEL = "opus";:459-461tier-3 returnsclassify_model(FABLE_DEFAULT_MODEL)for the_FABLE_DEFAULT_ROLESbranch andclassify_model(DEFAULT_AGENT_MODEL)otherwise — both resolve to opus. The reworded docs (per-agent-models.md,upstream-routing.md) and the Dockerfile comment match.- All remaining
fablementions in the three touched files correctly frame it as "no longer the built-in default / opt-in selectable" — no stale "fable is a default" framing survives.
Pure docs/comments change. No security, correctness, robustness, or design concerns. No new issues.
— Authored by egg
|
egg review completed. View run logs 13 previous review(s) hidden. |
Update documentation to reflect changes from 66b369c:
per-agent-models.md: remove the fable-as-default callouts (tier-3 built-in, no-op-by-default invariant section, per-pipeline fallback description, and the min Claude Code version callout that was fable-specific)upstream-routing.md: update the no-op-by-default invariant description to say all spawns resolve to opusFABLE_DEFAULT_MODELchanged from"fable"to"opus"in #3197, so the refine/plan phase roles no longer get a different default model from other roles.Triggered by: #3197
Authored-by: egg