From 187ec90440ddb4f946859eb2911a5d0231a95b0d Mon Sep 17 00:00:00 2001 From: daddy Date: Sat, 5 Sep 2026 22:23:52 +0000 Subject: [PATCH] PC3: checkpoint doc for what's built (M4 + M5 + foundation; M6-M10 not started) Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ --- docs/checkpoints/PC3.md | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 docs/checkpoints/PC3.md diff --git a/docs/checkpoints/PC3.md b/docs/checkpoints/PC3.md new file mode 100644 index 0000000..6b443ac --- /dev/null +++ b/docs/checkpoints/PC3.md @@ -0,0 +1,97 @@ +# Package Checkpoint 3 (PC3) + +> **Status: partial.** PC3's planned scope was M4-avatars + M5-multiplayer + +> Foundation Hardening + M6–M10 (see `docs/build-plan-v1.md`). As of +> 2026-09-05, **M4, M5, and most of Foundation Hardening are done and +> checkpoint-verified**; M6–M10 have not been started. This doc records what +> is real. Whether to call this "PC3" (redefined scope, M6–M10 → PC4) or keep +> PC3 open is a user decision. + +Built by Claude directly (fleet offline), branch `pc3` → `main`. + +## What's real and verified (`scripts/run_checkpoint_tests.py`, all green) + +| Check | Result | +|---|---| +| Alembic migrations, fresh DB | PASS | +| Backend `pytest` | 77/77 PASS (hermetic — auto-starts an ephemeral Postgres) | +| Godot smoke tests (~16 files) | ALL PASS | +| `smoke_test_network_client` (real dedicated server) | 4/4 PASS | +| 2-player multiplayer (`run_multiplayer_2p_test.sh`) | PASS | +| Fresh-clone boot (`verify_fresh_clone.sh`) | PASS | +| Linux + Windows exports | Build as real ELF64 / PE32+ binaries | + +### M4 — Avatars in the game + +- Placeholder avatar pack (14 GLBs, rigged 24-bone base body + attachments) + generated by `scripts/tools/gen_placeholder_avatars.gd`. Real art is a + content swap — catalog paths are stable. +- The avatar **loader was fixed** — it had never run against a real skeleton + (`Skeleton3D.has_bone()` isn't a Godot 4 method; the bone-copy dropped the + skin binding; attachments were parsed then discarded). +- `avatar_visualizer.gd` **rewritten** — the old one referenced a loader API + that never existed and didn't compile. +- Persistence: `avatar_loadouts` table + `GET/PUT /api/avatar/loadout` + (loadout stored as one JSON doc; server validates the envelope only). +- Wired into gameplay: the in-world player renders as the assembled avatar + (not a capsule); the loadout is fetched at login; "Customize Avatar" from + the main menu saves through to the backend. +- **Follow-up:** camera is still first-person, so the local player doesn't + see their own avatar much (third-person is a polish item); remote players' + avatar appearance is not replicated yet (they show as labelled capsules). + +### M5 — Real multiplayer + +- `server.gd` **actually runs a sim now** — loads the world level, spawns a + server player per peer, processes each peer's input queue in seq order at a + fixed 30 Hz, broadcasts full snapshots with a per-peer `last_seq`. (The + input queue was a no-op before.) +- `network_client.gd` reconciliation **replays in-flight inputs** from the + authoritative state (drops acked ones), snaps only on real drift. +- **Server orchestration** (`backend/app/services/game_servers.py`): one + headless Godot dedicated-server process per world, spawned on demand by + `POST /api/worlds/{id}/join`, port-allocated, with a status-file idle + reaper. Off by default; the playtest launcher (`checkpoint_ops.py`) + enables it. +- **Client play path**: world browser → `/join` → `Session` → `game.tscn` + connects → local player predicts with collision, input forwarded, server + position is a drift backstop, remote players render from snapshots, + disconnect returns to the world list. Falls back to local single-player + when the backend has no orchestration. +- **Verified**: two real client processes each `register → /join → play`, + hosted on an orchestrated server, see and move relative to each other + (`run_game_multiplayer_test.sh`). + +### Foundation Hardening + +- **Hermetic backend tests** — `cd backend && pytest` works from a clean + checkout (auto ephemeral Postgres + migrations, torn down after); skips + cleanly with a message if there's no Docker. +- **Fresh-clone boot check** — `verify_fresh_clone.sh` exports a pristine + tree, imports from scratch, boots headless, fails on any script error. + Also fixed the root cause: a stale `.godot/global_script_class_cache.cfg` + was committed to the repo. +- **Real age verification** — `/register` takes a date of birth (not a + checkbox), server computes age, 403 under 18. Still self-attested; the + limitation and the ID-check hook are documented + (`content_moderation.md` 5.2). +- **Auth rate limiting** — 10 attempts / min / IP on `/register` + `/login`. +- **CI workflow** — `.forgejo/workflows/checkpoint.yml` written, **not + running yet**: needs the operator to enable Forgejo Actions + register a + `host` runner (one-time; see `docs/ci.md`). Interim gate is + `run_checkpoint_tests.py` by hand / the dashboard. + +## Not in PC3 (planned but not started) + +- **M2** server-side world persistence +- **M6** scripting sandbox +- **M7** in-game editor +- **M8** social / chat +- **M9** economy +- **M10** discovery + +## Playtest + +Same as PC2 — grab the exe from the dashboard's `/checkpoints`, backend +pointed at it. New: with multiple people in the same world you now actually +see each other move.