docs(04-04): the blocking ONBD-02/ONBD-03 device gate — deployed + canaries green, six legs UNVERIFIED pending a real device
- 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
This commit is contained in:
@@ -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=<plain-gazetteer-id>` (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*
|
||||||
Reference in New Issue
Block a user