fix(3088): append missing STATE narrative sections on milestone close
This commit is contained in:
5
.changeset/fix-3088-milestone-state-fallback-sections.md
Normal file
5
.changeset/fix-3088-milestone-state-fallback-sections.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3122
|
||||
---
|
||||
**Milestone close now repairs missing STATE narrative sections** — when `## Current Position` or `## Operator Next Steps` headings are absent, milestone completion appends canonical sections so state remains deterministic and consistently points operators to `/gsd-new-milestone`.
|
||||
@@ -215,13 +215,20 @@ function cmdMilestoneComplete(cwd, version, options, raw) {
|
||||
`Last activity: ${today} — Milestone ${version} completed and archived\n\n`;
|
||||
if (positionPattern.test(stateContent)) {
|
||||
stateContent = stateContent.replace(positionPattern, (_m, header) => `${header}${closedPositionBody}`);
|
||||
} else {
|
||||
stateContent = `${stateContent.trimEnd()}\n\n## Current Position\n${closedPositionBody}`;
|
||||
}
|
||||
|
||||
// Normalize operator-next-step tails that can become stale after close.
|
||||
stateContent = stateContent.replace(
|
||||
/(##\s*Operator Next Steps\s*\n)([\s\S]*?)(?=\n##|$)/i,
|
||||
`$1\n- Start the next milestone with /gsd-new-milestone\n\n`,
|
||||
);
|
||||
const operatorPattern = /(##\s*Operator Next Steps\s*\n)([\s\S]*?)(?=\n##|$)/i;
|
||||
if (operatorPattern.test(stateContent)) {
|
||||
stateContent = stateContent.replace(
|
||||
operatorPattern,
|
||||
`$1\n- Start the next milestone with /gsd-new-milestone\n\n`,
|
||||
);
|
||||
} else {
|
||||
stateContent = `${stateContent.trimEnd()}\n\n## Operator Next Steps\n\n- Start the next milestone with /gsd-new-milestone\n`;
|
||||
}
|
||||
|
||||
writeStateMd(statePath, stateContent, cwd);
|
||||
}
|
||||
|
||||
@@ -1850,12 +1850,19 @@ export const milestoneComplete: QueryHandler = async (args, projectDir, workstre
|
||||
`Last activity: ${today} — Milestone ${version} completed and archived\n\n`;
|
||||
if (positionPattern.test(next)) {
|
||||
next = next.replace(positionPattern, (_m, header) => `${header}${closedPositionBody}`);
|
||||
} else {
|
||||
next = `${next.trimEnd()}\n\n## Current Position\n${closedPositionBody}`;
|
||||
}
|
||||
|
||||
next = next.replace(
|
||||
/(##\s*Operator Next Steps\s*\n)([\s\S]*?)(?=\n##|$)/i,
|
||||
`$1\n- Start the next milestone with /gsd-new-milestone\n\n`,
|
||||
);
|
||||
const operatorPattern = /(##\s*Operator Next Steps\s*\n)([\s\S]*?)(?=\n##|$)/i;
|
||||
if (operatorPattern.test(next)) {
|
||||
next = next.replace(
|
||||
operatorPattern,
|
||||
`$1\n- Start the next milestone with /gsd-new-milestone\n\n`,
|
||||
);
|
||||
} else {
|
||||
next = `${next.trimEnd()}\n\n## Operator Next Steps\n\n- Start the next milestone with /gsd-new-milestone\n`;
|
||||
}
|
||||
|
||||
return next;
|
||||
}, workstream);
|
||||
|
||||
@@ -247,6 +247,23 @@ describe('milestone complete command', () => {
|
||||
assert.ok(state.includes('/gsd-new-milestone'));
|
||||
});
|
||||
|
||||
test('appends canonical narrative sections when STATE.md headings are missing (#3088)', () => {
|
||||
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), `# Roadmap v1.0\n`);
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'STATE.md'),
|
||||
`# State\n\n**Status:** In progress\n**Last Activity:** 2025-01-01\n**Last Activity Description:** Working\n`
|
||||
);
|
||||
|
||||
const result = runGsdTools('milestone complete v1.0 --name Test', tmpDir);
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
|
||||
const state = fs.readFileSync(path.join(tmpDir, '.planning', 'STATE.md'), 'utf-8');
|
||||
assert.ok(state.includes('## Current Position'));
|
||||
assert.ok(state.includes('Phase: Milestone v1.0 complete'));
|
||||
assert.ok(state.includes('## Operator Next Steps'));
|
||||
assert.ok(state.includes('/gsd-new-milestone'));
|
||||
});
|
||||
|
||||
test('handles missing ROADMAP.md gracefully', () => {
|
||||
// Only STATE.md — no ROADMAP.md, no REQUIREMENTS.md
|
||||
fs.writeFileSync(
|
||||
|
||||
Reference in New Issue
Block a user