Files
Arah2/.planning/phases/03-mini-app-shell-geolocation/03-DEVICE-MATRIX.md
T

127 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 03 — Device-Matrix Exit Gate (ROADMAP Success Criterion 5)
**Deployed origin (staging):** https://araharah-bot.araharah-bot.workers.dev/
**Deployed version:** 2c1336e3-58f9-4b0b-86a8-b25de66e327c (via `npm run deploy` — theme → web → wrangler deploy with `web/dist` as static assets, D-13/D-14/D-15)
**Status: PENDING REAL-DEVICE VERIFICATION — the phase does not close until every leg has an explicit verdict.**
## Automated half (already green)
- `npm test -w web` — 33 passed, 0 failed (includes BA1–BA6 build-artifact gates over `web/dist`, HTML included)
- `npm test -w bot` — 48 passed, 0 failed
- `npm run capture -w web` — CAPTURE OK, 7/7 non-blank captures off `web/dist-harness`,
including the Desktop denied card, the `?pin=1` chat-pin relay, light + dark live shots,
and the DSGN-02 side-by-side. GEO-03 runtime probe: localStorage / sessionStorage /
cookies / IndexedDB all empty after a real boot-to-live cycle.
- Live canaries at the deployed origin: `GET /` → 200 text/html from the asset binding;
`POST /api/session` → 401 for unsigned bodies (the HMAC gate is live);
`getWebhookInfo` URL ends `/telegram/webhook` with no `last_error`;
`getChatMenuButton` type = `commands`.
## Bot API 10.2 origin prerequisite (hard, blocking)
`wrangler.jsonc`'s `run_worker_first` key drew an "Unexpected fields" warning from wrangler
4.151.3, but the deployed behavior was verified request-by-request: assets serve non-API
paths directly, `/api/*` and `/telegram/*` are answered by the Worker code (401/500, not
asset fallback) — D-13 routing holds in practice; the warnings are cosmetic at this wrangler
version.
- [ ] **BotFather Mini App URL == the deployed origin above.** Bot API 10.2 rejects Mini App
calls from any other origin silently — a mismatch means `Telegram.WebApp.*` no-ops with no
error. Check menu button (`/setmenubutton`) / WebApp URL in @BotFather
(`arasarah-bot.araharah-bot.workers.dev`), not a localhost or Pages URL.
Observed / Symptom: ______________________________________
## The six device legs (each: an explicit verdict + observation)
### 1. Android — real phone, Telegram Android (GEO-01)
- [ ] Boot: BOOT-01 (validating session) → BOOT-02 (acquiring location) → LIVE; the position
marker renders on the Rams basemap.
- [ ] Permission persistence: close the app fully, reopen — **no second permission prompt**.
The grant lives in Telegram's per-bot store on the device, outside the WebView.
Observed / Symptom: ______________________________________
### 2. Android stale-fix check (retires or confirms assumption A1)
- [ ] With the app LIVE, walk several metres and re-check. If the pin does not move, toggle
the phone's Location setting once (off → on) and record whether `navigator.geolocation`
then delivered a fresh fix, and whether the FIRST Android verification needed that toggle.
Result decides: **A1 stands** (toggle required) or **A1 retired** (no toggle needed).
Observed / Symptom (needed toggle? y/n): ______________________________________
### 3. iOS — real phone, Telegram iOS (if available)
- [ ] Boot to LIVE; marker renders; permission grant persists across a reopen.
Observed / Symptom: ______________________________________
(If no iOS device is available: record `UNVERIFIED — no device`; Success Criterion 5
stays open. Do not close the phase anyway.)
### 4. Desktop Telegram (GEO-02 end-to-end)
- [ ] Geolocation is absent by design (issue #77): the app shows the **denied card with
identical copy across all clients** (D-06, RESEARCH Pitfall 4) — no client-specific variant.
- [ ] Tap ASK VIA CHAT → POSTs `/api/location-fallback`; the location keyboard appears in the
user's own chat; tap it, share a live pin; the app picks it up via `GET /api/location`
(within its poll window) and reaches **LIVE**. This is GEO-02 end-to-end.
Observed / Symptom: ______________________________________
### 5. Plain browser (no Telegram context)
- [ ] Open the deployed URL directly in a desktop browser. Expected: the **denied card**
renders over the Rams shell (no `initData` → the HMAC session gate 401s), NOT a blank
page, NOT the live branch. A blank page is a FAIL.
(Optional extra observation: if a browser geolocation prompt leads to LIVE, note it —
but the pass condition for this leg is the deliberate denied state.)
Observed / Symptom: ______________________________________
### 6. Theme flip mid-session (PX-02 — manual-only verification)
- [ ] With the app LIVE on a real client, switch the Telegram theme **light ↔ dark
mid-session** without closing the app. Confirm: (a) shell chrome re-slots (document
background, shell ink swap); (b) the status strip stays matte-black; (c) **the map is
unchanged** — same style, no flash, no camera jump (D-10 / RESEARCH Pitfall 7).
Record a before/after screenshot in each direction and name the client used
(this leg can be folded into any of legs 1/3/4).
Verdict (chrome re-slotted? strip stayed black? map unchanged?): ______________________________________
## How to report back
- Type **"device matrix passed"** if all six legs reached LIVE or the documented
denied-and-recovered state (the theme-flip leg counts as passed when the chrome
re-slotted mid-session and the map was visibly unchanged).
- Otherwise report which leg failed and the exact symptom — a `/gsd-debug` gets opened for it.
- If no physical Android/iOS device is available: report that. The honest outcome is
Success Criterion 5 = UNVERIFIED; the phase is held open with the blocker recorded and
either a device acquired or the matrix explicitly deferred to Phase 7 hardening with
GEO-01/GEO-02 noted as unverified on real hardware. Never close the phase claiming
device verification that did not happen.
## Local-dev note (D-12 / assumption A3)
`localhost:8787` (via root `npm run dev` → `wrangler dev --port 8787 --local`) is a secure
context, so `navigator.geolocation` works under `wrangler dev` while a LAN-IP dev URL would
not. Remote staging (the deployed origin above) is used sparingly, immediately before a
real-device verification session, for exactly that reason.
## 2026-10-23 debug round 1 (mid-gate failure fixes)
**Reported failures + fixes (commit `b1d8768`, deploy `a21c0816`):**
1. *No webview entry from the bot* — root cause: phase 2 armed the menu button as
type `commands` and phase 3 never armed a web_app entry. Fix: new
`bot/scripts/set-menu-button.mjs` → `setChatMenuButton` type `web_app`,
url = deployed origin (verified live via `getChatMenuButton`).
⚠ Client-cached: the menu surface needs an app restart / `/`-autocomplete
to refresh (same quirk as phase 2).
2. *TRY AGAIN / ASK VIA CHAT dead on one card* — root cause: only the first
denied-card instance had listeners; the `awaiting-pin` variant is a second
`buildDeniedCard` instance (03-03 recorded stub). Fix: `wireDeniedActions`
wires BOTH instances in `web/src/main.ts`.
3. *Post-fix canaries*: `GET /` 200, unsigned `/api/session` 401, webhook armed
(`/telegram/webhook`, no last_error), menu button verified `web_app`.
**Notes for the re-run:** on plain Chrome (no Telegram), TRY AGAIN legitimately
re-renders the denied card — session can never validate without initData there;
the pass condition for leg 5 is the deliberate denied state itself. If Android
still shows dead/absent retry interplay after OS location is enabled, open a
follow-up.