[Backend] Fix the campaign journal 500 for campaigns with two GMs #411

Closed
opened 2026-08-25 20:44:51 +00:00 by claude-bot · 0 comments
Contributor

Severity: LOW

Found in the August 2026 session lifecycle review (#319).

The aggregated campaign journal endpoint throws a server error for any campaign with more than one GM, because it assumes exactly one GM row exists when querying for the GM's public notes to include alongside the reader's own — turning "my notes are gone" into the actual user-visible symptom of what is really a read-path crash, for a co-GM setup the rest of the app explicitly supports.

Evidence

  • webapp/backend/app/services/session_note_service.py:97-103 (get_campaign_notes) — gm_result.scalar_one_or_none() is called against a query (select(CampaignMember.user_id).where(..., role == MemberRole.gm)) that returns one row per GM in the campaign; with two or more GMs this raises MultipleResultsFound, which propagates to a 500 response.
  • Co-GM campaigns are an explicitly supported configuration elsewhere in the app, making this an oversight specific to this one query rather than a deliberate single-GM assumption.

Failure scenario
A campaign has two co-GMs, as the app is designed to allow. Any member opening their aggregated journal for that campaign hits get_campaign_notes, which crashes on the multi-row GM lookup — the journal page errors out (or shows nothing, depending on frontend error handling) for every member of that campaign, indefinitely, until a GM steps down or the query is fixed.

Proposed fix
Change the GM public-notes lookup to handle zero-or-more GMs — iterate all GM rows and include each GM's public note (or the most relevant one, if the product only wants a single "GM note" concept) instead of assuming exactly one.

Acceptance criteria

  • get_campaign_notes no longer raises on a campaign with more than one GM.
  • The journal correctly includes public GM notes for a two-GM campaign.
  • Regression test covers a campaign with 2+ GMs calling the journal endpoint.
**Severity: LOW** Found in the August 2026 session lifecycle review (#319). The aggregated campaign journal endpoint throws a server error for any campaign with more than one GM, because it assumes exactly one GM row exists when querying for the GM's public notes to include alongside the reader's own — turning "my notes are gone" into the actual user-visible symptom of what is really a read-path crash, for a co-GM setup the rest of the app explicitly supports. **Evidence** - `webapp/backend/app/services/session_note_service.py:97-103` (`get_campaign_notes`) — `gm_result.scalar_one_or_none()` is called against a query (`select(CampaignMember.user_id).where(..., role == MemberRole.gm)`) that returns one row per GM in the campaign; with two or more GMs this raises `MultipleResultsFound`, which propagates to a 500 response. - Co-GM campaigns are an explicitly supported configuration elsewhere in the app, making this an oversight specific to this one query rather than a deliberate single-GM assumption. **Failure scenario** A campaign has two co-GMs, as the app is designed to allow. Any member opening their aggregated journal for that campaign hits `get_campaign_notes`, which crashes on the multi-row GM lookup — the journal page errors out (or shows nothing, depending on frontend error handling) for every member of that campaign, indefinitely, until a GM steps down or the query is fixed. **Proposed fix** Change the GM public-notes lookup to handle zero-or-more GMs — iterate all GM rows and include each GM's public note (or the most relevant one, if the product only wants a single "GM note" concept) instead of assuming exactly one. **Acceptance criteria** - [ ] `get_campaign_notes` no longer raises on a campaign with more than one GM. - [ ] The journal correctly includes public GM notes for a two-GM campaign. - [ ] Regression test covers a campaign with 2+ GMs calling the journal endpoint.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#411
No description provided.