From 2537c286f92e8b3c74f9c9ed66b49ec7327102f0 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Fri, 14 Aug 2026 01:49:49 -0400 Subject: [PATCH] refactor(#1762): clarify verification-missing/unknown routing text (#3439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(#1762): assert reassuring verification-routing wording (RED) Regression test for #1762 — asserts readVerificationStatus's missing/ unknown next_action text reassures the user that execute-phase resumes at the verification gates without redoing work, instead of reading as a blind re-run instruction. Fails against current wording; the fix lands in the next commit. * fix(#1762): reassure verification-missing/unknown routing text is safe to run readVerificationStatus's 'missing' and 'unknown' next_action text read as "redo the implementation", when execute-phase's own discover_and_group_plans step (#2868) already resumes at the verification gates and skips execute_waves/checkpoint_handling entirely when every plan already has a SUMMARY.md. Reword both to say so explicitly, and soften the 'unknown' message to acknowledge a non-standard status may be an intentional marker rather than presuming re-verification is always the fix. Also updates progress.md's Route V.missing / V.unknown to consume the dynamic $VERIFICATION_NEXT_ACTION (matching V.gaps/V.human) instead of a hand-duplicated string, so the reassurance lands there too without a second copy to keep in sync. No change to next_command routing, status values, or the isPhaseComplete completeness predicate (still gated on status === 'passed' per the #2957 DISK-STRICT decision) — advisory text only. * fix(#1762): drop duplicated reassurance clause in progress.md routing text Review finding: the SUMMARY.md reassurance was stated once via the interpolated $VERIFICATION_NEXT_ACTION and again as a parenthetical on the command line, in both Route V.missing and Route V.unknown. Trimmed the parenthetical so $VERIFICATION_NEXT_ACTION stays the single source of truth. * docs(#1762): add changeset fragment Type Changed with a docs-exempt marker — advisory routing text only, no docs page documents this specific message today. * test(#1762): acknowledge progress.md emitted-content growth Route V.missing/V.unknown now render a small block referencing ${VERIFICATION_NEXT_ACTION} instead of a bare command line, growing progress.md by 376 bytes. Deliberate per the differential attribution check (ADR-2719). * chore: drop spent progress.md ack from #3218's emitted-drift fragment The #3218 growth it described is already on next (inert, per the lint's own note that spent acks 'can no longer clear anything'). Its presence collided with the new #1762 fragment naming the same bare filename, which lint-emitted-drift-ack rejects outright ('two ack sources may never name the same path'). #3218's other two acks (plan-phase.md, plan-review-convergence.md) are untouched. * docs(#1762): backfill changeset PR number --------- Co-authored-by: sim --- .changeset/vivid-moles-chatter.md | 6 +++++ gsd-core/workflows/progress.md | 22 ++++++++++++++++++- src/verification.cts | 4 ++-- .../1762-verification-routing-wording.json | 1 + .../3218-prompt-layer-plan-counts.json | 3 --- tests/verification-status.test.cjs | 8 +++++++ 6 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 .changeset/vivid-moles-chatter.md create mode 100644 tests/emitted-drift-acks/1762-verification-routing-wording.json diff --git a/.changeset/vivid-moles-chatter.md b/.changeset/vivid-moles-chatter.md new file mode 100644 index 000000000..b0422f200 --- /dev/null +++ b/.changeset/vivid-moles-chatter.md @@ -0,0 +1,6 @@ +--- +type: Changed +pr: 3439 +--- +**`/gsd-progress` no longer implies re-execution when only the verification report is missing** — the routing message now explains that running `/gsd-execute-phase` on a historical phase resumes at the verification gates and does not re-run already-summarized plans, and softens the unrecognized-status message to acknowledge an intentional non-standard marker. (#1762) + diff --git a/gsd-core/workflows/progress.md b/gsd-core/workflows/progress.md index 7728a9324..6fbc1bcfe 100644 --- a/gsd-core/workflows/progress.md +++ b/gsd-core/workflows/progress.md @@ -458,7 +458,17 @@ UAT.md exists with `status: partial` — testing session ended before all items All plans have summaries, but canonical verification has not passed. The phase is implementation-complete, not phase-complete. ``` -`/gsd:execute-phase {phase} ${GSD_WS}` — re-run execution verification +--- + +## Verification Report Missing + +**Phase {phase}** has all plans summarized, but no canonical `*-VERIFICATION.md` exists yet. ${VERIFICATION_NEXT_ACTION} + +`/clear` then: + +`/gsd:execute-phase {phase} ${GSD_WS}` — resumes at the verification gates + +--- ``` --- @@ -468,7 +478,17 @@ All plans have summaries, but canonical verification has not passed. The phase i VERIFICATION.md has an unexpected status. The phase is implementation-complete, not phase-complete. ``` +--- + +## Verification Status Unexpected + +**Phase {phase}** has all plans summarized, but its `*-VERIFICATION.md` reports an unexpected status. ${VERIFICATION_NEXT_ACTION} + +`/clear` then: + `/gsd:execute-phase {phase} ${GSD_WS}` — regenerate verification + +--- ``` --- diff --git a/src/verification.cts b/src/verification.cts index 3d7c014e4..d1eeae196 100644 --- a/src/verification.cts +++ b/src/verification.cts @@ -113,7 +113,7 @@ const VERIFICATION_ROUTING_TABLE: Record = { // the file has no parseable frontmatter status. Never emitted by the verifier. missing: { status: 'missing', - next_action: 'No verification report found — the verify step never completed. Re-run execute-phase.', + next_action: 'No verification report found — the verify step never completed. Running execute-phase is safe here: it resumes at the verification gates and does not re-run plans that already have a SUMMARY.md (see #2868).', next_command: 'execute-phase', }, // INTERNAL SENTINEL: constructed when the file has a status value not in @@ -504,7 +504,7 @@ function readVerificationStatus( const unknownRoute = VERIFICATION_ROUTING_TABLE['unknown']; return { status: unknownRoute.status, - next_action: `Unexpected verification status '${rawStatus}'. Re-run execute-phase verification.`, + next_action: `Unexpected verification status '${rawStatus}'. If this is an intentional non-standard marker (e.g. a hand-set failed/superseded state), no action is needed. Otherwise, run execute-phase to regenerate verification — it will not re-run plans that already have a SUMMARY.md.`, next_command: projectNextCommand(unknownRoute.next_command, runtime, phaseArg), ...(staleCheckIndeterminate ? { staleCheckIndeterminate: true } : {}), }; diff --git a/tests/emitted-drift-acks/1762-verification-routing-wording.json b/tests/emitted-drift-acks/1762-verification-routing-wording.json new file mode 100644 index 000000000..0d199358b --- /dev/null +++ b/tests/emitted-drift-acks/1762-verification-routing-wording.json @@ -0,0 +1 @@ +{"version":1,"paths":{"progress.md":{"reason":"#1762: Route V.missing and Route V.unknown now consume the dynamic ${VERIFICATION_NEXT_ACTION} block (matching the existing V.gaps/V.human format) instead of a hardcoded duplicate string, so the routing text stays reassuring and in sync with src/verification.cts's reworded next_action — deliberate growth, not drift."}}} diff --git a/tests/emitted-drift-acks/3218-prompt-layer-plan-counts.json b/tests/emitted-drift-acks/3218-prompt-layer-plan-counts.json index d1c2fb591..8f2b4a6c7 100644 --- a/tests/emitted-drift-acks/3218-prompt-layer-plan-counts.json +++ b/tests/emitted-drift-acks/3218-prompt-layer-plan-counts.json @@ -6,9 +6,6 @@ }, "plan-review-convergence.md": { "reason": "Issue #3218 (epic #3180 phase 8): replaced a raw `ls *-PLAN.md | wc -l` re-derivation with a `gsd_run query find-phase` call plus jq extraction of the count field, routing the plan count through scanPhasePlans (ADR-3180 §7.5) so superseded plans are excluded and the review converges on the live set." - }, - "progress.md": { - "reason": "Issue #3218 (epic #3180 phase 8): replaced a raw `ls *-PLAN.md | wc -l` re-derivation with a `gsd_run query find-phase` call plus jq extraction of the count field, and additionally carries the Route-0 dead-path fix (a branch that previously reported zero plans on the nested plans/ layout is now reachable and correct)." } } } diff --git a/tests/verification-status.test.cjs b/tests/verification-status.test.cjs index 68784ffa4..9e45b8d44 100644 --- a/tests/verification-status.test.cjs +++ b/tests/verification-status.test.cjs @@ -138,6 +138,10 @@ describe('verification-status', () => { assert.equal(result.status, 'missing'); assert.equal(result.next_command, '/gsd-execute-phase'); assert.ok(result.next_action.includes('verify step never completed')); + assert.ok( + result.next_action.includes('does not re-run plans that already have a SUMMARY.md'), + `next_action must reassure the user execute-phase will not redo work (#1762); got: ${result.next_action}`, + ); } finally { cleanup(dir); } @@ -155,6 +159,10 @@ describe('verification-status', () => { result.next_action.includes('bogus'), `next_action should mention the raw value; got: ${result.next_action}`, ); + assert.ok( + result.next_action.includes('intentional non-standard marker'), + `next_action must acknowledge an unrecognized status may be an intentional marker (#1762); got: ${result.next_action}`, + ); } finally { cleanup(dir); }