From 56cdebdeda5573e3fc5c7f4e3e1c83090ccd9c33 Mon Sep 17 00:00:00 2001 From: Tim McCarthy Date: Sat, 13 Jun 2026 09:03:52 -0700 Subject: [PATCH] Fix off-by-one in rollback button placement A rollback button on event E restores the state just after E. So the button on the latest event was a no-op (you're already there), while the scene-start event -- a valid earliest target -- correctly has one. The visible set was effectively shifted one event late. Hide the button on whichever event sits at the current position (the rollback head if set, else the latest checkpoint, now supplied by the backend as state.latest_checkpoint_id since the frontend's own reduce over the async-populated accumulator wasn't reliably reactive). In live play the latest event loses its redundant button; when rolled back, the "you are here" event has none while earlier events show rollback and later ones show redo. Verified in a browser across live, rolled-back, and redo states. Co-Authored-By: Claude Opus 4.8 --- frontend/src/components/EventLog.svelte | 6 +++++- src/pirats/crud_rollback.py | 13 ++++++++++++- src/pirats/main.py | 2 ++ tests/test_game.py | 6 ++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/EventLog.svelte b/frontend/src/components/EventLog.svelte index bde1085..1b66d09 100644 --- a/frontend/src/components/EventLog.svelte +++ b/frontend/src/components/EventLog.svelte @@ -42,6 +42,10 @@ // When set, the game is at a rolled-back state; events past this checkpoint are the // greyed, still-undoable future. Rolling forward to one of them redoes the rollback. $: head = state.game?.rollback_head_checkpoint_id ?? null; + // The point in time the game is currently at: the rollback head if set, otherwise + // the newest checkpoint (supplied by the backend). A button targeting it would be a + // no-op, so the "you are here" event — and, in live play, the latest event — has none. + $: currentPos = head !== null ? head : (state.latest_checkpoint_id ?? 0); $: mergePolled(state.events); @@ -175,7 +179,7 @@ {KIND_ICONS[event.kind] || KIND_ICONS.info} {event.message} {formatTime(event.timestamp)} - {#if canRollback && event.checkpoint_id > 0} + {#if canRollback && event.checkpoint_id > 0 && event.checkpoint_id !== currentPos}