/** * Wave 5 Step 14 — Group B command-template shape tests. * * Verifies that the 6 audit/analysis command templates in Group B have the * correct structural shape after the humanizer integration: * * - All 6 files: contain a Bash invocation block, reference the Read tool, * and contain the `--raw` flag (or the literal `"$ARGUMENTS"` string). * * - Findings-rendering files (drift.md, plugin-health.md, config-audit.md, * discover.md, analyze.md): reference at least one of * `userImpactCategory|userActionLanguage|relevanceContext`, and do NOT * contain hardcoded grade-prose tables of the form `[ABCDF]\s+grade\s+is`. * * - status.md: phase-label table is present, the machine field name * `current_phase` is preserved (machine contract), and at least one * humanized phase label appears ("Looking at your config files", * "Working out what to recommend", "Putting together your action plan", * "Making the changes", "Double-checking everything worked"). * * - Anchor must-contains from plan line 575–579: * - config-audit.md: contains userImpactCategory|userActionLanguage * - drift.md: contains --raw OR humanized */ import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { readFile } from 'node:fs/promises'; import { resolve, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const COMMANDS_DIR = resolve(__dirname, '..', '..', 'commands'); const GROUP_B_FILES = [ 'drift.md', 'plugin-health.md', 'config-audit.md', 'discover.md', 'analyze.md', 'status.md', ]; const FINDINGS_RENDERING_FILES = [ 'drift.md', 'plugin-health.md', 'config-audit.md', 'discover.md', 'analyze.md', ]; const HUMANIZED_FIELD_REGEX = /userImpactCategory|userActionLanguage|relevanceContext/; const RAW_OR_ARGUMENTS_REGEX = /--raw|"\$ARGUMENTS"/; const HARDCODED_GRADE_PROSE_REGEX = /[ABCDF]\s+grade\s+is/; const BASH_BLOCK_REGEX = /```bash\b/; const READ_TOOL_REGEX = /\bRead\s+tool\b|allowed-tools:.*\bRead\b/; const HUMANIZED_PHASE_LABELS = [ 'Looking at your config files', 'Working out what to recommend', 'Asking what you', 'Putting together your action plan', 'Making the changes', 'Double-checking everything worked', ]; async function readCommand(name) { return await readFile(resolve(COMMANDS_DIR, name), 'utf-8'); } test('Group B: every file contains a Bash invocation block', async () => { for (const name of GROUP_B_FILES) { const content = await readCommand(name); assert.match(content, BASH_BLOCK_REGEX, `${name} missing bash block`); } }); test('Group B: every file references the Read tool', async () => { for (const name of GROUP_B_FILES) { const content = await readCommand(name); assert.match(content, READ_TOOL_REGEX, `${name} missing Read tool reference`); } }); test('Group B: every file contains --raw or "$ARGUMENTS" (pass-through plumbing)', async () => { for (const name of GROUP_B_FILES) { const content = await readCommand(name); assert.match(content, RAW_OR_ARGUMENTS_REGEX, `${name} missing --raw / $ARGUMENTS plumbing`); } }); test('Group B findings-renderers: reference at least one humanized field', async () => { for (const name of FINDINGS_RENDERING_FILES) { const content = await readCommand(name); assert.match( content, HUMANIZED_FIELD_REGEX, `${name} must reference userImpactCategory, userActionLanguage, or relevanceContext`, ); } }); test('Group B findings-renderers: no hardcoded grade-prose tables', async () => { for (const name of FINDINGS_RENDERING_FILES) { const content = await readCommand(name); assert.doesNotMatch( content, HARDCODED_GRADE_PROSE_REGEX, `${name} contains a hardcoded "[grade] grade is..." prose table — humanizer owns grade vocabulary now`, ); } }); test('Group B anchor: config-audit.md references userImpactCategory|userActionLanguage', async () => { const content = await readCommand('config-audit.md'); assert.match(content, /userImpactCategory|userActionLanguage/); }); test('Group B anchor: drift.md references --raw or humanized', async () => { const content = await readCommand('drift.md'); assert.match(content, /--raw|humanized/); }); test('status.md: preserves current_phase machine field and adds humanized phase labels', async () => { const content = await readCommand('status.md'); // Machine contract preserved assert.match(content, /\bcurrent_phase\b/, 'status.md must keep current_phase as machine field'); // At least 3 of the 6 humanized phase labels appear const present = HUMANIZED_PHASE_LABELS.filter(label => content.includes(label)); assert.ok( present.length >= 3, `status.md must include at least 3 humanized phase labels; found ${present.length}: ${present.join(', ')}`, ); });