import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { RULE_CATALOGUE, RULE_KEYS, SEVERITY_VALUES, CATEGORY_VALUES, getRule, MEMORY_ROUTES, } from '../../lib/review/rule-catalogue.mjs'; test('RULE_CATALOGUE — every entry has all 4 required fields', () => { for (const entry of RULE_CATALOGUE) { assert.ok(typeof entry.rule_key === 'string' && entry.rule_key.length > 0, `bad rule_key: ${entry.rule_key}`); assert.ok(typeof entry.severity === 'string' && entry.severity.length > 0, `bad severity: ${entry.severity}`); assert.ok(typeof entry.category === 'string' && entry.category.length > 0, `bad category: ${entry.category}`); assert.ok(typeof entry.description === 'string' && entry.description.length > 0, `bad description for ${entry.rule_key}`); } }); test('RULE_CATALOGUE — no duplicate rule_key', () => { const seen = new Set(); for (const entry of RULE_CATALOGUE) { assert.ok(!seen.has(entry.rule_key), `duplicate rule_key: ${entry.rule_key}`); seen.add(entry.rule_key); } assert.equal(seen.size, RULE_CATALOGUE.length); }); test('RULE_CATALOGUE — all severity values within enum', () => { for (const entry of RULE_CATALOGUE) { assert.ok(SEVERITY_VALUES.includes(entry.severity), `${entry.rule_key} has invalid severity: ${entry.severity}`); } }); test('RULE_CATALOGUE — all category values within enum', () => { for (const entry of RULE_CATALOGUE) { assert.ok(CATEGORY_VALUES.includes(entry.category), `${entry.rule_key} has invalid category: ${entry.category}`); } }); test('RULE_KEYS.size === RULE_CATALOGUE.length (== 15) — pinned by doc-consistency', () => { assert.equal(RULE_KEYS.size, RULE_CATALOGUE.length); assert.equal(RULE_CATALOGUE.length, 15); }); test('RULE_CATALOGUE — the two Claude Code engine keys exist at their tiers (ordre 5)', () => { assert.equal(getRule('CODE_REVIEW_DEFECT')?.severity, 'MAJOR'); assert.equal(getRule('CODE_REVIEW_IMPROVEMENT')?.severity, 'MINOR'); assert.equal(getRule('SECURITY_REVIEW_VULNERABILITY')?.severity, 'BLOCKER'); }); test('RULE_CATALOGUE — every entry declares a memory_route (check | rule | null)', () => { for (const entry of RULE_CATALOGUE) { assert.ok('memory_route' in entry, `${entry.rule_key} has no memory_route`); assert.ok(entry.memory_route === null || MEMORY_ROUTES.includes(entry.memory_route), `${entry.rule_key} has invalid memory_route: ${entry.memory_route}`); } assert.equal(getRule('MISSING_BRIEF_REF').memory_route, null, 'review hygiene is never project memory'); assert.equal(getRule('COVERAGE_SILENT_SKIP').memory_route, null, 'review hygiene is never project memory'); }); test('getRule — returns frozen entry on hit, null on miss, null on bad input', () => { const hit = getRule('UNIMPLEMENTED_CRITERION'); assert.ok(hit !== null); assert.equal(hit.severity, 'BLOCKER'); assert.throws(() => { hit.severity = 'MINOR'; }); // frozen assert.equal(getRule('NOPE'), null); assert.equal(getRule(undefined), null); assert.equal(getRule(123), null); });