ktg-plugin-marketplace/plugins/config-audit/tests/agents/agent-prompt-shape.test.mjs
Kjell Tore Guttormsen ec4ac3e6d1 feat(humanizer): update agent system prompts [skip-docs]
Wave 5 Step 16 — final wave step. Threads humanizer-aware rendering
rules through the three agent prompts that produce user-facing output,
and adds a shape test that locks the structure.

- agents/analyzer-agent.md: documents the humanizer envelope shape
  (userImpactCategory, userActionLanguage, relevanceContext) in the
  Input section; new "Humanizer-aware rendering rules" subsection
  instructs the agent to: render humanized title/description/
  recommendation verbatim, group findings by userImpactCategory, lead
  each line with userActionLanguage, surface relevanceContext when
  not affects-everyone, and skip jargon-translation subroutines.
  --raw fallback documented (v5.0.0 verbatim severity prefiks).
- agents/planner-agent.md: documents the same vocabulary; instructs
  the planner to consume humanized fields from the analysis report,
  preserve titles verbatim, and order actions by both dependencies
  AND userActionLanguage urgency. Translation duties explicitly
  removed from the plan.
- agents/feature-gap-agent.md: replaces the inline t1/t2/t3/t4
  tier-to-prose section ladder with userActionLanguage-driven
  groupings ("Fix soon" → High Impact, "Fix when convenient" →
  Worth Considering, "Optional cleanup"/"FYI" → Explore When Ready);
  instructs skipping findings whose relevanceContext is
  test-fixture-no-impact; --raw fallback documented.

tests/agents/agent-prompt-shape.test.mjs (new, +6 tests, 786 → 792):
  - structural: humanized field reference + frontmatter preserved
  - per-agent anchors: analyzer groups by userImpactCategory; planner
    orders by userActionLanguage; feature-gap references
    test-fixture-no-impact
  - global: no "explain what {jargon} means" / "translate jargon" /
    "jargon-translation duty" prose anywhere

Self-audit: Grade A unchanged (config 97/100, plugin 100/100).
2026-05-01 19:53:59 +02:00

82 lines
3.1 KiB
JavaScript

/**
* Wave 5 Step 16 — Agent system-prompt shape tests.
*
* Verifies that the 3 agent prompt files have the correct structural shape
* after the humanizer integration:
*
* - Each file references at least one of the humanized field names by
* name: `userImpactCategory`, `userActionLanguage`, `relevanceContext`.
*
* - Each file does NOT contain a "explain what X means" subroutine —
* those translation duties are owned by the humanizer now.
*
* - Each file preserves its required frontmatter (name, description,
* model, color, tools).
*/
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 AGENTS_DIR = resolve(__dirname, '..', '..', 'agents');
const AGENT_FILES = [
'analyzer-agent.md',
'planner-agent.md',
'feature-gap-agent.md',
];
const HUMANIZED_FIELD_REGEX = /userImpactCategory|userActionLanguage|relevanceContext/;
const JARGON_TRANSLATION_INSTRUCTION_REGEX = /explain\s+what\s+\{[^}]+\}\s+means|translate\s+jargon|jargon[- ]translation\s+duty/i;
const FRONTMATTER_REGEX = /^---\s*\nname:\s+\S+/m;
async function readAgent(name) {
return await readFile(resolve(AGENTS_DIR, name), 'utf-8');
}
test('Agent prompts: every file references at least one humanized field', async () => {
for (const name of AGENT_FILES) {
const content = await readAgent(name);
assert.match(
content,
HUMANIZED_FIELD_REGEX,
`${name} must reference userImpactCategory, userActionLanguage, or relevanceContext`,
);
}
});
test('Agent prompts: no jargon-translation subroutines', async () => {
for (const name of AGENT_FILES) {
const content = await readAgent(name);
assert.doesNotMatch(
content,
JARGON_TRANSLATION_INSTRUCTION_REGEX,
`${name} must not contain "explain what {jargon} means" / "translate jargon" instructions — humanizer owns translation`,
);
}
});
test('Agent prompts: frontmatter preserved (name field present)', async () => {
for (const name of AGENT_FILES) {
const content = await readAgent(name);
assert.match(content, FRONTMATTER_REGEX, `${name} missing required frontmatter`);
}
});
test('analyzer-agent.md: instructs grouping by userImpactCategory', async () => {
const content = await readAgent('analyzer-agent.md');
assert.match(content, /group.*by\s+`?userImpactCategory`?/i, 'analyzer-agent must group findings by userImpactCategory');
});
test('planner-agent.md: instructs ordering by userActionLanguage', async () => {
const content = await readAgent('planner-agent.md');
assert.match(content, /order.*by\s+(dependencies\s+and\s+)?`?userActionLanguage`?|userActionLanguage\s+urgency/i, 'planner-agent must order actions by userActionLanguage');
});
test('feature-gap-agent.md: skips test-fixture-no-impact findings', async () => {
const content = await readAgent('feature-gap-agent.md');
assert.match(content, /test-fixture-no-impact/, 'feature-gap-agent must reference the test-fixture-no-impact relevanceContext');
});