diff --git a/src/resources/extensions/sf/markdown-renderer.js b/src/resources/extensions/sf/markdown-renderer.js index a0e3cae7d..9297d957b 100644 --- a/src/resources/extensions/sf/markdown-renderer.js +++ b/src/resources/extensions/sf/markdown-renderer.js @@ -587,7 +587,14 @@ function renderSlicePlanMarkdown(slice, tasks, gates = []) { } } lines.push(""); - return `${lines.join("\n").trimEnd()}\n`; + // Collapse 3+ consecutive newlines down to 2. Task descriptions sometimes + // contain double blanks (model-emitted multi-paragraph content + paragraph + // padding) that survive normalizeMarkdownBlockSpacing's heading-only logic. + // Without this, the rendered S0?-PLAN.md trips MD012/no-multiple-blanks in + // pre-execution checks and blocks the autonomous loop at execute-task. + // auto_fix_check_failures was supposed to handle this but doesn't run for + // .sf/milestones/ files — quicker to emit clean markdown at the source. + return `${lines.join("\n").trimEnd()}\n`.replace(/\n{3,}/g, "\n\n"); } export async function renderPlanFromDb(basePath, milestoneId, sliceId) { const slice = getSlice(milestoneId, sliceId);