Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD across contents and paths, upstream package/repo coordinates -> @golem15/msd-core and golem15com/msd-core. Deep links into upstream history, sibling upstream packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is. Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line, package/plugin identity, regenerated lockfile, install-tree fixtures, derived registries and benchmark baseline; migration checksum baseline re-locked (MSD keeps its own install state, so no install had applied the old sums); sort-order and regex-escaped expectations in tests adjusted.
77 lines
3.6 KiB
JavaScript
77 lines
3.6 KiB
JavaScript
/**
|
|
* mvp-phase workflow — contract test
|
|
* Verifies the workflow markdown contains the four agreed gates:
|
|
* 1. Phase existence + status guard (refuse in_progress/completed)
|
|
* 2. User-story prompt (three AskUserQuestion calls, As a / I want to / So that)
|
|
* 3. SPIDR splitting check
|
|
* 4. ROADMAP write (Mode + Goal)
|
|
* 5. Delegation to plan-phase
|
|
*/
|
|
const { test, describe } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const WORKFLOW = path.join(__dirname, '..', 'msd-core', 'workflows', 'mvp-phase.md');
|
|
|
|
function parseMvpPhaseContract(content) {
|
|
const lines = content.split(/\r?\n/);
|
|
const lowerLines = lines.map(line => line.toLowerCase());
|
|
const askCount = lowerLines.filter(line => line.includes('askuserquestion') || line.includes('vscode_askquestions')).length;
|
|
const spidrStepIndex = lowerLines.findIndex(line => line.includes('## 4. spidr splitting check'));
|
|
const planPhaseStepIndex = lowerLines.findIndex(line => line.includes('## 7. delegate to /msd plan-phase'));
|
|
|
|
return {
|
|
hasStatusGuard: lowerLines.some(line => line.includes('in_progress') || line.includes('completed')),
|
|
hasForceOverride: lowerLines.some(line => line.includes('--force') || line.includes('status guard')),
|
|
hasAsA: lowerLines.some(line => line.includes('as a')),
|
|
hasIWantTo: lowerLines.some(line => line.includes('i want to')),
|
|
hasSoThat: lowerLines.some(line => line.includes('so that')),
|
|
askCount,
|
|
hasSpidrReference: lowerLines.some(line => line.includes('spidr-splitting.md')),
|
|
hasModeLine: lowerLines.some(line => line.includes('**mode:** mvp')),
|
|
hasGoalLine: lowerLines.some(line => line.includes('**goal:**')),
|
|
hasRoadmapReference: lowerLines.some(line => line.includes('roadmap.md')),
|
|
spidrStepIndex,
|
|
planPhaseStepIndex,
|
|
hasUserStoryTemplateRef: lowerLines.some(line => line.includes('user-story-template.md')),
|
|
};
|
|
}
|
|
|
|
describe('mvp-phase workflow', () => {
|
|
const contract = parseMvpPhaseContract(fs.readFileSync(WORKFLOW, 'utf-8'));
|
|
|
|
test('declares phase status guard (refuse in_progress/completed unless --force)', () => {
|
|
assert.ok(contract.hasStatusGuard, 'workflow must reference status guard');
|
|
assert.ok(contract.hasForceOverride, 'workflow must mention force override or status guard');
|
|
});
|
|
|
|
test('runs three structured user-story prompts', () => {
|
|
assert.ok(contract.hasAsA);
|
|
assert.ok(contract.hasIWantTo);
|
|
assert.ok(contract.hasSoThat);
|
|
assert.ok(contract.askCount >= 3, `workflow must invoke AskUserQuestion at least 3 times for the story prompts (got ${contract.askCount})`);
|
|
});
|
|
|
|
test('runs SPIDR splitting check after user story', () => {
|
|
assert.ok(contract.spidrStepIndex >= 0, 'workflow must define an SPIDR step');
|
|
assert.ok(contract.hasSpidrReference, 'workflow must reference the SPIDR rules file');
|
|
});
|
|
|
|
test('writes Mode: mvp + Goal: line to ROADMAP.md', () => {
|
|
assert.ok(contract.hasModeLine, 'workflow must specify the **Mode:** mvp line');
|
|
assert.ok(contract.hasRoadmapReference, 'workflow must reference ROADMAP.md');
|
|
assert.ok(contract.hasGoalLine, 'workflow must update the **Goal:** line');
|
|
});
|
|
|
|
test('delegates to /msd plan-phase after ROADMAP write', () => {
|
|
assert.ok(contract.planPhaseStepIndex >= 0, 'plan-phase delegation step must be present');
|
|
assert.ok(contract.spidrStepIndex >= 0, 'SPIDR check step must be present');
|
|
assert.ok(contract.planPhaseStepIndex > contract.spidrStepIndex, 'plan-phase delegation must come AFTER SPIDR check');
|
|
});
|
|
|
|
test('references user-story-template.md', () => {
|
|
assert.ok(contract.hasUserStoryTemplateRef);
|
|
});
|
|
});
|