Commit graph

6 commits

Author SHA1 Message Date
7df8e0d65b feat(scanners): a redundancy claim that belongs to one model is scoped to it
Anthropic documents that Claude Opus 5 verifies its own work, and that telling
it to double-check or to delegate verification to a subagent causes
over-verification -- token cost with no quality gain. The general subtraction
detector (BP-SUB-001) already surfaces those blocks for every user, with no
model-awareness at all.

`optimize --subtract --for-model <name>` adds the missing half. It ANNOTATES a
subset of the candidates --subtract already produced; it is not a second
detector and can never widen the candidate set. A second SUBTRACT_DETECTORS
entry would have collided with BP-SUB-001 on de-dup, and a prose-only signal in
the agent prompt would have been untestable.

There is no auto-detection, by measurement rather than omission: a CLAUDE.md has
no frontmatter and no resolvable target model, and this operator's own `route`
skill deliberately runs a different model per session -- the same file is read
by whichever model comes next. So the model is named, and the citation is
reported as conditional everywhere a human sees it (agent report copy, and the
Step 7a listing that is the last surface before an approval file).

Precision comes from the TARGET, not the verb list. Measured across the
409-file corpus: 392 BP-SUB-001 candidates, 31 (7.9%) carry a verify verb, and
0 also carry a reflexive or delegated target. Two independent raw-text greps
found 0 as well, so the zero is the corpus rather than an over-narrow regex.
Those 31 verb-only blocks -- "sjekk relevante config-filer", "Type-sjekk:
pyright", "To verify plugin functionality" -- are exactly the false positives a
verb-only version would have produced, which is BP-JUDG-001's 7/7 failure
arriving one lens over. The numbers live in the register entry's note and are
pinned by a test, because a session that cannot see the measurement reads the
zero as a broken detector and loosens it.

`recognized` is reported separately from `matchedCount`: a typo'd model name and
a genuinely clean config both yield zero, and without the distinction the CLI
would report a silent no-op as good news. Dogfooded on the real machine --
`opus-5` gives recognized:true/matchedCount:0, `oppus5` gives recognized:false.

source.published is absent because the guide carries no visible publish date;
its absence is asserted so a later session does not invent one to match the
other entries' shape. Both quoted sentences were verified verbatim 2026-08-12.

The payload stays additive -- forModel and per-candidate modelScope appear only
under the flag, so a plain --subtract run is byte-identical to before (asserted
on the serialized bytes, since a key set to undefined passes a shallow check).

Suite 1724 -> 1752 (+28). The one remaining failure is the pre-existing
drift-cli --output-file crash, untouched by this work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BRuXt6tZyowi8QYNKLSHQm
2026-08-12 23:16:23 +02:00
6bb100f2e0 docs(knowledge): the judgment axis is knowledge, not a detector (B2)
Article rule 1 ("give Claude judgement instead of rules") gets its register
entry, and deliberately no detector. `BP-JUDG-001` carries `lensCheck: null`.

The cut between deterministic prefilter and prose judge was the open design
decision. It was settled by measurement, and the measurement declined both
halves:

- 409 real CLAUDE.md files (38488 lines, 8689 prose blocks): the caging class
  fires 7 times, and all 7 are false positives ("rendered prose-side",
  "naming is a flag on the class"). Verified along an independent grep path
  that bypasses block-splitting and sentence-splitting entirely, in both word
  orders: 5 lines and 1 line, none an instruction.
- The narrow variant (absolute + form noun + numeric cap) fired 8 times —
  one duplicated block seen seven times across plugin caches, precision 0 %.
  The pre-committed rule required 90 % over 20 distinct fires.
- Where the shape does occur — 45 lines across 4755 skill/agent/command files
  — it is the author's editorial policy (emoji, sentence length, slide
  titles). Nothing in the text separates that from a vendor's over-tight
  guardrail, and the article's reasoning does not transfer: the model is not
  the author of a user's config.

So no CA-OPT-002; finding-codes keeps OPT next-free = 2. The numbers live in
the entry's own `note`, so the next session does not re-derive the question.

Two premises the chunk falsified. The brief justified a separate axis by
saying these blocks sit inside `floor-exclusion`'s floor — but the article's
own canonical line carries no floor marker at all, so "inside the floor"
cannot define the axis (the corpus tendency is 76 %, which is a tendency, not
a mechanism). And the fasit's own form-noun vocabulary was wrong: `name` and
`format` alone drove 97 % of fires.

Not folded into `--subtract`: a third "loosen instead of delete" verdict in
the subtraction judge is the AS#5 mixing STATE forbids, and with the corrected
vocabulary there are 0 collisions to arbitrate anyway.

Guards, both seen red against their own defect first: the entry must exist,
be confirmed, date its source and name NO lensCheck; and every lensCheck in
the register must be backed by a real detector.

