From 43475a2e0f8993f97f38d4255a7b13993f67334f Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Fri, 14 Aug 2026 09:20:50 -0400 Subject: [PATCH] fix(#3440): retire GAP CLOSURE PLANS CREATED marker, document artifact return contract (#3443) * fix(#3440): retire GAP CLOSURE PLANS CREATED marker, document artifact return contract * chore(#3440): backfill changeset pr number * docs(#3440): mark changeset docs-exempt with audit reason --------- Co-authored-by: sim --- .changeset/jolly-geese-wake.md | 6 ++++++ agents/gsd-planner.md | 2 +- gsd-core/references/planner-guidance.md | 12 +++--------- tests/planner-decomposition.test.cjs | 26 +++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 .changeset/jolly-geese-wake.md diff --git a/.changeset/jolly-geese-wake.md b/.changeset/jolly-geese-wake.md new file mode 100644 index 000000000..dcc58a6cc --- /dev/null +++ b/.changeset/jolly-geese-wake.md @@ -0,0 +1,6 @@ +--- +type: Changed +pr: 3443 +--- +**Gap-closure planning no longer documents a completion marker nothing reads** — the planner emitted `## GAP CLOSURE PLANS CREATED` but no workflow had a dispatch branch for it, so completion was always detected via the `gap_closure: true` fix-plan artifacts anyway; the dead marker is retired and the artifact route (verify-work `--gaps` spawn → plans → `execute-phase --gaps-only`) is now the documented contract. (#3440) + diff --git a/agents/gsd-planner.md b/agents/gsd-planner.md index 4769df146..631eef3f0 100644 --- a/agents/gsd-planner.md +++ b/agents/gsd-planner.md @@ -934,7 +934,7 @@ Return structured planning outcome to orchestrator. -See @~/.claude/gsd-core/references/planner-guidance.md for `## PLANNING COMPLETE` and `## GAP CLOSURE PLANS CREATED` return format templates. +See @~/.claude/gsd-core/references/planner-guidance.md for return formats; gap-closure returns are artifact-based (#3440). See @~/.claude/gsd-core/references/planner-chunked.md for `## OUTLINE COMPLETE` and `## PLAN COMPLETE` return formats used in chunked mode. diff --git a/gsd-core/references/planner-guidance.md b/gsd-core/references/planner-guidance.md index a7b758000..6a31c8e63 100644 --- a/gsd-core/references/planner-guidance.md +++ b/gsd-core/references/planner-guidance.md @@ -162,24 +162,18 @@ Derive plans from actual work. Granularity determines compression tolerance, not Run `/clear` first for a fresh context window, then execute: `/gsd:execute-phase {phase}` ``` -## Gap Closure Plans Created Return Format +## Gap Closure Return (artifact-based — #3440) -```markdown -## GAP CLOSURE PLANS CREATED +Gap-closure completion has **no completion marker**: nothing consumes one. The return contract is the artifacts themselves — `verify-work.md` spawns you in `--gaps` mode, and your output is complete when the fix plans are on disk carrying `gap_closure: true` in their frontmatter; the spawning workflow detects the files (never a return string), and `/gsd:execute-phase {phase} --gaps-only` consumes them. (The former `GAP CLOSURE PLANS CREATED` completion marker was retired as vestigial — it had no dispatch branch anywhere.) **Phase:** {phase-name} **Closing:** {N} gaps from {VERIFICATION|UAT}.md -### Plans - | Plan | Gaps Addressed | Files | |------|----------------|-------| | {phase}-04 | [gap truths] | [files] | -### Next Steps - -Execute: `/gsd:execute-phase {phase} --gaps-only` -``` +**Next step for the orchestrator:** `/gsd:execute-phase {phase} --gaps-only` ## Checkpoint Reached / Revision Complete diff --git a/tests/planner-decomposition.test.cjs b/tests/planner-decomposition.test.cjs index 2894b9d79..7d6eee9cf 100644 --- a/tests/planner-decomposition.test.cjs +++ b/tests/planner-decomposition.test.cjs @@ -120,6 +120,32 @@ describe('reference files contain key content from original mode sections', () = assert.ok(hasGapContent, 'planner-gap-closure.md must contain gap closure mode content'); }); + // #3440: the planner's gap-closure return has NO completion marker — nothing + // consumed `## GAP CLOSURE PLANS CREATED` (no dispatch branch anywhere), so + // emitting it was a lie about the return contract. Completion is detected via + // the `gap_closure: true` fix-plan artifacts. This guard goes red if the + // marker (or an equivalent unconsumed sentinel) reappears in either producer. + test('gap-closure return is artifact-based — no unconsumed completion marker (#3440)', () => { + const guidance = fs.readFileSync( + path.join(PROJECT_ROOT, 'gsd-core', 'references', 'planner-guidance.md'), 'utf-8'); + const planner = fs.readFileSync( + path.join(PROJECT_ROOT, 'agents', 'gsd-planner.md'), 'utf-8'); + for (const [label, content] of [['planner-guidance.md', guidance], ['gsd-planner.md', planner]]) { + assert.ok( + !content.includes('## GAP CLOSURE PLANS CREATED'), + `${label} must not emit the retired marker — no workflow dispatches on it (#3440)`, + ); + } + assert.ok( + guidance.includes('gap_closure: true'), + 'planner-guidance.md must document the artifact return contract (gap_closure: true plans)', + ); + assert.ok( + guidance.includes('--gaps-only'), + 'planner-guidance.md must name the consumer route (execute-phase --gaps-only)', + ); + }); + test('planner-revision.md contains revision content', () => { const content = fs.readFileSync(REVISION_REF, 'utf-8'); const hasRevisionContent = content.includes('revision') ||