docs(android): bake the version gate, identity model + native build into the docs

ARCHITECTURE §2 (client-version gate + frozen wire contract + gate x offline),
§3 (local-guest / server-guest / reconciliation identity), §13 (native Capacitor
build). FUNCTIONAL (+_ru) a new "Native app (Android)" domain. TESTING (the
clientver/gate Go tests, the native/update e2e + retry mapping, and the manual
on-device Android smoke checklist). deploy/README (GATEWAY_MIN_CLIENT_VERSION +
the wire-break bump discipline + the Android build/release runbook). ui/README
native VITE_* vars. Mark F done in ANDROID_PLAN.md.
This commit is contained in:
Ilia Denisov
2026-07-12 20:38:58 +02:00
parent ca2c6487cf
commit eec225c4ee
7 changed files with 150 additions and 3 deletions
+24 -1
View File
@@ -31,7 +31,20 @@ tests or touching CI.
build's `/e2edict/`, copied in by `scripts/e2e-dict.mjs` from `E2E_DICT_DIR` — the `ui`
CI job fetches the `scrabble-dictionary` release like the Go jobs; locally it defaults to
the sibling `scrabble-solver/dawg`. These dawgs are never committed and never enter the
production build.
production build. The **native offline-first** spec (`e2e/native.spec.ts`) injects
`window.androidBridge` (so `@capacitor/core` resolves the platform to `android` — a bare
`Capacitor.getPlatform` stub is clobbered by the core shim), then asserts a no-session cold boot lands
in the **offline guest lobby** (not `/login`), plays a local vs_ai move from the **bundled** dawg tier
(`playwright.config.ts` bundles the dicts into `dist-e2e/dict/`), starts a hotseat game, and drives
`window.__native.reconcile()` to prove online lights up and Profile hides the Telegram/VK link buttons.
The **update overlay** spec (`e2e/update.spec.ts`) drives the `__update` hook to prove the terminal
update cover; `retry.test.ts` covers the `FailedPrecondition → update_required` mapping.
- **Client-version gate** (Go) — `gateway/internal/clientver` unit-tests the `v?MAJOR.MINOR.PATCH` parse
(with/without `v`, a `-N-gSHA` suffix, `dev`/empty ⇒ !ok) and ordering; `connectsrv`'s server tests
assert a too-old `Execute` returns `result_code = "update_required"` (and the op handler never ran), a
too-old `Subscribe` returns `FailedPrecondition`, and an absent header / empty min / unparseable header
/ equal version all pass (fail-open); `config` tests reject a non-empty, unparseable
`GATEWAY_MIN_CLIENT_VERSION`.
- **Render sidecar** — `renderer/` (Node + skia-canvas executing the shared
`ui/src/lib/gameimage.ts`) carries a `node --test` smoke: the committed fixture (a
real self-played 35-move game) must rasterize to a plausible PNG
@@ -175,6 +188,16 @@ tests or touching CI.
`inttest` drives the **feedback lifecycle** end to end: the guest / ban / pending gates, the reply
read + one-week visibility window, the account-role grant/revoke, and the admin queue filters with
delete / delete-all. The admin-console render test renders the feedback list + detail pages.
- **Native Android (manual on-device smoke)** — the packaged APK is verified by hand on a device /
emulator before release (the automated e2e covers the offline-first logic; WebView-specific chrome and
store behaviour are not reproducible in Playwright). Checklist: installs and cold-launches; in
**airplane mode** the cold launch lands in the **guest lobby**; play a local **vs_ai** move and a
**2-player hotseat** game with no network; the hardware **Back** button navigates then exits at the
root; a share / export link resolves to `erudit-game.ru` (not `file://`); turning the **network on**
lights up online play (a server guest is established); Profile offers **email** sign-in but no
Telegram / VK link; and with `GATEWAY_MIN_CLIENT_VERSION` bumped above the build, an online action
raises the terminal **update** overlay. Measure native chrome (safe-area / edge-to-edge) by CDP, not by
eyeballing a screenshot — an emulator WebView may be newer than a user's device (see `.claude/CLAUDE.md`).
## Principles