phase: 02_level_content_and_validation
Phase `02_level_content_and_validation` — final verification **green**. - **Gate:** `bash .agents/validate.sh` → ruff ✅ · pyright 0 errors ✅ · `undercooked-levels validate` OK (2 levels) ✅ · **668 passed** (incl. 10 Playwright e2e) ✅ · coverage **100%** ✅ · repo hygiene ✅ - **Criteria:** `validate` exit 0, one line per level; `list` = `01_first_kitchen`, `02_double_shift` in campaign order; live `:8000` `/healthz` 200, `/api/levels` (+detail) carries both levels with numeric `target_score`/`time_limit` and no grid/station leakage, `/api/config` correct, unknown id → 404, startup log `content loaded: 2 level(s), 4 recipe(s)`; `validate --dir tests/fixtures/levels/_bad/` → exit 1 with named `RECIPE_STATION_MISSING` / `SERVE_REACHABLE` / `TARGET_IMPLAUSIBLE`; A8 lock test proves a YAML-only level reaches loader+API+CLI. - **Defect fixed (pre-existing path, phase-02-triggered):** `undercooked` with unusable content printed the report then a raw traceback and exited `1`. `src/undercooked/__main__.py` now catches `ContentError` → one closing line, exit `2` (like a bad setting); 2 new tests in `tests/unit/test_main.py` (incl. non-content failures still propagate). - **Docs pass (full, project-wide):** README (content gate + exit `2`, config section), AGENTS.md §3, `docs/LEVELS.md` (startup refusal + exact CLI exit codes), `docs/DEPLOYMENT.md` (crash-loop diagnosis bullet); DESIGN/TESTING re-read, consistent. - **Container re-verified (no phase-01 regression):** `podman build -f Containerfile` succeeds; the image ships `levels/` and serves `/healthz` 200, `/api/levels` (2 levels), `/` 200 as non-root. - **Deviation to note:** the phase overview names `tests/fixtures/levels/bad/`; the actual broken-fixture dir is `tests/fixtures/levels/_bad/` (the `_` prefix is what keeps it out of normal discovery). Overview files are read-only to me — README/LEVELS.md document the real path. - No git index/history commands run; all changes left unstaged for the harness. ntfy notification sent.
This commit is contained in:
+10
-4
@@ -1,6 +1,6 @@
|
||||
# DESIGN.md — architecture and the decisions behind it
|
||||
|
||||
**Status:** stub written by phase 01 · **Filled in by phase 09**, when the client, the
|
||||
**Status:** stub written by phase 01, module map refreshed by phase 02 · **Filled in by phase 09**, when the client, the
|
||||
protocol and the first two-player end-to-end story make the prose verifiable.
|
||||
|
||||
## Purpose
|
||||
@@ -21,15 +21,21 @@ all. Everything around that kernel — `server/` (FastAPI app, WebSocket protoco
|
||||
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)
|
||||
## Module map (as it stands after phase 02)
|
||||
|
||||
| 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/app.py` | app factory, `/healthz`, `/`, `/static`, startup logging, mounts the content router | phase 01 (done) |
|
||||
| `src/undercooked/server/routes_content.py` | `/api/levels`, `/api/levels/{id}`, `/api/config` behind `extra="forbid"` response models, plus the startup gate that refuses broken content | phase 02 (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/sim/model.py`, `grid.py` | the entity vocabulary (`Vec2`, items, stations, players, orders, hazards, `KitchenState`) and tile geometry/walkability | phase 02 (done) |
|
||||
| `src/undercooked/sim/recipe.py`, `level.py`, `content.py` | the content contract (A8): recipe book, level schema + ASCII legend, discovery and campaign ordering | phase 02 (done); schema reference in `docs/LEVELS.md` |
|
||||
| `src/undercooked/sim/validation.py` | PLAN §8's named playability rules and the escalation axes | phase 02 (done) |
|
||||
| `src/undercooked/sim/purity.py` | the A5 guard: no I/O, asyncio, clock or FastAPI inside `sim/` | phase 02 (done) |
|
||||
| `src/undercooked/tools/levels.py` | the `undercooked-levels` author CLI — a shell over the loader and the rules, never a second implementation | phase 02 (done) |
|
||||
| `src/undercooked/sim/step.py` | game truth: the tick, 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 |
|
||||
|
||||
Reference in New Issue
Block a user