Beat dedupe misses same-moment duplicates and split moments, inflating the event log #588

Open
opened 2026-09-10 05:50:11 +00:00 by claude-bot · 3 comments
Contributor

Evidence, from the Gemma 4 26B run on the 2026-09-09 session (59 verified events):

[04:14] other   Idani investigates the depth of the water.
[04:14] other   Idani investigates the depth of the water.
[69:54] reveal  The GM reveals that Wyatt can interpret the map to find directions and a nearby city.
[71:26] reveal  The GM reveals that Wyatt can see a mid-sized city and a path to it on the map.

The first pair is the same sentence at the same timestamp and should never have survived dedupe_beats. The second is one moment reported twice a minute apart. There are also four separate events for waking up and realising the caverns moved them ("complete a long rest in the caverns", "complete a long rest", "wake up to find they have been moved", "realize they were in the shifting caverns").

dedupe_beats compares beats structurally (_same_event on ranges and actors), so two extraction passes that phrase the same moment slightly differently, or stamp it a minute apart, both survive. That inflates the event log #568 introduced, wastes compose budget, and makes the adaptive pass loop think a pass found something new when it found the same thing again.

Suggested approach. Extend _same_event with a content comparison for beats whose ranges are close: normalised token overlap on the summary above a threshold, plus the same actor set, collapses to one — preferring the verified beat, then the one with more evidence citations, which is the preference dedupe_beats already encodes. Keep it conservative: two genuinely different events at the same second do happen (simultaneous speech is why ranged timestamps exist).

Measure it on the replay, where the answer is known: 59 events with at least 6 collapsible, and the four waking-up rows should become one or two. The kind distribution is also worth recording while in here: other was 27 of 59, which suggests the extraction prompt's type list does not fit exploration sessions well — possibly a separate issue.

Related: #423 (why passes repeat), #568 (the log this inflates), #566 (ordering).

**Evidence, from the Gemma 4 26B run on the 2026-09-09 session** (59 verified events): ``` [04:14] other Idani investigates the depth of the water. [04:14] other Idani investigates the depth of the water. [69:54] reveal The GM reveals that Wyatt can interpret the map to find directions and a nearby city. [71:26] reveal The GM reveals that Wyatt can see a mid-sized city and a path to it on the map. ``` The first pair is the same sentence at the same timestamp and should never have survived `dedupe_beats`. The second is one moment reported twice a minute apart. There are also four separate events for waking up and realising the caverns moved them ("complete a long rest in the caverns", "complete a long rest", "wake up to find they have been moved", "realize they were in the shifting caverns"). `dedupe_beats` compares beats structurally (`_same_event` on ranges and actors), so two extraction passes that phrase the same moment slightly differently, or stamp it a minute apart, both survive. That inflates the event log #568 introduced, wastes compose budget, and makes the adaptive pass loop think a pass found something new when it found the same thing again. **Suggested approach.** Extend `_same_event` with a content comparison for beats whose ranges are close: normalised token overlap on the summary above a threshold, plus the same actor set, collapses to one — preferring the verified beat, then the one with more evidence citations, which is the preference `dedupe_beats` already encodes. Keep it conservative: two genuinely different events at the same second do happen (simultaneous speech is why ranged timestamps exist). **Measure it on the replay**, where the answer is known: 59 events with at least 6 collapsible, and the four waking-up rows should become one or two. The kind distribution is also worth recording while in here: `other` was 27 of 59, which suggests the extraction prompt's type list does not fit exploration sessions well — possibly a separate issue. Related: #423 (why passes repeat), #568 (the log this inflates), #566 (ordering).
Author
Contributor

