fix(init): prefer current milestone phase-op targets (#1068)
This commit is contained in:
@@ -365,6 +365,29 @@ function cmdInitPhaseOp(cwd, phase, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
let phaseInfo = findPhaseInternal(cwd, phase);
|
||||
|
||||
// If the only disk match comes from an archived milestone, prefer the
|
||||
// current milestone's ROADMAP entry so discuss-phase and similar flows
|
||||
// don't attach to shipped work that reused the same phase number.
|
||||
if (phaseInfo?.archived) {
|
||||
const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
|
||||
if (roadmapPhase?.found) {
|
||||
const phaseName = roadmapPhase.phase_name;
|
||||
phaseInfo = {
|
||||
found: true,
|
||||
directory: null,
|
||||
phase_number: roadmapPhase.phase_number,
|
||||
phase_name: phaseName,
|
||||
phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
|
||||
plans: [],
|
||||
summaries: [],
|
||||
incomplete_plans: [],
|
||||
has_research: false,
|
||||
has_context: false,
|
||||
has_verification: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to ROADMAP.md if no directory exists (e.g., Plans: TBD)
|
||||
if (!phaseInfo) {
|
||||
const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
|
||||
|
||||
@@ -475,6 +475,51 @@ describe('cmdInitPhaseOp fallback', () => {
|
||||
assert.strictEqual(output.has_plans, false);
|
||||
});
|
||||
|
||||
test('prefers current milestone roadmap entry over archived phase with same number', () => {
|
||||
const archiveDir = path.join(
|
||||
tmpDir,
|
||||
'.planning',
|
||||
'milestones',
|
||||
'v1.2-phases',
|
||||
'02-event-parser-and-queue-schema'
|
||||
);
|
||||
fs.mkdirSync(archiveDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(archiveDir, '02-CONTEXT.md'), '# Archived context');
|
||||
fs.writeFileSync(path.join(archiveDir, '02-01-PLAN.md'), '# Archived plan');
|
||||
fs.writeFileSync(path.join(archiveDir, '02-VERIFICATION.md'), '# Archived verification');
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
||||
`# Roadmap
|
||||
|
||||
<details>
|
||||
<summary>Shipped milestone v1.2</summary>
|
||||
|
||||
### Phase 2: Event Parser and Queue Schema
|
||||
**Goal:** Archived milestone work
|
||||
</details>
|
||||
|
||||
## Milestone v1.3 Current
|
||||
|
||||
### Phase 2: Retry Orchestration
|
||||
**Goal:** Current milestone work
|
||||
**Plans:** TBD
|
||||
`
|
||||
);
|
||||
|
||||
const result = runGsdTools('init phase-op 2', tmpDir);
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.phase_found, true);
|
||||
assert.strictEqual(output.phase_dir, null);
|
||||
assert.strictEqual(output.phase_name, 'Retry Orchestration');
|
||||
assert.strictEqual(output.phase_slug, 'retry-orchestration');
|
||||
assert.strictEqual(output.has_context, false);
|
||||
assert.strictEqual(output.has_plans, false);
|
||||
assert.strictEqual(output.has_verification, false);
|
||||
});
|
||||
|
||||
test('neither directory nor roadmap entry returns not found', () => {
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
||||
@@ -867,4 +912,3 @@ describe('cmdInitNewMilestone', () => {
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// roadmap analyze command
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user