Self-hostable game server control panel: Go controller + agent, 26 game modules, embedded web UI. One-line install via install.sh / install.ps1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
controller/.test — UI regression gate
Two layers, run them in this order.
1. gate-parse.mjs — static, zero dependencies, run ALWAYS
node controller/.test/gate-parse.mjs
Extracts every inline <script> block from controller/cmd/controller/static/{new,index,login}.html
and parses each one (acorn if installed locally, else node --check on
extracted temp files). Exit 0 = all blocks parse; non-zero prints the file,
block index, and the parser error.
This is the codified 2026-05-08 blank-page deploy gate: the panel HTML is
embedded via //go:embed, so go build succeeds even when a JS syntax error
would render the entire panel blank. Run this before every controller build
that touched static/*.html. Needs nothing but Node — no npm install, no
controller, no browser.
2. ui.spec.mjs — Playwright browser suite, needs a RUNNING controller
cd controller/.test
npm install && npx playwright install chromium # one-time
BASE_URL=http://127.0.0.1:8080 \
TEST_EMAIL=you@example.com TEST_PASSWORD=... \
npx playwright test ui.spec.mjs
Prereqs (see memory/build.md): Postgres dev container up
(docker compose -f docker-compose.dev.yml up -d), controller built and
running on BASE_URL (default http://127.0.0.1:8080).
| Check | Needs |
|---|---|
/login renders form, 0 console errors |
controller only |
/ without session redirects to /login |
controller only |
/ serves new.html by default, 0 hard console errors |
controller + TEST_EMAIL/TEST_PASSWORD |
panel_ui=classic cookie serves index.html, no redirect loop (the FileServer 301 gotcha, see memory/gotcha-fileserver-index-html-redirect-loop.md) |
controller + creds |
Command palette opens (Ctrl+K and #topbar-cmdk) |
controller + creds |
Hero-stat IDs (#stat-running/players/agents/cpu + hints, #status, #status-dot) attached |
controller + creds |
Without TEST_EMAIL/TEST_PASSWORD the authenticated tests self-skip
(Playwright annotation, not failure). Console errors that are clearly
missing-live-agent-shaped (websocket/agent connection noise) are annotated
needs-live-agent rather than failed — a live agent is never required.
Status honesty
gate-parse.mjs has been run for real on this repo. ui.spec.mjs was
authored against the real DOM IDs in static/new.html / static/login.html
and the root-route logic in httpapi.go, but a full run requires a local
Postgres + controller — if your box doesn't have the dev Postgres container,
the browser suite is unverified there.