diff --git a/.changeset/clever-ravens-romp.md b/.changeset/clever-ravens-romp.md new file mode 100644 index 000000000..3c806c7fc --- /dev/null +++ b/.changeset/clever-ravens-romp.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 3130 +--- +**`phase complete` no longer advances `next_phase` into 999.x backlog headings** — the roadmap heading scan (stage 2 of the next-phase cascade) accepted any higher-numbered heading without checking the sentinel convention, so a `Phase 999.1: Backlog Item` heading was treated as the next real phase. Sentinel phase ids (999.x backlog, 0.x drafts) are now skipped. (#2786) diff --git a/src/phase.cts b/src/phase.cts index e49d11bc5..6f6466c48 100644 --- a/src/phase.cts +++ b/src/phase.cts @@ -2576,6 +2576,11 @@ function cmdPhaseComplete(cwd: string, phaseNum: string, raw: boolean): void { ); let pm: RegExpExecArray | null; while ((pm = phasePattern.exec(roadmapForPhases)) !== null) { + // #2786: skip sentinel phase ids (999.x backlog, 0.x drafts) — stage 1 + // already skips 999 dirs on disk; stage 2's heading scan must not + // advance into backlog headings. Mirrors the /^999(?:\.|$)/ guard + // stage 1 uses at line 2536, but via isSentinelPhaseId for both ranges. + if (isSentinelPhaseId(pm[1])) continue; if (comparePhaseNum(pm[1], phaseNum) > 0) { nextPhaseNum = pm[1]; nextPhaseName = pm[2]