No behaviour changed — no new finding, no output change, nothing consumes the
entry yet — hence `docs`, not `feat`. Suite 1701 -> 1703/0; frozen v5.0.0 and
default-output baselines 0 changed files. Fasit:
docs/b2-judgment-lens-fasit.local.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017mCkx9wGywqNQzsXkBMzJ1
2026-08-12 20:31:22 +02:00
e861e63a7b feat(knowledge): model + effort routing enter the register, dated [skip-docs]
C1: two entries the optimization lens can cite for the model/effort axis,
both read out of the primary sources in this session rather than from the
plan's 2026-07-14 summary of them.

Verifying corrected the plan's own numbers: effort is settable in SIX
places, not five (/effort, the /model slider, --effort,
CLAUDE_CODE_EFFORT_LEVEL, settings effortLevel, skill/subagent
frontmatter), the default is high on every supporting model EXCEPT Opus
4.7 (xhigh), and the level count is model-dependent (Opus 4.6 and Sonnet
4.6 have no xhigh).

- BP-MODEL-001: subagent `model` defaults to `inherit`, so a subagent
  that names no model costs what the session costs; the documented pin
  is overridable by CLAUDE_CODE_SUBAGENT_MODEL and per-invocation model
- BP-MODEL-002: effort is an axis separate from model choice, and higher
  is not universally better (`max` "may show diminishing returns and is
  prone to overthinking")
- both carry the 2026-07-07 model/effort blog as a corroborating source
  with a real `published` date, so B1's evidence-age rule has teeth:
  measured stale with reasons ['evidence-age'] at a reference date 378
  days past publication while their verified stamps are pristine. The
  docs pages themselves get NO published date — they carry none, and
  guessing one in the field whose whole job is dating evidence is the
  lie the rule exists to catch
- new blanket guard: every corroborating source must carry a parseable
  published date. Without it newestEvidenceMs() returns null and the
  entry stays green on evidence of any age — a silent hole. Seen red
  against its own defect before it was trusted
- knowledge-refresh-cli's stale branch no longer expires on every new
  entry: its reference date has to sit after every `verified` stamp, was
  bumped once for BP-SUB-001 and would have needed a third bump now, so
  it moves to a date no stamp can reach

Register 14 -> 16 entries. Frozen v5.0.0 snapshots untouched (no scanner
output changes); suite 1579/0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NKjojcdYYiCQP5AudUyQ5e
2026-08-10 04:36:09 +02:00
d66035ed86 fix(knowledge): freshness can no longer be green on outdated evidence
assessFreshness aged only the entry's own source.verified stamp, so an
entry re-verified against an old source stayed green while a newer source
sat unnoticed (BP-SUB-001 was stamped 2026-07-31, a week after the
superseding-grade article of 2026-07-24 was published). The stamp
certifies the old source; it says nothing about the evidence.

- entries may carry corroborating sources[] with published dates
- new evidence-age rule: stale when the NEWEST published date across all
  sources exceeds evidenceStaleAfterDays (default 365); re-verifying the
  old source never clears it, only newer evidence does
- source.supersededBy marks a replaced source: stale regardless of stamp
- stale items now carry reasons[] (verified-age / no-verified-date /
  superseded / evidence-age)
- BP-SUB-001 gains the 2026-07-24 context-engineering article as a
  verified corroborating source (near-verbatim coverage). NOT added to
  BP-MECH-*/BP-SIZE-001: own verification found no mechanism-choice or
  size-limit content in the article, contrary to the brief's assumption.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NeaMRXVGzh9oSwigJDjE9
2026-08-03 11:36:57 +02:00
e9921d3c9d 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
2026-07-31 16:24:51 +02:00
55f83a3c99 feat(knowledge): best-practices register foundation — v5.7 Fase 1 Chunk 1
Add knowledge/best-practices.json: a machine-readable, provenance-stamped, schema-validated best-practices register — the source of truth for the upcoming v5.7 optimization lens (CA-OPT). 13 seed entries migrated from the v5.5 V-rows (loading-model + compaction facts) and the Anthropic 'Steering Claude Code' blog (mechanism-fit rules); each entry carries source.url + verified date + confidence. Only confirmed claims are user-facing (Verifiseringsplikt).

scanners/lib/best-practices-register.mjs: zero-dependency loader + validator (loadRegister/validateRegister/getEntry, native JSON.parse — not YAML, since the repo is zero-dep and yaml-parser.mjs can't parse arrays-of-objects). tests/lib/best-practices-register.test.mjs: 22 tests (schema, provenance integrity, negative cases, lookup).

Byte-stable: no scanner consumes the register yet (Chunk 2), so all scanner output is unchanged. Suite 1023->1045, self-audit A/A, readmeCheck passed. Full design: docs/v5.7-optimization-lens-plan.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 22:37:47 +02:00