--- phase: 07-mobile-test-harness reviewed: 2026-06-11T12:30:00Z depth: deep files_reviewed: 9 files_reviewed_list: - apps/pwa/playwright.config.ts - apps/pwa/e2e/global-setup.ts - apps/pwa/e2e/layout.spec.ts - apps/pwa/e2e/calendar.spec.ts - apps/pwa/e2e/lists.spec.ts - apps/pwa/e2e/README.md - apps/pwa/tsconfig.e2e.json - apps/pwa/vitest.config.ts - apps/pwa/package.json findings: critical: 0 critical_resolved: 1 blocker: 0 blocker_resolved: 2 warning: 0 warning_resolved: 7 info: 0 info_bydesign: 5 total: 0 status: clean --- # Phase 7: Code Review Report (DEEP) — Iteration 2 (--auto re-review) **Reviewed:** 2026-06-11 **Depth:** deep (cross-file call-chain analysis + live-stack verification) **Files Reviewed:** 9 (harness) **Status:** clean — zero open actionable findings ## Summary This is the iteration-2 re-review after the fixer applied 5 changes (commits `c564fc6` WR-07, `9c38dd3` WR-01+WR-02, `5322cfc` WR-06, `2b745ad` WR-05). The prior pass had resolved CR-01, BL-01, and BL-02; those resolution records are preserved below. **Verification performed this pass:** - Ran the full suite against the live dev stack (MariaDB :3306, API :3000 `DEV_AUTH_BYPASS=true`, Vite auto-started by `webServer`): **58 passed (55s)**. - Typecheck (`tsc --noEmit` + `tsc --project tsconfig.e2e.json --noEmit`): **exit 0**. - Probed `navigator.serviceWorker` availability on **both** engines to confirm the WR-07 fix is non-vacuous (see WR-07 below). - Probed `redirect:'manual'` response semantics to confirm the WR-01 gate distinguishes a dev-bypass 200 from an Authelia redirect. **Result:** all 7 prior warnings are resolved by the fixes (5 actionable + WR-03/WR-04 by-design), no fix introduced a regression or new defect, and no new cross-file issue was exposed. Setting `status: clean`. The 5 IN-\* items remain advisory/by-design and are listed under "Resolved / By-design"; none are actionable. --- ## Critical Issues (resolved — record preserved) ### CR-01 (RESOLVED in commit `fcc680e`): global-setup TRUNCATE had no fail-closed guard **File:** `apps/pwa/e2e/global-setup.ts:26-44` **Status:** RESOLVED — re-verified sound this pass. `globalSetup` TRUNCATEs `list_items`, `list_shares`, `lists`, `calendar_events` against whatever `DB_*` points at. The fix throws **before** opening any DB connection: 1. `NODE_ENV === 'production'` → throw (checked first). 2. `DEV_AUTH_BYPASS !== 'true'` → throw. This mirrors the API guard (`apps/api/src/auth/devBypass.ts`) ordering exactly and is coupled to the same switch that makes the API serve Dev User 1 without OIDC (`index.ts:24-25, 51-55`). Residual scope note carried as IN-05 (guard protects production, not "the wrong dev DB" — by design). --- ## Blocker Findings (resolved — record preserved) ### BL-01 (RESOLVED in commit `53c3ca5`): calendar populated-state assertions were vacuous **File:** `apps/pwa/e2e/calendar.spec.ts` **Status:** RESOLVED — re-verified non-vacuous this pass. The dead-`EmptyState` / always-rendered-wrapper assertions were replaced with a real DB→UI proof: `getByText('Seeded Test Event').first()` must be visible in the grid (`calendar.spec.ts:90-97`). Verified live: passes on both `iphone` (WebKit) and `pixel` (Chromium). With `/api/events` mocked empty the title is absent, so the assertion genuinely tracks the seed flowing DB → API → query → grid. The wrapper-visibility test (`:80-88`) was kept but its docstring now correctly states it only proves the grid mounts, not that the seed reached the UI. ### BL-02 (RESOLVED in commit `53c3ca5`): seed↔view month-boundary fragility **File:** `apps/pwa/e2e/global-setup.ts:119-154` **Status:** RESOLVED — re-verified deterministic this pass. The seed event is re-anchored to **noon-today (UTC)** (`global-setup.ts:127-129`) — always today's local calendar date, always inside the current-month view both phone-width profiles render. The prior `now+24h` could roll into the next month on a month's last day, making any "seeded event is visible" assertion date-fragile. The seed shape (`all_day=false`, `dtstart_utc` set, recurring flags false) matches the API's non-recurring-timed WHERE branch. Verified live on both engines. --- ## Resolved this iteration (fixer commits — verified, no regression) ### WR-01 (RESOLVED in `9c38dd3`): `/api/me` dev-bypass reachability gate **File:** `apps/pwa/e2e/global-setup.ts:75-90` The gate now probes `fetch(${baseURL}/api/me, { redirect: 'manual' })` after the `/health` poll and throws unless `res.ok`. Verified correct end-to-end: - **Dev-bypass-reachable API → 200.** `me.ts:30-42` short-circuits on `c.get('user')` (DEV_USER) with no DB round-trip, so the gate passes regardless of seed state and regardless of ordering (the probe runs before the seed — confirmed safe because `/api/me` has no DB dependency under bypass). The full suite passed with this gate live. - **Authelia-redirecting API → fails loudly.** With `redirect:'manual'`, a cross-origin 302 to Authelia surfaces as `type:'opaqueredirect'`, `status:0`, `ok:false` → gate throws. A same-origin redirect (e.g. `c.redirect('/')`) surfaces as `type:'basic'`, `status:302`, `ok:false` → also throws. Confirmed empirically against `/api/login` (302, `ok=false`). - **No false-fail in the supported setup:** in the dev-bypass stack the OIDC middleware is not mounted (`index.ts:51`), so `/api/me` always returns 200. No regression. The error message string contains `opaqueredirect` with no space — cosmetic only (it is the exact `Response.type` token undici emits); not actionable. ### WR-02 (RESOLVED in `9c38dd3`): explicit readiness flag **File:** `apps/pwa/e2e/global-setup.ts:54-73` The loop now uses an explicit `let ready = false` set inside the `res.ok` branch, and the post-loop check is `if (!ready) throw` — success is no longer inferred from `Date.now() >= deadline`. This removes both the false-positive-timeout (a success arriving in the final second can no longer be misreported as a timeout) and any false-positive-ready (the flag is only set on an actual `res.ok`). Timeout logic verified correct by reading; the gate ran green in the live suite. ### WR-05 (RESOLVED in `2b745ad`): dropped redundant `unroute` calls **Files:** `apps/pwa/e2e/calendar.spec.ts:133-135, 154, 176`; `apps/pwa/e2e/lists.spec.ts:90-92, 118` The trailing `page.unroute(...)` calls were removed and replaced with comments explaining that per-test context isolation handles cleanup. Verified this is correct, not a leak risk: - Every `page.route(...)` is registered **inside an individual test body**, never in a shared `beforeEach`/`beforeAll`. Playwright assigns each test a fresh `page`/`BrowserContext`, and route handlers are scoped to that page/context — they cannot leak into sibling tests. - The suite runs under `fullyParallel: true` with no `describe.serial`, so there is no shared-page path that could carry a route forward. - Cross-test isolation confirmed empirically: the populated-state calendar/lists tests (no mock) and the error/empty-state tests (with mock) all pass in the same run with no interference. The removed `unroute` calls were genuinely dead — they never ran when an `expect` threw (the whole point of those tests), so they had guaranteed nothing. Dropping them is strictly an improvement. ### WR-06 (RESOLVED in `5322cfc`): self-validation comment corrected **File:** `apps/pwa/e2e/layout.spec.ts:209-211, 250-252` The misleading "remove by reload" comments now read "REMOVE the injected style by deleting the `