From 15f38ce5e5d66d5a649658fb88ceac4dc2688200 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Sun, 23 Aug 2026 19:08:41 -0400 Subject: [PATCH] A turn's reel is exactly a turn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The window's straddle commands hold more than the turn they open and close: the opener carries the previous wizard's last draws, the closer the next wizard's first upkeep — so every instant replay ran on into the following turn (and, with the camera now following the turn-taker, jumped into the next wizard's head for the overrun). momentSteps trims both straddles at the boundary events: the reel opens on "X's turn begins" and stops at X's turnEnded, keeping only what belongs to X. Co-Authored-By: Claude Fable 5 --- packages/server/src/rooms.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/server/src/rooms.ts b/packages/server/src/rooms.ts index e93a952..651000c 100644 --- a/packages/server/src/rooms.ts +++ b/packages/server/src/rooms.ts @@ -464,9 +464,21 @@ export function momentSteps(room: Room, playerId: PlayerId, turnIndex: number): if (!result.ok) return { error: `replay diverged at seq ${entry.seq}` }; current = result.state; const before = counter; - for (const e of result.events) bump(e); + // The straddle commands hold more than this turn: the opener carries + // the previous wizard's last breaths, the closer the NEXT wizard's + // first. Trim both so the reel is exactly one turn — it opens on + // "X's turn begins" and stops at X's turnEnded. + let sliceStart = 0; + let sliceEnd = result.events.length; + result.events.forEach((e, i) => { + if (!TURN_BOUNDARY.has(e.type)) return; + bump(e); + if (counter === turnIndex && before < turnIndex) sliceStart = i; + if (counter === turnIndex + 1 && sliceEnd === result.events.length) sliceEnd = i; + }); if (before > turnIndex) break; if (before <= turnIndex && turnIndex <= counter) { + const kept = result.events.slice(sliceStart, sliceEnd); const prevAt = entry.seq > 0 ? room.log[entry.seq - 1]!.at : ""; const said = room.chat .filter((c) => c.at > prevAt && c.at <= entry.at) @@ -474,7 +486,7 @@ export function momentSteps(room: Room, playerId: PlayerId, turnIndex: number): steps.push({ seq: entry.seq, actor: entry.playerId, - events: redactFor(result.events, playerId), + events: redactFor(kept, playerId), view: viewFor(current, playerId), ...(said.length > 0 ? { chat: said } : {}), });