Seed a staging test user with games in every state - #1405
Conversation
Adds a seed_staging management command that creates a login user (staging-tester@example.com), opponents and a bot, then builds games through the real managers and adjudicator: pending, joinable, active at each order status, retreat and adjustment phases, civil disorder, eliminated, paused, draw proposed, solo win and loss, draw and abandoned. It refuses to run unless DEBUG or ENVIRONMENT=staging, and each run replaces the games it seeded before. The PR staging workflow sets SEED_STAGING_DATA=True on the Django service, and the entrypoint seeds (once per database clone) before Gunicorn starts, so the data is next to the database rather than thousands of round trips away on the Actions runner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017MmHa6RT4ZtHZueLJEZnkD
|
Warning WIP limit exceeded. There are now 6 open pull requests — the project target is 5 or fewer. Please close or merge an existing PR before continuing with this one. |
Staging Environment DeployedFrontend preview: https://deploy-preview-1405--diplicity-react.netlify.app The staging backend has a copy of the production database from the daily snapshot taken at Sun, 27 Sep 2026 07:31:24 GMT, with migrations from this PR applied. Log in as The frontend preview derives its backend URL from the PR number at build time. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017MmHa6RT4ZtHZueLJEZnkD
Staging Environment Torn DownThe staging environment for this PR has been removed. |
What this PR does
Staging testing relied on a real production account, and its state drifted. Its commitment rating fell to low, which blocks game creation, and there was no reliable way to reach specific game states. This PR adds a
seed_stagingmanagement command, and staging deploys now run it, so you can log in astest-user@example.com/passwordas soon as the backend is up.The command creates the tester, eight opponents and a DumbBot. It then builds 24 games through the real managers and adjudicator. Phases are resolved with
Phase.objects.resolve, and civil disorder, eliminations, victories and draw acceptance all come from the production code paths. The games cover these states:A few details:
DEBUG=TrueorENVIRONMENT=staging. Each run deletes the games it seeded last time (found by the seeded users) and seeds them again. You can also run it locally.How it runs on staging: the workflow sets
SEED_STAGING_DATA=Trueon the staging Django service. When that is set,entrypoint.shrunsseed_staging --skip-if-seededafter migrations and before Gunicorn starts. A container restart keeps your test state, and a redeploy re-clones the database and seeds fresh. The PR comment now lists the login.I didn't run the command from the Actions runner. A seed is about 6.7k queries, and at internet latency to Railway's public DB proxy that would take minutes. Inside the container it takes about 15s.
Also noted, but not changed here: deleting a game that has a replaced member fails the
member_unique_nation_per_gameconstraint. The cascade nullsreplaced_bybefore it deletes the rows. The seed works around this in its cleanup.Checklist
/review-pragainst this PR in Claude Code and addressed (or responded to) its findingsTestSeedStagingCommandinservice/game/tests.pychecks every state through the games list, draw-proposal, profile and login endpoints. It also covers the guard, re-seeding and--skip-if-seeded.Verified on a real staging deploy of this PR: the seed ran at startup, the tester login worked, and every game was in its expected state with high commitment. The account was then still
staging-tester@example.com; it was renamed totest-user@example.comafterwards, and production has no user with that email or thetest-userusername. If the staging service has a short healthcheck timeout, the extra ~15–30s at startup is worth watching.harness/tests.py::TestQualityMetricAggregation::test_accuracy_covers_ranked_samples_and_skips_the_restalso fails onmainwithout this change.🤖 Generated with Claude Code
https://claude.ai/code/session_017MmHa6RT4ZtHZueLJEZnkD