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
309 lines
12 KiB
JavaScript
309 lines
12 KiB
JavaScript
import { describe, it } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
loadRegister,
|
|
validateRegister,
|
|
getEntry,
|
|
CONFIDENCE_LEVELS,
|
|
REGISTER_PATH,
|
|
} from '../../scanners/lib/best-practices-register.mjs';
|
|
import { LENS_DETECTORS } from '../../scanners/lib/lens-prefilter.mjs';
|
|
import { SUBTRACT_DETECTORS } from '../../scanners/lib/subtraction-prefilter.mjs';
|
|
|
|
// A minimal well-formed entry; negative tests clone + mutate this.
|
|
const validEntry = () => ({
|
|
id: 'BP-TEST-001',
|
|
claim: 'A representative best-practice claim.',
|
|
confidence: 'confirmed',
|
|
source: { url: 'https://example.com/doc', title: 'Doc', verified: '2026-06-20' },
|
|
});
|
|
|
|
const wrap = (entries) => ({ version: 1, entries });
|
|
|
|
describe('CONFIDENCE_LEVELS', () => {
|
|
it('has the three documented levels', () => {
|
|
assert.deepStrictEqual([...CONFIDENCE_LEVELS].sort(), ['confirmed', 'inferred', 'unverified']);
|
|
});
|
|
it('is frozen', () => {
|
|
assert.throws(() => { CONFIDENCE_LEVELS.push('x'); }, TypeError);
|
|
});
|
|
});
|
|
|
|
describe('loadRegister (bundled register)', () => {
|
|
it('loads the bundled register file', () => {
|
|
const reg = loadRegister();
|
|
assert.equal(typeof reg, 'object');
|
|
assert.equal(reg.version, 1);
|
|
assert.ok(Array.isArray(reg.entries));
|
|
assert.ok(reg.entries.length > 0, 'register should ship with seed entries');
|
|
});
|
|
|
|
it('REGISTER_PATH points at knowledge/best-practices.json', () => {
|
|
assert.match(String(REGISTER_PATH), /knowledge\/best-practices\.json$/);
|
|
});
|
|
});
|
|
|
|
describe('bundled register integrity (Verifiseringsplikt)', () => {
|
|
const reg = loadRegister();
|
|
|
|
it('passes schema validation with zero errors', () => {
|
|
const result = validateRegister(reg);
|
|
assert.deepStrictEqual(result.errors, []);
|
|
assert.equal(result.valid, true);
|
|
});
|
|
|
|
it('has unique ids', () => {
|
|
const ids = reg.entries.map((e) => e.id);
|
|
assert.equal(new Set(ids).size, ids.length);
|
|
});
|
|
|
|
it('uses the BP-TOPIC-NNN id convention', () => {
|
|
for (const e of reg.entries) {
|
|
assert.match(e.id, /^BP-[A-Z]+-\d{3}$/, `bad id: ${e.id}`);
|
|
}
|
|
});
|
|
|
|
it('seeds only CONFIRMED claims (no unverified assertion enters the consumed register)', () => {
|
|
for (const e of reg.entries) {
|
|
assert.equal(e.confidence, 'confirmed', `${e.id} must be confirmed in the seed`);
|
|
}
|
|
});
|
|
|
|
it('every entry carries a source url + verified date', () => {
|
|
for (const e of reg.entries) {
|
|
assert.ok(e.source && e.source.url, `${e.id} missing source.url`);
|
|
assert.match(e.source.verified, /^\d{4}-\d{2}-\d{2}$/, `${e.id} bad verified date`);
|
|
}
|
|
});
|
|
|
|
// A corroborating source without a published date is a SILENT hole: newestEvidenceMs()
|
|
// returns null for the entry and the evidence-age rule cannot judge evidence it cannot
|
|
// date, so the entry stays green on evidence of any age. Assert the blanket invariant,
|
|
// not the entries that happen to have one today.
|
|
it('every corroborating source carries a published date (evidence-age rule has teeth)', () => {
|
|
for (const e of reg.entries) {
|
|
if (!Array.isArray(e.sources)) continue;
|
|
e.sources.forEach((s, i) => {
|
|
assert.match(
|
|
String(s && s.published),
|
|
/^\d{4}-\d{2}-\d{2}$/,
|
|
`${e.id} sources[${i}] (${s && s.url}) missing a parseable published date`
|
|
);
|
|
});
|
|
}
|
|
});
|
|
|
|
it('carries the model-routing entries (C1), each dated by a published source', () => {
|
|
for (const id of ['BP-MODEL-001', 'BP-MODEL-002']) {
|
|
const e = getEntry(reg, id);
|
|
assert.ok(e, `${id} missing from the bundled register`);
|
|
assert.equal(e.confidence, 'confirmed', `${id} must be confirmed`);
|
|
assert.equal(e.category, 'model-fit', `${id} wrong category`);
|
|
assert.ok(
|
|
e.source.url.startsWith('https://code.claude.com/docs/'),
|
|
`${id} primary source must be the official docs, got ${e.source.url}`
|
|
);
|
|
assert.ok(
|
|
Array.isArray(e.sources) && e.sources.some((s) => s.published),
|
|
`${id} must carry a corroborating source with a published date (B1 evidence-age rule)`
|
|
);
|
|
}
|
|
});
|
|
|
|
// B2. The judgment entry is knowledge WITHOUT a detector, and that is the
|
|
// measured outcome, not an omission: the caging class the article names fired
|
|
// 7 times across 409 real CLAUDE.md files and all 7 were false positives
|
|
// (docs/b2-judgment-lens-fasit.local.md §9.4). Asserting the absent lensCheck
|
|
// is what stops a later session from "completing" the entry by wiring a
|
|
// detector the corpus refused.
|
|
it('carries the judgment entry (B2) as detector-less knowledge', () => {
|
|
const e = getEntry(reg, 'BP-JUDG-001');
|
|
assert.ok(e, 'BP-JUDG-001 missing from the bundled register');
|
|
assert.equal(e.confidence, 'confirmed', 'BP-JUDG-001 must be confirmed');
|
|
assert.equal(e.category, 'judgment-fit', 'BP-JUDG-001 wrong category');
|
|
assert.equal(
|
|
e.lensCheck ?? null,
|
|
null,
|
|
'BP-JUDG-001 must NOT name a lensCheck — no detector survived measurement'
|
|
);
|
|
assert.equal(
|
|
e.source.url,
|
|
'https://claude.com/blog/the-new-rules-of-context-engineering-for-claude-5-generation-models',
|
|
'BP-JUDG-001 primary source must be the article that states rule 1'
|
|
);
|
|
assert.equal(e.source.published, '2026-07-24', 'BP-JUDG-001 must date its primary source');
|
|
assert.match(
|
|
String(e.note),
|
|
/409/,
|
|
'BP-JUDG-001 must carry the measured negative result, so it is not re-derived'
|
|
);
|
|
});
|
|
|
|
// The model-scoped prompting entry is an ANNOTATION on an existing BP-SUB-001
|
|
// candidate, not a detector of its own — same discipline as BP-JUDG-001 above,
|
|
// and asserted for the same reason: without this, a later session "completes"
|
|
// the entry by wiring a second SUBTRACT_DETECTORS entry, which would both
|
|
// widen the candidate set and collide with BP-SUB-001 on de-dup.
|
|
//
|
|
// `modelScope` is pinned because it is a DATA CONTRACT, not a label:
|
|
// `matchModelScope` looks the requested `--for-model` name up in exactly this
|
|
// array. Renaming or dropping it makes every lookup silently return null —
|
|
// the CLI would report `recognized: false` for a model the register still
|
|
// claims to cover, which is a quiet wrong answer, not a loud failure.
|
|
it('carries the model-scoped prompting entry (BP-PROMPT-001) as an annotation, not a detector', () => {
|
|
const e = getEntry(reg, 'BP-PROMPT-001');
|
|
assert.ok(e, 'BP-PROMPT-001 missing from the bundled register');
|
|
assert.equal(e.confidence, 'confirmed', 'BP-PROMPT-001 must be confirmed');
|
|
assert.equal(e.category, 'prompting-fit', 'BP-PROMPT-001 wrong category');
|
|
assert.equal(
|
|
e.mechanism,
|
|
'deletion',
|
|
'BP-PROMPT-001 rides the subtraction axis — an addition-shaped claim must not reuse this entry'
|
|
);
|
|
assert.equal(
|
|
e.lensCheck ?? null,
|
|
null,
|
|
'BP-PROMPT-001 must NOT name a lensCheck — it annotates BP-SUB-001 candidates, it does not detect'
|
|
);
|
|
assert.deepStrictEqual(
|
|
e.modelScope,
|
|
['opus-5'],
|
|
'BP-PROMPT-001 modelScope is the lookup key matchModelScope resolves --for-model against'
|
|
);
|
|
assert.equal(
|
|
e.source.url,
|
|
'https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-opus-5',
|
|
'BP-PROMPT-001 primary source must be the official Opus 5 prompting guide'
|
|
);
|
|
// The guide carries no visible publish/last-updated date (re-checked
|
|
// 2026-08-12). Asserting its ABSENCE keeps a later session from inventing
|
|
// one to satisfy a pattern the other entries happen to have.
|
|
assert.equal(
|
|
e.source.published,
|
|
undefined,
|
|
'BP-PROMPT-001 source has no visible published date — do not fabricate one'
|
|
);
|
|
assert.match(
|
|
String(e.note),
|
|
/--for-model/,
|
|
'BP-PROMPT-001 must record that it is gated behind an explicit flag'
|
|
);
|
|
// The corpus numbers live in the entry, not only in a gitignored fasit,
|
|
// for the same reason BP-JUDG-001's 409 does: a later session that cannot
|
|
// see the measurement re-derives it, and the cheapest re-derivation is to
|
|
// read the zero as a broken detector and loosen it. 31 is the load-bearing
|
|
// half — how many verb-only blocks the TARGET requirement rejected, i.e.
|
|
// the false positives a naive version of this check would have produced.
|
|
assert.match(
|
|
String(e.note),
|
|
/409/,
|
|
'BP-PROMPT-001 must carry the corpus size it was measured against'
|
|
);
|
|
assert.match(
|
|
String(e.note),
|
|
/(^|\s)31(\s|,)/,
|
|
'BP-PROMPT-001 must carry the count the target requirement rejected — the reason it is narrow'
|
|
);
|
|
});
|
|
|
|
// The register's own consumers key on lensCheck; an entry that names one it
|
|
// does not have would reach a payload with no detector behind it.
|
|
it('every lensCheck in the register is backed by a detector', () => {
|
|
const detectors = new Set([
|
|
...LENS_DETECTORS.map((d) => d.lensCheck),
|
|
...SUBTRACT_DETECTORS.map((d) => d.lensCheck),
|
|
// Scanner-side checks that are their own detector.
|
|
'procedure-in-claude-md',
|
|
'CA-OST-001',
|
|
'CA-CML-001',
|
|
'CA-SKL-002',
|
|
]);
|
|
for (const e of reg.entries) {
|
|
if (e.lensCheck == null) continue;
|
|
assert.ok(
|
|
detectors.has(e.lensCheck),
|
|
`${e.id} names lensCheck "${e.lensCheck}" with no detector behind it`
|
|
);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('validateRegister (negative cases)', () => {
|
|
it('accepts a minimal valid register', () => {
|
|
assert.equal(validateRegister(wrap([validEntry()])).valid, true);
|
|
});
|
|
|
|
it('rejects a non-object', () => {
|
|
assert.equal(validateRegister(null).valid, false);
|
|
assert.equal(validateRegister('nope').valid, false);
|
|
});
|
|
|
|
it('rejects a non-numeric version', () => {
|
|
const r = validateRegister({ version: 'one', entries: [validEntry()] });
|
|
assert.equal(r.valid, false);
|
|
assert.ok(r.errors.some((m) => /version/.test(m)));
|
|
});
|
|
|
|
it('rejects non-array entries', () => {
|
|
const r = validateRegister({ version: 1, entries: {} });
|
|
assert.equal(r.valid, false);
|
|
assert.ok(r.errors.some((m) => /entries/.test(m)));
|
|
});
|
|
|
|
it('rejects duplicate ids', () => {
|
|
const r = validateRegister(wrap([validEntry(), validEntry()]));
|
|
assert.equal(r.valid, false);
|
|
assert.ok(r.errors.some((m) => /duplicate/i.test(m)));
|
|
});
|
|
|
|
it('rejects a missing claim', () => {
|
|
const e = validEntry(); delete e.claim;
|
|
const r = validateRegister(wrap([e]));
|
|
assert.equal(r.valid, false);
|
|
assert.ok(r.errors.some((m) => /claim/.test(m)));
|
|
});
|
|
|
|
it('rejects an out-of-enum confidence', () => {
|
|
const e = validEntry(); e.confidence = 'maybe';
|
|
const r = validateRegister(wrap([e]));
|
|
assert.equal(r.valid, false);
|
|
assert.ok(r.errors.some((m) => /confidence/.test(m)));
|
|
});
|
|
|
|
it('rejects a malformed verified date', () => {
|
|
const e = validEntry(); e.source.verified = '20-06-2026';
|
|
const r = validateRegister(wrap([e]));
|
|
assert.equal(r.valid, false);
|
|
assert.ok(r.errors.some((m) => /verified|date/i.test(m)));
|
|
});
|
|
|
|
it('rejects a missing source url', () => {
|
|
const e = validEntry(); delete e.source.url;
|
|
const r = validateRegister(wrap([e]));
|
|
assert.equal(r.valid, false);
|
|
assert.ok(r.errors.some((m) => /source|url/i.test(m)));
|
|
});
|
|
|
|
it('rejects an out-of-enum severity when present', () => {
|
|
const e = validEntry(); e.severity = 'urgent';
|
|
const r = validateRegister(wrap([e]));
|
|
assert.equal(r.valid, false);
|
|
assert.ok(r.errors.some((m) => /severity/.test(m)));
|
|
});
|
|
|
|
it('accepts a valid optional severity', () => {
|
|
const e = validEntry(); e.severity = 'low';
|
|
assert.equal(validateRegister(wrap([e])).valid, true);
|
|
});
|
|
});
|
|
|
|
describe('getEntry', () => {
|
|
const reg = loadRegister();
|
|
it('returns the entry for a known id', () => {
|
|
const first = reg.entries[0];
|
|
assert.equal(getEntry(reg, first.id), first);
|
|
});
|
|
it('returns undefined for an unknown id', () => {
|
|
assert.equal(getEntry(reg, 'BP-NOPE-999'), undefined);
|
|
});
|
|
});
|