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 <sim@local>
This commit is contained in:
Tom Boucher
2026-08-14 09:20:50 -04:00
committed by GitHub
parent 6b34557ba3
commit 43475a2e0f
4 changed files with 36 additions and 10 deletions

View File

@@ -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)
<!-- docs-exempt: the retirement and its replacement contract live in gsd-core/references/planner-guidance.md, the runtime-loaded reference for this seam; no docs/ page documents the marker today (verified) and none is owed for its removal -->

View File

@@ -934,7 +934,7 @@ Return structured planning outcome to orchestrator.
<structured_returns>
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.

View File

@@ -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

View File

@@ -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') ||