Scaffold project and author 14-phase roadmap
Browser co-op kitchen game: FastAPI + native WebSockets, server-authoritative 20 Hz simulation, in-memory anonymous lobbies, data-driven YAML levels, Canvas 2D vanilla ES-module client with locally authored SVG art and no external CDNs. .agents/PLAN.md records the LOCKED decisions; .agents/user_stories/ holds the 12 flow contracts; .agents/phases/todo/ breaks them into 14 sequential, test-gated phases (71 task files), each leaving the app launchable and the suite green. LLM-Generated: true
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# AGENTS.md — operating rules for this repository
|
||||
|
||||
## 1. Read this order, every time
|
||||
|
||||
1. `.agents/PLAN.md` — master design. Its **Architectural Anchors** table holds the
|
||||
**LOCKED DECISIONS**, which are binding on every task and phase.
|
||||
2. This file.
|
||||
3. `.agents/phases/todo/<phase>/00_phase.md`, then the task file you are executing.
|
||||
4. The user story referenced by the phase (`.agents/user_stories/US-XX_*.md`).
|
||||
5. `.agents/phases/complete/*/00_phase.md` for what already exists (do not re-build it).
|
||||
|
||||
## 2. The phased protocol
|
||||
|
||||
- Phase state lives in files, not chat. Pending work: `.agents/phases/todo/NN_name/`
|
||||
(`00_phase.md` + `NN_task.md`). Finished work: `.agents/phases/complete/`.
|
||||
- Execution is owned by the `phased-execution` skill (`run-task.sh`, `run-phase.sh`,
|
||||
`auto-phase.sh`). Each task runs in a fresh subprocess and must pass
|
||||
`.agents/validate.sh` before it moves to `complete/`.
|
||||
- New work is authored by the `phase-authoring` skill as a phase directory — not
|
||||
implemented straight from chat.
|
||||
- **Never** modify `.agents/PLAN.md` or anything under `.agents/phases/complete/`.
|
||||
- **Ask the user** before editing an existing file in `.agents/phases/todo/`.
|
||||
- Do not renumber or reuse phase/task numbers.
|
||||
|
||||
## 3. LOCKED DECISIONS (summary — the table in PLAN.md is authoritative)
|
||||
|
||||
- **Python 3.12+ / uv / FastAPI / native WebSockets** (`uvicorn[standard]`). No
|
||||
Socket.IO, no SSE, no WebRTC, no REST for live game traffic.
|
||||
- **Server-authoritative fixed-tick simulation** (20 Hz) with client interpolation.
|
||||
The browser never decides anything true. `src/undercooked/sim/` is pure:
|
||||
**no FastAPI, no asyncio, no I/O, no wall-clock, no `random` without the round RNG**.
|
||||
- **No database, no ORM, no Alembic.** Live state lives in the room supervisor;
|
||||
results/scoreboards live in memory and die with the process. User-approved
|
||||
deviation from the default FastAPI stack.
|
||||
- **Data-driven content.** Levels/recipes/hazards come from YAML in `levels/` loaded
|
||||
through validated Pydantic models. No hard-coded level or recipe lists in Python.
|
||||
- **Client: Canvas 2D + vanilla ES modules + this repo's own SVG art.** No bundler,
|
||||
no framework, no CDN, no analytics, no external fonts.
|
||||
- **Tests: pytest + Playwright.** One Playwright suite per user story; multi-player
|
||||
stories use two browser contexts against one room.
|
||||
- Quality gate: ruff + pyright + full pytest, **>90% coverage** on new/modified code,
|
||||
**entire suite 100% passing** before a phase may complete or commit.
|
||||
|
||||
## 4. Definition of done (every task)
|
||||
|
||||
- [ ] Task's own work exists at the named paths and is importable/runnable.
|
||||
- [ ] Tests written for the task's logic (unit for pure logic, integration for
|
||||
rooms/protocol, e2e for user-visible flows) and passing.
|
||||
- [ ] **Full** project suite passes (`uv run pytest`), coverage gate met — including
|
||||
failures the task did not cause: fix them, do not skip, xfail, or delete tests.
|
||||
- [ ] `uv run ruff check .` and `uv run pyright` report zero errors.
|
||||
- [ ] `uv run undercooked-levels validate` passes if any level/content file changed.
|
||||
- [ ] `README.md` and `AGENTS.md` updated when the change is user-visible
|
||||
(setup, commands, config, protocol, features, conventions). Every phase's final
|
||||
pass re-reviews both **in full, project-wide** and fixes inconsistencies,
|
||||
including pre-existing ones.
|
||||
- [ ] App still launches: `uv run undercooked` serves `http://127.0.0.1:8000/healthz`
|
||||
with `200` and the client at `/`.
|
||||
- [ ] No behavior regression in any completed phase.
|
||||
|
||||
## 5. Hard rules
|
||||
|
||||
- **No external CDNs or remote assets.** `tests/unit/test_no_external_assets.py`
|
||||
fails the build on `http://`/`https://`/`//cdn` references in `app/static/` and
|
||||
templates. CSP is `default-src 'self'` (plus `ws:`/`wss:` same-origin).
|
||||
- **No new technology** (dependency, framework, service) without explicit written
|
||||
user permission recorded in the phase's `00_phase.md` and signed off into PLAN.md.
|
||||
- **The simulation is the single source of truth.** Client-side values are guesses.
|
||||
Never trust inbound coordinates, scores, timers, or level ids — validate every
|
||||
inbound field against the room's state (`server/protocol.py`).
|
||||
- **Anonymous by design.** No accounts, no emails, no cookies with personal data.
|
||||
Identity = a random per-browser token (`secrets.token_urlsafe`) held in
|
||||
`sessionStorage`. Names are sanitized, length-capped, non-authoritative.
|
||||
- **Frame and rate limits are enforced, not suggested**: `max_message_bytes`,
|
||||
`max_inputs_per_s`, room caps, and message-type whitelists per room state.
|
||||
- **Protocol changes need a version bump**: editing a wire message means editing
|
||||
`src/undercooked/server/protocol.py`, `docs/PROTOCOL.md`, and the client in the same task,
|
||||
and bumping `PROTOCOL_VERSION` (PLAN §11).
|
||||
- **Determinism is a contract.** `sim/step.py` must produce identical state given the
|
||||
same seed and input script — the replay tests in `tests/sim/` are the guard.
|
||||
- **ntfy is outbound-only.** Never use it to ask questions or wait for approval.
|
||||
If a task is ambiguous, make the best judgment consistent with PLAN.md, or stop
|
||||
and let the user rewrite the task.
|
||||
- **Commits** are made by the pipeline harness (`PHASE_COMMIT=1`), one atomic commit
|
||||
per completed phase, `--no-gpg-sign`, subject `phase: <NN_name>`. Child executors
|
||||
never run `git add`/`commit`/`mv`/`rm`/`stash`. When a human asks for a commit, use
|
||||
the `git-commit` skill (`--no-gpg-sign`, `LLM-Generated: true` trailer).
|
||||
- Do not commit `.env`, logs, coverage output, `.agents/phase-sessions/`,
|
||||
`.agents/pipeline.log`, or `.agents/reports/` (all gitignored).
|
||||
|
||||
## 6. Where things go
|
||||
|
||||
| Change | Location |
|
||||
|---|---|
|
||||
| Pure game rules (movement, stations, orders, scoring, hazards) | `src/undercooked/sim/` |
|
||||
| Level/recipe content | `levels/*.yaml` |
|
||||
| Rooms, lobby lifecycle, session records | `src/undercooked/server/rooms.py`, `room.py` |
|
||||
| Wire messages + validation | `src/undercooked/server/protocol.py`, `docs/PROTOCOL.md` |
|
||||
| HTTP app, static serving, headers | `src/undercooked/server/app.py` |
|
||||
| Renderer, HUD, input, interpolation | `app/static/js/`, `app/static/assets/` |
|
||||
| User-visible flow contract | `.agents/user_stories/US-XX_*.md` |
|
||||
|
||||
Tests mirror that: `tests/unit/`, `tests/server/` (HTTP routes and stores),
|
||||
`tests/integration/` (live uvicorn + WebSocket clients), `tests/sim/` (headless
|
||||
determinism and replays), `tests/e2e/` (Playwright, named `test_usNN_*.py`, marked `e2e`).
|
||||
Reference in New Issue
Block a user