Rolling back is now non-destructive: instead of truncating the future, it restores the target checkpoint's snapshot and points Game.rollback_head_checkpoint_id at it. Later checkpoints/events are kept and rendered greyed; rolling forward to one redoes the rollback (same endpoint). The abandoned future is discarded only when a new action is taken from a rolled-back state -- maintain_rollback_history truncates it, clears the head, and bumps rollback_timeline_version, now the sole trigger for the frontend log reset. - Game.rollback_head_checkpoint_id (nullable; in SNAPSHOT_EXCLUDE) + Alembic migration. - crud_rollback: rollback_to_checkpoint sets the head (None at latest); _discard_future + head-clear + version-bump moved into the next scene action's capture. - EventLog.svelte: greyed future, redo (forward) affordance, a "rolled back" banner; dropped the now-misleading destructive confirm. - Tests rewritten for head-pointer semantics (+ redo, action-after- rollback truncation, scene-end head clear); HTTP integration test extended to drive the full cycle over the wire. Verified end-to-end in a browser: rollback greys the future and reverts live state (captaincy/ranks), redo restores it, no errors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
85 KiB
85 KiB