The .planning → .gsd migration creates roadmaps and summaries but not VALIDATION files. deriveState() requires a terminal validation file (verdict: pass) to consider a milestone complete. Without it, every migrated milestone enters validating-milestone phase, blocking progress to the actual current milestone. For milestones where all slices are done, write a pass-through VALIDATION.md (verdict: pass, migrated: true) and SUMMARY.md so deriveState() skips them correctly. Updated integration test to verify VALIDATION/SUMMARY files are written and deriveState returns 'complete' phase with activeMilestone pointing to the last completed entry (expected behavior).
This commit is contained in:
parent
1aebc06c46
commit
b44896e187
2 changed files with 51 additions and 6 deletions
|
|
@ -483,6 +483,45 @@ export async function writeGSDDirectory(
|
|||
counts.research++;
|
||||
}
|
||||
|
||||
// For fully-completed milestones (all slices done), write a pass-through
|
||||
// validation file so deriveState() doesn't enter validating-milestone
|
||||
// phase for historical milestones that predate the validation gate (#819).
|
||||
const allSlicesDone = milestone.slices.length > 0 && milestone.slices.every(s => s.done);
|
||||
if (allSlicesDone) {
|
||||
const validationPath = join(mDir, `${milestone.id}-VALIDATION.md`);
|
||||
const validationContent = [
|
||||
`---`,
|
||||
`verdict: pass`,
|
||||
`migrated: true`,
|
||||
`---`,
|
||||
``,
|
||||
`# ${milestone.id} Validation`,
|
||||
``,
|
||||
`Migrated milestone — all slices were completed in the original project.`,
|
||||
``,
|
||||
].join('\n');
|
||||
await saveFile(validationPath, validationContent);
|
||||
paths.push(validationPath);
|
||||
counts.other++;
|
||||
|
||||
// Also write a milestone summary if one doesn't exist
|
||||
const summaryPath = join(mDir, `${milestone.id}-SUMMARY.md`);
|
||||
const summaryContent = [
|
||||
`---`,
|
||||
`status: done`,
|
||||
`migrated: true`,
|
||||
`---`,
|
||||
``,
|
||||
`# ${milestone.id}: ${milestone.title}`,
|
||||
``,
|
||||
`Migrated from .planning — ${milestone.slices.length} slices completed.`,
|
||||
``,
|
||||
].join('\n');
|
||||
await saveFile(summaryPath, summaryContent);
|
||||
paths.push(summaryPath);
|
||||
counts.other++;
|
||||
}
|
||||
|
||||
// Slices
|
||||
for (const slice of milestone.slices) {
|
||||
const sDir = join(mDir, 'slices', slice.id);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { writeGSDDirectory } from '../migrate/writer.ts';
|
|||
import { generatePreview } from '../migrate/preview.ts';
|
||||
import { parseRoadmap, parsePlan, parseSummary } from '../files.ts';
|
||||
import { deriveState } from '../state.ts';
|
||||
import { invalidateAllCaches } from '../cache.ts';
|
||||
import type {
|
||||
GSDProject,
|
||||
GSDMilestone,
|
||||
|
|
@ -207,6 +208,7 @@ async function main(): Promise<void> {
|
|||
|
||||
// (e) deriveState
|
||||
console.log(' --- deriveState ---');
|
||||
invalidateAllCaches();
|
||||
const state = await deriveState(base);
|
||||
assertEq(state.phase, 'executing', 'incomplete: deriveState phase is executing');
|
||||
assertTrue(state.activeMilestone !== null, 'incomplete: deriveState has activeMilestone');
|
||||
|
|
@ -262,14 +264,18 @@ async function main(): Promise<void> {
|
|||
assertTrue(!existsSync(join(m, 'M001-RESEARCH.md')), 'complete: M001-RESEARCH.md NOT written (null)');
|
||||
// No REQUIREMENTS.md since empty requirements
|
||||
assertTrue(!existsSync(join(base, '.gsd', 'REQUIREMENTS.md')), 'complete: REQUIREMENTS.md NOT written (empty)');
|
||||
// Completed milestone should have VALIDATION and SUMMARY from migration (#819)
|
||||
assertTrue(existsSync(join(m, 'M001-VALIDATION.md')), 'complete: M001-VALIDATION.md written for completed milestone');
|
||||
assertTrue(existsSync(join(m, 'M001-SUMMARY.md')), 'complete: M001-SUMMARY.md written for completed milestone');
|
||||
|
||||
// deriveState: all slices done, all tasks done — needs validation then milestone summary
|
||||
// Without VALIDATION file, it should be 'validating-milestone'
|
||||
// deriveState: all slices done, all tasks done — migration now writes
|
||||
// VALIDATION.md and SUMMARY.md for completed milestones (#819),
|
||||
// so the milestone should be fully complete.
|
||||
invalidateAllCaches();
|
||||
const state = await deriveState(base);
|
||||
// All slices are done in roadmap. No VALIDATION or SUMMARY exists.
|
||||
// deriveState should return 'validating-milestone' since validation gate precedes completion.
|
||||
assertEq(state.phase, 'validating-milestone', 'complete: deriveState phase is validating-milestone');
|
||||
assertTrue(state.activeMilestone !== null, 'complete: deriveState has activeMilestone');
|
||||
assertEq(state.phase, 'complete', 'complete: deriveState phase is complete (validation + summary written by migration)');
|
||||
// When all milestones are complete, activeMilestone points to the last entry (for display)
|
||||
assertTrue(state.activeMilestone !== null, 'complete: deriveState has activeMilestone (last entry)');
|
||||
assertEq(state.activeMilestone!.id, 'M001', 'complete: deriveState activeMilestone is M001');
|
||||
|
||||
// generatePreview for complete project
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue