// tests/lib/claude-md-scope.test.mjs // Fix round 4.5b2 part B, Step 1 (tag CAT): the rule catalogue holds the two // CLAUDE.md keys at MINOR (decision 98), and every text that counts the keys // says 17. Each [CAT] case fails at 96fba75 on an assertion. import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { existsSync, readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { RULE_CATALOGUE, RULE_KEYS, getRule } from '../../lib/review/rule-catalogue.mjs'; const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..'); const read = (rel) => { const p = join(ROOT, rel); assert.ok(existsSync(p), `${rel} exists`); return readFileSync(p, 'utf-8'); }; test('[CAT] the catalogue holds CLAUDE_MD_DEVIATION and CLAUDE_MD_STALE at MINOR with memory_route null', () => { for (const key of ['CLAUDE_MD_DEVIATION', 'CLAUDE_MD_STALE']) { assert.ok(RULE_KEYS.has(key), `RULE_KEYS holds ${key}`); const rule = getRule(key); assert.ok(rule !== null, `getRule(${key}) finds the entry`); assert.equal(rule.severity, 'MINOR', `${key} is MINOR`); assert.equal(rule.category, 'conformance', `${key} is conformance`); assert.equal(rule.memory_route, null, `${key} is never proposed as project memory`); assert.ok(typeof rule.description === 'string' && rule.description.length > 0, `${key} has a description`); } assert.equal( getRule('CLAUDE_MD_DEVIATION').description, "A change that breaks a line of the target repo's tracked CLAUDE.md, AGENTS.md or .claude/rules file.", ); assert.equal( getRule('CLAUDE_MD_STALE').description, 'A change that makes a line of such an instruction file untrue.', ); }); test('[CAT] the catalogue has 17 keys and docs/architecture.md and both reviewer agents say 17-key', () => { assert.equal(RULE_CATALOGUE.length, 17); assert.equal(RULE_KEYS.size, 17); const header = read('lib/review/rule-catalogue.mjs').split('\n').slice(0, 10).join('\n'); assert.match(header, /\b17 rule keys\b/, 'the catalogue header counts 17 rule keys'); const arch = read('docs/architecture.md'); assert.match(arch, /rule catalogue \(17 keys\)/); assert.match(arch, /the 17-key rule catalogue/); assert.doesNotMatch(arch, /\b(12|15)-key rule catalogue|rule catalogue \((12|15) keys\)/); for (const agent of ['agents/code-correctness-reviewer.md', 'agents/brief-conformance-reviewer.md']) { const text = read(agent); assert.match(text, /the 17-key catalogue/, `${agent} says 17-key`); assert.doesNotMatch(text, /\b(12|15)-key catalogue/, `${agent} no longer says 12-key`); } }); test('[CAT] the armB RULE_TIERS table holds both keys at MINOR', () => { const src = read('scripts/trekreview-armB.workflow.mjs'); const start = src.indexOf('const RULE_TIERS = {'); assert.ok(start !== -1, 'the script carries a RULE_TIERS literal block'); const block = src.slice(start, src.indexOf('};', start)); const tiers = Object.fromEntries([...block.matchAll(/([A-Z_]+):\s*'([A-Z]+)'/g)].map((m) => [m[1], m[2]])); assert.equal(tiers.CLAUDE_MD_DEVIATION, 'MINOR'); assert.equal(tiers.CLAUDE_MD_STALE, 'MINOR'); assert.equal(Object.keys(tiers).length, 17); });