fix: add defensive guards against undefined .filter() in auto-mode dispatch/recovery (#1180)
Auto-mode crashed with 'Cannot read properties of undefined (reading filter)' during partial execute-task recovery when derived state was structurally incomplete. Added ?? [] fallback guards on all .filter()/.find()/.map() calls that access state.registry, roadmap.slices, or similar derived arrays in the dispatch and recovery paths: - auto.ts: 3 state.registry.filter() calls - auto-recovery.ts: 1 roadmap.slices.find() call - auto-start.ts: 1 state.registry.filter() call These are belt-and-suspenders guards — the parsers always return arrays, but crash recovery can encounter partially written or corrupt state files where the parsers return unexpected shapes. Fixes #1176
This commit is contained in:
parent
8281a2ea75
commit
8d04ec19fd
3 changed files with 5 additions and 5 deletions
|
|
@ -227,7 +227,7 @@ export function verifyExpectedArtifact(unitType: string, unitId: string, base: s
|
|||
try {
|
||||
const roadmapContent = readFileSync(roadmapFile, "utf-8");
|
||||
const roadmap = parseRoadmap(roadmapContent);
|
||||
const slice = roadmap.slices.find(s => s.id === sid);
|
||||
const slice = (roadmap.slices ?? []).find(s => s.id === sid);
|
||||
if (slice && !slice.done) return false;
|
||||
} catch {
|
||||
// Corrupt/unparseable roadmap — fail verification so the unit
|
||||
|
|
|
|||
|
|
@ -415,7 +415,7 @@ export async function bootstrapAutoSession(
|
|||
ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
|
||||
ctx.ui.setFooter(hideFooter);
|
||||
const modeLabel = s.stepMode ? "Step-mode" : "Auto-mode";
|
||||
const pendingCount = state.registry.filter(m => m.status !== 'complete' && m.status !== 'parked').length;
|
||||
const pendingCount = (state.registry ?? []).filter(m => m.status !== 'complete' && m.status !== 'parked').length;
|
||||
const scopeMsg = pendingCount > 1
|
||||
? `Will loop through ${pendingCount} milestones.`
|
||||
: "Will loop until milestone complete.";
|
||||
|
|
|
|||
|
|
@ -877,7 +877,7 @@ async function showStepWizard(
|
|||
: "previous unit";
|
||||
|
||||
if (!mid || state.phase === "complete") {
|
||||
const incomplete = state.registry.filter(m => m.status !== "complete" && m.status !== "parked");
|
||||
const incomplete = (state.registry ?? []).filter(m => m.status !== "complete" && m.status !== "parked");
|
||||
if (incomplete.length > 0 && state.phase !== "complete" && state.phase !== "blocked" && state.phase !== "pre-planning") {
|
||||
const ids = incomplete.map(m => m.id).join(", ");
|
||||
const diag = `basePath=${s.basePath}, milestones=[${state.registry.map(m => `${m.id}:${m.status}`).join(", ")}], phase=${state.phase}`;
|
||||
|
|
@ -1171,7 +1171,7 @@ async function dispatchNextUnit(
|
|||
}
|
||||
}
|
||||
|
||||
const pendingIds = state.registry
|
||||
const pendingIds = (state.registry ?? [])
|
||||
.filter(m => m.status !== "complete")
|
||||
.map(m => m.id);
|
||||
pruneQueueOrder(s.basePath, pendingIds);
|
||||
|
|
@ -1186,7 +1186,7 @@ async function dispatchNextUnit(
|
|||
await closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
||||
}
|
||||
|
||||
const incomplete = state.registry.filter(m => m.status !== "complete" && m.status !== "parked");
|
||||
const incomplete = (state.registry ?? []).filter(m => m.status !== "complete" && m.status !== "parked");
|
||||
if (incomplete.length === 0) {
|
||||
// Genuinely all complete (parked milestones excluded) — merge milestone branch to main before stopping (#962)
|
||||
if (s.currentMilestoneId && isInAutoWorktree(s.basePath) && s.originalBasePath) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue