chore(plans): refresh todo.md after 260428-0927 plan ships

8 of 9 phases shipped (only manual PWA verification remains). Rewrite
the hand-off list to reflect current state: residual UX polish,
upstream-blocked tech debt, parking-lot features, and a "Recently
shipped" tail listing the 8 phases delivered today.
This commit is contained in:
2026-04-28 11:43:43 +07:00
parent 918fb1cda9
commit 0f4c616b41
+43 -48
View File
@@ -1,62 +1,44 @@
# Next-session TODO
Hand-off list as of 2026-04-27 (commit `ee71bf0`). Two pass-2 reviews
finished; below are items deferred for future cuts. None are blocking.
Hand-off list as of 2026-04-28 (commit `9f24b6d`). The
`260428-0927-implement-todo-backlog` plan shipped 8 of 9 phases — only
the manual PWA verification checklist remains. Below are residual /
new items deferred from that pass.
## Highest leverage (start here)
- **Test the auto-tick effect.** No integration test for
`PlayerBoard.svelte` bus-driven marking. The dedup-by-`at` fix is the
highest-risk uncovered code path — caught one P0 already, easy to
regress. See `plans/archive/260427-1036-three-mode-and-master-auto-tick/`
for context.
- **CI smoke check for inline scripts in built `index.html`.** SvelteKit
emits one inline bootstrap script; we relaxed CSP to `'unsafe-inline'`
to accommodate it. If a future SvelteKit change adds another inline
block, we want to notice — `grep -c '<script>' build/index.html` in CI.
- **Verify PWA install live.** Lighthouse PWA = 100/100 + manual install
test on Android Chrome and iOS Safari. Splash + theme color flow.
`BUILD_PROFILE=gh` deploy under `/loto/` base — confirm SW + manifest
paths still resolve.
- **Run Phase 9 — PWA install verification.** Manual checklist in
`plans/260428-0927-implement-todo-backlog/phase-09-pwa-verify-install.md`.
Needs production deploy on Cloudflare Pages + physical Android
Chrome + iOS Safari. Lighthouse PWA = 100/100, install flow,
airplane-mode offline, `curl -I` header check (script-src now
hashed, no longer `'unsafe-inline'`).
## UX polish (queued from pass-2)
## UX polish (carried over from pass-2)
- **Mode picker glyphs read unevenly.** Player rect = clear. Megaphone
= abstract. "Both" two stacked rectangles = looks like windows, not
roles. Redesign or add tiny role labels under each glyph.
- **`MasterEmptyState` ↔ PlayerBoard ghost-grid duplication.** Two
near-identical decorative components — extract a shared
`<GhostBoardPreview rows={N} />` if a third use appears.
- **Settings modal on iPhone SE.** Title + footer scroll off — make the
`<h2>` and the bottom button row sticky so the user can always close
the modal without scrolling all the way back.
- **Tier-2 confetti threshold.** 3+ row bingos on a 9-row card is rare;
consider triggering tier 2 on the 2nd bingo, or after a bingo + Chờ.
- **Confetti emoji variety.** Add 🥢 🎋 🏮 to mix the all-celebration
set. Randomize size 1.52.5rem.
- **Per-row "Chờ" visual indicator.** Subtle ring/glow on the
`section-label` band when a Chờ row exists in that section — reduces
reliance on the toast.
`<GhostBoardPreview rows={N} />` only if a third use appears.
(Rule-of-three not met yet.)
- **Maskable icon at 70% safe-zone.** Verify in Chrome DevTools "Show
maskable preview" before announcing PWA. May need to drop to 65% if
Android shape masks crop too tight. Roll into Phase 9 verification.
## Tech debt
- **Strict CSP via hashed inline script.** Today we ship
`script-src 'self' 'unsafe-inline'`. Computing the SHA-256 of
SvelteKit's bootstrap inline at build time and adding it to CSP
would close the relaxation. Brittle: hash changes per build. Worth
tooling if we want a real CSP grade.
- **LRU on audio cache.** Workbox already enforces `maxEntries: 400`,
but a "drop voices not used in 30 days" rule would be nicer than
age-only. Only matters at voices > 10.
- **`cookie` override is a temporary patch.** Remove the override
block in `package.json` once `@sveltejs/kit` ships a release with
`cookie >= 0.7.0` upstream. Same for `serialize-javascript@^7.0.5`
once `workbox-build` updates.
- **Maskable icon at 70% safe-zone.** Verify in Chrome DevTools
"Show maskable preview" before announcing PWA. May need to drop to
65% if Android shape masks crop too tight.
- **Voice list growth.** If we add voices > 2 (esp. > 10), revisit the
precache strategy — currently we precache only the default voice.
- **`cookie` and `serialize-javascript` overrides are temporary.**
Remove the `overrides` block in `package.json` once
`@sveltejs/kit` and `workbox-build` ship releases that pull
`cookie >= 0.7.0` and `serialize-javascript >= 7.0.5` upstream.
- **CSP hash brittleness.** `inject-csp-hashes.mjs` regenerates the
SvelteKit-bootstrap hash per build. If the bootstrap changes
format (e.g. SvelteKit moves to script-src-elem with nonce), the
marker `script-src 'self' 'unsafe-inline'` won't be present and
the script will exit 1. Watch for that on SvelteKit major bumps.
- **Voice list growth.** If we add voices > 2 (esp. > 10), revisit
the precache strategy — currently we precache only the default
voice. The 7d runtime cache covers the rest, but cold-start cost
on alternate voices grows linearly.
## New features (parking lot)
@@ -78,4 +60,17 @@ finished; below are items deferred for future cuts. None are blocking.
`code-reviewer-260427-2030-polish-pwa`
All under `plans/reports/`. Pass-1 unresolved items were verified
addressed in pass-2.
addressed in pass-2; pass-2 items were addressed across the
`260428-0927-implement-todo-backlog` phases.
## Recently shipped (260428-0927-implement-todo-backlog)
- ✅ Phase 1 — auto-tick integration test (8 cases, helper extracted)
- ✅ Phase 2 — CI inline-script guard (`npm run verify:build`)
- ✅ Phase 3 — mode picker "Both" glyph: grid + megaphone composite
- ✅ Phase 4 — settings modal sticky title/footer on small screens
- ✅ Phase 5 — per-section Chờ ring (amber, reduced-motion aware)
- ✅ Phase 6 — confetti tier-2 threshold + 🥢🎋🏮 + size jitter
- ✅ Phase 7 — strict CSP: SHA-256 hash of inline bootstrap, no
`'unsafe-inline'` in `script-src`
- ✅ Phase 8 — audio cache 30d → 7d + purgeOnQuotaError