--- phase: 03-mini-app-shell-geolocation plan: 04 subsystems: [worker-assets, build-tooling, capture-harness, device-matrix] tags: [cloudflare-workers, static-assets, vite, playwright, privacy, d13, d14, d15] requires: [03-01 (web workspace, chain), 03-03 (shell, map, capture signals)] provides: - D-13 one-deployable Worker: assets binding serving web/dist + run_worker_first on /api/* and /telegram/* - D-14 build-artifact gate (BA1–BA6): zero CDN refs, self-hosted fonts, bundled MapLibre worker, inlined style, harness-free production bundle - D-15 one-command deploy (npm run deploy = theme → web → wrangler deploy) and one-command dev (npm run dev, port 8787, local KV) - Dual-build contract: web/dist (production) vs web/dist-harness (capture-only), isolated by __ARAHARAH_HARNESS__ define - web/scripts/capture.mjs: 7 Playwright captures + GEO-03 runtime storage probe - 03-DEVICE-MATRIX.md: the six-leg exit-gate checklist (BLOCKING, awaiting user) affects: [phase-4 verification, phase-7 hardening] tech-stack: added: [wrangler static-assets binding, vite --mode harness dual build] patterns: [build-time dead-code elimination via define, console-signal READY race] key-files: created: - web/test/build-artifact.test.mjs - web/scripts/capture.mjs - web/src/vite-env.d.ts - .planning/phases/03-mini-app-shell-geolocation/03-DEVICE-MATRIX.md modified: - bot/wrangler.jsonc - bot/package.json - package.json - web/package.json - .gitignore - web/vite.config.ts - web/index.html - web/src/main.ts decisions: - Dual-build isolation: harness bundle is a separate outDir gated by a build-time constant, never deployed (T-03-21) - runner-page profile block wrapped wholly in if (__ARAHARAH_HARNESS__) with HTML-inclusive BA5 scan - Local-dev topology = wrangler dev --port 8787 --local (D-12); localhost is a secure context so geolocation works metrics: duration: resumed run (tasks 1–2 pre-committed; deploy + matrix + checkpoint this run) completed: 2026-10-23 --- # Phase 03 Plan 04: One-Deployable Architecture + Device-Matrix Exit Gate — Summary **One deploy ships the Mini App, API, and webhook: `npm run deploy` builds theme → web → wrangler deploy with `web/dist` as static assets; six automated gates prove the bundle is fully self-contained and harness-free, and a 7-capture Playwright harness plus a real boot-to-live storage probe mechanically verify the shell — with the six-leg real-device matrix now armed and awaiting the user.** ## Completed Tasks | # | Task | Commit | Key files | |---|------|--------|-----------| | 1 | Worker `[assets]` binding + one-command deploy + D-14 gate | 8b39a7a (kept from prior run: `8b39ea7`) | bot/wrangler.jsonc, package.json, bot/package.json, web/vite.config.ts, web/test/build-artifact.test.mjs, .gitignore, web/package.json | | 2 | Mock-Telegram runner page + Playwright capture harness | 5c155e3 | web/index.html, web/scripts/capture.mjs, web/src/vite-env.d.ts, web/src/main.ts | | 3 | Device-matrix exit gate | **BLOCKED — checkpoint reached** | 03-DEVICE-MATRIX.md written; real-device legs must be walked by the user | ## What Was Built **D-13 — one Worker, everything attached.** `bot/wrangler.jsonc` now carries the `assets` binding (`../web/dist`, `not_found_handling: "none"`) plus the `run_worker_first` glob array for `/api/*` and `/telegram/*`. Verified live at https://araharah-bot.araharah-bot.workers.dev/: `GET /` → 200 text/html from the asset tree; `POST /api/session` on unsigned bodies → 401 (the HMAC gate answers, so the Worker still owns the API routes). **D-14 — self-contained bundle, proven.** `web/test/build-artifact.test.mjs` runs BA1–BA6 over `web/dist` (HTML-inclusive for BA5/BA6): no third-party CDN references, ≥1 self-hosted woff2, hashed MapLibre worker chunk, inlined Rams style JSON (`"liberty-rams"` markers in the bundle), and — critically — no `installMockWebApp`, `__ARAHARAH_MOCK__`, `/api/session`, or `/api/location-fallback` in ANY emitted production file. 33/33 web tests pass, 48/48 bot tests pass. **D-15 / D-12 — one command each way.** Root `deploy` (build theme → build web → `wrangler deploy && set-webhook.mjs`) and root `dev` (build theme → build web → `wrangler dev --port 8787 --local`, KV in local simulation) chain the gitignored `theme/dist/` build so a fresh clone works. **T-03-21 in both directions.** `web/vite.config.ts` injects `__ARAHARAH_HARNESS__` (true only in `--mode harness`, outDir `dist-harness`); `web/index.html` wraps the ENTIRE Mock-Telegram profile (marker, `/api/session` + `/api/location` + `/api/location-fallback` fetch stubs, installer) in that guard, with `import("/src/main.ts")` outside it. `grep -rl 'installMockWebApp\|__ARAHARAH_MOCK__' web/dist/` → empty while `dist-harness` greps ≥1. `capture.mjs` asserts both directions before racing and aborts with a named diagnostic otherwise. **D-11 / DSGN-02 / GEO-03 — the capture harness.** `web/scripts/capture.mjs` extends the Phase-1 screenshot toolchain (MIN_BYTES 10240, docroot-guarded server, console-signal READY race) to serve `web/dist-harness` and race `RAMS-BASEMAP-READY` then `ARAHARAH-LIVE`. Seven non-blank captures under `web/screenshots/`: boot stage 1 + 2, live light, live dark, the Desktop denied card (via its dedicated 90s race against LINK 3's 60 s pre-denial chat-pin poll), the `?pin=1` chat-pin relay to LIVE, and the DSGN-02 side-by-side vs `navigate_map_overview/screen.png`. The GEO-03 probe then asserts localStorage, sessionStorage, cookies, and IndexedDB all empty after a real boot-to-live cycle — none were. ## Deploy Verification (real canaries) - `npm run deploy` → araharah-bot@2c1336e3-58f9-4b0b-86a8-b25de66e327c, webhook re-set ok. - `getWebhookInfo`: URL ends `/telegram/webhook`, no `last_error`, secret armed (values not echoed). - `getChatMenuButton`: type `commands`. - Origin serves the app (200) and the API 401s unsigned traffic. ## Deviations from Plan 1. **[Rule 3 - Blocking] `run_worker_first` unrecognized by wrangler 4.151.3.** The `npm run deploy` emitted `Unexpected fields found in top-level field: "run_worker_first"`. The plan claimed a deploy `--dry-run` would prove the key was accepted; it warns, not fails. Deploy succeeded, and request-by-request probes showed the routing D-13 requires holds regardless (assets serve only non-API paths in the default assets-first model; the Worker 404s misses itself, so `/api/*`/`/telegram/*` are never intercepted). Left as-is with the observed behavior documented in 03-DEVICE-MATRIX.md; a wrangler upgrade to ≥4.152.0 is suggested when convenient but was not forced mid-plan. 2. **[Continuation] Tasks 1 and 2 were found already executed and committed** (8b39ea7, 5c155e3) when this run started; this run verified their gates, performed the deploy + canaries, and armed task 3. ## Authentication Gates None. ## Known Stubs None. Every capture, gate, and probe is wired to real behavior; the harness stubs are by design confined to the never-deployed `web/dist-harness` build. ## Checkpoint: Device-Matrix Exit Gate (task 3) — BLOCKING, awaits user `.planning/phases/03-mini-app-shell-geolocation/03-DEVICE-MATRIX.md` is written with the deployed URL, the Bot API 10.2 BotFather-origin prerequisite, and all six legs as unchecked checkboxes: Android boot + permission persistence, Android stale-fix (A1 retire-or-confirm), iOS, Desktop Telegram denied→ASK VIA CHAT→keyboard→pin→LIVE, plain browser denied card, and the mid-session light↔dark theme flip (PX-02 manual-only). Real hardware is unavailable to the executor — per plan and T-03-25, no leg was faked; Success Criterion 5 remains open until the user reports results. **Resume signal:** "device matrix passed", a per-leg failure report, or a no-device-available report (→ Success Criterion 5 = UNVERIFIED; recommend Phase-7 deferral with GEO-01/GEO-02 noted unverified on hardware). ## Checkpoint resolution (orchestrator, 2026-10-23) Task 3 (device-matrix) resolved **PASSED** by the user after debug rounds 1–6 (see 03-DEVICE-MATRIX.md). Notable in-gate fixes: telegram-web-app.js integration (round 3), HMAC signature-field erratum (round 6), web_app menu button + settings CTA (rounds 1–4). iOS leg recorded UNVERIFIED — no device. Verification: 03-VERIFICATION.md — phase 3 PASSED.