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>
This commit is contained in:
parent
685b770cb9
commit
55f83a3c99
6 changed files with 452 additions and 24 deletions
156
tests/lib/best-practices-register.test.mjs
Normal file
156
tests/lib/best-practices-register.test.mjs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
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';
|
||||
|
||||
// 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`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue