Files
msd-core/tests/roadmap-command-router.test.cjs
Tom Boucher 0a12b06381 feat(#39): milestone-prefixed phase IDs (M-NN convention) + migration tool + validation (#565)
* feat(#39): milestone-prefixed phase IDs (M-NN convention) + migration tool + validation

- Add getMilestoneFromPhaseId() / getPhaseDirFromPhaseId() helpers to core.cjs
- Fix isDirInMilestone to match M-NN-style dirs (02-01-setup) against M-NN ROADMAP headings
- Extend heading regex to tolerate [bracket-token] scope prefix on phase headings
- Add W021 validation rule for milestone prefix mismatch
- Add gsd-tools roadmap validate + roadmap upgrade --convention milestone-prefixed
- Add phase_id_convention config field (null default, backwards-compatible)

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

* fix(#39): address 4 Codex review findings in milestone-prefixed phase ID implementation

- getMilestoneFromPhaseId: tighten regex to require a digit after the hyphen (rejects '1-' and '1-abc')
- isDirInMilestone: use convention-aware regex — only capture M-NN segments when ROADMAP itself uses hyphenated phase IDs, preventing legacy dirs like '01-02-setup' from being misread as phase '1-02'
- checkW021: add UNPREFIXED_PHASE_RE path so unprefixed headings (### Phase 1:) also fire W021 when convention is milestone-prefixed
- roadmap-upgrade: remove isMigratedDirName dir-name check (false-positive for legacy dirs); config + ROADMAP heading checks at lines 194 and 212 are sufficient

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

* chore: update changeset pr reference to #565

* fix(#39): restore phaseDirNameRe 2-digit minimum; add roadmap-upgrade to inventory

- validate.cjs: \d{1,} → \d{2,} to keep single-digit prefix rejection per W005 contract
- docs/INVENTORY.md: 79 → 80, add roadmap-upgrade.cjs row
- docs/INVENTORY-MANIFEST.json: regenerated (roadmap-upgrade.cjs entry)

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:15:55 -04:00

88 lines
2.4 KiB
JavaScript

'use strict';
const { describe, test, before, after } = require('node:test');
const assert = require('node:assert/strict');
const { routeRoadmapCommand } = require('../get-shit-done/bin/lib/roadmap-command-router.cjs');
// These tests exercise router dispatch with a deterministic runtime context.
let _prevWorkstream;
before(() => {
_prevWorkstream = process.env.GSD_WORKSTREAM;
process.env.GSD_WORKSTREAM = 'test-unit';
});
after(() => {
if (_prevWorkstream === undefined) delete process.env.GSD_WORKSTREAM;
else process.env.GSD_WORKSTREAM = _prevWorkstream;
});
describe('roadmap-command-router', () => {
test('routes roadmap analyze', () => {
const calls = [];
const roadmap = {
cmdRoadmapAnalyze: (cwd, raw) => calls.push({ cwd, raw }),
};
routeRoadmapCommand({
roadmap,
args: ['roadmap', 'analyze'],
cwd: '/tmp/proj',
raw: true,
error: (msg) => {
throw new Error(msg);
},
});
assert.equal(calls.length, 1);
assert.deepEqual(calls[0], { cwd: '/tmp/proj', raw: true });
});
test('routes roadmap get-phase and update-plan-progress with phase arg', () => {
const calls = [];
const roadmap = {
cmdRoadmapGetPhase: (cwd, phase, raw) => calls.push({ kind: 'get', cwd, phase, raw }),
cmdRoadmapUpdatePlanProgress: (cwd, phase, raw) => calls.push({ kind: 'update', cwd, phase, raw }),
};
routeRoadmapCommand({
roadmap,
args: ['roadmap', 'get-phase', '10'],
cwd: '/tmp/proj',
raw: false,
error: (msg) => {
throw new Error(msg);
},
});
routeRoadmapCommand({
roadmap,
args: ['roadmap', 'update-plan-progress', '10'],
cwd: '/tmp/proj',
raw: false,
error: (msg) => {
throw new Error(msg);
},
});
assert.deepEqual(calls, [
{ kind: 'get', cwd: '/tmp/proj', phase: '10', raw: false },
{ kind: 'update', cwd: '/tmp/proj', phase: '10', raw: false },
]);
});
test('errors on unknown roadmap subcommand', () => {
let message = null;
routeRoadmapCommand({
roadmap: {},
args: ['roadmap', 'nonsense'],
cwd: '/tmp/proj',
raw: false,
error: (msg) => {
message = msg;
},
});
assert.equal(message, 'Unknown roadmap subcommand. Available: analyze, get-phase, update-plan-progress, annotate-dependencies, validate, upgrade');
});
});