Replace plan-phase.md §5.6 (a 6-branch inline UI gate) with a capability-driven
loop.render-hooks plan:pre dispatch — the FIRST gate dispatch in any workflow.
A step (ui-phase, when:workflow.ui_phase) + a new blocking gate
(when:workflow.ui_safety_gate). New ui.plan-gate check verb returns
{frontend, hasUiSpec, block}; the dispatch runs it unconditionally then fires
the active step (pipeline) or halts on the active blocking gate (manual). The
gate-handling (run check.query; halt if blocking+block) is the reusable
phase-6 template for blocking-gate cutovers.
Config semantics fixed per #1022 + maintainer call: ui_phase gates plan-time
UI-SPEC generation, ui_safety_gate gates the planning block. Common case + all
ui_phase=false cases are equivalence-preserving; the one intended change is
{ui_phase:true, ui_safety_gate:false} now auto-generating in pipelines.
Review found it broken twice (non-generic dispatch, phase-lookup divergence,
then the step-only check nested in a gate loop) — fixed; final Codex pass
verified all 8 (ui_phase,ui_safety_gate)x{pipeline,manual} cases correct.
gsd-ui-phase skill + autonomous §3a.5 untouched (§3a.5 deferred).
getRoadmapPhaseWithFallback mirrors cmdRoadmapGetPhase for lookup parity.
Closes #1026
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -175,6 +175,47 @@ function searchPhaseInContent(content: string, escapedPhase: string, phaseNum: s
|
||||
};
|
||||
}
|
||||
|
||||
// ─── getRoadmapPhaseWithFallback ──────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Two-pass phase lookup that mirrors cmdRoadmapGetPhase's resolution strategy.
|
||||
*
|
||||
* Pass 1: current-milestone slice (extractCurrentMilestone).
|
||||
* Pass 2: full roadmap content (stripShippedMilestones) — covers cross-milestone
|
||||
* and older frontend phases that are no longer in the current milestone slice.
|
||||
*
|
||||
* Returns the phase section string if found, null if ROADMAP.md is missing,
|
||||
* or throws if ROADMAP.md read fails.
|
||||
*
|
||||
* Used by check-command-router (computeUiPlanGate) so ui-plan-gate uses the SAME
|
||||
* phase resolution as `roadmap.get-phase` — not a milestone-only subset.
|
||||
*/
|
||||
function getRoadmapPhaseWithFallback(cwd: string, phaseNum: string): string | null {
|
||||
const roadmapPath = planningPaths(cwd).roadmap;
|
||||
if (!fs.existsSync(roadmapPath)) return null;
|
||||
|
||||
const rawContent = fs.readFileSync(roadmapPath, 'utf-8');
|
||||
const milestoneContent = extractCurrentMilestone(rawContent, cwd);
|
||||
const fullContent = stripShippedMilestones(rawContent);
|
||||
|
||||
const exactSource = phaseMarkdownRegexSourceExact(phaseNum);
|
||||
if (exactSource) {
|
||||
const exactMilestone = searchPhaseInContent(milestoneContent, exactSource, phaseNum);
|
||||
if (exactMilestone && !exactMilestone.error) return exactMilestone.section ?? null;
|
||||
const exactFull = searchPhaseInContent(fullContent, exactSource, phaseNum);
|
||||
if (exactFull && !exactFull.error) return exactFull.section ?? null;
|
||||
}
|
||||
|
||||
const escapedPhase = phaseMarkdownRegexSource(phaseNum);
|
||||
const milestoneResult = searchPhaseInContent(milestoneContent, escapedPhase, phaseNum);
|
||||
const result = (milestoneResult && !milestoneResult.error)
|
||||
? milestoneResult
|
||||
: searchPhaseInContent(fullContent, escapedPhase, phaseNum) || milestoneResult;
|
||||
|
||||
if (!result || result.error) return null;
|
||||
return result.section ?? null;
|
||||
}
|
||||
|
||||
// ─── cmdRoadmapGetPhase ───────────────────────────────────────────────────────
|
||||
|
||||
function cmdRoadmapGetPhase(cwd: string, phaseNum: string, raw: boolean): void {
|
||||
@@ -710,6 +751,7 @@ function cmdRoadmapAnnotateDependencies(cwd: string, phaseNum: string | null | u
|
||||
|
||||
export = {
|
||||
cmdRoadmapGetPhase,
|
||||
getRoadmapPhaseWithFallback,
|
||||
cmdRoadmapAnalyze,
|
||||
cmdRoadmapUpdatePlanProgress,
|
||||
cmdRoadmapAnnotateDependencies,
|
||||
|
||||
Reference in New Issue
Block a user