feat(scanners): model/effort routing becomes a lever, not a 25th dimension (C4)
New GAP finding CA-GAP-028: authored subagents exist and not one of them names `model:` or `effort:`, so every delegated task runs on the main conversation's model (`model` defaults to `inherit`). Cites BP-MODEL-001/002, landed in C1. `whats-active` and `manifest` now carry `model`/`effort` per agent. Shipped as a conditional LEVER rather than a 25th dimension, and the choice was made by measurement: as a t3 dimension the agent-less marketplace-medium fixture would count it vacuously-present, moving the denominators 41->42 and utilization 44->45 — which flips `segment` "Developing"->"Competent" in the frozen v5.0.0 posture baseline, a field strip-retired-gap.mjs does not mask. A lever never enters those denominators. The general rule is now an invariant in CLAUDE.md. One check across both axes, not one per axis: it fires only when neither is used anywhere, so a deliberate everything-on-one-model policy stays silent. Cost is recall, chosen for precision. Found by dogfooding, fixed red-first: `model: inherit` is the documented default spelled out, so it must not count as routing — otherwise a config opts out of the opportunity without changing anything real. Two pre-existing defects surfaced and closed on the way: - The humanizer guard asserted TRANSLATIONS.GAP.static EQUALS the dimension titles, which forbade humanizing any lever — all three existing levers fell through to the generic "feature opportunity" default, wrong for a budget lever. Guard now requires coverage of every emittable title, seen red against those three before the entries were written. - Two hand-written copies of the lever list (finding-codes guard, humanizer guard) merged into one exported LEVERS registry carrying code AND title. - suppression-validation pinned CA-GAP-028 as an unoccupied number; C4 claimed it. Fixed structurally with a derived first-free id, not by picking a new literal — same class as #60's "bump this again". Suite 1596/0. Frozen v5.0.0 snapshots untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq3nye21RVYk4pZLeT8pGz
This commit is contained in:
parent
e861e63a7b
commit
9ae4be26d2
16 changed files with 512 additions and 31 deletions
|
|
@ -221,6 +221,46 @@ returns ≥1 chatty hook — surfaces the documented **filter-before-Claude-read
|
|||
grep ERROR and return only matches instead of a 10,000-line log). No chatty hook → silent (opportunity,
|
||||
not noise — same contract as the cliOverMcp / bundledSkills levers).
|
||||
|
||||
### feature-gap — agent model/effort routing lever (v5.14 C4, `CA-GAP-028`)
|
||||
|
||||
`agentModelRoutingLeverFinding` fires only when the target has **authored** subagents (the same
|
||||
`isAuthoredConfig` set the presence checks use, so plugin-bundled and fixture agents cannot make a
|
||||
machine look routed — M-BUG-13) and **not one of them** names `model:` or `effort:`. Cites
|
||||
`BP-MODEL-001` (a subagent's `model` defaults to `inherit`, so omitting it is a choice to pay the
|
||||
session's rate) and `BP-MODEL-002` (effort is a separate axis with its own frontmatter field).
|
||||
|
||||
**Why a lever and not a 25th dimension — decided by measurement, not taste.** A dimension is always
|
||||
evaluated, so "no agents at all" would have to read as *present*, and present weight feeds the
|
||||
utilization score. Measured on `tests/fixtures/marketplace-medium` (hermetic HOME) before the change:
|
||||
`utilization.score` 44, `segment` "Developing", where the "Competent" boundary is 45. As a t3
|
||||
dimension the denominators move 41→42 and the vacuous present pushes 18/41→19/42 = **45** — flipping
|
||||
`segment` in the frozen `v5.0.0/posture.json`, which `strip-retired-gap.mjs` does **not** mask (it
|
||||
drops only `utilization.score`/`overhang` and `feature_coverage.score`). A lever leaves every
|
||||
denominator alone and cannot move a score it never enters. The general rule now lives in CLAUDE.md
|
||||
(*GAP dimensions vs. levers*).
|
||||
|
||||
**One check across both axes, not one per axis.** It fires only when *neither* axis is used anywhere,
|
||||
so a deliberate everything-on-one-model policy stays silent. The cost is recall: a config that pins
|
||||
`model:` everywhere but never `effort:` gets no nudge. That is the v1 boundary, chosen for precision.
|
||||
|
||||
**`model: inherit` is not routing** — found by dogfooding, where installed agents write it out
|
||||
explicitly. `inherit` is the documented default, so spelling it out changes nothing about what the
|
||||
agent costs; counting it as a pin would let a config opt out of the opportunity without changing
|
||||
anything real. Effort has no documented sentinel of this kind, so it has no counterpart rule.
|
||||
|
||||
**Two silences that must not be conflated.** "No authored agents" (owned by dimension `t2_6`,
|
||||
*No custom subagents*) and "the only agents on disk are plugin-bundled" produce the same quiet
|
||||
output for different reasons. `tests/scanners/gap-agent-model-routing.test.mjs` P5 pins the second
|
||||
one specifically — it asserts the agent file *was* discovered before asserting silence, so the arm
|
||||
cannot pass for P4's reason.
|
||||
|
||||
**Humanizer coverage is now a blanket invariant.** The old guard asserted `TRANSLATIONS.GAP.static`
|
||||
keys *equal* `GAP_CHECKS` titles, which forbade humanizing any lever — so all three existing levers
|
||||
fell through to the generic GAP `_default` ("You have a feature opportunity worth a look"), wrong for
|
||||
a budget lever. The guard now requires a static entry for **every title GAP can emit** (dimensions ∪
|
||||
levers), and it was seen red against those three before the four entries were written. `TITLE_TO_ID`
|
||||
keeps strict equality with `GAP_CHECKS`: levers are not dimensions and must stay out of scoring.
|
||||
|
||||
### cache-prefix-scanner — @import extension (v5.10 B6)
|
||||
|
||||
CPS originally scanned only the files discovery classifies as `claude-md`. But a CLAUDE.md can pull
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue