fix(web): preserve the visible chat window during rewind (#1766)

* fix(web): preserve chat window during rewind

* fix(web): scope rewind invalidation preservation

* fix(web): clear unknown rewind boundaries

* fix(web): deduplicate rewind invalidations

* fix(web): retain rewind dedupe history
This commit is contained in:
Ananovo
2026-09-09 09:23:31 +08:00
committed by GitHub
parent fa1caf7d71
commit 17ee052d9a
9 changed files with 208 additions and 12 deletions
+1 -1
View File
@@ -140,7 +140,7 @@ Schema: `SyncEventSchema` in `shared/src/schemas.ts` (discriminated on `type`).
| `session-updated` | `sessionId`, `data?: Session \| SessionPatch` | See [Versioned patch algorithm](#versioned-patch-algorithm). |
| `session-removed` | `sessionId` | Drop the session from the list, drop its detail cache, clear its message window. |
| `message-received` | `sessionId`, `message: DecryptedMessage` | Ingest into the message window; advance the tail cursor (see [pagination](./pagination.md)). Also fired for the caller's own send (the localId echo). |
| `messages-invalidated` | `sessionId` | Message history changed **structurally** (rewind, fork, import, clear). Session scope: discard the whole window and run a fresh tail sync. Global scope: refetch the session list. |
| `messages-invalidated` | `sessionId`; rewind may also include `reason: 'rewind'` and `truncateFromLocalId` | Message history changed **structurally** (rewind, fork, import, clear). For a rewind, retain only the known prefix through the client boundary before tail-syncing; for every other invalidation, discard the whole window and run a fresh tail sync. Global scope: refetch the session list. |
| `scheduled-matured` | `sessionId` | A scheduled message became due and was handed to the agent. Refetch list/queue indicators. |
| `session-ended` | `sessionId`, `reason?: 'completed'\|'terminated'\|'error'\|'handoff'\|'cleared'` | Session lifecycle signal (the `session-updated` flow still carries the state change). |
| `machine-updated` | `machineId`, `data?: Machine \| MachinePatch \| null` | Full `Machine`: upsert (remove when `active:false`). `null`: machine removed. Patch `{active?, activeAt?, updatedAt?}`: `active:false` ⇒ remove, otherwise refetch machines. `data` absent ⇒ refetch. |