Files
pbakaus_impeccable/tests/skill-workflow/finish-handoff.test.mjs
T
Paul BakausandGitHub 6496f49a1e Fix skill workflow regression coverage (#783)
Clarify launcher fallback and completed documentation handoffs; separate bounded protocol checkpoints from opt-in browser-backed completion diagnostics. Correct fixture containment, target syntax, and artifact assertions. AI assistance: Codex, under maintainer direction.
2026-09-08 08:41:54 -07:00

94 lines
7.5 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.
import { it } from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import { prepareWorkspace, cleanupWorkspace, runTurn, fileLoaded, ENGINE_BIN } from '../skill-behavior/harness.mjs';
import { getModel, detectProvider, hasKey } from '../skill-behavior/providers.mjs';
import { assertCompleted, assertNoChangeDocumentation, assertDocumentationArtifacts } from './assertions.mjs';
import { missingReferences } from '../skill-behavior/assertions.mjs';
// A synthetic post-review checkpoint, not another full-build simulation.
// The page and system agree. A missing sidecar predates this task and is not
// permission to repair drift or rewrite the incumbent DESIGN.md.
const DESIGN = `# Field Manual
## Overview
An established, plain reading surface. Preserve this identity.
## Colors
White background (#ffffff), near-black text (#222222), blue links (#0645ad).
## Typography
System-ui body at 16px, line-height 1.6. Headings at 24px, weight 700.
## Layout
One column, max-width 65ch, padding 24px; no decorative containers.
`;
const PAGE = '<!doctype html><html lang="en"><meta charset="utf-8"><title>Keyboard guide</title><style>body{background:#fff;color:#222;font:16px/1.6 system-ui;max-width:65ch;margin:auto;padding:24px}h1{font-size:24px;font-weight:700}a{color:#0645ad}</style><main><h1>Keyboard guide</h1><p>Use Tab to move between controls. Press Enter to activate a link.</p><a href="#top" id="top">Back to top</a></main></html>';
const BRIEF = '# Keyboard guide\n\n## Direction contract\nTHESIS: A short reading page.\nOWN-WORLD: Inherit Field Manual.\nSTORY: Read keyboard instructions.\nFIRST VIEWPORT: Title, paragraph, link.\nFORM: Direct, precisely specified page; no seed required.\nFINISH: unreviewed and undocumented is unfinished.\n';
for (const modelId of (process.env.IMPECCABLE_SKILL_BEHAVIOR_MODELS || 'claude-sonnet-5').split(',').map((id) => id.trim()).filter(Boolean)) {
for (const mode of ['extension', 'new world', 'redesign']) {
const existingSystem = mode !== 'new world';
const preserveSystem = mode === 'extension';
it(`post-review ${mode} ${preserveSystem ? 'preserves' : 'records'} its system :: ${modelId}`,
{ skip: !ENGINE_BIN || !hasKey(detectProvider(modelId)) }, async (t) => {
const files = {
'PRODUCT.md': '# Field Manual\n\n## Platform\nweb\n\nA reference guide for keyboard users.\n',
...(existingSystem ? { 'DESIGN.md': preserveSystem ? DESIGN : '# Old Field Manual\n\nBeige cards, serif body type, orange links.\n' } : {}),
'index.html': PAGE,
'.impeccable/surfaces/index-html.md': mode === 'redesign'
? BRIEF.replace('Inherit Field Manual.', 'Approved replacement: white, blue links, system-ui, single column.') : BRIEF,
};
const workspace = prepareWorkspace({ files });
try {
const reference = fs.readFileSync(path.join(workspace, '.claude/skills/impeccable/reference/new-work.md'), 'utf8');
const result = await runTurn({
workspace, model: getModel(modelId), maxSteps: 12, timeoutMs: 180000, contextOnlyBash: true,
environment: 'This is a resumed post-review checkpoint. No subagent or browser tools are available. The review is closed; no further UI edits or screenshots are needed. Read/list/write tools are available.',
priorMessages: [
{ role: 'user', content: preserveSystem
? 'Use /impeccable to add the specified keyboard guide page inside the established Field Manual world. Keep the existing visual system. Do not repair unrelated project drift.'
: mode === 'redesign'
? 'Use /impeccable to redesign the keyboard guide. I approve replacing the old beige-card/serif/orange world with the plain single-column, system-font, white-background and blue-link identity. Update the system documentation from the finished page.'
: 'Use /impeccable to create Field Manuals first keyboard guide page. The chosen identity is plain, single-column, system fonts, white background and blue links.' },
{ role: 'assistant', content: [{ type: 'tool-call', toolCallId: 'load-new-work', toolName: 'read', input: { path: '.claude/skills/impeccable/reference/new-work.md' } }] },
{ role: 'tool', content: [{ type: 'tool-result', toolCallId: 'load-new-work', toolName: 'read', output: { type: 'text', value: reference } }] },
{ role: 'assistant', content: `Checkpoint: context and PRODUCT.md were loaded. The user confirmed the exact page and identity. The surface brief and index.html are written. Desktop/mobile captures were validated, the detector ran once, and the shipped finish reviewer returned ship with no open findings. ${preserveSystem
? 'DESIGN.md was loaded. No durable system changes were requested or introduced. The pre-existing missing .impeccable/design.json was reported but not repaired.'
: mode === 'redesign'
? 'The approved replacement world is implemented in index.html. DESIGN.md still describes the superseded identity; no design sidecar exists yet.'
: 'This is the first completed surface of the approved new world. No DESIGN.md or design sidecar exists yet.'}` },
],
userPrompt: 'Continue from this checkpoint and finish the task.',
});
assertCompleted(result);
t.diagnostic(`Documentation wrapper coverage gaps (diagnostic; contract and artifacts remain required): ${missingReferences(result.trace, ['degraded/documenter.md']).join(', ') || 'none'}`);
assert.ok(fileLoaded(result.trace, 'reference/document.md'), 'must consult the documentation contract');
for (const name of existingSystem ? ['index.html', 'DESIGN.md'] : ['index.html']) {
assert.ok(fileLoaded(result.trace, name), `documentation must check ${name}, not merely announce a no-op`);
}
for (const [name, contents] of Object.entries(files)) {
if (mode === 'redesign' && name === 'DESIGN.md') continue;
assert.equal(fs.readFileSync(path.join(workspace, name), 'utf8'), contents, `${name} must remain unchanged`);
}
if (preserveSystem) {
assertNoChangeDocumentation(result, { target: 'index.html', evidence: [/system-ui/i, /65\s*ch/i, /#0645ad/i] });
assert.equal(fs.existsSync(path.join(workspace, '.impeccable/design.json')), false, 'must not repair pre-existing sidecar drift unasked');
assert.deepEqual(result.trace.toolCalls.flatMap((call) => call.mutatedPaths || []), [], 'a no-change check must not mutate other project files');
} else {
const design = fs.readFileSync(path.join(workspace, 'DESIGN.md'), 'utf8');
if (mode === 'redesign') assert.notEqual(design, files['DESIGN.md'], 'approved redesign must replace the old system');
assertDocumentationArtifacts(design, fs.readFileSync(path.join(workspace, '.impeccable/design.json'), 'utf8'));
assert.match(design, /system-ui/);
const writes = result.trace.toolCalls.flatMap((call) => call.mutatedPaths || []);
assert.ok(writes.includes('DESIGN.md') && writes.includes('.impeccable/design.json'), 'both documentation artifacts must be written');
assert.deepEqual(writes.filter((file) => !['DESIGN.md', '.impeccable/design.json'].includes(file)), [], 'documentation must stay inside its write boundary');
}
} finally {
cleanupWorkspace(workspace);
}
});
}
}