186 lines
10 KiB
Markdown
186 lines
10 KiB
Markdown
# 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.
|
||
|
||
## 2026-10-23 debug round 2 (no prompt / no on-device enable path)
|
||
|
||
**Symptom (legs 1 + 5):** denied card shows but no native prompt ever appears,
|
||
and the card offers no way to actually enable location — TRY AGAIN instant
|
||
re-fails when access was previously denied/services off.
|
||
|
||
**Root cause:** the D-06 card only offered chain re-run + chat fallback. When
|
||
Telegram's LocationManager has a settings-resolvable denial (access denied
|
||
earlier, or services off), the ONLY realistic recovery is Telegram's own
|
||
permission pane — `LocationManager.openSettings()` — which was typed optional
|
||
but never invoked anywhere.
|
||
|
||
**Fix (commit after round 1, deploy `bb92dbeb`):**
|
||
- Denied cards gain a THIRD CTA — `LOCATION SETTINGS / TETAPAN LOKASI`
|
||
(new strings key pair; COPY5 gates still green) — rendered on
|
||
Telegram clients only (`wa.LocationManager` presence test).
|
||
- Click → `lm.openSettings()` (gateway re-runs the chain too, covering
|
||
clients without the API).
|
||
- `locationManagerUpdated` event listener re-runs the chain the moment
|
||
the user grants, instead of waiting for another tap.
|
||
- UI-SPEC amendment: copy table + denied-CTA list append this third action
|
||
(Telegram-only conditional); rationale recorded here per debug-round
|
||
protocol.
|
||
|
||
**Re-test instruction:** restart the Telegram client (menu is cached), open
|
||
the app from the menu button, on the denied card tap LOCATION SETTINGS →
|
||
grant location in Telegram's pane → the app should reach LIVE without
|
||
another tap. Legs 1/2/6 resume from there.
|
||
|
||
## 2026-10-23 debug round 3 (definitive production root cause)
|
||
|
||
**Symptom:** cards render but the app behaves as if there is NO Telegram at all —
|
||
no initData (session always 401s), no LOCATION SETTINGS button, BackButton dead.
|
||
Even the recenter/theme machinery could not function through real Telegram.
|
||
|
||
**Root cause:** `web/index.html` never loaded `telegram-web-app.js`. Telegram does
|
||
NOT auto-inject `window.Telegram` (03-RESEARCH.md line ~687 made the opposite call —
|
||
erratum logged in RESEARCH). Every production symptom traces to `getWebApp()` → null.
|
||
|
||
**Fix (deploy `3c25dd32`):** `<script src="https://telegram.org/js/telegram-web-app.js">`
|
||
added to `<head>` before the module script. Builds + 33/33 gates green.
|
||
Erratum recorded in 03-RESEARCH.md.
|
||
|
||
**Re-test:** restart Telegram client, reopen web app from the menu button —
|
||
expect the REAL boot (BOT-01 → BOT-02 → LIVE with an actual permission ask or
|
||
a live LocationManager read + LOCATION SETTINGS available on denial).
|
||
|
||
## 2026-10-23 debug round 4 (missing LOCATION SETTINGS on the main denied card)
|
||
|
||
**Symptom:** user still sees only TRY AGAIN / ASK VIA CHAT — no LOCATION SETTINGS.
|
||
|
||
**Root cause:** executor patch-order bug — round 2 attached
|
||
`withLocationSettings` only to the awaiting-pin card instance; the primary
|
||
denied card (the one shown at denial) never got the CTA.
|
||
|
||
**Fix (deploy `253d7a3e`):** both denied-shaped instances now build with the
|
||
Telegram-only settings CTA. Deployed `index.html` verified to carry
|
||
telegram-web-app.js (round 3 fix verified live via curl).
|