docs(04): plan revision 1 — fix wave-1 bundle proof + acceptance-criteria corrections

This commit is contained in:
araharah-executor
2026-10-24 00:02:27 +08:00
parent c0134c7e99
commit 4a83ec6871
5 changed files with 62 additions and 43 deletions
@@ -1077,32 +1077,41 @@ process.exitCode = top3Rate >= 0.9 && leaked.length === 0 ? 0 : 1;
---
## Open Questions
## Open Questions (RESOLVED)
> **STATUS: ALL RESOLVED (2026-10-23, during plan-phase).** Each question below carries its
> `(RESOLVED — …)` decision line; the decisions are binding and are implemented in plans
> 04-01…04-04. Where a plan CORRECTED the original recommendation, the correction is stated.
1. **Which deep-link carrier does Phase 4 ship?** (D-11 says `?startapp=dest_<id>`; the docs put `startapp` on direct links, not inline buttons.)
- **What we know:** `WebAppInfo.url` is an arbitrary HTTPS URL; community reports say query params survive; `startapp` is documented for `t.me` links and `startattach` for attachment-menu links; the `web_app` inline button is a distinct launch surface.
- **What's unclear:** whether Telegram's own clients preserve the query string on a `web_app` button URL across Android/iOS/Desktop.
- **Recommendation:** implement **Carrier A** (`web_app` button, `?dest=<id>` in the URL) as the primary, keep **Carrier B** (`t.me?startapp=`) for the ONBD-03 home-screen path, and **write the payload reader to accept both** (`location.search` first, then `initDataUnsafe.start_param`). Validate on a real device at the exit gate. **Flag to the user**, because it touches a locked decision's wording.
- **(RESOLVED — Carrier A (`?dest=<id>` in the `web_app` button's URL, read from `location.search`) is primary; Carrier B is the signed `initData`'s `start_param` field (the direct-link / home-screen path), NOT `initDataUnsafe` — the recommendation's `initDataUnsafe` reading was corrected: only the SIGNED `initData` is parsed. Both carriers share one validation. Device validation happens at 04-04's blocking gate. Plans 04-03/04-04.)**
2. **Is the venue card one message or two?**
- **What we know:** `sendVenue` has no `text` parameter; D-02 wants one tap to proceed; CONTEXT's "specific ideas" mention a one-line clinical confirmation.
- **What's unclear:** whether "one line confirming the destination" is a separate `sendMessage` before the card, or a property of the card's own `title`/`address`.
- **Recommendation:** **one `sendVenue`** whose `title` is the place name and `address` is the curated address — the native card *is* the confirmation, and this honours D-02's single-message shape. If the user wants a separate clinical line, it costs one extra message and must be added to the copy gate.
- **(RESOLVED — exactly one `sendVenue` per card; `sendVenue` has no `text` param, so the card's own `title` (canonical name) + `address` (curated, verbatim) IS the confirmation. Enforced by CR4's request-count gate. Plan 04-03.)**
3. **What is the exact corpus size and the exact per-query expectation?**
- **What we know:** D-13 says ~60–100 queries with the listed categories; D-14 sets ≥90% top-3 on positives.
- **What's unclear:** whether the 90% is measured over *all* positives or over positives *excluding* the typo bucket (typos are the hardest and the fuzzy tier's raison d'être).
- **Recommendation:** measure and report **per-category** rates (exact / abbreviation / glued / typo / alias), and set the D-14 gate on the **all-positives** figure, with per-category figures reported alongside so a regression is diagnosable. This is OpenCode's Discretion; state it in the plan.
- **(RESOLVED — the D-14 gate measures the ALL-POSITIVES top-3 rate (≥ 90%, threshold `0.9` pinned in the corpus file); per-category rates are REPORTED alongside and carry authoring floors (landmark ≥ 12, abbreviation ≥ 15, glued ≥ 6, typo ≥ 12, alias ≥ 12, negative ≥ 6). Plan 04-02, corpus format + CO7.)**
4. **Which `SearchSource` seam shape?**
- **What we know:** D-03 requires a pluggable interface with the gazetteer as implementation #1, WASM geocoder as #2, Photon as #3.
- **What's unclear:** whether the interface is synchronous or async, and whether it lives in the shared package or in `bot/src/search/`.
- **Recommendation:** `async search(): Promise<SearchHit[]>` (a network-backed backend #3 will need it), defined in the **shared package** so the webview can use the same types. The `byId(id)` lookup — needed by the callback handler and the webview — should be a **separate, synchronous** method on the interface, because both the callback handler and the deep-link reader need it and neither should await a network.
- **(RESOLVED — `SearchSource` lives in the shared `search/` workspace (`search/src/types.ts`): `async search(q): Promise<SearchHit[]>` plus a SEPARATE SYNCHRONOUS `byId(id)`. The package also exports a synchronous `search(text, limit?)` convenience wrapper for the corpus runner. Plans 04-01 (contract), 04-03/04-04 (consumers).)**
5. **Is the Overpass script required to have a *verified* run in this phase?**
- **What we know:** `overpass-api.de` returns **406 without a `User-Agent` and 200 with one** (verification pass, same host/same paths); `overpass.kumi.systems` and `overpass.private.coffee` are unreachable from this network (HTTP 000); `overpass.osm.ch` returns 400 (Switzerland-only); Nominatim and Geofabrik work.
- **What's unclear:** whether the phase's exit gate requires the Overpass path to have been exercised against live OSM.
- **Recommendation:** the plan should require the script to **run and produce a valid-shaped proposal file** (verified against a **committed fixture** of a real Overpass response, committed to the repo so the test is deterministic), and to document the live-source URL in the script's header. **The `User-Agent` header is load-bearing and must be asserted by a test** — a missing UA produces a 406 on every endpoint and looks like a dead service. The curated entries themselves should be coordinate-verified against **Nominatim** (reachable) — which satisfies D-06's "hand-curated seed" with real coordinates. **Do not plan around a blocked Overpass**: the live path works from this machine once the header is set; the fixture is for *determinism*, not for working around an outage.
- **(RESOLVED — no live-Overpass obligation: the script is proven offline against the COMMITTED fixture (`--source=fixture`), with `--source=overpass|nominatim` as the maintainer's live paths; the identifying `User-Agent` is mandatory and TP2-asserted; a busy instance soft-exits 0 (TP4); curated coordinates are spot-verified against Nominatim and recorded in `docs/SEARCH-QUALITY.md`. Plan 04-02.)**
---