More evidence from run 3 (Gemma 4 26B on the dev replay, 2026-09-11 03:28 UTC, run a0784433, at 6533fa1 with #591). 83 verified events, and the same-moment duplicates are still there:

  • Identical time:
    • 00:04:56 "Clio discovers the water is much deeper…", twice, word for word
    • 00:34:29 "The GM confirms there are plants growing in the area", twice
    • 00:47:09 "Viquilonto (Viq) finds a journal tucked under a rock", twice
  • Same time, different wording:
    • 00:09:08, 2 variants of "Clio catches Idani with the rope"
    • 00:15:04, 2 variants of "finds a rotting skeleton"
  • Split over seconds:
    • 00:53:26 / 00:53:33 / 00:53:36, the calliope emblem, three times
    • 00:43:34 / 00:44:08 / 00:44:34, the detect magic results, three times
    • 00:54:16 / 00:55:05, "The GM explains what a thresher is", twice

That's at least 10 surplus rows out of 83. Since #589 they matter for the prose too: the summary is written from 30 events stratified by time, so a triple costs the section it sits in two slots. The calliope triple and the detect magic triple sit in the 00:43 to 00:54 stretch, which is also where the summary lost the Thieves' Cant detail run 2 had kept.

The two identical-time cases are the cheapest win: same t_start and the same normalised summary text is safe to collapse with no judgement at all.

**More evidence from run 3** (Gemma 4 26B on the dev replay, 2026-09-11 03:28 UTC, run `a0784433`, at 6533fa1 with #591). 83 verified events, and the same-moment duplicates are still there: - **Identical time:** - 00:04:56 "Clio discovers the water is much deeper…", twice, word for word - 00:34:29 "The GM confirms there are plants growing in the area", twice - 00:47:09 "Viquilonto (Viq) finds a journal tucked under a rock", twice - **Same time, different wording:** - 00:09:08, 2 variants of "Clio catches Idani with the rope" - 00:15:04, 2 variants of "finds a rotting skeleton" - **Split over seconds:** - 00:53:26 / 00:53:33 / 00:53:36, the calliope emblem, three times - 00:43:34 / 00:44:08 / 00:44:34, the detect magic results, three times - 00:54:16 / 00:55:05, "The GM explains what a thresher is", twice That's at least 10 surplus rows out of 83. **Since #589 they matter for the prose too:** the summary is written from 30 events stratified by time, so a triple costs the section it sits in two slots. The calliope triple and the detect magic triple sit in the 00:43 to 00:54 stretch, which is also where the summary lost the Thieves' Cant detail run 2 had kept. The two identical-time cases are the cheapest win: same `t_start` and the same normalised summary text is safe to collapse with no judgement at all.
Author
Contributor

Picking up the judgement-free part only (2026-09-11), in one branch with #595.

  • The change: collapse beats with the same start timestamp and the same normalised text, keeping the first. The rows listed in the previous comment at 00:04:56, 00:34:29 and 00:47:09 are the target.
  • Recorded: a nullable beats_collapsed count on summarisation_runs. NULL means not measured, following the convention of hallucination_drops and name_snaps.
  • Leaving this issue open for same-moment rewordings and split moments, e.g. the calliope emblem at 00:53:26, 00:53:33 and 00:53:36. Those need judgement, and deserve their own measured change.
**Picking up the judgement-free part only** (2026-09-11), in one branch with #595. - **The change:** collapse beats with the same start timestamp and the same normalised text, keeping the first. The rows listed in the previous comment at 00:04:56, 00:34:29 and 00:47:09 are the target. - **Recorded:** a nullable `beats_collapsed` count on `summarisation_runs`. NULL means not measured, following the convention of `hallucination_drops` and `name_snaps`. - **Leaving this issue open** for same-moment rewordings and split moments, e.g. the calliope emblem at 00:53:26, 00:53:33 and 00:53:36. Those need judgement, and deserve their own measured change.
Author
Contributor

The exact-duplicate rule is merged (PR #598, main 0935b7a) and deployed to dev. It was measured on run 6d3e6f54 (Gemma 4 26B, 2026-09-11 05:45 UTC).

This run produced no exact duplicates, so the rule collapsed none. The log says: "Dedupe removed 126 beat(s) across the passes: 126 by shared citation and actor, 0 exact duplicate(s)". A normalised same-second, same-text query over the stored events agrees: 0 groups in run 4, against 3 in run 3. That's run-to-run variance in the model's output, not the rule at work. The rule is covered by 21 unit tests, but this run couldn't demonstrate it. beats_collapsed = 126 is that total.

What's left is rewordings, and there are more of them. Nine same-second pairs survived in run 4, each two phrasings of one moment:

  • 00:04:56 Clio on the water: "deeper, colder, and faster-moving" / "deeper, very cold, and moving deceptively"
  • 00:14:42 "discovers a campfire" / "finds a campfire in the cave"
  • 00:15:04 the skeleton, once as Harrowhark and Viq, once as Harrowhark
  • 00:39:55, 00:40:11, 00:40:24: GM descriptions paired with the players' readings of the same moment
  • 00:47:09 finding the journal, 00:47:36 its contents, 00:53:33 the calliope emblem, each told once from the GM's side and once from the player's

Most of the pairs are one moment told from the GM's side and from the player's. That's the next thing to collapse: same second, overlapping citation window, one GM-only actor list and one player actor list. It needs a judgement rule, measured on this replay. It's also where #596's table_admin label will change the picture, since several of the GM-side copies are description rather than events. So the judgement half here is best done after #596 is measured.

**The exact-duplicate rule is merged** (PR #598, main `0935b7a`) and deployed to dev. It was measured on run `6d3e6f54` (Gemma 4 26B, 2026-09-11 05:45 UTC). **This run produced no exact duplicates, so the rule collapsed none.** The log says: *"Dedupe removed 126 beat(s) across the passes: 126 by shared citation and actor, 0 exact duplicate(s)"*. A normalised same-second, same-text query over the stored events agrees: 0 groups in run 4, against 3 in run 3. That's run-to-run variance in the model's output, not the rule at work. The rule is covered by 21 unit tests, but this run couldn't demonstrate it. `beats_collapsed` = 126 is that total. **What's left is rewordings, and there are more of them.** Nine same-second pairs survived in run 4, each two phrasings of one moment: - 00:04:56 Clio on the water: "deeper, colder, and faster-moving" / "deeper, very cold, and moving deceptively" - 00:14:42 "discovers a campfire" / "finds a campfire in the cave" - 00:15:04 the skeleton, once as Harrowhark and Viq, once as Harrowhark - 00:39:55, 00:40:11, 00:40:24: GM descriptions paired with the players' readings of the same moment - 00:47:09 finding the journal, 00:47:36 its contents, 00:53:33 the calliope emblem, each told once from the GM's side and once from the player's Most of the pairs are one moment told **from the GM's side and from the player's**. That's the next thing to collapse: same second, overlapping citation window, one GM-only actor list and one player actor list. It needs a judgement rule, measured on this replay. It's also where #596's `table_admin` label will change the picture, since several of the GM-side copies are description rather than events. So the judgement half here is best done after #596 is measured.
Sign in to join this conversation.
No milestone
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#588
No description provided.