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>
92 lines
3.8 KiB
YAML
92 lines
3.8 KiB
YAML
name: PR checks
|
|
|
|
# Gitea Actions caution, learned elsewhere in this org: never leave an empty
|
|
# template expression anywhere in a `run:` script, not even inside a comment.
|
|
# The runner silently SKIPS the whole step without failing the job, and the
|
|
# problem is invisible in the workflow list.
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main]
|
|
push:
|
|
branches: [main]
|
|
|
|
jobs:
|
|
checks:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Check out
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
cache: npm
|
|
|
|
- name: Install
|
|
run: npm ci
|
|
|
|
- name: Design tokens
|
|
# PLAN.md §7 — no colour literal outside src/styles/tokens.css.
|
|
run: npm run check:tokens
|
|
|
|
- name: Branding pipeline
|
|
# PLAN.md §7 — brand-default is complete, every /brand/* URL the source asks for
|
|
# resolves against the route's own allowlist, and every brand string the boot
|
|
# rewrite replaces is distinctive enough to replace blindly.
|
|
run: npm run check:brand
|
|
|
|
- name: Types
|
|
run: npm run check
|
|
|
|
- name: Unit tests
|
|
# PLAN.md §8 — the beta signup's decision path: honeypot, form token, timing, rate
|
|
# limit, cap, validation, duplicate, removal.
|
|
#
|
|
# The first thing in this repository that the other checks cannot see. They all read
|
|
# the built output, and none of this appears there: a honeypot that has stopped
|
|
# working produces a build that is identical in every way to one where it works.
|
|
#
|
|
# The test file is NAMED rather than the directory passed. `node --test test/` fails
|
|
# on Node 22 with MODULE_NOT_FOUND — directory mode is not portable across the
|
|
# versions this org runs, and this workflow pins 22 while developers are on 24, so
|
|
# the shorter form would pass locally and break only here.
|
|
run: npm test
|
|
|
|
- name: Production build
|
|
run: npm run build
|
|
|
|
- name: Links
|
|
# PLAN.md §12 — every internal link resolves, and every outbound link into a
|
|
# RunicGateway repository points at a branch path rather than a commit permalink.
|
|
#
|
|
# It runs AFTER the build, and that ordering is the design rather than a
|
|
# convenience: it reads the built HTML, so links assembled from data files and
|
|
# template literals are checked as the strings they actually become. A source scan
|
|
# would see an expression and skip most of what phase 4 added.
|
|
#
|
|
# No network: the outbound rule is about the shape of a URL, and a build that
|
|
# fails because some other host is slow is a check people learn to ignore.
|
|
run: npm run check:links
|
|
|
|
- name: Platform facts
|
|
# PLAN.md §12 — every version, protocol number and bundle tag is re-read from
|
|
# its authority over the Gitea API and must agree with src/data/platform.json.
|
|
#
|
|
# This needs a token that can read the OTHER repositories in the org: link,
|
|
# servuo-plugins, website and installer. The automatic per-run token is scoped
|
|
# to this repository alone and 404s on all four, so the job uses the org-level
|
|
# REGISTRY_TOKEN, which already exists and already carries the right scope.
|
|
#
|
|
# The secret is named for the registry; the script reads GITEA_TOKEN. Mapping it
|
|
# here rather than renaming either side keeps the script's interface honest — it
|
|
# wants a Gitea token, not this org's particular secret.
|
|
#
|
|
# It runs last, and it is the only step that touches the network, so a Gitea
|
|
# outage cannot mask a real failure in the build.
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
run: npm run check:facts
|