refactor: hard-fork GSD -> MSD (Make Software Done)
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.
This commit is contained in:
@@ -4,18 +4,18 @@
|
||||
// Per CONTRIBUTING.md exception matrix.
|
||||
|
||||
/**
|
||||
* GSD Tools Tests - autonomous.md and complete-milestone.md workstream-scoped
|
||||
* MSD Tools Tests - autonomous.md and complete-milestone.md workstream-scoped
|
||||
* STATE/ROADMAP/archive paths (#4455)
|
||||
*
|
||||
* Both workflows used to read/write hardcoded literal `.planning/STATE.md` /
|
||||
* `.planning/ROADMAP.md` / `.planning/milestones/...` paths in their shell
|
||||
* fences — bypassing workstream scoping entirely. When GSD_WORKSTREAM is set,
|
||||
* fences — bypassing workstream scoping entirely. When MSD_WORKSTREAM is set,
|
||||
* `init.manager`/`init.complete-milestone` resolve `state_path`/`roadmap_path`/
|
||||
* `archive_dir` into the workstream, but the literal reads/writes still hit
|
||||
* root `.planning/` (or silently returned empty).
|
||||
*
|
||||
* These tests extract the real bash fences from the workflow files and
|
||||
* execute them (with a stubbed `gsd_run`) rather than string-matching the
|
||||
* execute them (with a stubbed `msd_run`) rather than string-matching the
|
||||
* markdown — the same idiom tests/new-milestone-clear-phases.test.cjs uses.
|
||||
*
|
||||
* One file (not two) per scripts/lint-test-file-count.cjs's per-module cap —
|
||||
@@ -31,7 +31,7 @@ const path = require('path');
|
||||
const os = require('os');
|
||||
const { runHook: runHookSeam } = require('./helpers/process-seam.cjs');
|
||||
const { throwIfFailed } = require('./helpers/git-fixture.cjs');
|
||||
const { scanFencedBlocks } = require('../gsd-core/bin/lib/markdown-sectionizer.cjs');
|
||||
const { scanFencedBlocks } = require('../msd-core/bin/lib/markdown-sectionizer.cjs');
|
||||
const { cleanup } = require('./helpers.cjs');
|
||||
|
||||
/** Return the raw text of every ```bash fenced block in `text`. */
|
||||
@@ -73,7 +73,7 @@ function extractFenceContaining(markdown, startMarker, endMarker, marker) {
|
||||
}
|
||||
|
||||
describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
const WORKFLOW_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'autonomous.md');
|
||||
const WORKFLOW_PATH = path.join(__dirname, '..', 'msd-core', 'workflows', 'autonomous.md');
|
||||
const content = fs.readFileSync(WORKFLOW_PATH, 'utf8');
|
||||
|
||||
const discoverPhasesFence = extractFenceBetween(content, '## 2. Discover Phases', '## 3. Execute Phase');
|
||||
@@ -83,7 +83,7 @@ describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
let tmpDir;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-autonomous-ws-'));
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-autonomous-ws-'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -91,43 +91,43 @@ describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
});
|
||||
|
||||
/**
|
||||
* Write a canned init.manager-shaped JSON payload and a gsd_run stub that
|
||||
* Write a canned init.manager-shaped JSON payload and a msd_run stub that
|
||||
* returns it verbatim. Each call also appends one byte to a call-log file
|
||||
* — NOT a shell variable increment, because `INIT_MANAGER=$(gsd_run ...)`
|
||||
* runs gsd_run inside the command-substitution SUBSHELL, so a variable
|
||||
* — NOT a shell variable increment, because `INIT_MANAGER=$(msd_run ...)`
|
||||
* runs msd_run inside the command-substitution SUBSHELL, so a variable
|
||||
* mutated there never survives back into the caller's shell.
|
||||
*/
|
||||
function stubGsdRun(jsonPayload) {
|
||||
function stubMsdRun(jsonPayload) {
|
||||
const jsonPath = path.join(tmpDir, 'init-manager.json');
|
||||
const callLogPath = path.join(tmpDir, 'gsd-run-calls.log');
|
||||
const callLogPath = path.join(tmpDir, 'msd-run-calls.log');
|
||||
fs.writeFileSync(jsonPath, JSON.stringify(jsonPayload));
|
||||
fs.writeFileSync(callLogPath, '');
|
||||
return `gsd_run() { printf 'x' >> "${callLogPath}"; cat "${jsonPath}"; }\n`;
|
||||
return `msd_run() { printf 'x' >> "${callLogPath}"; cat "${jsonPath}"; }\n`;
|
||||
}
|
||||
|
||||
/** Number of gsd_run invocations recorded by the most recent stubGsdRun-backed script. */
|
||||
function gsdRunCallCount() {
|
||||
return fs.readFileSync(path.join(tmpDir, 'gsd-run-calls.log'), 'utf8').length;
|
||||
/** Number of msd_run invocations recorded by the most recent stubMsdRun-backed script. */
|
||||
function msdRunCallCount() {
|
||||
return fs.readFileSync(path.join(tmpDir, 'msd-run-calls.log'), 'utf8').length;
|
||||
}
|
||||
|
||||
describe('discover_phases step: reads STATE.md from init.manager state_path, not a hardcoded literal', () => {
|
||||
test('flat mode: no GSD_WORKSTREAM — resolves the root STATE.md path (regression guard)', () => {
|
||||
test('flat mode: no MSD_WORKSTREAM — resolves the root STATE.md path (regression guard)', () => {
|
||||
const statePath = path.join(tmpDir, 'STATE-root.md');
|
||||
fs.writeFileSync(statePath, '# Root State\n');
|
||||
const script = `${stubGsdRun({ state_path: statePath })}${discoverPhasesFence}\nprintf 'STATE_CONTENT=[%s]\\n' "$STATE_CONTENT"`;
|
||||
const script = `${stubMsdRun({ state_path: statePath })}${discoverPhasesFence}\nprintf 'STATE_CONTENT=[%s]\\n' "$STATE_CONTENT"`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <discover_phases fence>');
|
||||
assert.ok(r.stdout.includes('STATE_CONTENT=[# Root State'),
|
||||
`expected root STATE.md content, got: ${r.stdout}`);
|
||||
});
|
||||
|
||||
test('GSD_WORKSTREAM=alpha: reads the workstream-scoped STATE.md, not the root one (#4455 regression)', () => {
|
||||
test('MSD_WORKSTREAM=alpha: reads the workstream-scoped STATE.md, not the root one (#4455 regression)', () => {
|
||||
const rootStatePath = path.join(tmpDir, 'STATE-root.md');
|
||||
fs.writeFileSync(rootStatePath, '# Root State — must not be read\n');
|
||||
const wsStatePath = path.join(tmpDir, 'STATE-alpha.md');
|
||||
fs.writeFileSync(wsStatePath, '# Workstream Alpha State\n');
|
||||
|
||||
const script = `${stubGsdRun({ state_path: wsStatePath })}${discoverPhasesFence}\nprintf 'STATE_CONTENT=[%s]\\n' "$STATE_CONTENT"`;
|
||||
const script = `${stubMsdRun({ state_path: wsStatePath })}${discoverPhasesFence}\nprintf 'STATE_CONTENT=[%s]\\n' "$STATE_CONTENT"`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <discover_phases fence>');
|
||||
assert.ok(r.stdout.includes('STATE_CONTENT=[# Workstream Alpha State'),
|
||||
@@ -141,20 +141,20 @@ describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
test('flat mode: resolves the root STATE.md path (regression guard)', () => {
|
||||
const statePath = path.join(tmpDir, 'STATE-root.md');
|
||||
fs.writeFileSync(statePath, '# Root State\n');
|
||||
const script = `${stubGsdRun({ state_path: statePath })}${iterateFence}`;
|
||||
const script = `${stubMsdRun({ state_path: statePath })}${iterateFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <iterate fence>');
|
||||
// The fence's own `cat "$STATE_PATH"` line prints the raw re-read to stdout.
|
||||
assert.ok(r.stdout.includes('# Root State'), `expected root STATE.md content, got: ${r.stdout}`);
|
||||
});
|
||||
|
||||
test('GSD_WORKSTREAM=alpha: re-reads the workstream STATE.md, not root (#4455 regression)', () => {
|
||||
test('MSD_WORKSTREAM=alpha: re-reads the workstream STATE.md, not root (#4455 regression)', () => {
|
||||
const rootStatePath = path.join(tmpDir, 'STATE-root.md');
|
||||
fs.writeFileSync(rootStatePath, '# Root State — must not be read\n');
|
||||
const wsStatePath = path.join(tmpDir, 'STATE-alpha.md');
|
||||
fs.writeFileSync(wsStatePath, '# Workstream Alpha State\n');
|
||||
|
||||
const script = `${stubGsdRun({ state_path: wsStatePath })}${iterateFence}`;
|
||||
const script = `${stubMsdRun({ state_path: wsStatePath })}${iterateFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <iterate fence>');
|
||||
assert.ok(r.stdout.includes('# Workstream Alpha State'),
|
||||
@@ -166,11 +166,11 @@ describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
test('does not double-fetch init.manager within the iterate fence (no-double-fetch requirement)', () => {
|
||||
const statePath = path.join(tmpDir, 'STATE-root.md');
|
||||
fs.writeFileSync(statePath, '# Root State\n');
|
||||
const script = `${stubGsdRun({ state_path: statePath })}${iterateFence}`;
|
||||
const script = `${stubMsdRun({ state_path: statePath })}${iterateFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <iterate fence>');
|
||||
assert.strictEqual(gsdRunCallCount(), 1,
|
||||
`iterate fence must call gsd_run exactly once (no double-fetch), got ${gsdRunCallCount()}; stdout: ${r.stdout}`);
|
||||
assert.strictEqual(msdRunCallCount(), 1,
|
||||
`iterate fence must call msd_run exactly once (no double-fetch), got ${msdRunCallCount()}; stdout: ${r.stdout}`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -180,7 +180,7 @@ describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
fs.mkdirSync(archiveDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(archiveDir, 'v1.0-ROADMAP.md'), '# Archived Roadmap\n');
|
||||
|
||||
const script = `milestone_version="1.0"\n${stubGsdRun({ archive_dir: archiveDir })}${lifecycle5bFence}`;
|
||||
const script = `milestone_version="1.0"\n${stubMsdRun({ archive_dir: archiveDir })}${lifecycle5bFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <lifecycle 5b fence>');
|
||||
// The fence concatenates with a literal bash `/` ("${ARCHIVE_DIR}/v...-ROADMAP.md"),
|
||||
@@ -191,7 +191,7 @@ describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
`expected ls to find the root archive file, got: ${r.stdout}`);
|
||||
});
|
||||
|
||||
test('GSD_WORKSTREAM=alpha: checks the workstream-scoped archive dir, not root (#4455 regression)', () => {
|
||||
test('MSD_WORKSTREAM=alpha: checks the workstream-scoped archive dir, not root (#4455 regression)', () => {
|
||||
const rootArchiveDir = path.join(tmpDir, 'milestones-root');
|
||||
fs.mkdirSync(rootArchiveDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(rootArchiveDir, 'v1.0-ROADMAP.md'), '# Root Archived Roadmap — must not be found\n');
|
||||
@@ -200,7 +200,7 @@ describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
fs.mkdirSync(wsArchiveDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(wsArchiveDir, 'v1.0-ROADMAP.md'), '# Workstream Archived Roadmap\n');
|
||||
|
||||
const script = `milestone_version="1.0"\n${stubGsdRun({ archive_dir: wsArchiveDir })}${lifecycle5bFence}`;
|
||||
const script = `milestone_version="1.0"\n${stubMsdRun({ archive_dir: wsArchiveDir })}${lifecycle5bFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <lifecycle 5b fence>');
|
||||
// See the flat-mode test above for why this is a literal `/` join, not path.join.
|
||||
@@ -213,21 +213,21 @@ describe('autonomous.md workstream-scoped paths (#4455)', () => {
|
||||
});
|
||||
|
||||
describe('complete-milestone.md workstream-scoped paths (#4455)', () => {
|
||||
const WORKFLOW_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'complete-milestone.md');
|
||||
const WORKFLOW_PATH = path.join(__dirname, '..', 'msd-core', 'workflows', 'complete-milestone.md');
|
||||
const content = fs.readFileSync(WORKFLOW_PATH, 'utf8');
|
||||
|
||||
const STEP_START = '<step name="reorganize_roadmap_and_delete_originals">';
|
||||
const STEP_END = '<step name="write_retrospective">';
|
||||
|
||||
const backlogFence = extractFenceContaining(content, STEP_START, STEP_END, 'BACKLOG_SECTION');
|
||||
const sentinelFence = extractFenceContaining(content, STEP_START, STEP_END, '.gsd-allow-shrink');
|
||||
const commitFilesFence = extractFenceContaining(content, STEP_START, STEP_END, 'gsd_run query commit');
|
||||
const sentinelFence = extractFenceContaining(content, STEP_START, STEP_END, '.msd-allow-shrink');
|
||||
const commitFilesFence = extractFenceContaining(content, STEP_START, STEP_END, 'msd_run query commit');
|
||||
const requirementsRmFence = extractFenceContaining(content, STEP_START, STEP_END, 'git rm');
|
||||
|
||||
let tmpDir;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-complete-milestone-ws-'));
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-complete-milestone-ws-'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -235,36 +235,36 @@ describe('complete-milestone.md workstream-scoped paths (#4455)', () => {
|
||||
});
|
||||
|
||||
/**
|
||||
* Write a canned init.complete-milestone-shaped JSON payload and a gsd_run
|
||||
* Write a canned init.complete-milestone-shaped JSON payload and a msd_run
|
||||
* stub that returns it for the `query init.complete-milestone` fetch, and
|
||||
* echoes `gsd_run_call:<argv>` for every OTHER call (e.g. `query commit
|
||||
* echoes `msd_run_call:<argv>` for every OTHER call (e.g. `query commit
|
||||
* ...`) — the same recording-stub idiom tests/new-milestone-clear-phases.
|
||||
* test.cjs uses, so the commit `--files` list can be asserted on directly.
|
||||
*/
|
||||
function stubGsdRun(jsonPayload) {
|
||||
function stubMsdRun(jsonPayload) {
|
||||
const jsonPath = path.join(tmpDir, 'init-cm.json');
|
||||
fs.writeFileSync(jsonPath, JSON.stringify(jsonPayload));
|
||||
return `gsd_run() { if [ "$1" = "query" ] && [ "$2" = "init.complete-milestone" ]; then cat "${jsonPath}"; else printf 'gsd_run_call:%s\\n' "$*"; fi; }\n`;
|
||||
return `msd_run() { if [ "$1" = "query" ] && [ "$2" = "init.complete-milestone" ]; then cat "${jsonPath}"; else printf 'msd_run_call:%s\\n' "$*"; fi; }\n`;
|
||||
}
|
||||
|
||||
describe('backlog extraction: reads ROADMAP.md from init.complete-milestone roadmap_path', () => {
|
||||
test('flat mode: no GSD_WORKSTREAM — resolves the root ROADMAP.md path (regression guard)', () => {
|
||||
test('flat mode: no MSD_WORKSTREAM — resolves the root ROADMAP.md path (regression guard)', () => {
|
||||
const roadmapPath = path.join(tmpDir, 'ROADMAP-root.md');
|
||||
fs.writeFileSync(roadmapPath, '# Roadmap\n\n## Backlog\n\n- 999.1 Root backlog item\n');
|
||||
const script = `${stubGsdRun({ roadmap_path: roadmapPath })}${backlogFence}\nprintf 'BACKLOG=[%s]\\n' "$BACKLOG_SECTION"`;
|
||||
const script = `${stubMsdRun({ roadmap_path: roadmapPath })}${backlogFence}\nprintf 'BACKLOG=[%s]\\n' "$BACKLOG_SECTION"`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <backlog fence>');
|
||||
assert.ok(r.stdout.includes('Root backlog item'),
|
||||
`expected root ROADMAP.md backlog content, got: ${r.stdout}`);
|
||||
});
|
||||
|
||||
test('GSD_WORKSTREAM=alpha: reads the workstream-scoped ROADMAP.md, not root (#4455 regression)', () => {
|
||||
test('MSD_WORKSTREAM=alpha: reads the workstream-scoped ROADMAP.md, not root (#4455 regression)', () => {
|
||||
const rootRoadmapPath = path.join(tmpDir, 'ROADMAP-root.md');
|
||||
fs.writeFileSync(rootRoadmapPath, '# Roadmap\n\n## Backlog\n\n- 999.1 Root backlog item — must not be read\n');
|
||||
const wsRoadmapPath = path.join(tmpDir, 'ROADMAP-alpha.md');
|
||||
fs.writeFileSync(wsRoadmapPath, '# Roadmap\n\n## Backlog\n\n- 999.1 Workstream Alpha backlog item\n');
|
||||
|
||||
const script = `${stubGsdRun({ roadmap_path: wsRoadmapPath })}${backlogFence}\nprintf 'BACKLOG=[%s]\\n' "$BACKLOG_SECTION"`;
|
||||
const script = `${stubMsdRun({ roadmap_path: wsRoadmapPath })}${backlogFence}\nprintf 'BACKLOG=[%s]\\n' "$BACKLOG_SECTION"`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <backlog fence>');
|
||||
assert.ok(r.stdout.includes('Workstream Alpha backlog item'),
|
||||
@@ -278,20 +278,20 @@ describe('complete-milestone.md workstream-scoped paths (#4455)', () => {
|
||||
test('flat mode: sentinel names the root ROADMAP.md path (regression guard)', () => {
|
||||
const roadmapPath = path.join(tmpDir, 'ROADMAP-root.md');
|
||||
fs.mkdirSync(path.join(tmpDir, '.planning'), { recursive: true });
|
||||
const script = `${stubGsdRun({ roadmap_path: roadmapPath })}${sentinelFence}`;
|
||||
const script = `${stubMsdRun({ roadmap_path: roadmapPath })}${sentinelFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <sentinel fence>');
|
||||
const sentinelContent = fs.readFileSync(path.join(tmpDir, '.planning', '.gsd-allow-shrink'), 'utf8').trim();
|
||||
const sentinelContent = fs.readFileSync(path.join(tmpDir, '.planning', '.msd-allow-shrink'), 'utf8').trim();
|
||||
assert.strictEqual(sentinelContent, roadmapPath);
|
||||
});
|
||||
|
||||
test('GSD_WORKSTREAM=alpha: sentinel names the workstream ROADMAP.md, not root (#4455 regression)', () => {
|
||||
test('MSD_WORKSTREAM=alpha: sentinel names the workstream ROADMAP.md, not root (#4455 regression)', () => {
|
||||
const wsRoadmapPath = path.join(tmpDir, 'ROADMAP-alpha.md');
|
||||
fs.mkdirSync(path.join(tmpDir, '.planning'), { recursive: true });
|
||||
const script = `${stubGsdRun({ roadmap_path: wsRoadmapPath })}${sentinelFence}`;
|
||||
const script = `${stubMsdRun({ roadmap_path: wsRoadmapPath })}${sentinelFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <sentinel fence>');
|
||||
const sentinelContent = fs.readFileSync(path.join(tmpDir, '.planning', '.gsd-allow-shrink'), 'utf8').trim();
|
||||
const sentinelContent = fs.readFileSync(path.join(tmpDir, '.planning', '.msd-allow-shrink'), 'utf8').trim();
|
||||
assert.strictEqual(sentinelContent, wsRoadmapPath);
|
||||
assert.notStrictEqual(sentinelContent, path.join(tmpDir, '.planning', 'ROADMAP.md'));
|
||||
});
|
||||
@@ -299,7 +299,7 @@ describe('complete-milestone.md workstream-scoped paths (#4455)', () => {
|
||||
|
||||
describe('safety commit --files list: STATE/ROADMAP/archive/MILESTONES/PROJECT paths all scoped together', () => {
|
||||
function runCommitFence(cmJson) {
|
||||
const script = `${stubGsdRun(cmJson)}${commitFilesFence}`;
|
||||
const script = `${stubMsdRun(cmJson)}${commitFilesFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <commit --files fence>');
|
||||
return r.stdout;
|
||||
@@ -316,7 +316,7 @@ describe('complete-milestone.md workstream-scoped paths (#4455)', () => {
|
||||
milestones_path: milestonesPath, project_path: projectPath,
|
||||
});
|
||||
|
||||
assert.ok(out.includes('gsd_run_call:query commit'), `expected the commit call to be recorded, got: ${out}`);
|
||||
assert.ok(out.includes('msd_run_call:query commit'), `expected the commit call to be recorded, got: ${out}`);
|
||||
assert.ok(out.includes(statePath), `expected root STATE.md in --files, got: ${out}`);
|
||||
assert.ok(out.includes(roadmapPath), `expected root ROADMAP.md in --files, got: ${out}`);
|
||||
assert.ok(out.includes(`${archiveDir}/v[X.Y]-ROADMAP.md`), `expected root archive ROADMAP in --files, got: ${out}`);
|
||||
@@ -324,17 +324,17 @@ describe('complete-milestone.md workstream-scoped paths (#4455)', () => {
|
||||
assert.ok(out.includes(projectPath), `expected root PROJECT.md in --files, got: ${out}`);
|
||||
});
|
||||
|
||||
test('GSD_WORKSTREAM=alpha: --files lists workstream-scoped STATE/ROADMAP/archive/MILESTONES paths, but PROJECT.md STAYS root (#4455 regression)', () => {
|
||||
test('MSD_WORKSTREAM=alpha: --files lists workstream-scoped STATE/ROADMAP/archive/MILESTONES paths, but PROJECT.md STAYS root (#4455 regression)', () => {
|
||||
const wsStatePath = path.join(tmpDir, 'STATE-alpha.md');
|
||||
const wsRoadmapPath = path.join(tmpDir, 'ROADMAP-alpha.md');
|
||||
const wsArchiveDir = path.join(tmpDir, 'milestones-alpha');
|
||||
const wsMilestonesPath = path.join(tmpDir, 'MILESTONES-alpha.md');
|
||||
// PROJECT.md is genuinely SHARED across workstreams — never cloned per
|
||||
// workstream (gsd-core/references/workstream-flag.md marks it
|
||||
// workstream (msd-core/references/workstream-flag.md marks it
|
||||
// `# Shared`; new-milestone.md states it outright; cmdWorkstreamCreate
|
||||
// never creates one under a workstream dir). The real
|
||||
// cmdInitCompleteMilestone therefore ALWAYS returns the root path for
|
||||
// project_path regardless of GSD_WORKSTREAM — reflected here by
|
||||
// project_path regardless of MSD_WORKSTREAM — reflected here by
|
||||
// passing the SAME root-shaped value the flat-mode test above uses,
|
||||
// not a workstream-shaped one. An earlier version of this fix wrongly
|
||||
// pinned MILESTONES.md and PROJECT.md as identically workstream-scoped
|
||||
@@ -368,17 +368,17 @@ describe('complete-milestone.md workstream-scoped paths (#4455)', () => {
|
||||
const requirementsPath = path.join(tmpDir, 'REQUIREMENTS-root.md');
|
||||
fs.writeFileSync(requirementsPath, '# Requirements\n');
|
||||
fs.mkdirSync(path.join(tmpDir, '.git'), { recursive: true }); // git rm needs a repo; the stub below intercepts it
|
||||
const script = `git() { printf 'git_call:%s\\n' "$*"; }\n${stubGsdRun({ requirements_path: requirementsPath })}${requirementsRmFence}`;
|
||||
const script = `git() { printf 'git_call:%s\\n' "$*"; }\n${stubMsdRun({ requirements_path: requirementsPath })}${requirementsRmFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <requirements rm fence>');
|
||||
assert.ok(r.stdout.includes(`git_call:rm ${requirementsPath}`),
|
||||
`expected git rm to target the root REQUIREMENTS.md, got: ${r.stdout}`);
|
||||
});
|
||||
|
||||
test('GSD_WORKSTREAM=alpha: removes the workstream-scoped REQUIREMENTS.md, not root (#4455 follow-up regression)', () => {
|
||||
test('MSD_WORKSTREAM=alpha: removes the workstream-scoped REQUIREMENTS.md, not root (#4455 follow-up regression)', () => {
|
||||
const wsRequirementsPath = path.join(tmpDir, 'REQUIREMENTS-alpha.md');
|
||||
fs.writeFileSync(wsRequirementsPath, '# Requirements\n');
|
||||
const script = `git() { printf 'git_call:%s\\n' "$*"; }\n${stubGsdRun({ requirements_path: wsRequirementsPath })}${requirementsRmFence}`;
|
||||
const script = `git() { printf 'git_call:%s\\n' "$*"; }\n${stubMsdRun({ requirements_path: wsRequirementsPath })}${requirementsRmFence}`;
|
||||
const r = runHookSeam('-c', [script], { interpreter: 'bash', cwd: tmpDir });
|
||||
throwIfFailed(r, 'bash <requirements rm fence>');
|
||||
assert.ok(r.stdout.includes(`git_call:rm ${wsRequirementsPath}`),
|
||||
|
||||
Reference in New Issue
Block a user