Files
modbison/docs/testing
claude-checkpoint-tooling bd44ecba14 Client-side position sync + prediction/reconciliation
Real client-side networking for the player controller, verified with a
genuine two-process integration test (an actual dedicated server process
+ a real ENet-connected client), per docs/architecture/networking.md §5.

scripts/network_client.gd: NetworkClient -- predicts movement locally on
input (same movement constants as scripts/player_spawner.gd), sends input
to the server via RPC, and reconciles against the server's authoritative
snapshots when they diverge beyond a threshold.

scripts/network_receiver_proxy.gd + network_player_proxy.gd: the RPC
plumbing that makes this actually route correctly, which took real
debugging to get right:
- Godot's rpc_id() resolves the receiving node by matching the sending
  node's NodePath between peers. scripts/server.gd is the SceneTree root
  node "Server" when the dedicated server runs, and spawns each player as
  "Player_<peer_id>" under itself -- so the client needs its own node
  tree at those same paths purely for RPC routing.
- Godot also enforces an RPC "node checksum": both peers must declare the
  *same set* of @rpc methods at a matching path, or every RPC at that
  path fails, not just a genuinely missing one. Every @rpc method on
  scripts/server.gd's root and scripts/player_spawner.gd had to be
  mirrored here (mostly as no-op stubs), not just the ones this class
  actually calls.

Known, explicitly-scoped simplification (stated in the code, not hidden):
scripts/server.gd's snapshot doesn't currently echo back a per-peer "last
input seq processed", so reconciliation corrects against the most recent
prediction rather than true tick-exact rollback-and-replay
(networking.md §5.2 step 4). A real follow-up once the server echoes
that ack, not faked here.

Verified: real two-process test (godot --headless --path . scenes/
server.tscn as an actual persistent process, a second process running
scripts/smoke_test_network_client.gd against it over real ENet) --
4/4 passing: connects, predicts locally before any server round trip,
sends real input, and a deliberately-desynced position (moved 9999 units
away) gets corrected by the very next real snapshot. Full existing
client suite (10 suites) + 61 backend pytest still passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M6rUEynmv2QmweocAQYARN
2026-08-21 01:21:37 +00:00
..

Testing at Package Checkpoints

A Package Checkpoint (PC1, PC2, ...) is a periodic review point — every few real milestones, the client and server builds get packaged together and independently reviewed before anyone calls anything actually done. See project_agp in Claude's memory, or ask, for the full definition; this doc is just the mechanical "how do I run the tests" part of that review.

Running the suite

python scripts/run_checkpoint_tests.py

Brings up a throwaway Postgres, runs Alembic migrations against it, runs the backend pytest suite, starts the backend server, and runs every Godot headless smoke test (scripts/smoke_test_*.gd) against it. Tears the Postgres container down afterward (--keep-postgres to skip that if you want to poke at the DB after a failure).

If port 5432 is already taken on the machine, pass --postgres-port with something else.

Exit code is 0 only if everything that actually ran passed — suites with nothing to run yet (no Godot binary found, no smoke test scripts yet) are reported SKIPPED, not treated as a failure.

What this does and doesn't prove

Passing this script means: migrations apply cleanly to a genuinely empty database, the backend's unit-level logic is correct, and whatever Godot smoke tests exist actually round-trip against a live backend. It does not mean full endpoint/integration coverage exists — see test_inventory.md for the current, honest list of what's tested and what isn't. A checkpoint review should still involve reading the actual diffs for anything this script's current coverage doesn't reach, not just running green and calling it done.

Growing this over time

As real integration tests get added (endpoint tests hitting the FastAPI app, more Godot smoke coverage beyond health_check), they should land under backend/tests/ / scripts/smoke_test_*.gd respectively — this script picks up new files automatically, nothing to register by hand. Update test_inventory.md's tables when you do, so the inventory stays a source of truth instead of quietly going stale.

Eventual goal (not implemented yet): gate merges to main on this script passing, the same way a real CI pipeline would. For now it's a manual step run at checkpoint review time.