* fix(#3262): guard phase writes against milestone-scope headings * fix(#3262): fill changeset pr with 3446 --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -26,7 +26,7 @@ const { SCOPE } = planningScopeMod;
|
||||
type Scope = planningScopeMod.Scope;
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import roadmapParserModule = require('./roadmap-parser.cjs');
|
||||
const { stripShippedMilestones, extractCurrentMilestone, extractCurrentMilestoneScoped, replaceInCurrentMilestone, listMilestoneHeadings } = roadmapParserModule;
|
||||
const { stripShippedMilestones, extractCurrentMilestone, extractCurrentMilestoneScoped, replaceInCurrentMilestone, listMilestoneHeadings, scanMilestonePhaseIds } = roadmapParserModule;
|
||||
import { tokenizeHeadings } from './markdown-sectionizer.cjs';
|
||||
import { updateTableCell } from './markdown-table.cjs';
|
||||
import { clampPercent } from './phase-lifecycle.cjs';
|
||||
@@ -622,6 +622,40 @@ function cmdRoadmapAnalyze(cwd: string, raw: boolean): void {
|
||||
output(result, raw, undefined);
|
||||
}
|
||||
|
||||
// ─── cmdRoadmapMilestoneScope ────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* #3262 (write-time milestone-scope guard): read-only probe emitting the
|
||||
* current milestone window's IDENTITY — its scope classification and the
|
||||
* phase ids it declares — so the edit-phase workflow can capture it before
|
||||
* its in-place section write, re-derive it after, and roll back on any
|
||||
* change. This is the milestone-scope sibling of the workflow's existing
|
||||
* `depends_on` gate, expressed as a command because the workflow's write is
|
||||
* assistant-driven free-text surgery, not a code path.
|
||||
*
|
||||
* Deliberately NOT `cmdRoadmapAnalyze`: analyze's #3165 recovery re-populates
|
||||
* `phases` from the shipped-milestone-stripped document when the scoped
|
||||
* window is suspect, which is right for a human-facing progress report and
|
||||
* wrong for a before/after equality probe — the refill would mask exactly
|
||||
* the narrowing this guard exists to detect. This probe reports the RAW
|
||||
* window (`extractCurrentMilestoneScoped` + `scanMilestonePhaseIds`), no
|
||||
* fallback, so a narrowed window is always visible as a changed phase set.
|
||||
*/
|
||||
function cmdRoadmapMilestoneScope(cwd: string, raw: boolean): void {
|
||||
const roadmapPath = planningPaths(cwd).roadmap;
|
||||
|
||||
if (!fs.existsSync(roadmapPath)) {
|
||||
output({ error: 'ROADMAP.md not found', scope: SCOPE.UNREADABLE, phases: [], phase_count: 0 }, raw, undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const rawContent = fs.readFileSync(roadmapPath, 'utf-8');
|
||||
const { value: window, scope } = extractCurrentMilestoneScoped(rawContent, cwd);
|
||||
// Document order (Set insertion order) — deterministic for a given document.
|
||||
const phases = [...scanMilestonePhaseIds(window)];
|
||||
output({ scope, phases, phase_count: phases.length }, raw, undefined);
|
||||
}
|
||||
|
||||
// ─── cmdRoadmapUpdatePlanProgress ─────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -1153,6 +1187,7 @@ export = {
|
||||
cmdRoadmapGetPhase,
|
||||
getRoadmapPhaseWithFallback,
|
||||
cmdRoadmapAnalyze,
|
||||
cmdRoadmapMilestoneScope,
|
||||
cmdRoadmapUpdatePlanProgress,
|
||||
cmdRoadmapAnnotateDependencies,
|
||||
buildPhaseHeadingRegex,
|
||||
|
||||
Reference in New Issue
Block a user