D4 asked for screenshots of the review stack rather than placeholders. Seventeen
of them: eleven of the site in a browser, six of the app on a phone, all from one
demo deployment wired to a running ServUO shard over a real sidecar, captured on
one day (D42).
The deployment is branded "Runic Gateway Demo" rather than a real community (D43),
and the captures sit beside the claims they support — the homepage, /features/, and
five of the administration pages phase 7 could describe but not show (D44).
The rig is committed rather than remembered (D45):
scripts/seedDemo.mjs content, by driving the site's own API — never SQL,
because a row the product could not have produced is
a screenshot of a product that does not exist
src/data/screens.mjs every capture: route, viewport, scroll, alt, caption
scripts/captureScreens.mjs npm run screens:capture
scripts/checkScreens.mjs the ninth check script, in CI
Shard-side dressing is servuo-plugins' scaffolding (D46), never deployed.
The rig found five things nothing else had. One is fixed upstream — a fresh
module-uo install pinned wire protocol 3 against a sidecar speaking 4, released as
v1.0.2, which this repo's own facts check then caught in platform.json. Four are
raised as product observations and worked around in the rig: a renamed guild
member never reaches the site, a guild deleted while the shard is down is a ghost
row forever, "Houses in danger" cannot show a house that was already collapsing,
and the app's news list prints raw ISO timestamps.
Players online reads 0. Logging a character in needs a UO client driven by hand,
and that is where this stopped — PLAN.md §10 says exactly why, and how to retake
the two frames that would change.
Co-Authored-By: Claude <noreply@anthropic.com>
Recovering installer's orphan tag published v0.1.1, which moved the platform
under this branch and turned checkFacts red -- the check working exactly as it
should, since a version this site quotes had changed.
FAIL release installer
platform.json says : v0.1.0
installer releases/latest says : v0.1.1
The 500 that orphaned the tag was a race with the tag push one second earlier,
not a structural failure: re-running the workflow took the built-in orphan-tag
recovery path and published all four assets unchanged.
So the stale-path Aside stops saying "v0.1.0 is still the current download",
which is no longer true, and says the durable thing instead -- v0.1.0 prints
the old path, v0.1.1 prints the real one -- which stays correct however many
releases follow. platform.json and the PLAN.md version table move to v0.1.1,
and the phase 7 findings record the pipeline defect as a fourth finding.
Co-Authored-By: Claude <noreply@anthropic.com>
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>
`data/` without a leading slash matches a directory of that name at any
depth, so it silently swallowed src/data/platform.json -- the single file
every page and checkFacts.mjs reads.
The working tree still had it, so `npm run verify` passed locally with all
14 facts green. CI cloned fresh and `astro check` failed on the missing
module. Anchored both patterns to the repository root.
Verified the way it should have been the first time: exported HEAD to a
clean directory, npm ci, and ran the checks there rather than in the tree
that was hiding the problem.
Co-Authored-By: Claude <noreply@anthropic.com>