fix(backend): stop the summariser reading a GM's answer as an event (#584) #585
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/584-gm-answer-context"
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?
Closes #584.
The defect. Every summariser tried on the 2026-09-09 session, local and hosted, put the party in Ironroot Hold, the one place the session establishes they are far away from. The run holds a verified beat, "The party is currently located in Ironroot Hold", citing the GM's line "You're in Ironroot Hold" — which answered a player asking where they had been before the caves. The validator confirms the words were spoken and who spoke them; it cannot read tense, so a false event passes every check and every composer repeats it.
The fix is the prompt. One rule beside the existing table-talk rule: a GM line answering a player's question, about earlier events, the rules, the map or a name, states context rather than something happening now, and is not an event unless the surrounding lines show the fiction changing. The narration and
narratedrules are untouched; this carves an exception out of them.The code-side check reports, and never rejects.
answer_shaped_beatsflags a beat whose cited lines are all short GM lines shortly after a player's question, logged as a count. It is not aproblemsentry, on evidence rather than taste: a problems entry removes the beat from compose and from the anchors, so one false positive silently deletes a real event. Measured on the golden transcript, the tight predicate flags 1 of 71 GM lines; loosening the lookback to six lines with no length bound flags 40 of 71, including the session's pivotal reveal. A terse GM would lose their most important beat, and there is no real-speech corpus in the repo to fix a threshold against. So it is an instrument, not a gate, and its docstring is honest about what it misses.Eval note. The scores are byte-identical before and after (coverage 0.950, attribution 0.950, chronology 1.000, beat validation 0.950), and that identity is itself the finding: all four scorers measure recall or correctness, so none can penalise a summary for containing an extra false event. Filed as a follow-up.
Tests: 12 new in
test_beat_service.pyincluding a case pinning that the validator still accepts the trap beat, plus end-to-end coverage that the count is logged and the beat text is not. Full suite 3,097 passed; formatted with CI's ruff.🤖 Generated with Claude Code