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
|
|
@ -30,7 +30,7 @@ Per-command flags, patterns, and feature lists live in `README.md` and `/config-
|
|||
|---------|-------------|
|
||||
| `/config-audit drift` | Compare current config against saved baseline |
|
||||
| `/config-audit plugin-health` | Audit plugin structure, frontmatter, cross-plugin coherence |
|
||||
| `/config-audit whats-active` | Read-only inventory of active plugins/skills/MCP/hooks/CLAUDE.md (with token estimates) |
|
||||
| `/config-audit whats-active` | Read-only inventory of active plugins/skills/agents/MCP/hooks/CLAUDE.md (with token estimates, and `model`/`effort` per agent) |
|
||||
| `/config-audit knowledge-refresh` | Refresh the best-practices register (stale check + web poll). Human-approved writes; **not byte-stable** |
|
||||
| `/config-audit campaign` | Machine-wide audit ledger + token bill across repos. Human-approved writes; **not byte-stable** |
|
||||
| `/config-audit discover` | Run discovery phase only |
|
||||
|
|
@ -79,6 +79,8 @@ Workflow: `/config-audit → discover + analyze (auto) → plan → implement
|
|||
|
||||
Finding ID format: `CA-{SCANNER}-{NNN}` — e.g. `CA-CML-001`, `CA-SET-003`, `CA-HKV-002`, `CA-RUL-005`, `CA-TOK-005`, `CA-CPS-001`, `CA-SKL-001`, `CA-OST-001`, `CA-OPT-001`, `CA-AGT-001`.
|
||||
|
||||
**GAP dimensions vs. levers (invariant).** `GAP_CHECKS` holds the 24 *dimensions* — always evaluated, always counted in the utilization denominators (`TIER_COUNTS` / `TOTAL_DIMENSIONS` in `scoring.mjs`, and `TITLE_TO_ID` there). A *lever* is a finding the scanner emits after the loop and only under a measured condition; it carries no tier, never enters those denominators, and is registered in the exported `LEVERS` object (code + title in one place, because the finding-code guard needs the code and the humanizer-coverage guard needs the title). Adding a dimension moves every user's utilization score and can flip the reported `segment` in a frozen baseline — adding a lever cannot. When a check is only meaningful for configs that already have some feature, it is a lever.
|
||||
|
||||
**`{NNN}` names the CHECK, never the emission position (invariant).** `scanners/lib/finding-codes.mjs` is the single authority: every `finding()` call passes a `code`, and an undeclared or missing one **throws** — there is no counter fallback, because a fallback lets a half-converted scanner ship IDs that look valid. Adding a check takes the next free number for that scanner, never the next source-order position; removing one moves its key to `RETIRED_CODES` and its number is never reissued. IDs are therefore **not unique per finding** — one check failing in three files emits three findings sharing an ID, and `(id, file, line)` is the instance key that `fix-engine` verification uses. Frozen `v5.0.0` baselines mask IDs (`tests/helpers/mask-finding-ids.mjs`) instead of re-deriving them; the check→number pairs are pinned exhaustively in `tests/lib/finding-codes.test.mjs`.
|
||||
|
||||
## Conventions
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue