feat(beta): phase 5 — the app page and the closed-beta signup
All checks were successful
PR checks / checks (pull_request) Successful in 1m5s
All checks were successful
PR checks / checks (pull_request) Successful in 1m5s
Builds `/app/` and `/beta/`, the SQLite signup store, the rate limiting and the export CLI of PLAN.md §8, and adds this repository's first test suite. Four decisions of record, D26–D29 (§8, "How phase 5 built the app and the beta"): - D26 — the screenshot slot ships empty, reserved for phase 9. §10 promised `/app/` "the 14 existing screenshots"; they are a July trusted-device smoke test against an unseeded dev instance, captured before the theming work, and five of the fourteen are two-factor prompts. Shipping them would break D4. Phase 9 already builds the rig, so it gains an emulator pass. - D27 — the public demo is the tester target. `ConnectScreen.kt` gates the whole app on a validated deployment address, so a tester needs somewhere to point it. The beta therefore waits on the demo VM, and the page says so. - D28 — `/beta` handles its own POST; there is no `/api/beta-signup`. An endpoint cannot report a validation error without JavaScript. §6's diagram is amended. - D29 — the APK and the beta get equal billing, and the APK link is off: `androidApk.serviceable` is false because the published v0.5.0 build does not work. The panel stays and states that plainly rather than being removed. Three mechanisms the plan did not anticipate: - `liveBrand()` — a server-rendered page never passes through the boot rewrite, so `/beta` reads the mounted brand.json itself. Pasting the Play opt-in URL in takes effect on the next request rather than the next restart. - `checkLinks.mjs` derives on-demand routes from `prerender = false` in the source. A PLANNED_ROUTES entry would have been wrong: its reverse check fires when a route has been built, and an on-demand route never produces a file, so the entry could never rot out. - `npm test` — the five existing checks all read built output, and none of this logic appears there. A honeypot can stop working and leave the build identical. Also: `checkFacts.mjs` gains the APK assets and `minSdk`, and learns that RFC 2606 reserved domains are not contact addresses; the D13 rule is otherwise unchanged. Verified end to end against the built server: every outcome renders with no JavaScript, cross-origin POSTs are refused, a mounted opt-in URL appears without a restart, and the export CLI round-trips. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,28 @@
|
||||
|
||||
"androidApplicationId": "com.runicgateway.app",
|
||||
|
||||
"$comment_androidApk": [
|
||||
"Phase 5 / `/app/`. The app is not on any store, so the only way to install it is the",
|
||||
"signed APK attached to each Android-app release. `asset` and `checksums` are the two",
|
||||
"assets checkFacts.mjs asserts exist on releases/latest, and `minSdk` is re-read from",
|
||||
"the app's build.gradle.kts — so the download block on /app/ cannot outlive the file it",
|
||||
"points at, and 'Android 10 or newer' cannot outlive the number that makes it true.",
|
||||
"",
|
||||
"`serviceable` is the one value here with no authority to check it against, and it is",
|
||||
"deliberately manual. It answers a question no API can: does the published build",
|
||||
"actually work. The org lead reports v0.5.0's does not, so the download block renders a",
|
||||
"'being replaced' state instead of a link, and flipping this to true is the single edit",
|
||||
"that turns the link back on once a working build is released. A check cannot run an",
|
||||
"APK; a person can, and this is where they record that they did."
|
||||
],
|
||||
"androidApk": {
|
||||
"asset": "runic-gateway-0.5.0.apk",
|
||||
"checksums": "SHA256SUMS",
|
||||
"minSdk": 29,
|
||||
"minAndroid": "10",
|
||||
"serviceable": false
|
||||
},
|
||||
|
||||
"gitea": {
|
||||
"base": "https://gitea.whitlocktech.com",
|
||||
"org": "RunicGateway"
|
||||
|
||||
Reference in New Issue
Block a user