docs: record Sprint 9 post-deploy dismiss-bug fix across all 6 running docs

Sprint 9 (commit 6e386ba) shipped a working OnboardingTour but a
broken dismiss path: clicking X / Skip / Esc / "Got it" did
nothing. Root cause: useOnboarding().reset() was wired to the
dismiss handler at App.tsx, but reset() does the inverse of
dismiss — it clears the localStorage key and flips isComplete to
FALSE, so the tour re-rendered, the early-return did not fire,
and the dialog stayed visible. Fix: commit 1562929 split the
dismiss and reset paths into two distinct callbacks (onComplete
and onReset). User confirmed browser smoke passes.

This commit updates the 6 running docs that track Sprint 9:

- .agent/plan.md — S9.4.1 sub-task (post-deploy fix) added.
- .agent/context.md — D9 (root cause + fix) + Q4 (Vitest?) added.
- Review/sprint9-verification.md — full post-deploy fix section
  appended (root cause, fix, post-fix verification, lessons).
- Review/handoff-ui-audit.md — Sprint 9 status banner + Last
  updated footer updated to reference the fix commit.
- fix-ui-audit.md — T3.4.1 sub-task added under the T3.4
  verification gate.
- docs/HANDOFF.md — post-deploy fix paragraph added to the
  Sprint 9 section.

All 6 docs now reflect the post-deploy reality. No code changes.
This commit is contained in:
2026-06-05 14:09:10 -07:00
parent 1562929f6b
commit 4c85c929d3
6 changed files with 83 additions and 6 deletions
+2
View File
@@ -194,12 +194,14 @@ User direction 2026-06-05: "Proceed with the next phase in the redesign." §Futu
- **D6. rAF polling for the anchor's `getBoundingClientRect`.** Runs only while the tour is open. Cancellable. One DOM read per frame; well under 1% CPU on a 60Hz display.
- **D7. Focus captured on open (primary action), restored on close.** Uses `previouslyFocused.current = document.activeElement` on mount; restores on unmount. Standard focus-trap pattern, minus the trap (the dialog is intentionally non-modal — the user can interact with the page below).
- **D8. The 4 anchor points are stable elements that already exist in the DOM.** The Dashboard's `<Card>` wrapping the Weekly Overview, the Pantry's page header, the Recipes Filters button, the Shopping List page header. Each gets `data-tour="<id>"`. The anchor also has an off-route fallback (centered card + "Open <page>" CTA) so a first-time user who lands on `/pantry` can still see the Dashboard step (with a one-click nav).
- **D9. Sprint 9 post-deploy bug fix (2026-06-05).** The dismiss path (X / Skip / Esc / "Got it") was wired to `useOnboarding().reset()` via `onComplete`, but `reset()` does the *inverse* of dismiss — clears the localStorage key AND flips `isComplete` to `false`. So clicking X wrote the key, but the App-level flag flipped in the wrong direction, the tour's `if (isComplete || !currentStep) return null` early-return never fired, and the dialog stayed visible. **Fix (`1562929`)**: split the dismiss and reset paths into two distinct callbacks. `useOnboarding` now exposes `markComplete()` (state flip to `true`) in addition to `reset()` (state flip to `false`). `OnboardingTour` takes two props: `onComplete` (dismiss) and `onReset` (re-show). `App.tsx` wires `onComplete → onboarding.markComplete()` and `onReset → onboarding.reset()`. The tour's `finish()` still calls `writeComplete()` + `onComplete()`; `markComplete` is the matching App-side state setter. Cleaned up: `markComplete` no longer double-writes localStorage. The bug was missed in initial verification because `npm run build` was green and no browser smoke was run before deploy.
## Open questions to surface to the user, not to assume
- **Q1. Should the tour show on every page or only `/`?** Default: `/` only. Other pages need `?reset-tour=1`. If the user lands on a non-root page first, the tour does NOT auto-show. Documented in `Review/sprint9-verification.md` smoke step 2.
- **Q2. Should the tour re-show on logout / new device?** Default: no. The localStorage key is per-browser, not per-family-profile. If the user has multiple devices or shares a device, the tour shows once per browser. A future migration could move the key to the family profile, but that's a Sprint 11+.
- **Q3. Should the tour re-show on a recipe update / catalog change?** Default: no. The tour is a one-shot. New users see it; existing users don't.
- **Q4. Should we add a Vitest unit test for `useOnboarding` to lock the dismiss/reset/show state transitions?** Default: not now (would require adding `vitest` + `happy-dom` to frontend dev-deps; violates "no new npm deps"). Trade-off: relying on browser smoke for the dismiss path means the same class of bug can re-appear if a future change mis-wires the callbacks. Worth lifting the "no new npm deps" rule *for testing only* in a future sprint.
## Sprint 9 verification gate