[Backend] Stop the storyline auto-rebuild from overwriting GM manual edits #400
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: HIGH
Found in the August 2026 session lifecycle review (#319).
A GM who spends time polishing the campaign storyline's prose loses that work the moment any session in the campaign is transcribed, re-transcribed, or has its summary touched — because the storyline body is unconditionally rebuilt from raw session summaries on every one of those events, with no distinction between "generated" and "GM-authored" content, and no history to recover from.
Evidence
webapp/backend/app/routers/campaigns.py:3330-3352(patch_storyline) —PATCH /campaigns/{id}/storylinewritesstoryline.body = body.body(:3349) directly; this is explicitly documented as "GM manual edit of the storyline body" (:3336).webapp/backend/app/tasks/reminder_tasks.py:4144-4171(_update_campaign_storyline_async) —new_bodyis rebuilt from scratch by concatenating one auto-generated chapter per completed session (_chapter(),:4145-4147), andstoryline.body = new_body(:4171) overwrites whatever was there — including a GM's hand-edit — every time this task runs. Thefull_regenerateflag (:4149-4159) makes no difference: both branches compute the identical rebuilt body, so there is no code path that preserves an existing body at all.webapp/backend/app/services/summary_events.py:70—update_campaign_storylineis one of the tasks fired unconditionally (not gated byfirst_time) fromon_session_summary_available, which is called after every transcription, every GM summary edit, and every canonical-name pick, for any session in the campaign — not just the one the GM most recently touched.Failure scenario
A GM spends an hour after session 12 turning six raw AI summaries into a cohesive, well-written campaign chronicle in the storyline editor. The following week, session 13 is transcribed.
on_session_summary_availablefires for session 13, which enqueuesupdate_campaign_storyline— a task with no idea a hand-edit exists — and it silently rebuilds and overwrites the entire storyline body back to raw concatenated summaries. There is no history table for storylines, so the GM's authorship is gone with no way to diff or recover it, and it will happen again next session.Proposed fix
Give
CampaignStorylineamanually_edited_at(or a booleanis_manually_edited) flag set bypatch_storyline. Haveupdate_campaign_storylinecheck it: if set, append the new chapter's summary to a separate addendum field (or skip the automatic rebuild and notify the GM there's a new session to fold in) rather than clobberingbody. A full-regenerate action should remain available but must be an explicit GM action (already exists asregenerate_storyline,campaigns.py:3358) — the automatic per-session rebuild should never silently overwrite manual prose. This is the same "guard the overwrite path" pattern needed for canonical-name summary regeneration (tracked separately); both belong to the same "never silently overwrite explicit GM authorship" principle.Acceptance criteria
CampaignStorylinetracks whether its body has been manually edited by a GM.update_campaign_storyline's automatic per-session trigger never overwrites a manually-edited body.