fix(web): skip history replacements whose target seq is absent#9
Open
Antisophy wants to merge 1 commit into
Open
fix(web): skip history replacements whose target seq is absent#9Antisophy wants to merge 1 commit into
Antisophy wants to merge 1 commit into
Conversation
A replace-style boundary event can reference a message the client does not have: a live boundary broadcast racing a still-streaming history load, or a boundary persisted under an older seq numbering (observed after the 2026-07-20 upstream rebase on a large compacted session: 'History replacement matched 0 messages at seq 7433'). The reducer threw for that case, which wedged the whole session view on every load, permanently sticking the task at 'Loading session...'. Drop the unmatched replacement with a console diagnostic instead: the cost is one message rendering without its replacement, against a permanently unviewable session. Structural violations (multiple matches, identity mismatch) still throw. The history-replay flush path already treats a missing target as 'defer'; this aligns the reducer's own behavior for the paths without a defer queue.
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.
replaceHistoryBoundarythrows when a replace-style boundary event references a message seq the client's reduced state does not contain. Two ways to get there in practice:pendingHistoryBoundariesdefer only guards the separately-routedtask_history_boundary_replacedkind; boundary-carrying events flowing throughhandleTaskMessagereach the reducer unguarded), andHistory replacement matched 0 messages at seq 7433, which permanently wedged the session view at "Loading session..." with no recovery short of code changes.Since the throw converts a cosmetic inconsistency into an unviewable session, this makes the matched-0 case fail soft: drop the replacement with a console diagnostic and return the state unchanged. The cost is one message rendering without its replacement until seqs realign. The structural invariants keep throwing (multiple matches, canonical-identity mismatch), and the replay flush path's defer behavior is unchanged; this only aligns the reducer's own behavior for the paths that have no defer queue.
The existing "rejects invalid replacement targets" test pinned the throw; it now asserts the skip returns the same state instance. Full
nix flake checksuite is green on the branch.