ktg-plugin-marketplace/plugins/config-audit/tests/commands/group-b-shape.test.mjs
Kjell Tore Guttormsen 6f38a6340e 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
2026-05-01 19:45:55 +02:00

134 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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(', ')}`,
);
});