# Reference Web Application — the pattern every governed project copies (GOV-B7.4, Standard v3.9)

Built under CR-010, 2026-09-01, as the acceptance evidence for REQ-SYS-13 / REQ-PIL-033 / REQ-UC-015
(the mandatory web-application function). Pure Python standard library — no pip installs — so it runs
anywhere Python runs, and it containerises in one small image.

## What it proves (and how to re-prove it)

| Claim | Evidence command |
|---|---|
| Starts from one command | `python3 run.py --engine stub` (or `--engine glm` with `GLM_API_KEY` set) |
| Serves a login page | open `http://127.0.0.1:8000` — named-user login, scrypt-hashed at rest, 5-fail lockout |
| Completes an adapter round-trip | sign in, send a message → reply via the adapter interface (`--engine stub` echoes offline; `--engine glm` calls the real engine) |
| No key in any client-served file | `tests/test_app.py::test_07` sets a canary `GLM_API_KEY` and crawls every client-reachable path |
| Outbound requests guarded | `tests/test_app.py::TestGuard` — http/https only, host validated, loopback/private/link-local refused, connection pinned to the validated IP (no DNS rebinding), redirects refused |
| Responsive, fills the screen | `static/app.css` — mobile-first fluid grid, `100dvh`, centered wide-screen cap, `@media` breakpoints (the DEF-093 fix pattern) |
| Deploy-anywhere | `docker build -t project-webapp . && docker run -p 8000:8000 -e GLM_API_KEY=… project-webapp` |

Full suite: `python3 -m unittest discover -s tests` — 16 tests (also runs under pytest).

## The rules it embodies

- **GOV-B7.3 / PIL-WA-3**: the API key is read from the server ENVIRONMENT at call time. It is never in a
  file under `static/`, never in a response, never logged. Putting it anywhere client-reachable is a Class 1 defect.
- **GOV-B7.1**: named local user accounts (`users.json`, server-side, scrypt hashes; first run prints a
  one-time admin password, or seed with `ADMIN_USER` / `ADMIN_PASS`).
- **Pluggable engines**: add a module under `adapters/` implementing `BaseAdapter` and register it in
  `app.ADAPTERS`. GLM ships first; Kimi, Gemini, Claude and GPT adapters are per-project additions.
- **INV-6 discipline client-side**: engine output is rendered with `textContent`, never as HTML.

## Known state (honest)

- The **real-engine round-trip with a real GLM key is NOT CLOSED** — it needs Zaid's key at runtime
  (`GLM_API_KEY=… python3 run.py`, then one message in the UI). The stub round-trip and the guard tests are verified.
- `users.py`, the store and the demo once exposed a two-instance seeding bug (fixed 2026-09-01 after the live
  demo caught it; the test suite was re-pointed at the handler's store so it can never mask that class again).
