Repository navigation
feat(game): WhoCards sole controller + 90-day retention script - #340
Conversation
Privacy screen names WhoCards as controller, says the host sees only who joined, and promises answers + recap emails go 90 days after the workshop. Adds pnpm --filter website game:retention (dry-run unless --apply). Closes #317
✅ Deploy Preview for whocards-app canceled.
|
✅ Deploy Preview for whocards-calmly ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
⛔ Files ignored due to path filters: 1
📒 Files selected for processing: 6
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| await db.transaction(async (tx) => { | ||
| const players = tx | ||
| .select({id: gamePlayer.id}) | ||
| .from(gamePlayer) | ||
| .where(inArray(gamePlayer.gameId, gameIds)) | ||
| await tx.delete(gameResponse).where(inArray(gameResponse.playerId, players)) | ||
| await tx.update(gamePlayer).set({email: null}).where(inArray(gamePlayer.gameId, gameIds)) |
There was a problem hiding this comment.
purgeGames trusts IDs selected earlier without checking whether those games still qualify. A host can start a new round in an old game left live after findExpiredGames returns. Although its activity date is now recent, cleanup still deletes all its saved answers and clears its recap email addresses. This was reproduced with a successful round start followed by cleanup using the earlier selection.
Lock each game using the same lock as startRound, then recheck its activity date before deleting. This data-loss issue must be fixed before merging.
| await seedGame('OLD', daysAgo(120), daysAgo(91)) | ||
| await seedGame('EDGE', daysAgo(120), daysAgo(89)) | ||
| await seedGame('NEW', daysAgo(10), daysAgo(10)) | ||
| await seedGame('EMPTY', daysAgo(200), null) |
There was a problem hiding this comment.
seedGame always creates ended games, and its no-round case returns before adding any players or emails. The existing tests still pass when the creation-date fallback for games without rounds is disabled, so they do not protect cleanup of email addresses from abandoned games. Current cleanup works for that scenario; this is a non-blocking regression-coverage gap.
Add an old, non-ended game with an email but no rounds. Verify that selection finds it and cleanup clears it.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Artifacts
Isolated mutation validation script
- Runs the original tests and both comparisons using disposable copied sources, captures executed source and output, and verifies cleanup without modifying tracked retention files.
Abandoned no-round game regression test
- Seeds an old lobby game with an email and no rounds, then asserts selection and email purge, providing the missing coverage.
Original retention tests with current code
- Executed the original retention suite and captured its source and output; both tests pass.
Existing retention tests with no-round fallback disabled
- Executed unchanged copied tests against the mutated copied module; both tests still pass, confirming the coverage gap.
Abandoned-game selection and purge with current code
- Executed the supplemental test against current code; the old no-round lobby game is selected and its email is cleared.
Abandoned-game regression test with fallback disabled
- Executed the same supplemental test against the mutation; selection returns no games and the assertion fails, proving the added test detects the regression.
Complete validation run and cleanup output
- Captured the validation driver's four test runs and successful cleanup checks; the expected pass/pass/pass/fail comparison completed without tracked source edits.
Privacy screen: WhoCards = sole controller, no Unloop, no joint controllers. Host sees who joined, not answers. Answers + recap emails deleted 90 days after workshop.
Retention script:
pnpm --filter website game:retention(dry-run),-- --applyto delete. Run 2027-01-13.#317 📋 · Closes #317
For AI
Copy (
packages/game/src/player-copy.ts, EN only, TODO removed):Nowhere else repeated the joint-controller/Unloop wording (checked emails, website, app).
apps/website/src/assets/legal/pp.mduntouched (out of scope).Plan doc
docs/plans/2026-10-10-sdd-workshop-game.md: fixed lines 147 and 261. Also changed the T9 title "(joint controllers)" to "(single controller)", dropped the joint-controller risk row, and the GDPR retention bullet now says 90 days and names the script.Retention
apps/website/src/server/game/retention.ts:findExpiredGames(db, now)picks games whose last activity (greatest(created_at, max(round.started_at), max(round.ends_at))) is more than 90 days old and that still have responses or emails. It ignores status, so a game nobody ended still expires.purgeGames(db, ids)deletes allgame_responserows for those games' players and nullsgame_player.email, in one transaction.apps/website/scripts/game-retention.ts: sits next toreconcile-resend.ts. Gets DB_URL fromwith-env+@whocards/env/db. Prints code, last-activity date, counts, title. On error it prints only the message.tsxdevDep to website. It was missing, andreconcile:resendneeded it too. Same version as apps/emails, already in the lockfile.game_feedbacktext and player names. Say if those should go too.Verified
pnpm checkgreen (22/22 turbo tasks; website 369 tests, including 2 new PGlite retention tests).--applydeleted it. A rerun found 0 games, and NEW1 was untouched. Never run against prod.astro devexits before it's ready in the agent worktree, with no output. The copy is static data rendered as a list byPrivacyinsdd-2026/_components/join.tsx.Do not merge until cleanup locks games and rechecks current eligibility before deleting retained data. The abandoned-game test gap is non-blocking.
Findings
T-Rex evidence
Isolated mutation validation script
Abandoned no-round game regression test
Original retention tests with current code
Existing retention tests with no-round fallback disabled
Abandoned-game selection and purge with current code
Abandoned-game regression test with fallback disabled
Complete validation run and cleanup output
Evidence from the check
Evidence from the check
Command output from the check
Command output from the check
Command output from the check
Command output from the check
Command output from the check
Summary
Updates the privacy notice to name WhoCards as the sole controller and promise deletion after 90 days.
Author
acharlopexplicitly leaves player names andgame_feedbacktext outside this change. Authoracharlopintentionally plans a manual retention run for 2027-01-13.Reviews (1) · Last reviewed commit: "feat(game): WhoCards as sole controller ..." · Reviewed by Greptile