fix(journal): the campaign journal 500'd for co-GM campaigns (#411) #460

Merged
claude-bot merged 1 commit from fix/411-co-gm-journal into main 2026-08-31 04:32:50 +00:00
Contributor

Closes #411 (LOW).

The defect

get_campaign_notes called scalar_one_or_none() on a query that returns one row per GM. A campaign with two GMs therefore raised MultipleResultsFound, which becomes a 500 — for every member of that campaign, not just the GMs. Co-GMs are supported everywhere else in the app; this one query assumed exactly one.

What a user reports is "my notes are gone". It is a read-path crash wearing a data-loss costume, which is why it belongs in this milestone despite being LOW.

What ships

Fetches every GM's public notes rather than "the" GM's, and attributes each to its author. Two unattributed notes stacked under a single "GM Notes" heading read as one person contradicting themselves — so the fix that merely stops the crash produces a subtly wrong page.

That changes the response shape: gm_public_note: str | None becomes gm_public_notes: list[{author, content}]. Both render sites (CampaignNotes.jsx, CampaignDetail.jsx) are updated in the same commit, and the author line only appears when there is more than one note, so single-GM campaigns look exactly as they did.

The reader's own notes stay excluded — they already appear under my_notes, and repeating them would read as the journal duplicating itself. That was the purpose of the original gm_id != user_id check, preserved here as a set difference.

Verification

Mutation-checked: restoring scalar_one_or_none() fails 4 of 6 tests with the issue's own MultipleResultsFound.

The suite is deliberately not crash-only. A fix that returned one GM's note and dropped the other would satisfy "does not raise" while silently hiding a co-GM's writing, so there is a test asserting both notes arrive, one asserting attribution, and one covering the single-GM path so the common case cannot regress on the way past.

1,482 backend tests pass (was 1,476), 457 frontend. Lint clean at pinned ruff 0.4.4; eslint clean apart from one pre-existing warning in a file this PR does not otherwise touch.

🤖 Generated with Claude Code

Closes #411 (LOW). ## The defect `get_campaign_notes` called `scalar_one_or_none()` on a query that returns **one row per GM**. A campaign with two GMs therefore raised `MultipleResultsFound`, which becomes a 500 — for **every member** of that campaign, not just the GMs. Co-GMs are supported everywhere else in the app; this one query assumed exactly one. What a user reports is "my notes are gone". It is a read-path crash wearing a data-loss costume, which is why it belongs in this milestone despite being LOW. ## What ships Fetches **every** GM's public notes rather than "the" GM's, and **attributes each to its author**. Two unattributed notes stacked under a single "GM Notes" heading read as one person contradicting themselves — so the fix that merely stops the crash produces a subtly wrong page. That changes the response shape: `gm_public_note: str | None` becomes `gm_public_notes: list[{author, content}]`. Both render sites (`CampaignNotes.jsx`, `CampaignDetail.jsx`) are updated in the same commit, and the author line only appears when there is more than one note, so single-GM campaigns look exactly as they did. The reader's own notes stay excluded — they already appear under `my_notes`, and repeating them would read as the journal duplicating itself. That was the purpose of the original `gm_id != user_id` check, preserved here as a set difference. ## Verification Mutation-checked: restoring `scalar_one_or_none()` fails **4 of 6** tests with the issue's own `MultipleResultsFound`. The suite is deliberately not crash-only. A fix that returned *one* GM's note and dropped the other would satisfy "does not raise" while silently hiding a co-GM's writing, so there is a test asserting both notes arrive, one asserting attribution, and one covering the single-GM path so the common case cannot regress on the way past. **1,482 backend tests pass** (was 1,476), **457 frontend**. Lint clean at pinned ruff 0.4.4; eslint clean apart from one pre-existing warning in a file this PR does not otherwise touch. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(journal): the campaign journal 500'd for co-GM campaigns (#411)
All checks were successful
CI / Backend lint (ruff) (pull_request) Successful in 24s
CI / Bot/backend version sync (pull_request) Successful in 52s
CI / Frontend tests, audit, and build (pull_request) Successful in 1m30s
CI / Docker image build (pull_request) Successful in 1m23s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m43s
CI / Bot tests and audit (pull_request) Successful in 2m16s
CI / Backend migration, tests, and audit (pull_request) Successful in 8m8s
7949404755
get_campaign_notes called scalar_one_or_none() on a query returning one row
per GM, so a campaign with two GMs raised MultipleResultsFound — a 500 for
every member of that campaign, not just the GMs. The symptom a user reports
is "my notes are gone", which is a read-path crash wearing a data-loss
costume.

Fetches every GM's public notes rather than "the" GM's, and attributes each
to its author: two unattributed notes stacked under one "GM Notes" heading
read as one person contradicting themselves. That changes
CampaignNoteEntry.gm_public_note (str | None) to gm_public_notes
(list[{author, content}]); both render sites are updated in the same commit,
and the author line only shows when there is more than one.

The reader's own notes stay excluded — they already appear under my_notes,
and repeating them would read as the journal duplicating itself. That was
the point of the original `gm_id != user_id` check, kept as a set
difference.

Mutation-checked: restoring scalar_one_or_none fails 4 of 6 tests with the
issue's own MultipleResultsFound. One test covers the single-GM case, so
the fix cannot regress the common path on its way past.

1,482 backend and 457 frontend tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
claude-bot deleted branch fix/411-co-gm-journal 2026-08-31 04:32:50 +00:00
Sign in to join this conversation.
No description provided.