perf(server): bound orchestration replay and slow-client live buffers - #216
perf(server): bound orchestration replay and slow-client live buffers#216leoisadev1 wants to merge 3 commits into
Conversation
Catch-up replay used to load a global event range, then filter per chat. A stale cursor or a few huge tool payloads could decode gigabytes, and a slow WebSocket client could retain live events without a memory bound. Recursive page concatenation also kept consumed pages alive. Thread resume now measures and reads only that chat's rows through a captured head, with 1,000-event and 8 MiB payload budgets. Shell resume still uses the global range but measures serialized payload bytes before decoding. Live shell and thread subscriptions share a per-subscription budget that includes the unacknowledged RPC batch; overflow detaches the producer and tells the client to resume from its last sequence. Event-store pages are released as they are consumed. Adapted from T3 Code pingdotgg#8992, pingdotgg#9521, pingdotgg#9715, pingdotgg#9726, and pingdotgg#10777. Preserves Akeru bot/group/channel shell fields and Chat error copy. Old clients that omit afterSequence still get a snapshot. Grok 4.6 High in Grok Build via Orca.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Greptile SummaryThis change bounds orchestration catch-up and live subscription memory, adds thread-scoped replay statistics and reads, coalesces live thread updates under a shared retention budget, and releases consumed event-store pages. The outstanding shell replay path can still include an event newer than its captured replay head when persisted sequence numbers have gaps, then deliver that event again from the already-attached live stream. Confidence Score: 4/5Not safe to merge until the outstanding shell replay defect is fixed. The prior shell replay finding remains outstanding. The replay call uses the difference between the captured head and client cursor as an event count rather than an upper sequence boundary. When sequence values are sparse, replay can include a newer event outside the captured range; because live delivery is attached first, that same event can then be delivered again from the buffered live stream.
What T-Rex did
|
The shared projection-query layer keeps SQLite AUTOINCREMENT after DELETE, so a hard-coded 1..4 range could miss the inserted rows. Use RETURNING sequence. Grok 4.6 High in Grok Build via Orca.
|
This is Leo's agent. Holding refreshed head 1d2a9ab despite green Repository checks: the actual refreshed Greptile assessment is 4/5 with an outstanding shell replay boundary finding. Independent source tracing corroborates the mismatch: ws.ts passes headSequence - afterSequence to readEvents; OrchestrationEngine forwards that as the row limit; the event-store SQL only applies sequence > cursor and LIMIT, without sequence <= captured head. The reviewer reports a real WebSocket sparse-sequence reproduction; I have not independently executed that reproduction. Required scoped repair: bound shell catch-up to captured head before coalescing, or expose a bounded sequence-range read, and add a committed deterministic WebSocket test with sequence gaps and a newer event already queued live. Assert that the newer event is delivered only once from the live tail, with no replay past the captured boundary. Preserve snapshot fallback and memory budgets; rerun focused tests and fresh PRGL. Existing 155 passing tests and browser synchronization checks do not cover this case. This path is inherited rather than introduced by the branch refresh, but it remains an unresolved acceptance finding. Orca is unavailable, so this comment is not verified worker delivery or executed repair. |
Problem
WebSocket catch-up replay loaded a global event range and filtered per chat afterwards. A stale cursor, or a handful of large tool payloads, could decode gigabytes and OOM the server. Slow clients could also retain live shell and thread events without a memory bound, including the batch waiting for an RPC ACK. Recursive event-store page concatenation kept consumed pages alive.
Adaptation
Thread resume now measures and reads only that chat's rows through a captured head, with a 1,000-event cap and an 8 MiB serialized payload budget. A recreated chat ID falls back to a fresh snapshot. Shell resume still uses the global range, but it measures payload bytes in SQL before decoding and snapshots when the gap or budget is unsafe.
Live shell and thread subscriptions share a per-subscription budget that includes queued, coalescing, and unacknowledged work. Overflow detaches the producer even without another pull and returns
OrchestrationGetSnapshotErrorso the client can resume from its last sequence. Event-store pages are released as they are consumed.Akeru bot, group, channel, and people fields on the shell snapshot stay in place. Missing-chat errors still say Chat, not Thread. Clients that omit
afterSequencestill get a snapshot, including pre-pagination clients.Upstream credits
Reviewed adaptations of T3 Code:
Local #16 bootstrap replay, #143 coalescing, and #198 raw-observer policy are preserved. Provider adapters are unchanged.
Scope
Server wire/replay only. Client stream lifetime, config bootstrap, reducer reference stability, and static HTTP caching are separate PRs.
Verification
Focused tests:
vp run --filter akeru-bot typecheckpassedIsolated web client, home
/tmp/akeru-replay-verify.VTW8Fb, populated fixture, worktree ports 6892/14932:/bots/ui-scout. Scout chat, roster, reply/react/read-aloud, and composer rendered./bots/ui-scoutand the same messages, so reconnect resumed the subscription instead of an empty load.These stills are the screens after those actions. They do not replace the pair, reload, second-client, and viewport steps above.
Limitations
This PR does not change provider adapters. Effect stays at beta.103;
Stream.paginateis available locally. Native mobile was not required for this server change.Grok 4.6 High in Grok Build via Orca.