fix(server,web): make projection rebuilds restore full history - #25
Merged
Merged
Conversation
Migration 045 wipes all projection tables and resets the replay cursor to 0, but bootstrap read the backlog with readFromSequence's default 1,000-event limit. On a 27k-event store the rebuild silently stopped after the oldest 1,000 events, live events then stamped the cursor to the head, and nearly every thread and project vanished from the UI with no error. Pass Number.MAX_SAFE_INTEGER so bootstrap replays everything past the cursor, matching readAll's behavior. Fable 5 via Claude Code
The turns projector's thread.reverted handler kept only turns with checkpoint evidence at or below the revert baseline. Turns recorded while checkpointing was unavailable have no checkpoint_turn_count, so the first revert on the thread deleted them — and since thread detail paginates by turns, their retained messages became unreachable, indistinguishable from data loss. Use the same collectRevertedTurnIds denylist as the message, activity, and plan projectors so a revert only ever removes the turns it actually reverted. Fable 5 via Claude Code
Migration 046 re-runs 045's wipe-and-replay so the event history rebuilds through the fixed turns projector, restoring turn rows the first rebuild dropped. Bump the thread snapshot cache to v7 so warm browser caches cold-load the rebuilt projections instead of resuming past them. Fable 5 via Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Migration 045's wipe-and-replay rebuild lost data two different ways:
readFromSequencedefaults its limit to 1,000, so the rebuild replayed only the first 1,000 of ~27k events, then live events stamped the cursors to head — every thread newer than the oldest three silently vanished, with no error.thread.revertedhandler kept only turns with checkpoint evidence at or below the revert baseline. Turns recorded while checkpointing was unavailable have nocheckpoint_turn_count, so the first revert deleted them — and since thread detail paginates by turns, their retained messages became unreachable, indistinguishable from data loss.Fix
Number.MAX_SAFE_INTEGER).collectRevertedTurnIdsdenylist as the message/activity/plan projectors, so a revert only ever removes the turns it actually reverted. Regression test covers a checkpointless turn surviving a revert alongside a reverted post-baseline turn.Note: the boot that runs migration 046 replays the full event history before the server starts listening (~30 min on the daily-driver DB).
Fable 5 via Claude Code