feat(humanizer): update audit/analysis command templates group B [skip-docs]

Wave 5 Step 14. Threads the humanizer vocabulary through the remaining
six audit/analysis command templates and adds a shape test that locks
the structure plus a pair of anchor must-contains.

- commands/drift.md: --raw pass-through; new/resolved/changed-finding
  rendering instructions reference userActionLanguage and
  relevanceContext rather than raw severity.
- commands/plugin-health.md: --raw pass-through; finding rendering
  groups by userImpactCategory and leads with userActionLanguage.
- commands/config-audit.md (router): replaces the 25-line A/B/C/D/F
  prose ladder with a humanized stderr-scorecard reference + three
  userActionLanguage-grouped "What you can do next" branches; --raw
  threaded through both scan-orchestrator and posture invocations.
- commands/discover.md: --raw pass-through; finding-summary rendering
  groups by userImpactCategory.
- commands/analyze.md: --raw pass-through; analyzer-agent prompt now
  instructs grouping by userImpactCategory and leading with
  userActionLanguage; humanized title/description/recommendation
  strings rendered verbatim, no paraphrasing.
- commands/status.md: phase-label humanization table — current_phase
  machine field name preserved, user-facing labels translated
  ("Looking at your config files", "Working out what to recommend",
  "Asking what you'd like to focus on", "Putting together your action
  plan", "Making the changes", "Double-checking everything worked");
  --raw preserves verbatim machine field values.

tests/commands/group-b-shape.test.mjs (new, +8 tests, 772 → 780):
  - structural: bash block + Read tool + --raw/$ARGUMENTS plumbing
    across all 6 files
  - findings-renderers: humanized field reference + no grade-prose
  - anchor must-contains per plan: config-audit.md ⊇
    userImpactCategory|userActionLanguage; drift.md ⊇ --raw|humanized
  - status.md: current_phase preserved + ≥3 humanized phase labels
This commit is contained in:
Kjell Tore Guttormsen 2026-05-01 19:45:55 +02:00
commit 6f38a6340e
7 changed files with 234 additions and 49 deletions

View file

@ -0,0 +1,134 @@
/**
* 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 575579:
* - 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(', ')}`,
);
});