From 7b02c7dd4a3a7670d7d70ee91af522a9446851e8 Mon Sep 17 00:00:00 2001 From: araharah-executor Date: Sat, 24 Oct 2026 01:44:51 +0800 Subject: [PATCH] =?UTF-8?q?docs(04-04):=20the=20blocking=20ONBD-02/ONBD-03?= =?UTF-8?q?=20device=20gate=20=E2=80=94=20deployed=20+=20canaries=20green,?= =?UTF-8?q?=20six=20legs=20UNVERIFIED=20pending=20a=20real=20device?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - deploy 31138f79 live at https://araharah-bot.araharah-bot.workers.dev; MINI_APP_URL == origin; menu button web_app armed; commands re-registered (help/privacy/cari); unsigned webhook 401; the live app chunk carries 30/30 gazetteer ids + zero crypto tokens - getWebhookInfo last_error is STALE (2026-10-22, phase-3 era, pre-dates both wave deploys; pending 0) — re-read at leg 1 - all six physical legs recorded UNVERIFIED — the phase stays open until a real Android/iOS/Desktop walks them; no faked verdicts --- .../04-DEVICE-GATE.md | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 .planning/phases/04-destination-search-kl-gazetteer/04-DEVICE-GATE.md diff --git a/.planning/phases/04-destination-search-kl-gazetteer/04-DEVICE-GATE.md b/.planning/phases/04-destination-search-kl-gazetteer/04-DEVICE-GATE.md new file mode 100644 index 0000000..686276b --- /dev/null +++ b/.planning/phases/04-destination-search-kl-gazetteer/04-DEVICE-GATE.md @@ -0,0 +1,139 @@ +# Phase 04 — Device Gate: the ONBD-02 deep-link carrier + the ONBD-03 home-screen launch + +**Deployed origin:** https://araharah-bot.araharah-bot.workers.dev/ +**Deployed version:** `31138f79-3385-4079-a9a8-f1351da3b149` (`npm run deploy` — theme → web → `wrangler deploy` with `web/dist` as static assets + `set-webhook.mjs` re-arm) +**Status: PENDING REAL-DEVICE VERIFICATION — the phase does not close until every leg has an explicit verdict. Every leg below is currently `UNVERIFIED`; no device is attached to this environment. Do NOT fake device results.** + +## What this gate decides + +ONBD-02's carrier is the ONE requirement whose success depends on undocumented Telegram +client behaviour: the bot's OPEN button is a `web_app` inline button whose URL carries +`?dest=` (RESEARCH Pitfall 1 — `WebAppInfo` has exactly one field, +`url`, so `start_param` cannot ride an inline button). The webview reads the URL query +first, the signed `initData`'s `start_param` second, with one shared validation. Only a +real client proves Telegram actually delivers the button's query string into the webview. + +## Automated half (already green — this deploy, 2026-10-23) + +- `npm test -w web` — 57 passed, 0 failed (DP1–DP12 destination gates, HS1–HS9 home-screen + gates, BA1–BA8 build gates incl. the NEW BA7 bot/web id-set parity gate + BA8 no-crypto gate, + the extended GEO-03 storage gate incl. the explicit `web/src/search` pin) +- `npm test -w bot` — 65 passed, 0 failed (CR1–CR15 `/cari` payload gates; the deep-link + contract's other half) +- `npm run search:corpus` — threshold PASS: top-3 68/68 (100%), negatives refused 7/7, + refusal margin 0.643 < 0.72 (the D-14 close holds; lever: None) +- `npm run capture -w web` — **CAPTURE OK — 8/8 non-blank captures**, including the NEW + `shell-dest-preload.png` (?mock=android&dest=suria-klcc → ARAHARAH-DEST + `state=resolved` → the DESTINATION card rendered **Suria KLCC / Jalan Ampang, 50088 + Kuala Lumpur** over the live map, ADD TO HOME SCREEN in the strip). GEO-03 runtime + probe: app storage surfaces empty after boot-to-live. +- Shipped-bundle canary (live origin, `cache: no-store`): `assets/main-B7xbFMG5.js` + carries **all 30/30 gazetteer ids**, ZERO crypto tokens (`createHmac`/`crypto.subtle`/ + `sha256`/`HMAC(` absent), the ONBD-03 copy present. `web/dist/index.html` carries no + harness markers (BA5/BA6 hold in production). + +## Deploy canaries (2026-10-23, post-deploy) + +| Canary | Result | +|--------|--------| +| `getWebhookInfo.url` | `https://araharah-bot.araharah-bot.workers.dev/telegram/webhook` (ends `/telegram/webhook`) ✓ | +| `getWebhookInfo.last_error` | **STALE** — "500 Internal Server Error" dated 2026-10-22 11:18 UTC (phase-3 era, BEFORE the 04-03 and 04-04 deploys); `pending_update_count: 0`. The field cannot clear until the next real update is delivered — re-read it during leg 1 and record what you see. | +| `getChatMenuButton` | `web_app` → `https://araharah-bot.araharah-bot.workers.dev/` ✓ (was un-armed on the first canary read — re-armed with `node bot/scripts/set-menu-button.mjs`) | +| `getMyCommands` | default scope + `all_private_chats` + `ms` scope all list `help`, `privacy`, `cari` ✓ (re-registered with `node bot/scripts/register-commands.mjs`. Note: a `language_code:"en"` lookup returns `[]` because en IS the language-agnostic default set — language-specific sets exist only for `ms`. This is Telegram's scoping semantics, not a registration failure.) | +| Unsigned webhook POST | **401** (the `X-Telegram-Bot-Api-Secret-Token` gate is live) ✓ | +| `MINI_APP_URL` (wrangler vars) | `https://araharah-bot.araharah-bot.workers.dev` — equals the deployed origin exactly ✓ (binding visible in the deploy log) | +| Secrets | never echoed — the bot token was only ever concatenated into Bot API URLs, never printed ✓ | + +## Bot API 10.2 origin prerequisite (hard, blocking) + +- [ ] **@BotFather's Mini App URL == `https://araharah-bot.araharah-bot.workers.dev`.** The + Bot API cannot read the BotFather-side value, so this half is verified on the device: if + the origins mismatch, Bot API 10.2 silently no-ops every `Telegram.WebApp.*` call and + EVERY leg below fails with a blank-shell symptom. The bot-side origins (menu button, + OPEN button via `MINI_APP_URL`) are confirmed equal above — confirm the BotFather side + matches while walking leg 1. + Observed / Symptom: ______________________________________ + +## The six device legs (each: an explicit verdict + observation) + +### 1. ONBD-02 — Android (the carrier that matters) + +- [ ] Send `/cari KLCC` in the bot's chat → a NATIVE venue card for Suria KLCC appears with + "OPEN IN ARAHARAH" + 2–4 alternates. +- [ ] Tap OPEN → the Mini App opens **with the destination PRELOADED**: the DESTINATION card + shows **Suria KLCC / Jalan Ampang, 50088 Kuala Lumpur** over the live map. +- [ ] FAIL SYMPTOMS: a blank map, an empty card stack, or "Destination unavailable" = the + `web_app` button's query string did not survive into the webview (Carrier A collapsed → + pull the carrier-swap lever: `miniAppUrlFor(origin, id)` in `bot/src/bot/commands/cari.ts` + is the ONE place the link is built). +- [ ] While here: re-read `getWebhookInfo.last_error` — it should now be cleared (the + pre-deploy stale error dated 2026-10-22 must not reappear). + Verdict: `UNVERIFIED` (needs Android device) + Client version / OS: ____________ Observed / Symptom: ______________________________________ + +### 2. ONBD-02 — iOS + +- [ ] The same flow on an iPhone: `/cari KLCC` → venue card → OPEN → the destination card + shows Suria KLCC preloaded. +- [ ] Expect `checkHomeScreenStatus` to report `"unknown"` (iOS platform behaviour — see + leg 4; NOT a failure). + Verdict: `UNVERIFIED` (needs iOS device) + Client version / OS: ____________ Observed / Symptom: ______________________________________ + +### 3. ONBD-02 — Telegram Desktop + +- [ ] The same flow on Desktop: `/cari KLCC` → venue card → OPEN. +- [ ] Desktop has no Telegram geolocation (phase 3's issue #77), so observe the DESTINATION + CARD specifically — the location half is phase 3's separate matrix and is NOT this leg. + The boot lands on the denied/awaiting-pin location card first; send a chat pin (attach → + Location) to push the chain live, and the destination card then holds the center register. +- [ ] FAIL SYMPTOM: "Destination unavailable" or a blank map. + Verdict: `UNVERIFIED` (needs Desktop client) + Client version / OS: ____________ Observed / Symptom: ______________________________________ + +### 4. ONBD-03 — home screen add + launch + +- [ ] With the app open, tap the app's "ADD TO HOME SCREEN" affordance (or Telegram's own + "Add to Home Screen" menu item) → the icon appears on the phone's home screen. +- [ ] Close the app fully → tap the icon → the app opens into the SEARCH-READY state: the + map renders, the strip shows its normal boot state, NO destination, NO crash, NO blank map + (D-12: the startapp-less boot is unchanged). +- [ ] On iOS, `checkHomeScreenStatus` reports `"unknown"` — that is the DOCUMENTED platform + limitation (Telegram-iOS #1729, closed as expected behaviour). The affordance still shows + the neutral "ADD TO HOME SCREEN" prompt. This MUST NOT be recorded as a failure. +- [ ] On Android, after adding, the affordance should HIDE (status `"added"`) — record + whether it did. + Verdict: `UNVERIFIED` (needs a phone) + Client version / OS: ____________ Observed / Symptom: ______________________________________ + +### 5. The honest unknown-id state + +- [ ] Open the Mini App with a deliberately wrong id — append `?dest=not-a-real-place` to the + deployed URL (browser or a crafted link): expected the "DESTINATION / Destination + unavailable / That place is not in this build. Search again from the bot." surface. +- [ ] FAIL SYMPTOMS: a blank map, a fabricated pin, a crash — none may occur. + Verdict: `UNVERIFIED` + Observed / Symptom: ______________________________________ + +### 6. The honest refusal + +- [ ] Send `/cari Kuching` in the chat → a plain-text reply naming the v1 area, with NO venue + card, NO inline keyboard, NO pin (SRCH/D-13 negative-refusal law, live on the real bot). + Verdict: `UNVERIFIED` + Observed / Symptom: ______________________________________ + +## If a leg fails + +- Legs 1–3 (carrier): pull the carrier-swap lever — `miniAppUrlFor(origin, id)` in + `bot/src/bot/commands/cari.ts` is the single place the deep link is built (04-03 kept it + swappable for exactly this contingency). The webview reader already accepts BOTH carriers. +- Leg 4: the affordance is behind the Bot API 8.0 guard — record the client's Bot API + version (`wa.version`) if it no-ops. +- Record the verdict inline above, then update `.planning/STATE.md` "Blockers/Concerns" + (the executor leaves this to the orchestrator) — the phase stays OPEN on any + FAIL/UNVERIFIED, never silently closed on unverified hardware. + +--- + +*Phase: 04-destination-search-kl-gazetteer — plan 04-04 blocking gate* +*Automated legs + deploy: 2026-10-23; physical legs: pending user*