Files
msd-core/gsd-core/references/verify-mvp-mode.md
Tom Boucher ec7e49a64c fix(#3576): repair all 43 dead references/ cites and gate the canonical resolvable form (#3596)
* test(#3576): gate shipped reference citations on the canonical resolvable form

Failing-first gate for #3576: a backticked bare references/<name>.md cite
resolves from no install location (agents, workflows, and references all
install where a bare relative references/ path is dead). The gate walks the
runtime-loaded trees the issue prescribes, strips @~/ include tokens
PER-TOKEN (a line-skip guard would miss a bare cite sharing a line with an
include — the issue-named trap), pins the genuinely relative ../ href and
canonical forms as non-offenders, and checks canonical cite targets exist.
43 offenders today across 19 files.

* fix(#3576): repair all 43 dead references/ cites to the canonical resolvable form

Every backticked bare references/<name>.md cite across the 19 shipped files
rewritten to gsd-core/references/<name>.md — the form every required_reading
block and @~/ include already uses, and the only form that resolves from any
install location. All 20 cited targets verified to exist; the one genuinely
relative href (plan-phase.md's ../references/mvp-concepts.md) is untouched
(the repair is backtick-anchored). Growth acks: new fragment for the three
first-time paths, #3206-pattern appends to the five fragments already naming
the other grown files (two ack sources may never name the same path).
execute-phase.md lands at 93,391/93,400 and gsd-executor.md at 49,150/49,152
— exactly the issue's projections; every repair fits.

* fix(#3576): drop stale default.md growth ack (nested modes file is hash-attributed, not growth-ratcheted)

Review finding: the emitted-attribution ratchet covers only top-level
workflows/ + agents/ files; discuss-phase/modes/default.md's delta is
source-attributed, so acknowledging its growth is a stale entry the
differential lane fails on.

* chore(#3576): add changeset fragment

* chore(#3576): backfill changeset pr number

---------

Co-authored-by: sim <sim@local>
2026-08-17 15:24:24 -04:00

5.4 KiB

Verify-Work — MVP Mode UAT Framing

Loaded by verify-work workflow and gsd-verifier agent only when the phase under verification has mode: mvp in ROADMAP.md. Reframes UAT generation from technical checks to user-flow walk-throughs.

Core rule

Show expected, ask if reality matches — same philosophy as standard verify-work (from workflows/verify-work.md). The MVP-mode change is WHAT gets shown:

  • Standard verify-work: "The API endpoint at /users/register returns 201 with the new user's ID." → user confirms.
  • MVP verify-work: "Open the registration page. Fill in 'name', 'email', 'password'. Click Submit. You should see your dashboard with your name in the header." → user confirms.

The user-flow form mirrors what a real user does: open, fill, click, see. No HTTP verbs, no JSON shapes, no error codes.

When this framing applies

The framing fires when:

  • The phase under verification has **Mode:** mvp in ROADMAP.md (parsed via gsd-tools query roadmap.get-phase --pick mode).
  • AND the phase has a user-story-formatted goal (set by /gsd mvp-phase per Phase 2): "As a [user role], I want to [capability], so that [outcome]."

If the phase has mode: mvp but the goal is NOT in user-story format, the verifier surfaces this as a discrepancy and asks the user to run /gsd mvp-phase to reformat the goal — same pattern as the planner agent under MVP_MODE (per gsd-core/references/planner-mvp-mode.md).

Generated UAT script structure under MVP mode

The UAT script generated by verify-work under MVP mode has THREE sections, in this exact order:

1. User-flow walk-through (always first, always required)

Derive ordered steps from the phase's user-story goal:

  1. The first step opens the entry point ("Open the app", "Navigate to /register", "Run gsd mvp-phase 1").
  2. Each subsequent step is one user action: fill, click, type, observe.
  3. The final step asserts the user-visible outcome from the [outcome] clause of the user story.

Format each step as: "Step N: [action] — Expected: [what the user should see]". The user responds with one of:

  • yes / y / next / empty → step passes
  • Anything else → step is logged as an issue, and the script halts (do not proceed to step N+1 with a broken N).

If ALL user-flow steps pass, advance to section 2. If any step fails, the verdict is FAIL — do not run technical checks.

2. Technical checks (only if section 1 passes)

After the user flow passes, run the technical checks that would normally run in non-MVP mode:

  • API endpoint schema verification (if the phase shipped APIs)
  • Error state behavior (4xx, 5xx codes; invalid input handling)
  • Edge cases (empty data, large data, concurrent requests if applicable)
  • Cross-browser / cross-runtime checks (if applicable)

These are the same checks verify-work would run without MVP mode — just deferred until the user flow proves the slice actually works for a user.

3. Coverage check (always last, always required)

Verify that the user-story [outcome] clause is observably true in the codebase:

  • If the outcome is "I can access my dashboard", verify a dashboard route exists and renders for an authenticated user.
  • If the outcome is "I can bulk-import contacts", verify the import path produces persisted records.

Coverage is a goal-backward check: "did this phase deliver what its user story promised?" — sourced from the existing gsd-verifier agent's goal-backward methodology, narrowed to the user story.

Anti-patterns to reject under MVP mode

  • Lead with technical checks. "Step 1: GET /api/users/me returns 200." Reject. The user does not see API endpoints. Reorder so a user action comes first.
  • Schema-as-feature. "User has a name field on the User model." Reject. The user does not see database fields. Express the same check as a user-visible outcome ("the user's name appears in the dashboard header").
  • Skip user flow because the test passed. The unit test passing in CI is not evidence that the user flow works. The user-flow walk-through is mandatory under MVP mode even when all unit tests are green.

Compatibility with existing verify-work philosophy

The "show expected, ask if reality matches" model is preserved. The user still types yes / next / empty to advance. The UAT.md state file format is unchanged. Only the WHAT changes — under MVP mode, the "expected" is a user-visible outcome rather than a technical assertion.

Output: VERIFICATION.md changes under MVP mode

The gsd-verifier agent produces VERIFICATION.md. Under MVP mode, the report adds a top-level "User Flow Coverage" section that maps each step of the user story to evidence in the codebase:

## User Flow Coverage

User story: «As a new user, I want to register and log in, so that I can access my dashboard.»

| Step | Expected | Evidence | Status |
|------|----------|----------|--------|
| Register | Form at /register accepts name/email/password | src/app/register/page.tsx:12 (form component) | ✓ |
| Submit | Persists user, redirects to /dashboard | src/api/register/route.ts:34 (db.insert + redirect) | ✓ |
| See dashboard | Dashboard page renders, shows user's name | src/app/dashboard/page.tsx:8 (greeting line) | ✓ |
| Outcome | "Access my dashboard" — user lands on a populated page | dashboard route + greeting both verified above | ✓ |

Standard technical-check sections of VERIFICATION.md remain (API verification, error handling, etc.) but are appended below "User Flow Coverage", not above.