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:
@@ -3,10 +3,10 @@
|
||||
// runtime loads — testing text content tests the deployed contract.
|
||||
|
||||
/**
|
||||
* GSD Code Review Tests
|
||||
* MSD Code Review Tests
|
||||
*
|
||||
* Validates all code review artifacts from Phases 1-4:
|
||||
* - Agent frontmatter (gsd-code-reviewer, gsd-code-fixer)
|
||||
* - Agent frontmatter (msd-code-reviewer, msd-code-fixer)
|
||||
* - Command structure (code-review.md, code-review-fix.md)
|
||||
* - Workflow structure (code-review.md, code-review-fix.md)
|
||||
* - Config key registration (workflow.code_review, workflow.code_review_depth)
|
||||
@@ -24,8 +24,8 @@ const { test, describe } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { scanFencedBlocks } = require('../gsd-core/bin/lib/markdown-sectionizer.cjs');
|
||||
const { splitLines } = require('../gsd-core/bin/lib/text-lines.cjs');
|
||||
const { scanFencedBlocks } = require('../msd-core/bin/lib/markdown-sectionizer.cjs');
|
||||
const { splitLines } = require('../msd-core/bin/lib/text-lines.cjs');
|
||||
|
||||
/** Return the raw text of every ```bash fenced block in `content`. */
|
||||
function extractBashBlocks(content) {
|
||||
@@ -39,19 +39,19 @@ function extractBashBlocks(content) {
|
||||
return blocks;
|
||||
}
|
||||
const os = require('os');
|
||||
const { runGsdTools, createTempProject, createTempGitProject, cleanup } = require('./helpers.cjs');
|
||||
const { runMsdTools, createTempProject, createTempGitProject, cleanup } = require('./helpers.cjs');
|
||||
const { runNode } = require('./helpers/process-seam.cjs');
|
||||
const { escapeRegex } = require('../gsd-core/bin/lib/pattern.cjs');
|
||||
const { escapeRegex } = require('../msd-core/bin/lib/pattern.cjs');
|
||||
const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, '..');
|
||||
const GSD_TOOLS_BIN = path.join(REPO_ROOT, 'gsd-core', 'bin', 'gsd-tools.cjs');
|
||||
const MSD_TOOLS_BIN = path.join(REPO_ROOT, 'msd-core', 'bin', 'msd-tools.cjs');
|
||||
|
||||
// --- Test Environment Setup ---
|
||||
|
||||
const AGENTS_DIR = path.join(__dirname, '..', 'agents');
|
||||
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
|
||||
const WORKFLOWS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows');
|
||||
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'msd');
|
||||
const WORKFLOWS_DIR = path.join(__dirname, '..', 'msd-core', 'workflows');
|
||||
|
||||
/**
|
||||
* Parse top-level (non-nested, non-escaped) Skill() invocations from a workflow .md file.
|
||||
@@ -189,130 +189,130 @@ function parseSkillCallBody(body) {
|
||||
}
|
||||
|
||||
// Plugin directory resolution (cross-platform safe)
|
||||
const PLUGIN_WORKFLOWS_DIR = process.env.GSD_PLUGIN_ROOT || path.join(os.homedir(), '.claude', 'gsd-core', 'workflows');
|
||||
const PLUGIN_WORKFLOWS_DIR = process.env.MSD_PLUGIN_ROOT || path.join(os.homedir(), '.claude', 'msd-core', 'workflows');
|
||||
const PLUGIN_AVAILABLE = fs.existsSync(PLUGIN_WORKFLOWS_DIR);
|
||||
|
||||
// --- CR-AGENT: code review agent frontmatter ---
|
||||
|
||||
describe('CR-AGENT: code review agent frontmatter', () => {
|
||||
test('gsd-code-reviewer.md has required frontmatter fields', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-reviewer.md'), 'utf-8');
|
||||
test('msd-code-reviewer.md has required frontmatter fields', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-reviewer.md'), 'utf-8');
|
||||
const frontmatter = content.split('---')[1] || '';
|
||||
|
||||
assert.ok(frontmatter.includes('name:'), 'gsd-code-reviewer missing name:');
|
||||
assert.ok(frontmatter.includes('description:'), 'gsd-code-reviewer missing description:');
|
||||
assert.ok(frontmatter.includes('tools:'), 'gsd-code-reviewer missing tools:');
|
||||
assert.ok(frontmatter.includes('color:'), 'gsd-code-reviewer missing color:');
|
||||
assert.ok(frontmatter.includes('name:'), 'msd-code-reviewer missing name:');
|
||||
assert.ok(frontmatter.includes('description:'), 'msd-code-reviewer missing description:');
|
||||
assert.ok(frontmatter.includes('tools:'), 'msd-code-reviewer missing tools:');
|
||||
assert.ok(frontmatter.includes('color:'), 'msd-code-reviewer missing color:');
|
||||
});
|
||||
|
||||
test('gsd-code-fixer.md has required frontmatter fields', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('msd-code-fixer.md has required frontmatter fields', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
const frontmatter = content.split('---')[1] || '';
|
||||
|
||||
assert.ok(frontmatter.includes('name:'), 'gsd-code-fixer missing name:');
|
||||
assert.ok(frontmatter.includes('description:'), 'gsd-code-fixer missing description:');
|
||||
assert.ok(frontmatter.includes('tools:'), 'gsd-code-fixer missing tools:');
|
||||
assert.ok(frontmatter.includes('color:'), 'gsd-code-fixer missing color:');
|
||||
assert.ok(frontmatter.includes('name:'), 'msd-code-fixer missing name:');
|
||||
assert.ok(frontmatter.includes('description:'), 'msd-code-fixer missing description:');
|
||||
assert.ok(frontmatter.includes('tools:'), 'msd-code-fixer missing tools:');
|
||||
assert.ok(frontmatter.includes('color:'), 'msd-code-fixer missing color:');
|
||||
});
|
||||
|
||||
test('gsd-code-reviewer.md has Read, Bash, Glob, Grep, Write tools', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-reviewer.md'), 'utf-8');
|
||||
test('msd-code-reviewer.md has Read, Bash, Glob, Grep, Write tools', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-reviewer.md'), 'utf-8');
|
||||
const frontmatter = content.split('---')[1] || '';
|
||||
|
||||
assert.ok(frontmatter.includes('Read'), 'gsd-code-reviewer missing Read tool');
|
||||
assert.ok(frontmatter.includes('Bash'), 'gsd-code-reviewer missing Bash tool');
|
||||
assert.ok(frontmatter.includes('Glob'), 'gsd-code-reviewer missing Glob tool');
|
||||
assert.ok(frontmatter.includes('Grep'), 'gsd-code-reviewer missing Grep tool');
|
||||
assert.ok(frontmatter.includes('Write'), 'gsd-code-reviewer missing Write tool');
|
||||
assert.ok(frontmatter.includes('Read'), 'msd-code-reviewer missing Read tool');
|
||||
assert.ok(frontmatter.includes('Bash'), 'msd-code-reviewer missing Bash tool');
|
||||
assert.ok(frontmatter.includes('Glob'), 'msd-code-reviewer missing Glob tool');
|
||||
assert.ok(frontmatter.includes('Grep'), 'msd-code-reviewer missing Grep tool');
|
||||
assert.ok(frontmatter.includes('Write'), 'msd-code-reviewer missing Write tool');
|
||||
});
|
||||
|
||||
test('gsd-code-fixer.md has Read, Edit, Write, Bash, Grep, Glob tools', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('msd-code-fixer.md has Read, Edit, Write, Bash, Grep, Glob tools', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
const frontmatter = content.split('---')[1] || '';
|
||||
|
||||
assert.ok(frontmatter.includes('Read'), 'gsd-code-fixer missing Read tool');
|
||||
assert.ok(frontmatter.includes('Edit'), 'gsd-code-fixer missing Edit tool');
|
||||
assert.ok(frontmatter.includes('Write'), 'gsd-code-fixer missing Write tool');
|
||||
assert.ok(frontmatter.includes('Bash'), 'gsd-code-fixer missing Bash tool');
|
||||
assert.ok(frontmatter.includes('Read'), 'msd-code-fixer missing Read tool');
|
||||
assert.ok(frontmatter.includes('Edit'), 'msd-code-fixer missing Edit tool');
|
||||
assert.ok(frontmatter.includes('Write'), 'msd-code-fixer missing Write tool');
|
||||
assert.ok(frontmatter.includes('Bash'), 'msd-code-fixer missing Bash tool');
|
||||
});
|
||||
|
||||
test('gsd-code-reviewer.md does not have skills: in frontmatter', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-reviewer.md'), 'utf-8');
|
||||
test('msd-code-reviewer.md does not have skills: in frontmatter', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-reviewer.md'), 'utf-8');
|
||||
const frontmatter = content.split('---')[1] || '';
|
||||
|
||||
assert.ok(!frontmatter.includes('skills:'),
|
||||
'gsd-code-reviewer has skills: in frontmatter — breaks Gemini CLI');
|
||||
'msd-code-reviewer has skills: in frontmatter — breaks Gemini CLI');
|
||||
});
|
||||
|
||||
test('gsd-code-fixer.md does not have skills: in frontmatter', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('msd-code-fixer.md does not have skills: in frontmatter', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
const frontmatter = content.split('---')[1] || '';
|
||||
|
||||
assert.ok(!frontmatter.includes('skills:'),
|
||||
'gsd-code-fixer has skills: in frontmatter — breaks Gemini CLI');
|
||||
'msd-code-fixer has skills: in frontmatter — breaks Gemini CLI');
|
||||
});
|
||||
|
||||
test('gsd-code-fixer.md rollback uses git checkout (not Write tool)', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('msd-code-fixer.md rollback uses git checkout (not Write tool)', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
assert.ok(content.includes('git checkout --'),
|
||||
'gsd-code-fixer rollback should use git checkout -- {file} for atomic rollback');
|
||||
'msd-code-fixer rollback should use git checkout -- {file} for atomic rollback');
|
||||
assert.ok(!content.includes('PRE_FIX_CONTENT'),
|
||||
'gsd-code-fixer should not use PRE_FIX_CONTENT in-memory capture (use git checkout instead)');
|
||||
'msd-code-fixer should not use PRE_FIX_CONTENT in-memory capture (use git checkout instead)');
|
||||
});
|
||||
|
||||
test('gsd-code-fixer.md success_criteria consistent with rollback strategy (git checkout)', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('msd-code-fixer.md success_criteria consistent with rollback strategy (git checkout)', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
// eslint-disable-next-line local/no-unbounded-quantifier -- parses this repo's own agent .md content, fixed-size author-controlled content
|
||||
const successCriteria = content.match(/<success_criteria>([\s\S]*?)<\/success_criteria>/)?.[1] || '';
|
||||
assert.ok(successCriteria.includes('git checkout'),
|
||||
'gsd-code-fixer success_criteria must reference git checkout rollback');
|
||||
'msd-code-fixer success_criteria must reference git checkout rollback');
|
||||
assert.ok(!successCriteria.includes('Write tool with captured'),
|
||||
'gsd-code-fixer success_criteria must not say Write tool for rollback');
|
||||
'msd-code-fixer success_criteria must not say Write tool for rollback');
|
||||
});
|
||||
|
||||
test('gsd-code-fixer.md flags logic-bug fixes for human review', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('msd-code-fixer.md flags logic-bug fixes for human review', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
assert.ok(content.includes('requires human verification'),
|
||||
'gsd-code-fixer should flag logic-bug fixes as requiring human verification');
|
||||
'msd-code-fixer should flag logic-bug fixes as requiring human verification');
|
||||
});
|
||||
|
||||
test('gsd-code-reviewer.md REVIEW.md spec includes files_reviewed_list field', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-reviewer.md'), 'utf-8');
|
||||
test('msd-code-reviewer.md REVIEW.md spec includes files_reviewed_list field', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-reviewer.md'), 'utf-8');
|
||||
assert.ok(content.includes('files_reviewed_list'),
|
||||
'gsd-code-reviewer REVIEW.md frontmatter spec must include files_reviewed_list for --auto scope persistence');
|
||||
'msd-code-reviewer REVIEW.md frontmatter spec must include files_reviewed_list for --auto scope persistence');
|
||||
});
|
||||
|
||||
// #2825: gsd-code-fixer is the only writer that hand-rolls a git worktree; it
|
||||
// #2825: msd-code-fixer is the only writer that hand-rolls a git worktree; it
|
||||
// must honor workflow.use_worktrees (the documented opt-out) like its four
|
||||
// sibling writer workflows, and never rm -rf a possible Windows reparse point.
|
||||
test('#2825 gsd-code-fixer.md reads workflow.use_worktrees and gates git worktree add on it', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('#2825 msd-code-fixer.md reads workflow.use_worktrees and gates git worktree add on it', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
assert.ok(
|
||||
content.includes('workflow.use_worktrees'),
|
||||
'gsd-code-fixer setup_worktree must read the workflow.use_worktrees config flag (#2825)',
|
||||
'msd-code-fixer setup_worktree must read the workflow.use_worktrees config flag (#2825)',
|
||||
);
|
||||
// The git worktree add must be CONDITIONAL on the flag, not unconditional.
|
||||
// Locate the worktree-add line and confirm a USE_WORKTREES gate precedes it.
|
||||
assert.ok(
|
||||
/USE_WORKTREES=.false./.test(content) || content.includes('if [ "$USE_WORKTREES" = "false" ]'),
|
||||
'gsd-code-fixer must gate worktree creation on USE_WORKTREES=false (skip when opted out) (#2825)',
|
||||
'msd-code-fixer must gate worktree creation on USE_WORKTREES=false (skip when opted out) (#2825)',
|
||||
);
|
||||
});
|
||||
|
||||
test('#2825 gsd-code-fixer.md forbids rm -rf on a possible reparse point (Windows junction safety)', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('#2825 msd-code-fixer.md forbids rm -rf on a possible reparse point (Windows junction safety)', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
assert.ok(
|
||||
/rm -rf.*reparse point|reparse point.*rm -rf|NEVER .rm -rf.|never use .rm -rf/i.test(content),
|
||||
'gsd-code-fixer must forbid rm -rf on a possible reparse point/junction (#2825) — on Windows that is the delete-the-target path',
|
||||
'msd-code-fixer must forbid rm -rf on a possible reparse point/junction (#2825) — on Windows that is the delete-the-target path',
|
||||
);
|
||||
});
|
||||
|
||||
test('#2825 gsd-code-fixer.md records where verification ran (main checkout vs worktree)', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-code-fixer.md'), 'utf-8');
|
||||
test('#2825 msd-code-fixer.md records where verification ran (main checkout vs worktree)', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'msd-code-fixer.md'), 'utf-8');
|
||||
assert.ok(
|
||||
// eslint-disable-next-line local/no-unbounded-quantifier -- parses this repo's own agent .md content, fixed-size author-controlled content
|
||||
/verification[\s\S]*(main checkout|worktree)|(main checkout|worktree)[\s\S]*verification/i.test(content),
|
||||
'gsd-code-fixer REVIEW-FIX.md must record where verification ran (main checkout vs worktree) so a reader knows if the numbers are reproducible (#2825)',
|
||||
'msd-code-fixer REVIEW-FIX.md must record where verification ran (main checkout vs worktree) so a reader knows if the numbers are reproducible (#2825)',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -320,11 +320,11 @@ describe('CR-AGENT: code review agent frontmatter', () => {
|
||||
// --- CR-CMD: code review command structure ---
|
||||
|
||||
describe('CR-CMD: code review command structure', () => {
|
||||
test('code-review.md has correct frontmatter name: gsd:code-review', () => {
|
||||
test('code-review.md has correct frontmatter name: msd:code-review', () => {
|
||||
const content = fs.readFileSync(path.join(COMMANDS_DIR, 'code-review.md'), 'utf-8');
|
||||
const frontmatter = content.split('---')[1] || '';
|
||||
|
||||
assert.ok(frontmatter.includes('name: gsd:code-review'),
|
||||
assert.ok(frontmatter.includes('name: msd:code-review'),
|
||||
'code-review.md missing correct name in frontmatter');
|
||||
});
|
||||
|
||||
@@ -396,11 +396,11 @@ describe('CR-WORKFLOW: code review workflow structure', () => {
|
||||
'code-review.md workflow missing check_config_gate step');
|
||||
});
|
||||
|
||||
test('code-review.md workflow references gsd-code-reviewer agent', () => {
|
||||
test('code-review.md workflow references msd-code-reviewer agent', () => {
|
||||
const content = fs.readFileSync(path.join(WORKFLOWS_DIR, 'code-review.md'), 'utf-8');
|
||||
|
||||
assert.ok(content.includes('gsd-code-reviewer'),
|
||||
'code-review.md workflow does not reference gsd-code-reviewer agent');
|
||||
assert.ok(content.includes('msd-code-reviewer'),
|
||||
'code-review.md workflow does not reference msd-code-reviewer agent');
|
||||
});
|
||||
|
||||
test('code-review-fix.md workflow has <step name="initialize">', () => {
|
||||
@@ -410,11 +410,11 @@ describe('CR-WORKFLOW: code review workflow structure', () => {
|
||||
'code-review-fix.md workflow missing initialize step');
|
||||
});
|
||||
|
||||
test('code-review-fix.md workflow references gsd-code-fixer agent', () => {
|
||||
test('code-review-fix.md workflow references msd-code-fixer agent', () => {
|
||||
const content = fs.readFileSync(path.join(WORKFLOWS_DIR, 'code-review-fix.md'), 'utf-8');
|
||||
|
||||
assert.ok(content.includes('gsd-code-fixer'),
|
||||
'code-review-fix.md workflow does not reference gsd-code-fixer agent');
|
||||
assert.ok(content.includes('msd-code-fixer'),
|
||||
'code-review-fix.md workflow does not reference msd-code-fixer agent');
|
||||
});
|
||||
|
||||
test('code-review-fix.md workflow has iteration cap', () => {
|
||||
@@ -456,7 +456,7 @@ describe('CR-WORKFLOW: code review workflow structure', () => {
|
||||
'code-review-fix.md should use portable while-read loop instead of mapfile');
|
||||
});
|
||||
|
||||
// #3661: configurable code-review hook point (see .gsd/phase/feat-3661-code-review-hook-point/
|
||||
// #3661: configurable code-review hook point (see .msd/phase/feat-3661-code-review-hook-point/
|
||||
// 40-design.md and 50-test-matrix.md Section G) — manual invocation reads
|
||||
// workflow.code_review directly (independent of the automatic loop-point
|
||||
// selector workflow.code_review_point) instead of gating on registry
|
||||
@@ -474,8 +474,8 @@ describe('CR-WORKFLOW: code review workflow structure', () => {
|
||||
const stepContent = extractStepBody(content, 'check_config_gate');
|
||||
assert.ok(stepContent, 'code-review.md missing check_config_gate step');
|
||||
|
||||
assert.ok(/gsd_run query config-get workflow\.code_review\b/.test(stepContent),
|
||||
'check_config_gate must read workflow.code_review via gsd_run query config-get');
|
||||
assert.ok(/msd_run query config-get workflow\.code_review\b/.test(stepContent),
|
||||
'check_config_gate must read workflow.code_review via msd_run query config-get');
|
||||
});
|
||||
|
||||
test('G2: checkConfigGateNoLongerProbesExecutePostHooks', () => {
|
||||
@@ -560,7 +560,7 @@ describe('CR-CONFIG: config key registration', () => {
|
||||
test('config-set accepts workflow.code_review', () => {
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const result = runGsdTools('config-set workflow.code_review true', tmpDir);
|
||||
const result = runMsdTools('config-set workflow.code_review true', tmpDir);
|
||||
assert.ok(result.success, `config-set should accept workflow.code_review: ${result.error}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
@@ -570,7 +570,7 @@ describe('CR-CONFIG: config key registration', () => {
|
||||
test('config-set accepts workflow.code_review_depth', () => {
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const result = runGsdTools('config-set workflow.code_review_depth standard', tmpDir);
|
||||
const result = runMsdTools('config-set workflow.code_review_depth standard', tmpDir);
|
||||
assert.ok(result.success, `config-set should accept workflow.code_review_depth: ${result.error}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
@@ -581,10 +581,10 @@ describe('CR-CONFIG: config key registration', () => {
|
||||
const tmpDir = createTempProject();
|
||||
t.after(() => cleanup(tmpDir));
|
||||
|
||||
const setResult = runGsdTools(['config-set', 'workflow.code_review', 'true'], tmpDir);
|
||||
const setResult = runMsdTools(['config-set', 'workflow.code_review', 'true'], tmpDir);
|
||||
assert.ok(setResult.success, `config-set workflow.code_review failed: ${setResult.error}`);
|
||||
|
||||
const getResult = runGsdTools(['config-get', 'workflow.code_review'], tmpDir);
|
||||
const getResult = runMsdTools(['config-get', 'workflow.code_review'], tmpDir);
|
||||
assert.ok(getResult.success, `config-get workflow.code_review failed: ${getResult.error}`);
|
||||
assert.strictEqual(getResult.output, 'true',
|
||||
`workflow.code_review should return "true", got ${getResult.output}`);
|
||||
@@ -594,23 +594,23 @@ describe('CR-CONFIG: config key registration', () => {
|
||||
const tmpDir = createTempProject();
|
||||
t.after(() => cleanup(tmpDir));
|
||||
|
||||
const setResult = runGsdTools(['config-set', 'workflow.code_review_depth', 'standard'], tmpDir);
|
||||
const setResult = runMsdTools(['config-set', 'workflow.code_review_depth', 'standard'], tmpDir);
|
||||
assert.ok(setResult.success, `config-set workflow.code_review_depth failed: ${setResult.error}`);
|
||||
|
||||
const getResult = runGsdTools(['config-get', 'workflow.code_review_depth'], tmpDir);
|
||||
const getResult = runMsdTools(['config-get', 'workflow.code_review_depth'], tmpDir);
|
||||
assert.ok(getResult.success, `config-get workflow.code_review_depth failed: ${getResult.error}`);
|
||||
assert.strictEqual(getResult.output, '"standard"',
|
||||
`workflow.code_review_depth should return '"standard"', got ${getResult.output}`);
|
||||
});
|
||||
|
||||
// ── #3661: workflow.code_review_point — CLI-behavioral (50-test-matrix.md
|
||||
// Section F, rows F4-F7). Uses createTempGitProject + runGsdTools + the real
|
||||
// gsd-tools subprocess (via runNode), not source-grep, per the matrix's
|
||||
// Section F, rows F4-F7). Uses createTempGitProject + runMsdTools + the real
|
||||
// msd-tools subprocess (via runNode), not source-grep, per the matrix's
|
||||
// coverage-strategy note.
|
||||
|
||||
function renderHooksEnvelope(tmpDir, point) {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'loop', 'render-hooks', point, '--cwd', tmpDir],
|
||||
[MSD_TOOLS_BIN, 'loop', 'render-hooks', point, '--cwd', tmpDir],
|
||||
{ cwd: REPO_ROOT, timeoutMs: PROBE_TIMEOUT_MS },
|
||||
);
|
||||
assert.strictEqual(result.exitCode, 0, `Expected exit 0 for render-hooks ${point}. stderr: ` + (result.stderr || ''));
|
||||
@@ -639,7 +639,7 @@ describe('CR-CONFIG: config key registration', () => {
|
||||
const tmpDir = createTempGitProject();
|
||||
t.after(() => cleanup(tmpDir));
|
||||
|
||||
const setResult = runGsdTools(['config-set', 'workflow.code_review_point', 'execute:wave:post'], tmpDir);
|
||||
const setResult = runMsdTools(['config-set', 'workflow.code_review_point', 'execute:wave:post'], tmpDir);
|
||||
assert.ok(setResult.success, `config-set workflow.code_review_point failed: ${setResult.error}`);
|
||||
|
||||
const postEnvelope = renderHooksEnvelope(tmpDir, 'execute:post');
|
||||
@@ -654,7 +654,7 @@ describe('CR-CONFIG: config key registration', () => {
|
||||
const tmpDir = createTempProject();
|
||||
t.after(() => cleanup(tmpDir));
|
||||
|
||||
const result = runGsdTools(['config-set', 'workflow.code_review_point', 'bogus'], tmpDir);
|
||||
const result = runMsdTools(['config-set', 'workflow.code_review_point', 'bogus'], tmpDir);
|
||||
assert.strictEqual(result.success, false, 'config-set must reject an out-of-enum workflow.code_review_point value');
|
||||
assert.match(
|
||||
result.error || '',
|
||||
@@ -663,7 +663,7 @@ describe('CR-CONFIG: config key registration', () => {
|
||||
);
|
||||
|
||||
// The rejected value must not have been persisted.
|
||||
const getResult = runGsdTools(['config-get', 'workflow.code_review_point'], tmpDir);
|
||||
const getResult = runMsdTools(['config-get', 'workflow.code_review_point'], tmpDir);
|
||||
assert.ok(getResult.success, `config-get workflow.code_review_point failed: ${getResult.error}`);
|
||||
assert.notStrictEqual(getResult.output, '"bogus"', 'out-of-enum value must not be silently accepted/persisted');
|
||||
});
|
||||
@@ -713,20 +713,20 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
// a genuine hang, not a test artifact (#4209 round 5, BL-01). This test's subject is the
|
||||
// FENCE's own bash control flow (CODE_REVIEW_POINT/EXPLICIT_JOINED computed correctly and
|
||||
// threaded into dispatch-step's argv) — not the external CLI dispatch-step goes on to spawn.
|
||||
// `gsd_run` stays real for `config-get`/`review-lane explicit-from-argv` (what this test
|
||||
// `msd_run` stays real for `config-get`/`review-lane explicit-from-argv` (what this test
|
||||
// verifies) and is short-circuited ONLY for `review-lane dispatch-step`, whose argv is
|
||||
// captured to a file for assertion instead of executed for real.
|
||||
const driver = [
|
||||
`GSD_TOOLS=${JSON.stringify(GSD_TOOLS_BIN)}`,
|
||||
`MSD_TOOLS=${JSON.stringify(MSD_TOOLS_BIN)}`,
|
||||
`DISPATCH_ARGS_PATH=${JSON.stringify(dispatchArgsPath)}`,
|
||||
'gsd_run() {',
|
||||
'msd_run() {',
|
||||
' if [ "$1" = "review-lane" ] && [ "$2" = "dispatch-step" ]; then',
|
||||
' printf \'%s\\n\' "$@" > "$DISPATCH_ARGS_PATH"',
|
||||
' cat >/dev/null',
|
||||
' echo \'{"ok":true,"dispatched":false,"selection":{},"results":[]}\'',
|
||||
' return 0',
|
||||
' fi',
|
||||
' node "$GSD_TOOLS" "$@"',
|
||||
' node "$MSD_TOOLS" "$@"',
|
||||
'}',
|
||||
`REPO_ROOT=${JSON.stringify(tmpDir)}`,
|
||||
'REVIEW_DEPTH=standard',
|
||||
@@ -785,7 +785,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
const tmpDir = createTempGitProject();
|
||||
try {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
[MSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
'--repo-root', tmpDir, '--depth', 'standard', '--base-sha', 'deadbeef',
|
||||
'--run-dir', tmpDir, '--cwd', tmpDir, '--explicit', 'not-a-real-reviewer-xyz',
|
||||
'--cap-id', 'code-review', '--point', 'execute:post', '--raw'],
|
||||
@@ -808,7 +808,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
const tmpDir = createTempGitProject();
|
||||
try {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
[MSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
'--repo-root', tmpDir, '--depth', 'standard', '--base-sha', 'deadbeef',
|
||||
'--run-dir', tmpDir, '--cwd', tmpDir, '--explicit', 'codex',
|
||||
'--cap-id', 'no-such-capability-xyz', '--point', 'execute:post', '--raw'],
|
||||
@@ -828,7 +828,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
const tmpDir = createTempGitProject();
|
||||
try {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
[MSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
'--repo-root', tmpDir, '--depth', 'standard', '--base-sha', 'deadbeef',
|
||||
'--run-dir', tmpDir, '--cwd', tmpDir, '--explicit', 'codex', '--raw'],
|
||||
{ cwd: REPO_ROOT, timeoutMs: PROBE_TIMEOUT_MS, input: 'src/foo.ts\n' },
|
||||
@@ -846,7 +846,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
const tmpDir = createTempGitProject();
|
||||
try {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
[MSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
'--repo-root', tmpDir, '--depth', 'standard', '--base-sha', 'deadbeef',
|
||||
'--run-dir', tmpDir, '--cwd', tmpDir, '--explicit', 'codex',
|
||||
'--cap-id', 'code-review', '--raw'],
|
||||
@@ -864,7 +864,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
|
||||
test('review-lane explicit-from-argv matches CLI flags against the merged roster (#4209 RQ-02)', () => {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'review-lane', 'explicit-from-argv', '--', '--codex', '--agy'],
|
||||
[MSD_TOOLS_BIN, 'review-lane', 'explicit-from-argv', '--', '--codex', '--agy'],
|
||||
{ cwd: REPO_ROOT, timeoutMs: PROBE_TIMEOUT_MS },
|
||||
);
|
||||
assert.strictEqual(result.exitCode, 0, `expected exit 0, stderr: ${result.stderr || ''}`);
|
||||
@@ -873,7 +873,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
|
||||
test('review-lane explicit-from-argv resolves to empty when no known flag is present', () => {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'review-lane', 'explicit-from-argv', '--'],
|
||||
[MSD_TOOLS_BIN, 'review-lane', 'explicit-from-argv', '--'],
|
||||
{ cwd: REPO_ROOT, timeoutMs: PROBE_TIMEOUT_MS },
|
||||
);
|
||||
assert.strictEqual(result.exitCode, 0, `expected exit 0, stderr: ${result.stderr || ''}`);
|
||||
@@ -896,7 +896,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
// eslint-disable-next-line local/no-unbounded-quantifier -- bounded author-controlled workflow markdown
|
||||
const stepMatch = workflowContent.match(/<step name="dispatch_reviewer_lanes">([\s\S]*?)<\/step>/);
|
||||
const stepContent = stepMatch[1];
|
||||
const calls = stepContent.match(/gsd_run review-lane dispatch-step/g) || [];
|
||||
const calls = stepContent.match(/msd_run review-lane dispatch-step/g) || [];
|
||||
assert.strictEqual(calls.length, 1,
|
||||
`dispatch_reviewer_lanes must call review-lane dispatch-step exactly once, found ${calls.length}`);
|
||||
});
|
||||
@@ -954,7 +954,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
const tmpDir = createTempGitProject();
|
||||
try {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
[MSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
'--repo-root', tmpDir, '--depth', 'standard', '--base-sha', 'deadbeef',
|
||||
'--run-dir', tmpDir, '--cwd', tmpDir,
|
||||
'--cap-id', 'code-review', '--point', 'execute:post', '--raw'],
|
||||
@@ -973,7 +973,7 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
const tmpDir = createTempGitProject();
|
||||
try {
|
||||
const result = runNode(
|
||||
[GSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
[MSD_TOOLS_BIN, 'review-lane', 'dispatch-step',
|
||||
'--repo-root', tmpDir, '--depth', 'standard', '--base-sha', 'deadbeef',
|
||||
'--run-dir', tmpDir, '--cwd', tmpDir, '--explicit', 'not-a-real-reviewer-xyz',
|
||||
'--cap-id', 'code-review', '--point', 'execute:post', '--raw'],
|
||||
@@ -1029,13 +1029,13 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
dispatched: true,
|
||||
ok: false,
|
||||
results: [
|
||||
{ slug: 'codex', ok: true, reviewPath: '/tmp/gsd-review-codex.md' },
|
||||
{ slug: 'codex', ok: true, reviewPath: '/tmp/msd-review-codex.md' },
|
||||
{ slug: 'agy', ok: false, reason: 'invoke_failed', detail: 'binary not found' },
|
||||
],
|
||||
}));
|
||||
assert.match(stderr, /external reviewer lane 'agy' failed \(invoke_failed: binary not found\)/,
|
||||
`expected a per-lane failure warning, got stderr: ${stderr}`);
|
||||
assert.strictEqual(stdout.trim(), '- codex: /tmp/gsd-review-codex.md',
|
||||
assert.strictEqual(stdout.trim(), '- codex: /tmp/msd-review-codex.md',
|
||||
'the lane that succeeded must still produce an evidence line');
|
||||
});
|
||||
|
||||
@@ -1045,10 +1045,10 @@ describe('CR-REVIEWER-LANES: optional external source-reviewer dispatch (#4209)'
|
||||
const payloadPath = path.join(tmpDir, 'dispatch-result.json');
|
||||
fs.writeFileSync(payloadPath, JSON.stringify({
|
||||
dispatched: true, ok: true,
|
||||
results: [{ slug: 'codex', ok: true, reviewPath: '/tmp/gsd-review-codex.md' }],
|
||||
results: [{ slug: 'codex', ok: true, reviewPath: '/tmp/msd-review-codex.md' }],
|
||||
}));
|
||||
const { stdout, stderr } = runReducer(`@file:${payloadPath}`);
|
||||
assert.strictEqual(stdout.trim(), '- codex: /tmp/gsd-review-codex.md',
|
||||
assert.strictEqual(stdout.trim(), '- codex: /tmp/msd-review-codex.md',
|
||||
`expected the @file:-wrapped payload to be unwrapped and parsed, got stdout: ${stdout} stderr: ${stderr}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
@@ -1082,7 +1082,7 @@ describe('CR-INTEGRATION: workflow integration points', () => {
|
||||
});
|
||||
|
||||
// #3661: the generic execute:wave:post step-dispatch contract
|
||||
// (loop-hook-dispatch.md § step) invokes `Skill(skill="gsd-<ref.skill>")` with no
|
||||
// (loop-hook-dispatch.md § step) invokes `Skill(skill="msd-<ref.skill>")` with no
|
||||
// phase argument, but code-review.md's `initialize` step requires one positionally
|
||||
// (`PHASE_ARG="${1}"`) — without it the review reports "Phase not found" and exits.
|
||||
// Caught by the orthogonal spec review; fixed with a precedented carve-out in step
|
||||
@@ -1096,8 +1096,8 @@ describe('CR-INTEGRATION: workflow integration points', () => {
|
||||
|
||||
assert.ok(stepContent.includes('ref.skill == "code-review"'),
|
||||
'step 5.75 must carve out ref.skill == "code-review" from the generic step-dispatch contract');
|
||||
assert.ok(/Skill\(skill="gsd-code-review",\s*args="\$\{PHASE_NUMBER\}"\)/.test(stepContent),
|
||||
'step 5.75 must dispatch code-review with an explicit args="${PHASE_NUMBER}", matching code_review_gate\'s invocation — the bare generic Skill(skill="gsd-<ref.skill>") form has no phase argument and code-review.md requires one');
|
||||
assert.ok(/Skill\(skill="msd-code-review",\s*args="\$\{PHASE_NUMBER\}"\)/.test(stepContent),
|
||||
'step 5.75 must dispatch code-review with an explicit args="${PHASE_NUMBER}", matching code_review_gate\'s invocation — the bare generic Skill(skill="msd-<ref.skill>") form has no phase argument and code-review.md requires one');
|
||||
});
|
||||
|
||||
test('execute-phase.md does NOT contain ls.*REVIEW.md.*head pattern', { skip: !PLUGIN_AVAILABLE ? 'Plugin dir not installed' : false }, () => {
|
||||
@@ -1125,12 +1125,12 @@ describe('CR-INTEGRATION: workflow integration points', () => {
|
||||
const start = content.indexOf('**Step 6.25: Code review (auto)**');
|
||||
// #2994 (pre-existing since #2994's earlier quick-verification.md extraction,
|
||||
// 18ff35d20): Step 6.5's content moved into
|
||||
// gsd-core/workflows/quick/steps/quick-verification.md behind a
|
||||
// `<!-- gsd:section id="quick-verification" -->` marker, so the literal
|
||||
// msd-core/workflows/quick/steps/quick-verification.md behind a
|
||||
// `<!-- msd:section id="quick-verification" -->` marker, so the literal
|
||||
// "**Step 6.5: Verification" heading text no longer follows Step 6.25 in
|
||||
// this file — the marker is the correct end-of-step delimiter now (mirrors
|
||||
// phase6-review-capabilities.test.cjs's identical retarget for the same move).
|
||||
const end = content.indexOf('<!-- gsd:section id="quick-verification"', start);
|
||||
const end = content.indexOf('<!-- msd:section id="quick-verification"', start);
|
||||
assert.ok(start !== -1 && end !== -1, 'quick.md missing Step 6.25 code review section');
|
||||
const reviewContent = content.slice(start, end);
|
||||
|
||||
@@ -1146,62 +1146,62 @@ describe('CR-INTEGRATION: workflow integration points', () => {
|
||||
// not the user-installed plugin dir. The plugin dir can lag behind the repo until the
|
||||
// user re-installs, so asserting against it produces false negatives. The repo file
|
||||
// is the source of truth and is always present in CI checkouts.
|
||||
test('autonomous.md contains gsd-code-review skill invocation', () => {
|
||||
test('autonomous.md contains msd-code-review skill invocation', () => {
|
||||
const content = fs.readFileSync(path.join(WORKFLOWS_DIR, 'autonomous.md'), 'utf-8');
|
||||
|
||||
// Parse Skill(...) invocations into structured objects and assert canonical
|
||||
// hyphen form is referenced. Canonical command form is hyphen
|
||||
// (gsd-code-review); colon form (gsd:code-review) is the legacy
|
||||
// (msd-code-review); colon form (msd:code-review) is the legacy
|
||||
// frontmatter-name form removed in PR #2819.
|
||||
const invocations = parseWorkflowSkillInvocations(content);
|
||||
const skillNames = invocations.map(inv => inv.skill);
|
||||
assert.ok(skillNames.includes('gsd-code-review'),
|
||||
`autonomous.md must invoke Skill(skill="gsd-code-review", ...); found skills: ${JSON.stringify(skillNames)}`);
|
||||
assert.ok(!skillNames.includes('gsd:code-review'),
|
||||
'autonomous.md must not use legacy colon form gsd:code-review (canonical is hyphen form)');
|
||||
assert.ok(skillNames.includes('msd-code-review'),
|
||||
`autonomous.md must invoke Skill(skill="msd-code-review", ...); found skills: ${JSON.stringify(skillNames)}`);
|
||||
assert.ok(!skillNames.includes('msd:code-review'),
|
||||
'autonomous.md must not use legacy colon form msd:code-review (canonical is hyphen form)');
|
||||
});
|
||||
|
||||
test('autonomous.md auto-fix uses consolidated gsd-code-review --fix invocation (#2790)', () => {
|
||||
// After #2790, gsd-code-review-fix was absorbed into gsd-code-review as
|
||||
test('autonomous.md auto-fix uses consolidated msd-code-review --fix invocation (#2790)', () => {
|
||||
// After #2790, msd-code-review-fix was absorbed into msd-code-review as
|
||||
// the --fix flag. The autonomous workflow must invoke the consolidated
|
||||
// form, not the deleted gsd-code-review-fix skill.
|
||||
// form, not the deleted msd-code-review-fix skill.
|
||||
const content = fs.readFileSync(path.join(WORKFLOWS_DIR, 'autonomous.md'), 'utf-8');
|
||||
|
||||
const invocations = parseWorkflowSkillInvocations(content);
|
||||
const skillNames = invocations.map(inv => inv.skill);
|
||||
assert.ok(!skillNames.includes('gsd-code-review-fix'),
|
||||
`autonomous.md must not invoke deleted gsd-code-review-fix skill (consolidated into --fix); found: ${JSON.stringify(skillNames)}`);
|
||||
assert.ok(!skillNames.includes('gsd:code-review-fix'),
|
||||
'autonomous.md must not use legacy colon form gsd:code-review-fix');
|
||||
assert.ok(!skillNames.includes('msd-code-review-fix'),
|
||||
`autonomous.md must not invoke deleted msd-code-review-fix skill (consolidated into --fix); found: ${JSON.stringify(skillNames)}`);
|
||||
assert.ok(!skillNames.includes('msd:code-review-fix'),
|
||||
'autonomous.md must not use legacy colon form msd:code-review-fix');
|
||||
|
||||
// Find a gsd-code-review invocation that carries the --fix flag (the
|
||||
// Find a msd-code-review invocation that carries the --fix flag (the
|
||||
// consolidated auto-fix entry point).
|
||||
const fixInvocation = invocations.find(inv => {
|
||||
if (inv.skill !== 'gsd-code-review') return false;
|
||||
if (inv.skill !== 'msd-code-review') return false;
|
||||
const tokens = new Set((inv.args ?? '').split(/\s+/).filter(Boolean));
|
||||
return tokens.has('--fix');
|
||||
});
|
||||
assert.ok(fixInvocation,
|
||||
`autonomous.md must invoke Skill(skill="gsd-code-review", args="... --fix ...") for auto-fix; found: ${JSON.stringify(invocations)}`);
|
||||
`autonomous.md must invoke Skill(skill="msd-code-review", args="... --fix ...") for auto-fix; found: ${JSON.stringify(invocations)}`);
|
||||
});
|
||||
|
||||
test('autonomous.md contains --auto flag on consolidated --fix invocation (#2790)', () => {
|
||||
const content = fs.readFileSync(path.join(WORKFLOWS_DIR, 'autonomous.md'), 'utf-8');
|
||||
|
||||
// Find the gsd-code-review invocation that carries --fix (the consolidated
|
||||
// Find the msd-code-review invocation that carries --fix (the consolidated
|
||||
// auto-fix entry point), then assert --auto is one of its arg tokens.
|
||||
// Tokenize via whitespace-split to avoid substring matches that could
|
||||
// conflate --auto with --auto-foo.
|
||||
const invocations = parseWorkflowSkillInvocations(content);
|
||||
const fixInvocation = invocations.find(inv => {
|
||||
if (inv.skill !== 'gsd-code-review') return false;
|
||||
if (inv.skill !== 'msd-code-review') return false;
|
||||
const tokens = new Set((inv.args ?? '').split(/\s+/).filter(Boolean));
|
||||
return tokens.has('--fix');
|
||||
});
|
||||
assert.ok(fixInvocation, 'autonomous.md missing Skill(skill="gsd-code-review", args="... --fix ...") invocation');
|
||||
assert.ok(fixInvocation, 'autonomous.md missing Skill(skill="msd-code-review", args="... --fix ...") invocation');
|
||||
const argTokens = new Set((fixInvocation.args ?? '').split(/\s+/).filter(Boolean));
|
||||
assert.ok(argTokens.has('--auto'),
|
||||
`autonomous.md gsd-code-review-fix args missing --auto flag; got args="${fixInvocation.args}"`);
|
||||
`autonomous.md msd-code-review-fix args missing --auto flag; got args="${fixInvocation.args}"`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1215,7 +1215,7 @@ describe('CR-INTEGRATION: workflow integration points', () => {
|
||||
/**
|
||||
* Regression test for bug #2839
|
||||
*
|
||||
* /gsd-code-review-fix cleanup tail is non-transactional. If the agent is
|
||||
* /msd-code-review-fix cleanup tail is non-transactional. If the agent is
|
||||
* interrupted (system restart, OOM kill) AFTER the last fix commit but
|
||||
* BEFORE `git worktree remove`, the worktree is orphaned in
|
||||
* `git worktree list`, the agent's branch is left with unmerged commits,
|
||||
@@ -1228,14 +1228,14 @@ describe('CR-INTEGRATION: workflow integration points', () => {
|
||||
* REMOVED only after `git worktree remove` completes, so the cleanup
|
||||
* tail is transactional from the orchestrator's perspective. If the
|
||||
* process dies in between, the sentinel is left behind pointing at the
|
||||
* orphan worktree and branch — a future run, /gsd-resume-work, or
|
||||
* /gsd-progress can detect and complete the recovery.
|
||||
* orphan worktree and branch — a future run, /msd-resume-work, or
|
||||
* /msd-progress can detect and complete the recovery.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// allow-test-rule: source-text-is-the-product (see #2839)
|
||||
// The gsd-code-fixer agent's working instructions ARE the product — Claude
|
||||
// The msd-code-fixer agent's working instructions ARE the product — Claude
|
||||
// follows them at runtime. Structural assertions over the markdown source
|
||||
// test the deployed contract. See bug-2686 for the same pattern.
|
||||
|
||||
@@ -1254,14 +1254,14 @@ function extractStep(content, stepName) {
|
||||
return m ? m[1] : null;
|
||||
}
|
||||
|
||||
describe('bug-2839: /gsd-code-review-fix cleanup is transactional', () => {
|
||||
describe('bug-2839: /msd-code-review-fix cleanup is transactional', () => {
|
||||
let agentPath;
|
||||
let agentContent;
|
||||
let frontmatter;
|
||||
|
||||
before(() => {
|
||||
agentPath = path.join(__dirname, '..', 'agents', 'gsd-code-fixer.md');
|
||||
assert.ok(fs.existsSync(agentPath), 'agents/gsd-code-fixer.md must exist');
|
||||
agentPath = path.join(__dirname, '..', 'agents', 'msd-code-fixer.md');
|
||||
assert.ok(fs.existsSync(agentPath), 'agents/msd-code-fixer.md must exist');
|
||||
agentContent = fs.readFileSync(agentPath, 'utf-8');
|
||||
frontmatter = parseFrontmatter(agentContent);
|
||||
assert.ok(frontmatter, 'agent must have YAML frontmatter');
|
||||
@@ -1270,7 +1270,7 @@ describe('bug-2839: /gsd-code-review-fix cleanup is transactional', () => {
|
||||
test('agent declares a recovery sentinel filename', () => {
|
||||
assert.ok(
|
||||
agentContent.includes(SENTINEL_NAME),
|
||||
`gsd-code-fixer.md must reference the recovery sentinel ${SENTINEL_NAME} so an interrupted cleanup tail is discoverable (#2839)`
|
||||
`msd-code-fixer.md must reference the recovery sentinel ${SENTINEL_NAME} so an interrupted cleanup tail is discoverable (#2839)`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1319,7 +1319,7 @@ describe('bug-2839: /gsd-code-review-fix cleanup is transactional', () => {
|
||||
for (const key of ['worktree_path', 'branch', 'padded_phase']) {
|
||||
assert.ok(
|
||||
agentContent.includes(key),
|
||||
`recovery sentinel must record \`${key}\` so a future /gsd-resume-work or /gsd-progress can locate the orphan state (#2839)`
|
||||
`recovery sentinel must record \`${key}\` so a future /msd-resume-work or /msd-progress can locate the orphan state (#2839)`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user