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).
82 lines
3.1 KiB
JavaScript
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');
|
|
});
|