feat(sf): wire ADR-011 progressive planning dispatch rule

Adds 'planning (sketch + progressive_planning) → refine-slice' rule
in auto-dispatch.ts, fired BEFORE the existing 'planning → plan-slice'
rule. Activates when:
- state.phase === 'planning'
- prefs?.phases?.progressive_planning === true
- slice has is_sketch=1 in the DB

When all three conditions hold, dispatches the refine-slice unit using
the existing buildRefineSlicePrompt + prompts/refine-slice.md (both
ported in earlier commits). Otherwise falls through to plan-slice
(graceful downgrade — current behavior is preserved when the flag is
off, which is the default).

Why this matters: without progressive planning, the milestone planner
has to either fully-plan every slice upfront (rots quickly) or hand-
wave each slice (executors overscope). Sketch+refine lets the planner
write 2-3 sentences of scope per slice and have refine-slice expand it
just-in-time using prior slice summaries as context — keeping each
plan sized for the actual current reality.

Defensive read of slice.is_sketch with try/catch: pre-migration installs
without the column simply fall through to plan-slice, no error. The DB
DDL migration will land separately as part of the full progressive-
planning rollout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mikael Hugo 2026-05-02 19:14:21 +02:00
parent fef2e4b6f4
commit 0c78b00381

View file

@ -22,6 +22,7 @@ import {
buildPlanSlicePrompt, buildPlanSlicePrompt,
buildReactiveExecutePrompt, buildReactiveExecutePrompt,
buildReassessRoadmapPrompt, buildReassessRoadmapPrompt,
buildRefineSlicePrompt,
buildReplanSlicePrompt, buildReplanSlicePrompt,
buildResearchMilestonePrompt, buildResearchMilestonePrompt,
buildResearchSlicePrompt, buildResearchSlicePrompt,
@ -60,6 +61,7 @@ import {
getMilestone, getMilestone,
getMilestoneSlices, getMilestoneSlices,
getPendingGates, getPendingGates,
getSlice,
getSliceTasks, getSliceTasks,
isDbAvailable, isDbAvailable,
markAllGatesOmitted, markAllGatesOmitted,
@ -976,6 +978,43 @@ export const DISPATCH_RULES: DispatchRule[] = [
}; };
}, },
}, },
{
// ADR-011 progressive planning: when a slice was created as a sketch
// (slices.is_sketch=1) and the phases.progressive_planning preference is
// enabled, dispatch refine-slice instead of plan-slice. The refine unit
// expands the stored sketch_scope into a full plan using prior slice
// summaries as authoritative context. When the preference is off, sketches
// fall through to the normal plan-slice rule below — a graceful downgrade.
name: "planning (sketch + progressive_planning) → refine-slice",
match: async ({ state, mid, midTitle, basePath, prefs }) => {
if (state.phase !== "planning") return null;
if (!state.activeSlice) return null;
if (prefs?.phases?.progressive_planning !== true) return null;
const sid = state.activeSlice.id;
const sTitle = state.activeSlice.title;
let isSketch = false;
try {
const sliceRow = getSlice(mid, sid);
isSketch = sliceRow?.is_sketch === 1;
} catch {
/* DB unavailable or column missing on pre-migration installs — fall through */
return null;
}
if (!isSketch) return null;
return {
action: "dispatch",
unitType: "refine-slice",
unitId: `${mid}/${sid}`,
prompt: await buildRefineSlicePrompt(
mid,
midTitle,
sid,
sTitle,
basePath,
),
};
},
},
{ {
name: "planning → plan-slice", name: "planning → plan-slice",
match: async ({ state, mid, midTitle, basePath }) => { match: async ({ state, mid, midTitle, basePath }) => {