feat: remind the people who haven't answered "Are you in?" (#1158) #1168

Merged
claude-bot merged 28 commits from feat/1158-nudge-unanswered into main 2026-10-13 05:48:44 +00:00
Collaborator

Closes #1158 (D302, D303). Backend, bot and frontend in one change.

  • The nudge. One plain Discord line that pings the linked players with no answer, takes ✅ ❌ ❔ as answers, and carries no person-written text: mentions, fixed words, the session number, the time in the campaign's zone with each reader's own time in brackets, and a validated link.
    <@…> Are you in for Session 14, Tuesday 13 October at 8:00 pm CDT (<t:…:t> your time)? React ✅ if you are in, ❌ if you are not, ❔ if you might. Answer here: <url>
  • Two triggers. A GM button on the session page ("Remind who hasn't answered", POST /sessions/{id}/remind-unanswered, audited, at most once in 12 hours), and an automatic nudge rsvp_nudge_minutes before a confirmed session (campaign setting, default 2880, can be turned off; once per confirmed time).
  • Who. Players with no answer who have not muted the campaign. Never for a vote, a pencilled, cancelled, started or played session, or an archived campaign. A campaign with no Discord gets an in-app session_reminder with the answer buttons; a webhook-only campaign gets a 409 from the button.
  • Send once. A conditional UPDATE claims the send and commits before anything goes out; a failed send restores the previous values.
  • Bot. New event session_rsvp_nudge, offered only to a bot whose /identity lists the feature; an older bot ignores it. Additive: no BOT_CONTRACT_VERSION bump. faces.py gains only the nudge; _handle_vote_reminder's allowed_mentions is tightened from users=True to the exact ids.
  • Migration e1158a1b2c3d (after e1159a1b2c3d): two columns on sessions, one on campaigns; real downgrade.

Not in the nudge: people with no linked Discord (naming them is person-written text; see #1166).

Verified

On docker-test: bot suite (709 passed); test_rsvp_nudge.py and the title-reader guard (39); an earlier wider backend run of 19 modules (578 passed, before the last payload change, not re-run since); alembic upgrade, downgrade -1, upgrade (before the re-point onto e1159a1b2c3d); ruff; version and changelog checks; frontend lint; the touched vitest files alone.

Not run: the full frontend suite (timed out under host load), the full backend suite, journeys, build; nothing after merging main (two doc conflicts resolved by hand). Not checkable on dev: the dev bot has no Discord token. No render check yet of the button and the setting.

🤖 Generated with Claude Code

Closes #1158 (D302, D303). Backend, bot and frontend in one change. - **The nudge.** One plain Discord line that pings the linked players with no answer, takes ✅ ❌ ❔ as answers, and carries no person-written text: mentions, fixed words, the session number, the time in the campaign's zone with each reader's own time in brackets, and a validated link. `<@…> Are you in for Session 14, Tuesday 13 October at 8:00 pm CDT (<t:…:t> your time)? React ✅ if you are in, ❌ if you are not, ❔ if you might. Answer here: <url>` - **Two triggers.** A GM button on the session page ("Remind who hasn't answered", `POST /sessions/{id}/remind-unanswered`, audited, at most once in 12 hours), and an automatic nudge `rsvp_nudge_minutes` before a confirmed session (campaign setting, default 2880, can be turned off; once per confirmed time). - **Who.** Players with no answer who have not muted the campaign. Never for a vote, a pencilled, cancelled, started or played session, or an archived campaign. A campaign with no Discord gets an in-app `session_reminder` with the answer buttons; a webhook-only campaign gets a 409 from the button. - **Send once.** A conditional `UPDATE` claims the send and commits before anything goes out; a failed send restores the previous values. - **Bot.** New event `session_rsvp_nudge`, offered only to a bot whose `/identity` lists the feature; an older bot ignores it. Additive: no `BOT_CONTRACT_VERSION` bump. `faces.py` gains only the nudge; `_handle_vote_reminder`'s `allowed_mentions` is tightened from `users=True` to the exact ids. - **Migration** `e1158a1b2c3d` (after `e1159a1b2c3d`): two columns on `sessions`, one on `campaigns`; real downgrade. Not in the nudge: people with no linked Discord (naming them is person-written text; see #1166). ## Verified On `docker-test`: bot suite (709 passed); `test_rsvp_nudge.py` and the title-reader guard (39); an earlier wider backend run of 19 modules (578 passed, before the last payload change, not re-run since); alembic upgrade, downgrade -1, upgrade (before the re-point onto `e1159a1b2c3d`); ruff; version and changelog checks; frontend lint; the touched vitest files alone. Not run: the full frontend suite (timed out under host load), the full backend suite, journeys, `build`; nothing after merging main (two doc conflicts resolved by hand). Not checkable on dev: the dev bot has no Discord token. No render check yet of the button and the setting. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge main into feat/1158: the nudge migration follows the end-time repair
Some checks failed
CI / Backend lint (ruff) (pull_request) Successful in 35s
CI / Does this change touch the recording path? (pull_request) Successful in 26s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m11s
CI / Bot/backend version sync (pull_request) Successful in 1m4s
CI / Feedback site tests (pull_request) Successful in 1m52s
CI / Bot tests and audit (pull_request) Successful in 2m27s
CI / Docker image build (pull_request) Successful in 5m57s
CI / Frontend (shard 2/2) (pull_request) Successful in 10m10s
CI / Frontend (shard 1/2) (pull_request) Successful in 12m5s
CI / Backend migration, tests, and audit (pull_request) Failing after 22m37s
CI / End-to-end journeys (phone) (pull_request) Successful in 17m51s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 19m54s
CI / End-to-end journeys (desktop) (pull_request) Successful in 20m8s
bd24d9bf09
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge main into feat/1158: the nudge migration follows the series skips
All checks were successful
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m8s
CI / Backend lint (ruff) (pull_request) Successful in 1m12s
CI / Bot/backend version sync (pull_request) Successful in 1m2s
CI / Does this change touch the recording path? (pull_request) Successful in 40s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Feedback site tests (pull_request) Successful in 1m49s
CI / Bot tests and audit (pull_request) Successful in 2m26s
CI / Docker image build (pull_request) Successful in 3m27s
CI / Frontend (shard 1/2) (pull_request) Successful in 11m35s
CI / Frontend (shard 2/2) (pull_request) Successful in 16m54s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 13m56s
CI / End-to-end journeys (desktop) (pull_request) Successful in 14m7s
CI / End-to-end journeys (phone) (pull_request) Successful in 13m29s
CI / Backend migration, tests, and audit (pull_request) Successful in 50m53s
3bc7de37a2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude-bot scheduled this pull request to auto merge when all checks succeed 2026-10-13 04:57:24 +00:00
claude-bot deleted branch feat/1158-nudge-unanswered 2026-10-13 05:48:44 +00:00
Sign in to join this conversation.
No description provided.