feat(optimize): add --subtract, the subtraction axis, behind a deterministic floor
Every command so far asked an addition question — what to add, what to move, what it costs. Nothing asked what is no longer earning its always-loaded rent. This adds that axis as a fourth lensCheck on the existing hybrid motor rather than a new scanner or a 22nd command: the measured payoff (~18% of one file) justifies a mode, not machinery. It is the only lens that proposes REMOVING config, so it carries a guarantee the others don't need: a load-bearing block is never a candidate. Precision is asymmetric — a missed dead line costs a few tokens per turn, a deleted one costs a wrong remote or a broken script — so the floor is decided in code (lib/floor-exclusion.mjs) before the opus judge sees anything, never in prose. Granularity is the leaf block, with two structural exceptions: a paragraph ending in ':' merges with the list it introduces, and an ordered list is a contract whose steps inherit floor from any sibling. Unordered lists deliberately do not inherit — a load-bearing bullet and a disposable one routinely share a list, and container-reasoning is the error the hand-built ground truth exists to catch. Verified against that ground truth (built before any classifier existed), with the comparison machine-checked rather than read by eye: zero load-bearing blocks proposed, 11/18 deletable groups surfaced, ~756 tok ~ 18% of a ~4300 token file — inside the pre-registered band. The first run found five floor violations the synthesized fixture missed; each got a structural rule and a fixture shape so it cannot regress. Three real bugs the dogfood run exposed, all now covered: - JS \b is ASCII-only, so /\bunngå\b/ never matches — every Norwegian keyword ending in æ/ø/å was silently dead. - A bare word/word is not a path; "pros/cons" vetoed the largest deletable block until PATH_RE was tightened to rooted paths and globs. - "Mid-sentence" must key on a preceding lowercase letter; the loose version read **bold labels:** and quoted openers as entities, costing 4 of 11 groups. BP-SUB-001 is grounded entirely in the Anthropic steering blog already cited by BP-MECH-001..004 and asserts nothing from the talk that motivated the feature — no "80%", no ablation figure. Suite 1365 -> 1382/0. Frozen v5.0.0 snapshots untouched; plain optimize output byte-identical on identical input (--subtract adds keys only when passed). knowledge-refresh-cli's reference date moved to 2026-08-01: its premise that every seed entry was verified 2026-06-20 expired when BP-SUB-001 got a genuine verification date, and backdating the entry to fit the test would have been a lie about when its source was checked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RW2haJXbxZpKivKHseSXNh
This commit is contained in:
parent
c0625c568f
commit
e9921d3c9d
13 changed files with 1080 additions and 32 deletions
26
README.md
26
README.md
|
|
@ -279,6 +279,7 @@ Your team configuration changes over time. Track it:
|
|||
| `/config-audit manifest` | Ranked table of every token source (CLAUDE.md, rules, agents, skills, output styles, MCP, hooks) sorted by estimated tokens — each tagged with its **load pattern** (always-loaded / on-demand / external) plus an **always-loaded subtotal** ("≈X tokens enter context every turn before you type"). Component-level: no coarse plugin roll-up (it would double-count) |
|
||||
| `/config-audit feature-gap` | Context-aware feature recommendations grouped by impact |
|
||||
| `/config-audit optimize` | Optimization lens (mechanism-fit): config that works but fits a better mechanism — procedure→skill, lifecycle→hook, unscoped path→rule, "never"→permission. Hybrid motor (deterministic pre-filter + opus precision gate), every finding cites a best-practices-register rule |
|
||||
| `/config-audit optimize --subtract` | **Subtraction lens** — the inverse question no other command asks: what no longer earns its always-loaded rent? Ranks CLAUDE.md blocks that correct general model *behaviour* rather than stating a local fact, split into **dead** (never missed) and **earned** (returns if the model stumbles), with the token payoff (`BP-SUB-001`). **Load-bearing local facts are excluded deterministically before the judge sees anything** — remotes, versions, paths, filenames, policy invariants and unresolvable entity names are never candidates, and an ordered list is treated as a contract. Opt-in, proposes only, never writes. Pair with `--global` to reach the user-level CLAUDE.md, where the always-loaded cost actually sits |
|
||||
| `/config-audit fix` | Auto-fix deterministic issues with backup + verification |
|
||||
| `/config-audit rollback` | Restore configuration from a previous backup |
|
||||
| `/config-audit plan` | Generate prioritized action plan from audit findings |
|
||||
|
|
@ -595,6 +596,31 @@ date, and a `confidence`. It is the source of truth for the optimization lens (O
|
|||
`scanners/lib/best-practices-register.mjs` (zero-dependency, native JSON). See
|
||||
`docs/v5.7-optimization-lens-plan.md`.
|
||||
|
||||
### The subtraction floor
|
||||
|
||||
`optimize --subtract` is the only lens that proposes *removing* configuration, so it carries a
|
||||
guarantee the others do not need: **a load-bearing block is never a candidate.** Precision here
|
||||
is asymmetric — a missed dead line costs a few tokens per turn, while a deleted load-bearing
|
||||
line costs a wrong remote or a broken script — so the floor is decided in code
|
||||
(`scanners/lib/floor-exclusion.mjs`), before the opus judge sees anything, rather than being
|
||||
left to prose judgement.
|
||||
|
||||
A block is floored when it carries an underivable local literal (inline code span, rooted path,
|
||||
domain, concrete filename, version pin), when it states a policy invariant (secrets,
|
||||
credentials, production, prompt-injection boundaries — floor *by decision*, not by
|
||||
classification), or when it names a capitalized entity the mechanism cannot resolve without a
|
||||
dictionary. That last rule is a deliberate conservative default: it declines to decide and
|
||||
keeps the block, paying in recall rather than risk.
|
||||
|
||||
Granularity is the **leaf block** — one list item including its wrapped continuation lines, or
|
||||
one paragraph — with two structural exceptions: a paragraph ending in `:` merges with the list
|
||||
it introduces, and an *ordered* list is treated as a contract whose steps inherit floor from
|
||||
any sibling. Unordered lists deliberately do not inherit, so a load-bearing bullet and a
|
||||
disposable one can coexist in the same list. Measured against a hand-built ground truth
|
||||
(35 blocks, 13 genuinely ambiguous): zero load-bearing blocks proposed, 11 of 18 deletable
|
||||
groups surfaced, ≈18 % of an always-loaded file. On a well-maintained config this axis is
|
||||
mostly a no-op — which is itself the finding.
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue