Reported directly by the user playtesting the exported exe: Play was permanently disabled and there was no way to log in or register. Root cause: main_menu.tscn wired Play and Quit, but nothing was ever connected to _on_login_button_pressed()/_on_register_button_pressed() -- the AuthPanel, its form, and all its backend-calling logic were fully correct, just completely unreachable. The script's own top comment even said "(the existing Play/Quit buttons)" as if Play/Quit somehow doubled as login triggers, which they never did -- a sign nobody ever actually clicked through the running scene, only checked things at the API level. Fix: added a real AuthButtonsRow (LoginButton, RegisterButton) wired to the existing handlers, which now hide themselves once auth succeeds. Also fixed grab_focus() targeting the AuthPanel (which can't accept focus, just a background warning) to focus the username field instead. Verified via two new smoke tests (smoke_test_main_menu_ui.gd, smoke_test_main_menu_full_flow.gd) using a *real signal emission* on the buttons, not a direct method call -- that distinction is exactly what would have caught the original bug. Full click-through confirmed against a real backend: open register form, fill it, submit, Play actually becomes enabled, welcome message shows, auth buttons hide. Also documents a real headless-testing gotcha found while verifying this: a synthetic Button.pressed.emit() on an await-using handler doesn't reliably get driven forward in --script/SceneTree mode the way real GUI input dispatch does -- confirmed by comparing direct-call vs emit() behavior side by side. Not a bug in the actual click-driven flow, a test-harness quirk to route around (call the handler directly, awaited, instead of emitting the signal). Full checkpoint suite re-verified clean on this branch: migrations, 68/68 pytest, all 6 Godot smoke tests (including the 2 new ones, picked up automatically by run_checkpoint_tests.py's glob). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.