mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 08:03:20 +00:00
fix(native-chat): let a retraction prune its rows without retiring the epoch
Correcting the previous commit. Skipping a retraction frame outright stopped it pruning the mirrored rows, so a worktree the host no longer publishes would have kept a chat on screen with nothing behind it. Apply the frame as before and clear its cursors instead of recording them, which is what the mainstream session-tabs path does. The unpublished sentinel keeps its cursor now too: it is skipped rather than cleared, so a stale frame arriving late is still fenced. Adds the case the earlier version would have broken.
This commit is contained in:
@@ -140,6 +140,17 @@ describe('a revealed chat survives the frames the reveal provokes', () => {
|
||||
expect(chatTabIds(state)).toEqual([SESSION_TAB])
|
||||
})
|
||||
|
||||
it('still prunes the mirrored rows when the host retracts the worktree', () => {
|
||||
// The retraction must not merely stop fencing later frames — it has to take the rows with it,
|
||||
// or a worktree the host no longer publishes keeps a chat on screen that nothing backs.
|
||||
let state = apply(baseState(), chatFrame(RENDERER_EPOCH, 120))
|
||||
expect(chatTabIds(state)).toEqual([SESSION_TAB])
|
||||
|
||||
state = apply(state, { ...chatFrame('removed:abc', 0), tabs: [], removed: true } as never)
|
||||
|
||||
expect(chatTabIds(state)).toEqual([])
|
||||
})
|
||||
|
||||
it('still ignores a genuinely superseded republication', () => {
|
||||
// The fences exist for a reason: without an intervening non-publication frame, an older
|
||||
// version under the same lineage must still lose.
|
||||
|
||||
@@ -74,16 +74,11 @@ export function applyLocalStructuredSessionTabSnapshots<
|
||||
if (getExecutionHostIdForWorktree(next, snapshot.worktree) !== 'local') {
|
||||
continue
|
||||
}
|
||||
// A frame that carries no publication is not a later publication to fence against. Recording
|
||||
// its epoch retires the renderer's own — which is a module constant for the process lifetime,
|
||||
// and nothing un-retires it — so every republication afterwards is dropped until a reload
|
||||
// mints a new one. That is what made a revealed chat invisible: the click's own inventory
|
||||
// refresh reads `none`/v0 for a worktree the host holds no entry for, and poisons the reveal
|
||||
// that follows it. The mainstream session-tabs path clears its tracking here for the same
|
||||
// reason; this one recorded the sentinel instead.
|
||||
if (snapshot.removed === true || !hostSnapshotAffirmsWorktreeContents(snapshot)) {
|
||||
localStructuredSessionVersionByWorktree.delete(snapshot.worktree)
|
||||
localStructuredSessionEpochHistoryByWorktree.delete(snapshot.worktree)
|
||||
// "Ask me later", not an answer: a worktree the host holds no entry for still answers a forced
|
||||
// inventory, with `none` at version 0. Absence there proves nothing, so it neither applies nor
|
||||
// records — recording it would retire the epoch below. Its cursor is left alone, so a genuinely
|
||||
// stale frame arriving late is still fenced.
|
||||
if (!hostSnapshotAffirmsWorktreeContents(snapshot)) {
|
||||
continue
|
||||
}
|
||||
const prior = localStructuredSessionVersionByWorktree.get(snapshot.worktree)
|
||||
@@ -109,6 +104,18 @@ export function applyLocalStructuredSessionTabSnapshots<
|
||||
}
|
||||
)
|
||||
next = patch === next ? next : ({ ...next, ...patch } as State)
|
||||
if (snapshot.removed === true) {
|
||||
// A retraction still had to be applied above — the mirrored rows must go — but it is not a
|
||||
// publication to fence later frames against. The renderer publishes under one epoch string
|
||||
// for its whole lifetime, so recording a retraction retires that epoch permanently, and
|
||||
// every republication afterwards is dropped until a reload mints a new one. That is what
|
||||
// left a revealed chat invisible: closing the last chat prunes the host's entry, the
|
||||
// retraction retired the renderer's epoch, and the tab the reveal published was discarded.
|
||||
// The mainstream session-tabs path clears its tracking here for exactly this reason.
|
||||
localStructuredSessionVersionByWorktree.delete(snapshot.worktree)
|
||||
localStructuredSessionEpochHistoryByWorktree.delete(snapshot.worktree)
|
||||
continue
|
||||
}
|
||||
localStructuredSessionVersionByWorktree.set(snapshot.worktree, {
|
||||
publicationEpoch: snapshot.publicationEpoch,
|
||||
snapshotVersion: snapshot.snapshotVersion
|
||||
|
||||
Reference in New Issue
Block a user