diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 9d49922..f073d1b 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -25,7 +25,7 @@ Full phase detail archived in [`milestones/v1.0-ROADMAP.md`](milestones/v1.0-ROA Make FamilySync configurable, administrable, and maintainable for real multi-member use — without hand-editing env files or the database. The new critical path runs **mobile test harness → Gitea CI** (CI consumes the harness specs for UI regression), and the **admin role → reminders / setup wizard** chain (a single `/api/admin` + `/api/setup` route surface carrying the v1.1 DB migration). Faster write-back is a fully independent track. -- [ ] **Phase 7: Mobile Test Harness** - Mobile-emulated, authenticated PWA browser harness so the assistant (and CI) can catch mobile-only defects +- [x] **Phase 7: Mobile Test Harness** - Mobile-emulated, authenticated PWA browser harness so the assistant (and CI) can catch mobile-only defects (completed 2026-06-11) - [ ] **Phase 8: Gitea CI** - Full regression on PR to main (lint/typecheck/unit/API-integration vs a MariaDB service container **+ the Phase 7 mobile harness as a UI-regression step against a CI-hosted dev stack**) + Docker image publish on merge - [ ] **Phase 9: Faster Write-Back** - Event-driven outbox drain so edits land in ~1-2s instead of ~15s, preserving every outbox durability guarantee - [ ] **Phase 10: Admin Role & Settings** - DB foundation (is_admin / reminder_lead / app_config) + role-gated admin UI to rotate app passwords and designate the shared calendar @@ -67,7 +67,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem **Wave 3** *(blocked on Wave 2 completion)* - [x] 07-03-PLAN.md — layout.spec.ts: tap targets >=44px, no overflow, in-viewport, accessible names (UI-SPEC Rules 1-4) + harness self-validation injected-defect proofs (Wave 3) -- [ ] 07-04-PLAN.md — calendar.spec.ts + lists.spec.ts: populated/empty/error states (Rules 4/5) + DEV_AUTH_BYPASS auth-reached + no-SW-controller precondition (Wave 3) +- [x] 07-04-PLAN.md — calendar.spec.ts + lists.spec.ts: populated/empty/error states (Rules 4/5) + DEV_AUTH_BYPASS auth-reached + no-SW-controller precondition (Wave 3) **UI hint**: yes @@ -200,7 +200,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem | 4. Shared Lists + Live Sync | v1.0 | 7/7 | Complete | 2026-06-09 | | 5. Web Push Notifications | v1.0 | 8/8 | Complete | 2026-06-10 | | 6. UX Polish | v1.0 | 6/6 | Complete | 2026-06-10 | -| 7. Mobile Test Harness | v1.1 | 3/4 | In Progress| | +| 7. Mobile Test Harness | v1.1 | 4/4 | Complete | 2026-06-11 | | 8. Gitea CI | v1.1 | 0/? | Not started | - | | 9. Faster Write-Back | v1.1 | 0/? | Not started | - | | 10. Admin Role & Settings | v1.1 | 0/? | Not started | - | @@ -213,7 +213,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem **Goal:** [Captured for future planning] Abstract the calendar backend behind a provider interface so Fastmail/CalDAV is one implementation among potentially many. Shipping with a single provider is fine, but the broker, sync, and event-expansion layers should be structured so additional providers (e.g. other CalDAV hosts, Google Calendar, generic ICS feeds) can be added without rework. Captures the "provider" seam as an explicit architectural concern. **Requirements:** TBD -**Plans:** 3/4 plans executed +**Plans:** 4/4 plans complete Plans: diff --git a/.planning/STATE.md b/.planning/STATE.md index 1287206..7a73f20 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,16 +2,16 @@ gsd_state_version: 1.0 milestone: v1.1 milestone_name: Operability & Polish -status: executing -stopped_at: Phase 7 UI-SPEC approved -last_updated: "2026-06-11T06:02:41.305Z" +status: verifying +stopped_at: Completed 07-04-PLAN.md +last_updated: "2026-06-11T06:13:24.004Z" last_activity: 2026-06-11 -- Phase 07 execution started progress: total_phases: 14 - completed_phases: 0 + completed_phases: 1 total_plans: 4 - completed_plans: 3 - percent: 0 + completed_plans: 4 + percent: 7 --- # Project State @@ -27,7 +27,7 @@ See: .planning/PROJECT.md (updated 2026-06-10) Phase: 07 (mobile-test-harness) — EXECUTING Plan: 4 of 4 -Status: Ready to execute +Status: Phase complete — ready for verification Last activity: 2026-06-11 -- Phase 07 execution started ## Performance Metrics @@ -80,6 +80,7 @@ Last activity: 2026-06-11 -- Phase 07 execution started | Phase 07 P01 | 310 | 3 tasks | 7 files | | Phase 07 P02 | 196 | 2 tasks | 4 files | | Phase 07-mobile-test-harness P03 | 480 | 2 tasks | 2 files | +| Phase 07-mobile-test-harness P04 | 22 | 2 tasks | 2 files | ## Accumulated Context @@ -127,6 +128,8 @@ Recent decisions affecting current work: - [Phase 06-05]: AuthSplash state machine: loading/redirecting/dead-end; CalendarContent renders only on meQuery.isSuccess (D-10); sessionExpired flag via Zustand + global QueryCache/MutationCache onError (D-11); one-shot redirect guard re-armed only on explicit user tap - [Phase 06-06]: Schedule-X all-day CSS: .sx__all-day-event does not exist in v4.6.0; real selectors are .sx__date-grid-event (week/day) + .sx__month-grid-event:not(:has(.sx__month-grid-event-time)) (month); --sx-color-primary-container remapped as fallback - [Phase 06]: Phase-level UX fixes (surfaced during UAT, not in any single plan): AppNav made persistent across routes — nav no longer disappears on /lists (commits 6070437 RED + 051874b fix); BottomTabBar hidden on desktop — no longer overlaps sidebar Settings affordance (commits 740e342 RED + 089b53d fix) +- [Phase ?]: D-04-SCHEDULE-X-LOCATOR: Used .sx-react-calendar-wrapper CSS class to assert Schedule-X grid — no semantic role on outer wrapper div +- [Phase ?]: D-04-EMPTY-NETWORK-SIM: Lists empty state simulated via page.route to 200 empty array — preserves seeded DB for parallel workers (D-06 / T-07-11) ### Roadmap Evolution @@ -187,9 +190,9 @@ Recent decisions affecting current work: ## Session Continuity -Last session: 2026-06-11T06:02:41.295Z -Stopped at: Phase 7 UI-SPEC approved -Resume file: .planning/phases/07-mobile-test-harness/07-UI-SPEC.md +Last session: 2026-06-11T06:13:23.996Z +Stopped at: Completed 07-04-PLAN.md +Resume file: None ## Operator Next Steps diff --git a/.planning/phases/07-mobile-test-harness/07-04-SUMMARY.md b/.planning/phases/07-mobile-test-harness/07-04-SUMMARY.md new file mode 100644 index 0000000..aaf42f1 --- /dev/null +++ b/.planning/phases/07-mobile-test-harness/07-04-SUMMARY.md @@ -0,0 +1,107 @@ +--- +phase: 07-mobile-test-harness +plan: "04" +subsystem: test-harness +tags: [playwright, e2e, calendar, lists, populated-state, error-state, empty-state, auth-bypass, service-worker] +dependency_graph: + requires: + - "apps/pwa/playwright.config.ts (07-01) — iphone/pixel project matrix, serviceWorkers: 'block', globalSetup path" + - "apps/pwa/e2e/global-setup.ts (07-02) — /health readiness gate + DB seed (calendar_id=10 'Seeded Test Event', 'E2E Grocery List' for user_id=1)" + - "apps/pwa/e2e/layout.spec.ts (07-03) — locator patterns and conventions mirrored" + provides: + - "apps/pwa/e2e/calendar.spec.ts — TEST-01 (populated + error) + TEST-02 (auth-bypass + SW precondition) assertions for /calendar" + - "apps/pwa/e2e/lists.spec.ts — TEST-01 (populated + network-simulated empty) assertions for /lists" + - "20 tests total (8 calendar + 12 lists, per profile) — all passing on iphone/WebKit and pixel/Chromium" + affects: + - "Phase 08 CI (both specs run as regression gates)" +tech_stack: + added: [] + patterns: + - "page.route('/api/*', fulfill 500) registered BEFORE page.goto — error-state simulation (Pattern 5)" + - "page.unroute() immediately after assertion — route mocks scoped to single test (T-07-11)" + - "page.locator('.sx-react-calendar-wrapper') — CSS class fallback for widget wrapper with no semantic role" + - "getByRole('button', { name: 'Open list: E2E Grocery List' }) — aria-label stable anchor on ListCard" + - "page.route('/api/lists', fulfill 200 []) — network-simulated empty state without DB mutation (D-06)" + - "page.evaluate(() => navigator.serviceWorker.controller) — runtime SW controller assertion" +key_files: + created: + - apps/pwa/e2e/calendar.spec.ts + - apps/pwa/e2e/lists.spec.ts + modified: [] +key_decisions: + - "D-04-SCHEDULE-X-LOCATOR: Asserted .sx-react-calendar-wrapper via CSS class (page.locator) since Schedule-X's React adapter emits no semantic role on the outer wrapper div — documented in index.css. No data-testid added to source; the CSS class is stable within @schedule-x/react." + - "D-04-POPULATED-NO-EVENT-CHIP: Populated calendar test asserts grid visible + empty-absent (NOT event chip text) — chip visibility depends on Schedule-X's default view and the seed event date relative to today; date-dependent assertions are exactly the drift the phase avoids (UI-SPEC Rule 6 rationale)." + - "D-04-EMPTY-STATE-NETWORK-SIM: Lists empty state simulated via page.route to 200 [] rather than DB mutation — preserves seeded populated state for concurrent test workers and satisfies D-06 deterministic seed / T-07-11 mock isolation." + - "D-04-LISTCARD-ARIA-LABEL: Lists populated test locates card by getByRole('button', { name: 'Open list: E2E Grocery List' }) — ListCard.tsx renders a