Files
msd-core/tests/autonomous-ui-steps.test.cjs
Tom Boucher 6fc84528e5 fix(#448): resolve UI safety gate helper against the GSD install dir (#539)
* fix(#448): resolve UI safety gate helper against the GSD install dir

The §5.6 UI Design Contract Gate (and autonomous §3a.5) resolved
ui-safety-gate.cjs via `git rev-parse --show-toplevel`, i.e. the
consuming project's git root — which has no bin/lib. The node call
failed, its exit code was conflated with "no UI", and the gate
silently no-opped so frontend phases skipped the UI-SPEC prompt.

Resolve the helper against the GSD install dir via RUNTIME_DIR (the
same idiom §1 uses for gsd-tools), with git-toplevel and $HOME/.claude
fallbacks. When the helper genuinely can't be found, fail OPEN with a
stderr warning (assume UI present) rather than silently skipping.

Tests: bug-3706 structural guard now requires RUNTIME_DIR resolution
and forbids the consuming-project GSD_REPO_ROOT anchor; a new
behavioral test resolves and runs the helper from a temp consuming
project (no bin/lib) with RUNTIME_DIR set. autonomous-ui-steps updated
to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(#448): add changeset fragment for PR #539

* fix(#448): add get-shit-done/bin/lib/ to UI gate probe and deploy helper there

The installer copies get-shit-done/ to the target but not root bin/lib/, so
the helper was never found for installed users. Placing ui-safety-gate.cjs in
get-shit-done/bin/lib/ ensures the installer deploys it, and probing that path
first makes the gate work correctly in installed runtimes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update changeset to cover get-shit-done/bin/lib/ deployment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update inventory for ui-safety-gate.cjs in get-shit-done/bin/lib/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 14:42:37 -04:00

151 lines
5.5 KiB
JavaScript

/**
* Tests that autonomous.md includes ui-phase and ui-review steps for frontend phases.
*
* Issue #1375: autonomous workflow skips ui-phase and ui-review for frontend phases.
* The per-phase execution loop should be: discuss -> ui-phase -> plan -> execute -> verify -> ui-review
* for phases with frontend indicators.
*/
const { describe, it, test, beforeEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const WORKFLOW_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'autonomous.md');
describe('autonomous workflow ui-phase and ui-review integration (#1375)', () => {
let content;
beforeEach(() => {
assert.ok(fs.existsSync(WORKFLOW_PATH), 'workflows/autonomous.md should exist');
content = fs.readFileSync(WORKFLOW_PATH, 'utf-8');
});
describe('step 3a.5 — UI design contract before planning', () => {
test('autonomous.md contains a UI design contract step between discuss and plan', () => {
assert.ok(
content.includes('3a.5'),
'should have step 3a.5 for UI design contract'
);
});
test('UI design contract step detects frontend indicators via shell-free Node gate (#3718)', () => {
// After #3718: the gate is implemented in bin/lib/ui-safety-gate.cjs (Node.js)
// piped from stdin, avoiding silent failure on Windows PowerShell and ARG_MAX.
// After #448: the helper is resolved against the GSD install dir (RUNTIME_DIR),
// not the consuming project's git root, so it is actually found at runtime.
assert.ok(
content.includes('ui-safety-gate.cjs'),
'should invoke shell-free Node gate for cross-platform portability (#3718)'
);
assert.ok(
content.includes('RUNTIME_DIR'),
'should resolve the gate helper against the GSD install dir (RUNTIME_DIR), not the consuming project root (#448)'
);
});
test('UI design contract step checks for existing UI-SPEC.md', () => {
assert.ok(
content.includes('UI-SPEC.md'),
'should check for existing UI-SPEC.md'
);
});
test('UI design contract step respects workflow.ui_phase config toggle', () => {
assert.ok(
content.includes('workflow.ui_phase'),
'should respect workflow.ui_phase config toggle'
);
});
test('UI design contract step invokes gsd:ui-phase skill', () => {
assert.ok(
content.includes('skill="gsd-ui-phase"'),
'should invoke gsd-ui-phase via Skill()'
);
});
test('UI design contract step appears before plan step (3b)', () => {
const uiPhasePos = content.indexOf('3a.5');
const planPos = content.indexOf('**3b. Plan**');
assert.ok(
uiPhasePos < planPos,
'step 3a.5 (UI design contract) should appear before step 3b (plan)'
);
});
});
describe('step 3d.5 — UI review after execution', () => {
test('autonomous.md contains a UI review step after execution', () => {
assert.ok(
content.includes('3d.5'),
'should have step 3d.5 for UI review'
);
});
test('UI review step checks for UI-SPEC existence before running', () => {
// The UI review should only run if a UI-SPEC was created/exists
const reviewSection = content.slice(content.indexOf('3d.5'));
assert.ok(
reviewSection.includes('UI_SPEC_FILE'),
'UI review step should check for UI-SPEC file existence'
);
});
test('UI review step respects workflow.ui_review config toggle', () => {
assert.ok(
content.includes('workflow.ui_review'),
'should respect workflow.ui_review config toggle'
);
});
test('UI review step invokes gsd:ui-review skill', () => {
assert.ok(
content.includes('skill="gsd-ui-review"'),
'should invoke gsd-ui-review via Skill()'
);
});
test('UI review is advisory (non-blocking)', () => {
const reviewSection = content.slice(content.indexOf('3d.5'));
assert.ok(
reviewSection.includes('advisory') || reviewSection.includes('non-blocking') || reviewSection.includes('regardless of score'),
'UI review should be advisory and not block phase progression'
);
});
test('UI review step appears after execution routing (3d)', () => {
const executeRouting = content.indexOf('**3d. Post-Execution Routing**');
const uiReviewPos = content.indexOf('3d.5');
assert.ok(
uiReviewPos > executeRouting,
'step 3d.5 (UI review) should appear after step 3d (post-execution routing)'
);
});
});
describe('success criteria updated', () => {
test('success criteria includes UI-aware flow', () => {
assert.ok(
content.includes('ui-phase') && content.includes('ui-review'),
'success criteria should reference ui-phase and ui-review'
);
});
test('success criteria mentions frontend phases get UI-SPEC before planning', () => {
assert.ok(
content.includes('Frontend phases') || content.includes('frontend phases'),
'success criteria should mention frontend phases'
);
});
test('success criteria notes UI review is advisory', () => {
const criteriaSection = content.slice(content.indexOf('<success_criteria>'));
assert.ok(
criteriaSection.includes('advisory') || criteriaSection.includes('non-blocking'),
'success criteria should note UI review is advisory/non-blocking'
);
});
});
});