Release: promote development → master (old Android WebView support + unsupported-engine telemetry) #178

Merged
developer merged 3 commits from development into master 2026-07-04 21:23:30 +00:00
Owner

Release: promote developmentmaster

Two features, both already merged to development, CI-green and verified on the test contour:

  • #176 — Old Android in-app WebView support. The Telegram/VK in-app WebView showed a white screen on an old frozen Chromium (≈66). Fixed: build.target es2022→es2019 (esbuild down-levels the syntax); a conditional core-js loader (only old engines download polyfills.js, modern payload/size-budget untouched); a board cqwvmin glyph fallback (Chrome <105). Below the hard floor (Chrome 67 — BigInt/Proxy are unpolyfillable) a permanent ES5 boot guard shows a friendly "your device's OS/browser can't run the app" screen (with the web-version link inside a Mini App) + a Diagnostic view — instead of a white screen.

  • #177 — Unsupported-engine telemetry. The boot guard beacons POST /telemetry/unsupported (deduped in localStorage), the gateway folds it into unsupported_engine_total{reason, chromium} (cardinality-bounded, UA logged not labelled), surfaced on the Scrabble — Users Grafana dashboard beside app opens.

Diff: 14 files, +575/-5 (git diff origin/master..origin/development). No unrelated changes.

After merge (separate, owner-driven)

A PR into master is test-only — this does NOT deploy to production. The prod rollout is the manual prod-deploy.yaml (confirm=deploy). Per the runbook: tag vX.Y.Z on master (last release was v1.8.0 — this is a feature release), then trigger the prod deploy. I'd run /deploy-check first (the telemetry adds a gateway endpoint + a Caddy route — deploy-touching).

## Release: promote `development` → `master` Two features, both already merged to `development`, CI-green and verified on the test contour: - **#176 — Old Android in-app WebView support.** The Telegram/VK in-app WebView showed a white screen on an old frozen Chromium (≈66). Fixed: `build.target` es2022→es2019 (esbuild down-levels the syntax); a conditional core-js loader (only old engines download `polyfills.js`, modern payload/size-budget untouched); a board `cqw`→`vmin` glyph fallback (Chrome <105). Below the hard floor (Chrome 67 — BigInt/Proxy are unpolyfillable) a permanent ES5 boot guard shows a friendly "your device's OS/browser can't run the app" screen (with the web-version link inside a Mini App) + a Diagnostic view — instead of a white screen. - **#177 — Unsupported-engine telemetry.** The boot guard beacons `POST /telemetry/unsupported` (deduped in localStorage), the gateway folds it into `unsupported_engine_total{reason, chromium}` (cardinality-bounded, UA logged not labelled), surfaced on the **Scrabble — Users** Grafana dashboard beside app opens. Diff: 14 files, +575/-5 (`git diff origin/master..origin/development`). No unrelated changes. ## After merge (separate, owner-driven) A PR into `master` is **test-only** — this does NOT deploy to production. The prod rollout is the manual `prod-deploy.yaml` (`confirm=deploy`). Per the runbook: **tag `vX.Y.Z` on `master`** (last release was v1.8.0 — this is a feature release), then trigger the prod deploy. I'd run **/deploy-check** first (the telemetry adds a gateway endpoint + a Caddy route — deploy-touching).
developer added 3 commits 2026-07-04 21:21:06 +00:00
feat(ui): support old Android in-app WebViews (es2019 + core-js + engine screen)
CI / changes (push) Successful in 2s
CI / unit (push) Has been skipped
CI / integration (push) Has been skipped
CI / ui (push) Successful in 1m5s
CI / conformance (push) Successful in 9s
CI / gate (push) Successful in 0s
CI / deploy (push) Successful in 1m54s
4dfedd02a3
Old Android System WebViews (the Telegram/VK in-app browser; a real device with Google
Play auto-updates the WebView, but emulators / no-Play / restricted devices stay frozen)
showed a white screen. Two causes, fixed in order:

- build.target es2022 shipped ?./?? verbatim, which the old engine cannot parse. Lowered
  to es2019 so esbuild down-levels the syntax.
- The es2020+ runtime globals the bundle and its deps call (globalThis, structuredClone,
  Array.at, ...) are missing on those engines. A conditional core-js loader (emitPolyfills
  writes dist/polyfills.js, document.write'd by an index.html gate only when needed) covers
  them; modern engines download nothing, so the bundle-size budget is untouched.

BigInt (the 64-bit FlatBuffers timestamp decode) and Proxy (Svelte 5 runes) cannot be
polyfilled, so the effective floor is Chrome 67. Below it, a permanent ES5 boot guard in
index.html shows a friendly "this device's OS or browser can't run the app" screen (with
the web-version link inside a Mini App) and a "Diagnostic information" view with a Copy
button, instead of a white screen. A reactive net raises the same screen on an uncaught
boot error that never signals window.__booted.

Board tile glyphs used container-query units (cqw, Chrome 105+) under .cell font-size:0,
so they collapsed to 0px on Chrome 74 (invisible letters); added vmin fallbacks.

The unsupported-engine telemetry beacon is a separate follow-up PR.
feat(gateway): unsupported-engine telemetry beacon + Grafana counter
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 1m5s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m40s
2feb638329
The index.html boot guard now fires a fire-and-forget beacon (POST /telemetry/unsupported)
when it turns a client away on the unsupported-engine screen, so the owner can see — on the
Users dashboard beside "app opens" — how many real clients hit it and on which engines.

- Client: navigator.sendBeacon (fetch fallback) with a localStorage dedup keyed by app version
  + reason + Chromium, so a user reopening the app is one report, not ten.
- Gateway: a new unauthenticated POST /telemetry/unsupported handler (the client never booted,
  so it carries no session), per-IP public-limited and body-capped, mirroring the export-download
  route. It folds the beacon into the OTel counter unsupported_engine_total {reason =
  no_bigint/no_proxy/boot_error/other, chromium}, with reason allow-listed and the Chromium major
  reduced to a bounded range (normalizeUnsupported) so a spoofed beacon cannot inflate the metric
  cardinality; the full user agent is logged, not labelled.
- Caddy: /telemetry/* added to the @gateway matcher (else it falls to the landing catch-all).
- Grafana: two panels on the Scrabble — Users dashboard (by reason, by Chromium major).
- Docs: ARCHITECTURE.md §11.

Tests: recordUnsupportedEngine (metric split), normalizeUnsupported (cardinality bounding), and
the handler route end to end (204 / 405 / counter). go build+vet+test and gofmt clean; ui
check/build/e2e green; the client beacon + dedup verified against a forced hard-gate (BigInt
removed) — one POST, deduped on reopen, correct reason/chromium/version labels.
Merge pull request 'feat(gateway): unsupported-engine telemetry beacon + Grafana counter' (#177) from feature/unsupported-engine-telemetry into development
CI / changes (push) Successful in 2s
CI / unit (push) Successful in 10s
CI / integration (push) Successful in 19s
CI / ui (push) Successful in 1m6s
CI / conformance (push) Successful in 9s
CI / gate (push) Successful in 0s
CI / deploy (push) Successful in 1m44s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Successful in 1m5s
CI / conformance (pull_request) Successful in 9s
CI / deploy (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
fcedadcb5b
owner approved these changes 2026-07-04 21:21:52 +00:00
developer merged commit 45957bdcd6 into master 2026-07-04 21:23:30 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#178