feat(route)!: Fable rows are a hand-written override, never a route.sh outcome

The operator removed the "Fable can only be suggested after a failed Opus
5/xhigh session" policy on 2026-08-06 - it stood in the way too often. Until
now that policy was implemented as code: --opus-xhigh-failed was the ONLY
way route.sh's SELECTION chain could reach rows 5-6 (Fable), so the rubric
still enforced a policy the operator had already dropped.

Given a choice between (A) deleting the branches and the flag outright, so
the calculator's output range closes at row 4, or (C) keeping a path that
renders a Fable row on explicit instruction with rule=operator-override, the
operator chose A (AskUserQuestion) - CLAUDE.md is explicit that the rubric
stays the only deterministic lookup and a Fable choice is now always a
deviation from it, recorded in STATE as an override rather than produced
here. board.sh is untouched and still parses "Fable 5/high"/"Fable 5/xhigh"
written by hand into a board line (route-selftest.sh section 6 now pins that
half directly, since route.sh can no longer produce the strings itself).

TDD: every affected selftest check was rewritten to fail against the
unmodified route.sh first (72->68/69, confirmed red), then route.sh was
edited to match. --opus-xhigh-failed is gone outright - passing it now exits
2 like any other unknown argument, not silently accepted as a no-op.

route-selftest.sh: 73 -> 69 checks (three checks tested command shapes
row_advisor() can no longer produce; the two row-5/row-6 reachability checks
in section 1 collapsed into one "the flag is gone" check). coord 191, board
142 unaffected. Suite total 406 -> 402.

Also folds in a standalone fix already pushed this session: section 14 was
gating the wrong CLI fact (whether "claude --advisor fable" is rejected,
which row_advisor() never depends on) instead of the one it actually rests
on (whether opus/sonnet can advise a FABLE main model). Re-pointed and
verified against the installed CC 2.1.226.

Verified before committing: grepped every repo under ~/repos for a route
line carrying --opus-xhigh-failed (none - one repo has it in prose only,
not in its <!-- route: --> comment) and ran board.sh --plan/--brief over the
real tree to confirm no repo's command line broke. Sent a follow-up
coord-send to catalog superseding an earlier now-stale "406" stat-line
correction with the current 402.

skills/route/SKILL.md: usage block, "last-session record" framing, and the
closing --opus-xhigh-failed paragraph rewritten to match. CLAUDE.md, README
and CHANGELOG updated (checks 73->69, badge 406->402, new 0.21.0 entry).
Version bumped 0.20.3 -> 0.21.0 across plugin.json, package.json and all
three skill frontmatters (breaking CLI removal at 0.x -> minor, per v0.20.0
precedent).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ap1WKHCDPcSfpjo4ds2dQX
This commit is contained in:
Kjell Tore Guttormsen 2026-08-09 22:03:05 +02:00
commit dd8f3ce042
10 changed files with 172 additions and 124 deletions

View file

@ -192,7 +192,7 @@ marketplace plugin. Three components, one boundary:
rationale, and prints one block of `key=value` lines: the rubric row, the rule
that fired, the `next-cost` value, a pasteable startup command, the one-row
cheaper fallback, and the STATE.md comment lines. Pinned by
`route-selftest.sh` (73 checks).
`route-selftest.sh` (69 checks).
**It is here because it is the WRITER for the field `board.sh` already reads.**
`next-cost` had a reader and no writer, so it was hand-typed every session and
@ -228,6 +228,19 @@ marketplace plugin. Three components, one boundary:
token — advisor validation runs before the empty-prompt check, so `-p ""`
reaches the validator and stops there.
**Rows 5-6 are never a `route.sh` outcome.** Until 2026-08-06 they fired
only from an explicit `--opus-xhigh-failed` flag, mirroring a global
CLAUDE.md policy that Fable could only be *suggested* after a failed Opus
5/xhigh session. That policy was removed by operator decision — "for ofte
ER Fable riktig" — and the flag went with it rather than being repurposed:
`route.sh`'s output range is now closed at row 4, and a Fable choice is
always a hand-written deviation from the rubric, recorded in STATE as an
override per the model-selection rule in the global CLAUDE.md, never
produced by the calculator. `board.sh` still parses "Fable 5/high" and
"Fable 5/xhigh" written by hand into the board line — that parsing is what
the override actually uses, and it is pinned separately from anything
`route.sh` emits (route-selftest.sh section 6).
**`--last-effort` is MEASURED from `CLAUDE_EFFORT`, and the calculator must
never default it.** Claude Code exports that variable into every tool-use
context as the session's current effort, so the caller reads it and passes it
@ -288,7 +301,7 @@ obligations in another repo.
- TDD: no behavior change without a failing selftest check first.
`bash scripts/coord-selftest.sh` must exit 0 (191/191),
`bash scripts/board-selftest.sh` must exit 0 (142/142) and
`bash scripts/route-selftest.sh` must exit 0 (73/73).
`bash scripts/route-selftest.sh` must exit 0 (69/69).
- English for all code, docs, and commit messages (public repo). Norwegian
trigger aliases in the skill description are deliberate.
- Conventional Commits: `type(scope): description`.