diff --git a/.changeset/1921-verify-work-gap-recovery.md b/.changeset/1921-verify-work-gap-recovery.md new file mode 100644 index 000000000..776f031bb --- /dev/null +++ b/.changeset/1921-verify-work-gap-recovery.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 2025 +--- +**`/gsd:verify-work` preserves verification state across gap-closure execution and no longer auto-promotes deferred follow-ups into blocking gaps** — resuming after `/gsd:execute-phase --gaps-only` used to lose the verification state: the UAT `## Gaps` still read `status: failed` even after their fix plans executed, so verify-work re-diagnosed them as fresh blockers, spawned a new gap plan, and reported only the new plan as verified. A state contract now links each gap to its fix plan: every UAT gap carries a stable `gap_id` (`G-{phase}-{N}`), gap-closure plans tag the ids they address in their frontmatter (`gap_ids: […]`), and a new `reconcile_gaps` step on resume marks a gap `status: resolved` when its plan has a matching `*-SUMMARY.md` — so fixed gaps aren't re-diagnosed and the phase can close. Separately, a deferred-follow-up branch captures future-work ideas (signals like "later", "next version", "out of scope") into a `## Deferred Follow-Ups` section instead of creating a blocking gap/plan. (#1921) diff --git a/gsd-core/workflows/verify-work.md b/gsd-core/workflows/verify-work.md index f9f47c63c..7bacf8577 100644 --- a/gsd-core/workflows/verify-work.md +++ b/gsd-core/workflows/verify-work.md @@ -372,6 +372,28 @@ reason: "{verbatim user response}" Note: Blocked tests do NOT go into the Gaps section (they aren't code issues — they're prerequisite gates). +**If response indicates a deferred follow-up (NOT a current-phase blocker):** +- "later", "future", "follow-up", "next version", "out of scope", "nice to have", "not now", "defer", "down the road", "separate phase", "phase 2" + +These are future-work ideas, not code issues for the current phase. Capture them WITHOUT creating a gap plan (#1921 — a deferred follow-up must never become a blocking gap or spawn a fix plan): + +Update Tests section: +``` +### {N}. {name} +expected: {expected} +result: skipped +reason: "Deferred follow-up: {verbatim user response}" +``` + +Append to UAT.md `## Deferred Follow-Ups` (create the section if absent): +```yaml +- test: {N} + idea: "{verbatim user response}" + deferred_at: {today} +``` + +Do NOT append to `## Gaps` — deferred follow-ups are not blocking gaps. Continue to the next test. + **If response is anything else:** - Treat as issue description @@ -393,7 +415,8 @@ severity: {inferred} Append to Gaps section (structured YAML for plan-phase --gaps): ```yaml -- truth: "{expected behavior from test}" +- gap_id: G-{phase}-{N} # Stable id (phase + test number) — gap-closure plans tag it in their frontmatter so verify-work can reconcile resolved gaps on resume (#1921). + truth: "{expected behavior from test}" status: failed reason: "User reported: {verbatim user response}" severity: {inferred} @@ -411,9 +434,35 @@ If more tests remain → Update Current Test, go to `present_test` If no more tests → Go to `complete_session` + +**Reconcile diagnosed gaps against completed gap-closure plans (#1921):** + +When verify-work resumes after `/gsd:execute-phase --gaps-only`, the UAT `## Gaps` entries still read `status: failed` even though their fix plans have executed. Without reconciliation verify-work re-diagnoses them as fresh blockers and spawns new gap plans — losing the verification state. This step closes the loop. + +Read the UAT `## Gaps` section and the phase dir `*-PLAN.md` frontmatter. For each gap with `status: failed`: +1. Find a `*-PLAN.md` whose frontmatter `gap_ids` includes the gap's `gap_id` (`G-{phase}-{N}`). +2. If such a plan exists AND has a matching `*-SUMMARY.md` in the phase dir (the plan was executed by `--gaps-only`), the gap is **resolved** — update its YAML in place: + ```yaml + - gap_id: G-{phase}-{N} + status: resolved # was: failed + resolved_by: {plan basename} + resolved_at: {today} + ``` +3. If no plan references the `gap_id`, or the plan has no SUMMARY, leave the gap `status: failed` (still open). + +Read plan frontmatter directly in-context — do not pipe it through a shell parser. After reconciliation, announce: +``` +Reconciled gap-closure state: {resolved_count} gap(s) resolved by executed plans, {open_count} still open. +``` + +Resolved gaps are NOT re-diagnosed and do NOT spawn new gap plans. If the user later reports the same behavior as still broken, treat it as a new issue (a regression) with a fresh `gap_id`. + + **Resume testing from UAT file:** +**First run `reconcile_gaps`** (above) so gaps already fixed by `/gsd:execute-phase --gaps-only` are marked `resolved` before testing resumes (#1921). + Read the full UAT file. Find first test with `result: [pending]`. @@ -652,7 +701,7 @@ Display: Spawn gsd-planner in --gaps mode: -``` +```` Agent( prompt=""" @@ -673,13 +722,22 @@ ${AGENT_SKILLS_PLANNER} Output consumed by /gsd:execute-phase Plans must be executable prompts. + +**Gap linkage (#1921):** each created `*-PLAN.md` MUST list the UAT gap ids it addresses in its frontmatter: +```yaml +--- +gap_closure: true +gap_ids: [G-{phase}-{N}, ...] # the ## Gaps gap_id values this plan fixes +--- +``` +This lets `/gsd:verify-work` reconcile resolved gaps on resume (a gap whose plan has a matching `*-SUMMARY.md` is marked `status: resolved`, not re-diagnosed as a fresh blocker). """, subagent_type="gsd-planner", model="{planner_model}", description="Plan gap fixes for Phase {phase}" ) -``` +```` > **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available. diff --git a/tests/fixtures/golden-install-parity/antigravity.json b/tests/fixtures/golden-install-parity/antigravity.json index e884fbf03..0c5f07c65 100644 --- a/tests/fixtures/golden-install-parity/antigravity.json +++ b/tests/fixtures/golden-install-parity/antigravity.json @@ -303,7 +303,7 @@ "gsd-core/workflows/update.md": "2c58df5e21c41c31", "gsd-core/workflows/validate-phase.md": "6c0ab739d15709fa", "gsd-core/workflows/verify-phase.md": "8070a098ab538b33", - "gsd-core/workflows/verify-work.md": "d8e44ebee36b01e5", + "gsd-core/workflows/verify-work.md": "be699ed7920f61b0", "hooks/gsd-check-update-worker.js": "fa301e6366270d5f", "hooks/gsd-check-update.js": "4617a98bf529e4c3", "hooks/gsd-config-reload.js": "96546e0e8bb47904", diff --git a/tests/fixtures/golden-install-parity/augment.json b/tests/fixtures/golden-install-parity/augment.json index e3557f981..c72ac8f1d 100644 --- a/tests/fixtures/golden-install-parity/augment.json +++ b/tests/fixtures/golden-install-parity/augment.json @@ -373,7 +373,7 @@ "gsd-core/workflows/update.md": "fd160e13f8b7e83c", "gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa", "gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c", - "gsd-core/workflows/verify-work.md": "5ed471293dc6835f", + "gsd-core/workflows/verify-work.md": "34e980a6950cd83c", "hooks/gsd-check-update-worker.js": "cc1ef5f840f9dfc9", "hooks/gsd-check-update.js": "7b3a7983d5f1f5d3", "hooks/gsd-config-reload.js": "96546e0e8bb47904", diff --git a/tests/fixtures/golden-install-parity/claude.json b/tests/fixtures/golden-install-parity/claude.json index 7a285ad10..423300360 100644 --- a/tests/fixtures/golden-install-parity/claude.json +++ b/tests/fixtures/golden-install-parity/claude.json @@ -302,7 +302,7 @@ "gsd-core/workflows/update.md": "f9e7d8a760d0d3c8", "gsd-core/workflows/validate-phase.md": "2ac231dc541441c2", "gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a", - "gsd-core/workflows/verify-work.md": "2b49359ed055f9c4", + "gsd-core/workflows/verify-work.md": "efe57bdbbb3af03f", "hooks/gsd-check-update-worker.js": "a530efdb5fdc0da3", "hooks/gsd-check-update.js": "25cde66a12d6b886", "hooks/gsd-config-reload.js": "96546e0e8bb47904", diff --git a/tests/fixtures/golden-install-parity/cline.json b/tests/fixtures/golden-install-parity/cline.json index 734dc44ab..1616c4e1b 100644 --- a/tests/fixtures/golden-install-parity/cline.json +++ b/tests/fixtures/golden-install-parity/cline.json @@ -306,7 +306,7 @@ "gsd-core/workflows/update.md": "165beec33490bd28", "gsd-core/workflows/validate-phase.md": "5b4ae14c87859bd2", "gsd-core/workflows/verify-phase.md": "20e90407e1e531fc", - "gsd-core/workflows/verify-work.md": "343a1c8615c06c2b", + "gsd-core/workflows/verify-work.md": "6fa216623778c541", "scripts/changeset/README.md": "86ff89331dfd94b2", "scripts/changeset/cli.cjs": "68f92a344b199271", "scripts/changeset/github-release-notes.cjs": "795677f0c009b132", diff --git a/tests/fixtures/golden-install-parity/codebuddy.json b/tests/fixtures/golden-install-parity/codebuddy.json index 09416cee7..2071962c8 100644 --- a/tests/fixtures/golden-install-parity/codebuddy.json +++ b/tests/fixtures/golden-install-parity/codebuddy.json @@ -373,7 +373,7 @@ "gsd-core/workflows/update.md": "5ff1f77222977648", "gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa", "gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c", - "gsd-core/workflows/verify-work.md": "5ed471293dc6835f", + "gsd-core/workflows/verify-work.md": "34e980a6950cd83c", "hooks/gsd-check-update-worker.js": "bdc9324a2f080ddd", "hooks/gsd-check-update.js": "b7669f605631e506", "hooks/gsd-config-reload.js": "96546e0e8bb47904", diff --git a/tests/fixtures/golden-install-parity/codex.json b/tests/fixtures/golden-install-parity/codex.json index f150fac04..623d795ff 100644 --- a/tests/fixtures/golden-install-parity/codex.json +++ b/tests/fixtures/golden-install-parity/codex.json @@ -338,7 +338,7 @@ "gsd-core/workflows/update.md": "5c35c0ec0f462ea6", "gsd-core/workflows/validate-phase.md": "020201a41049679f", "gsd-core/workflows/verify-phase.md": "b9f70235e777aa81", - "gsd-core/workflows/verify-work.md": "d24a21519c50b1f8", + "gsd-core/workflows/verify-work.md": "69e27f6f419d0bba", "hooks/gsd-check-update.js": "ef48957eb6ac6a10", "hooks/gsd-context-monitor.js": "76fecaaa2babd6c1", "scripts/changeset/README.md": "86ff89331dfd94b2", diff --git a/tests/fixtures/golden-install-parity/copilot.json b/tests/fixtures/golden-install-parity/copilot.json index c375753f6..94ceacf54 100644 --- a/tests/fixtures/golden-install-parity/copilot.json +++ b/tests/fixtures/golden-install-parity/copilot.json @@ -304,7 +304,7 @@ "gsd-core/workflows/update.md": "f444a7cfcd246cfb", "gsd-core/workflows/validate-phase.md": "2f705775a4b76d42", "gsd-core/workflows/verify-phase.md": "59d1046b3a2bc481", - "gsd-core/workflows/verify-work.md": "74d024e92d8ca2b0", + "gsd-core/workflows/verify-work.md": "58e9b1b16f773b53", "hooks/gsd-session.json": "0a462834f2a28fee", "scripts/changeset/README.md": "86ff89331dfd94b2", "scripts/changeset/cli.cjs": "68f92a344b199271", diff --git a/tests/fixtures/golden-install-parity/cursor.json b/tests/fixtures/golden-install-parity/cursor.json index dc2e7f08f..cfb4a61bf 100644 --- a/tests/fixtures/golden-install-parity/cursor.json +++ b/tests/fixtures/golden-install-parity/cursor.json @@ -373,7 +373,7 @@ "gsd-core/workflows/update.md": "23e294ba707c3580", "gsd-core/workflows/validate-phase.md": "2df0c6e298a5f249", "gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a", - "gsd-core/workflows/verify-work.md": "74f5f7349ea9f757", + "gsd-core/workflows/verify-work.md": "145596b2542c457a", "hooks/gsd-cursor-post-tool.js": "019d503aee8b4a3f", "hooks/gsd-cursor-session-start.js": "c6e04ed597ea7020", "scripts/changeset/README.md": "86ff89331dfd94b2", diff --git a/tests/fixtures/golden-install-parity/hermes.json b/tests/fixtures/golden-install-parity/hermes.json index 2bb6ec260..9a09017f5 100644 --- a/tests/fixtures/golden-install-parity/hermes.json +++ b/tests/fixtures/golden-install-parity/hermes.json @@ -303,7 +303,7 @@ "gsd-core/workflows/update.md": "7499bb4cb2a3ce6f", "gsd-core/workflows/validate-phase.md": "75e8971d3981d06b", "gsd-core/workflows/verify-phase.md": "84e00bd685006870", - "gsd-core/workflows/verify-work.md": "f7750a6cce6d5391", + "gsd-core/workflows/verify-work.md": "e56e07475d5eb51e", "hooks/gsd-check-update-worker.js": "7989cc2bedd1138d", "hooks/gsd-check-update.js": "25f5ad726f76fc11", "hooks/gsd-config-reload.js": "880b696458e85e9b", diff --git a/tests/fixtures/golden-install-parity/kilo.json b/tests/fixtures/golden-install-parity/kilo.json index 4818d444d..163013a8e 100644 --- a/tests/fixtures/golden-install-parity/kilo.json +++ b/tests/fixtures/golden-install-parity/kilo.json @@ -373,7 +373,7 @@ "gsd-core/workflows/update.md": "07dc2fba78ad1865", "gsd-core/workflows/validate-phase.md": "557e3251e3b9349a", "gsd-core/workflows/verify-phase.md": "0d4ffabc1caa473a", - "gsd-core/workflows/verify-work.md": "41a198eb414e051e", + "gsd-core/workflows/verify-work.md": "b68ac37f6301a3b5", "hooks/gsd-check-update-worker.js": "c992bbad91d0e994", "hooks/gsd-check-update.js": "fdd77abe7ef26a2d", "hooks/gsd-config-reload.js": "96546e0e8bb47904", diff --git a/tests/fixtures/golden-install-parity/kimi.json b/tests/fixtures/golden-install-parity/kimi.json index fce5a3af1..8ad180f00 100644 --- a/tests/fixtures/golden-install-parity/kimi.json +++ b/tests/fixtures/golden-install-parity/kimi.json @@ -339,7 +339,7 @@ "gsd-core/workflows/update.md": "6718e0632bba26ca", "gsd-core/workflows/validate-phase.md": "2c6d7671fcaabcaa", "gsd-core/workflows/verify-phase.md": "98a995046bdb6c3c", - "gsd-core/workflows/verify-work.md": "5ed471293dc6835f", + "gsd-core/workflows/verify-work.md": "34e980a6950cd83c", "scripts/changeset/README.md": "86ff89331dfd94b2", "scripts/changeset/cli.cjs": "68f92a344b199271", "scripts/changeset/github-release-notes.cjs": "795677f0c009b132", diff --git a/tests/fixtures/golden-install-parity/opencode.json b/tests/fixtures/golden-install-parity/opencode.json index dacda292c..f9bacfedd 100644 --- a/tests/fixtures/golden-install-parity/opencode.json +++ b/tests/fixtures/golden-install-parity/opencode.json @@ -373,7 +373,7 @@ "gsd-core/workflows/update.md": "71b6cd852f38b4bc", "gsd-core/workflows/validate-phase.md": "abcdbc1b56780565", "gsd-core/workflows/verify-phase.md": "5bd04b040cd071dd", - "gsd-core/workflows/verify-work.md": "f7dad67215e6b730", + "gsd-core/workflows/verify-work.md": "f0d205568abfaf74", "hooks/gsd-check-update-worker.js": "385fb7c67810baf6", "hooks/gsd-check-update.js": "4549451414ffa7d7", "hooks/gsd-config-reload.js": "96546e0e8bb47904", diff --git a/tests/fixtures/golden-install-parity/qwen.json b/tests/fixtures/golden-install-parity/qwen.json index bec6afbe0..70a06b4a6 100644 --- a/tests/fixtures/golden-install-parity/qwen.json +++ b/tests/fixtures/golden-install-parity/qwen.json @@ -303,7 +303,7 @@ "gsd-core/workflows/update.md": "b34cb866152d4de3", "gsd-core/workflows/validate-phase.md": "e989cbaa4228564c", "gsd-core/workflows/verify-phase.md": "a8679ba1d84145c5", - "gsd-core/workflows/verify-work.md": "5d523d416fef66f0", + "gsd-core/workflows/verify-work.md": "b5afb65fdf311301", "hooks/gsd-check-update-worker.js": "4bb354044e0dff91", "hooks/gsd-check-update.js": "d2065cb3e725a42a", "hooks/gsd-config-reload.js": "4f52b8a0120bb1b8", diff --git a/tests/fixtures/golden-install-parity/trae.json b/tests/fixtures/golden-install-parity/trae.json index a045862ef..cf7f47c38 100644 --- a/tests/fixtures/golden-install-parity/trae.json +++ b/tests/fixtures/golden-install-parity/trae.json @@ -303,7 +303,7 @@ "gsd-core/workflows/update.md": "1f935251fca1f276", "gsd-core/workflows/validate-phase.md": "1c0ebe56d96a14d1", "gsd-core/workflows/verify-phase.md": "53cbdce394dcdac0", - "gsd-core/workflows/verify-work.md": "17b2f2591c3f642e", + "gsd-core/workflows/verify-work.md": "d3a0970205acc6a5", "scripts/changeset/README.md": "86ff89331dfd94b2", "scripts/changeset/cli.cjs": "68f92a344b199271", "scripts/changeset/github-release-notes.cjs": "795677f0c009b132", diff --git a/tests/fixtures/golden-install-parity/windsurf.json b/tests/fixtures/golden-install-parity/windsurf.json index ae20090c1..5ed6aac92 100644 --- a/tests/fixtures/golden-install-parity/windsurf.json +++ b/tests/fixtures/golden-install-parity/windsurf.json @@ -303,7 +303,7 @@ "gsd-core/workflows/update.md": "79aaf4b8f1f83045", "gsd-core/workflows/validate-phase.md": "2db47bf5547d7b9d", "gsd-core/workflows/verify-phase.md": "ea7f8a705b297e27", - "gsd-core/workflows/verify-work.md": "bbf699e62d93d05b", + "gsd-core/workflows/verify-work.md": "5ad63a5edfb6acac", "scripts/changeset/README.md": "86ff89331dfd94b2", "scripts/changeset/cli.cjs": "68f92a344b199271", "scripts/changeset/github-release-notes.cjs": "795677f0c009b132", diff --git a/tests/workflow-size-baseline.json b/tests/workflow-size-baseline.json index bf1ba001e..797f01b89 100644 --- a/tests/workflow-size-baseline.json +++ b/tests/workflow-size-baseline.json @@ -88,5 +88,5 @@ "update.md": 20914, "validate-phase.md": 10789, "verify-phase.md": 40772, - "verify-work.md": 35215 + "verify-work.md": 38267 }