**Phase 01 final verification pass — all criteria green**
- Verified (nothing left to implement; all 4 task files already in `complete/`): toolchain lock, typed `Settings`+`.env.example`, debugpy bootstrap, app factory, CLI (`--host/--port/--reload/--levels-dir`, `python -m undercooked`), static shell + `/static`, security headers, no-CDN/doc guards, `validate.sh`.
- `uv sync --extra dev` → exit 0; `uv.lock` present (untracked → harness commits it with the phase).
- `uv run undercooked --host 127.0.0.1 --port 8000` → `curl /healthz` = 200 `{"status":"ok","version":"0.1.0","rooms":0}` (superset of the criterion's body — now documented in README); `curl /` = 200 shell HTML; static css/js 200; CSP/nosniff/no-referrer/DENY on 200, 404 and 405 too.
- `DEBUGPY=1`: port 5678 is held on this machine by the user's own podman dev-container debugpy adapter — **no live change made/killed**; verified via `DEBUGPY=1 DEBUGPY_PORT=5679` → listener opens, `/healthz` still 200; the occupied-port case degraded gracefully as designed (warning, server serves). Bad config → one line + exit 2 ✓.
- `bash .agents/validate.sh` (root **and** `.agents/`) → exit 0: `ruff check .` 0 errors, `pyright` 0 errors, levels-CLI notice-skip (matches README prose), **284 passed** full suite incl. 10 Playwright e2e, coverage **100.00%** (floor 90), repo hygiene clean. `uv run pytest -m e2e` → 10 passed.
- Docs fixed: README Status → phase 01 complete + next pending 02 (was pointing at `todo/01…`), documented real `/healthz` body, precedence now "CLI flags > env > .env > default", added the PLAN §13-promised **How to play** section (honest about shell-only today), Layout rows marked what exists vs phases 02/07. AGENTS.md: recorded the `data:`-URL exemption in the no-CDN rule (test allows it) and matched the session-token rule to the browser's WebCrypto/base64url implementation. Also corrected a stale "session-wide chromium" docstring in `tests/e2e/conftest.py` (fixtures are function-scoped).
- Deviations: no container build run (needs an image pull; not a phase criterion — `Containerfile`/`compose.yaml` reviewed and consistent with `docs/DEPLOYMENT.md`); `HEAD /` is 405 (routes are GET-only by design; health checks use GET). No git index/history commands run.
- Next pending phase: `02_level_content_and_validation`.
44 lines
2.7 KiB
Markdown
44 lines
2.7 KiB
Markdown
# DESIGN.md — architecture and the decisions behind it
|
||
|
||
**Status:** stub written by phase 01 · **Filled in by phase 09**, when the client, the
|
||
protocol and the first two-player end-to-end story make the prose verifiable.
|
||
|
||
## Purpose
|
||
|
||
This document explains the shape of the server and the client in prose: which module owns
|
||
what, why the boundaries are drawn where they are, and the reasoning behind the LOCKED
|
||
decisions A1–A12 of `.agents/PLAN.md` §3. `PLAN.md` states *what* was decided and stays
|
||
frozen; this file is where the *why* lives and where a later phase records the
|
||
consequences of those decisions once the code proves them out.
|
||
|
||
## The two-line version
|
||
|
||
One asyncio process holds every room. The browser is an untrusted thin client: it sends
|
||
inputs, receives snapshots, and interpolates. All truth lives in
|
||
`src/undercooked/sim/`, a pure function of `(state, dt)` with no I/O, no clock and no
|
||
unseeded randomness, which is what makes headless determinism tests (A5/A21) possible at
|
||
all. Everything around that kernel — `server/` (FastAPI app, WebSocket protocol, room
|
||
supervisor, in-memory session records) and `app/static/` (vanilla ES modules, Canvas 2D)
|
||
— exists only to move bytes between a player's hands and the simulation.
|
||
|
||
## Module map (as it stands after phase 01)
|
||
|
||
| Path | Owns | Filled in by |
|
||
|---|---|---|
|
||
| `src/undercooked/config.py` | the only read of the environment → typed, validated `Settings` | phase 01 (done) |
|
||
| `src/undercooked/debug.py` | `DEBUGPY`-gated debugger bootstrap (A18) | phase 01 (done) |
|
||
| `src/undercooked/server/app.py` | app factory, `/healthz`, `/`, `/static`, startup logging | phase 01 (done) |
|
||
| `src/undercooked/server/headers.py` | CSP + the four other security headers on every response | phase 01 (done) |
|
||
| `src/undercooked/sim/` | game truth: model, `step()`, interactions, scoring, hazards | phase 03–04 |
|
||
| `src/undercooked/server/room.py`, `rooms.py` | one match, its FSM and tick task; the registry that owns all of them | phase 05–06 |
|
||
| `src/undercooked/server/protocol.py` | versioned wire messages, whitelists, inbound validation | phase 06 |
|
||
| `src/undercooked/server/sessions.py` | bounded in-memory progression records (A6: no database) | phase 05 |
|
||
| `app/static/js/` | screen state machine, net buffer/interpolation/prediction, renderer, HUD | phase 07–08 |
|
||
|
||
## What this document will contain when it is filled in
|
||
|
||
The request/response and tick data flow with real timings, the room lifecycle state
|
||
machine as built, the arbitration rule for contested resources, the client prediction and
|
||
reconciliation model, and one worked paragraph per anchor in A1–A12 covering the
|
||
alternatives that were rejected and the measured cost of the choice that was taken.
|