perf(desktop): merge archived observer pages a page at a time - #6065
perf(desktop): merge archived observer pages a page at a time#6065Chessing234 wants to merge 3 commits into
Conversation
The channel-scoped archive window is deliberately uncapped — MAX_OBSERVER_EVENTS protects the live per-agent store only — so it grows with the age of the channel. appendArchivedChannelEvent merged one event at a time, and each call did a linear dedup scan of the whole window and then re-sorted it, so a page of P events into a window of M cost O(P x M) comparisons plus P sorts. Paging back therefore got slower the further back it went, which is the transcript-window lag reported on long-lived agent channels. ingestArchivedObserverEvents now groups a page by (agent, channel) and merges each group once: one pass to index the existing window into a Set, one to filter, one sort. Within-page duplicates are still dropped — the per-event version got that for free by appending to the window each time. Measured locally, 25 pages of 200 events into one channel (5000-event window): 7287 ms before, 78 ms after. Nothing about what is retained changes. Refs block#5985 Signed-off-by: Taksh <takshkothari09@gmail.com>
Four cases pinning what the batch merge must keep doing: a newest-first page lands ascending; duplicates are dropped both within a page and against the already-loaded window; one page spanning two channels keeps the windows separate; and a 1-event page merged into a 2000-event window neither drops nor reorders it. The existing 31 tests in this file pass unchanged. Refs block#5985 Signed-off-by: Taksh <takshkothari09@gmail.com>
themiguelamador
left a comment
There was a problem hiding this comment.
The page-at-a-time merge itself is sound and preserves the tested behavior. I found one minor documentation issue in the touched path:
- P3 — Update the archive-ingest contract after changing the implementation. The function docs still said channel-scoped events route through
appendAgentEvent, claimed a live-delivered event is skipped by archive ingestion, and a nearby merge comment still named the removed singular helper. The stores are deliberately separate; cross-store dedup occurs inmergeObserverEventWindows, while this helper now performs archive-local batching/dedup. Leaving the old contract here would misdirect the next change in a subtle stateful path.
Fix branch: https://github.com/Complear/buzz/tree/review/pr-6065-fix
Commit: d1315b388
Validation: the full desktop suite passed (4,958 tests), along with desktop typecheck, full desktop checks, and git diff --check. The check output contains only the four pre-existing advisory Biome diagnostics outside this PR.
…hanged Review finding (P3, themiguelamador on block#6065): the docs in the touched path still described the pre-batch implementation. - `ingestArchivedObserverEvents` said it "routes through `appendAgentEvent`" and that live-delivered events are "silently skipped". Neither holds: channel-scoped events go to `appendArchivedChannelEvents`, only the channelId-less ones fall through to `appendAgentEvent`, and since `archiveEventsByChannel` is written from that helper alone, no live event is ever in the window to dedup against. Cross-store dedup happens at read time in `mergeObserverEventWindows`. - `appendArchivedChannelEvents` inherited the same wrong "identical to `appendAgentEvent` ... silently skipped" sentence; its dedup is archive-local, over the window and within the incoming page. - `mergeObserverEventWindows` still named the removed singular `appendArchivedChannelEvent`. Also split the doc block that the batch commit left stranded above `archiveDedupKey`: the merge contract was documenting the key helper, and the key helper had no comment of its own. Signed-off-by: Taksh <takshkothari09@gmail.com>
|
Confirmed and fixed in All three doc claims check out, and I verified the load-bearing one rather than taking it on trust: Fixed:
One thing you didn't list that I hit while making the change: the batch commit inserted Verification: desktop typecheck, biome, and the focused ingest suite (35 passed). |
Refs #5985 — the "archive path is unbounded" half, taken as a cost problem rather than a retention-policy one.
appendArchivedChannelEventmerged one event at a time, and each call did a linear dedup scan of the whole channel window and then re-sorted it. Ingesting a page of P events into a window of M therefore cost O(P x M) comparisons plus P full sorts. The archive window is deliberately uncapped —MAX_OBSERVER_EVENTSprotects the live per-agent store only — so M grows with the age of the channel, and paging back gets slower the further back you go. That is the transcript-window lag the issue describes on otherwise idle hardware.ingestArchivedObserverEventsnow groups a page by(agent, channel)and merges each group once: one pass to index the existing window into aSet, one to filter, one sort.Measured, same workload both ways (25 pages of 200 events into one channel, ending at a 5000-event window), via the repo test loader on this machine:
Scope, deliberately. This changes only how a page is merged — not what is retained, not the cap, not the SQL. The issue's second half (retention of
kind 24200telemetry that converts to a metric 0.76% of the time) is a product decision about what to keep, and the deep-history separation between the live and archive windows is load-bearing by design, so neither belongs in the same change. If the archive read should also carry aLIMIT, that is worth doing on top of this — it is a smaller win once the merge is linear, and it changes what the user can scroll back to.Tests — 4 new cases pinning what the batch merge must keep doing:
The 31 existing tests in
ingestArchivedObserverEvents.test.mjspass unchanged, which is the main safety argument — the security guards and drop rules on that path are untouched.Verified locally in
desktop/:pnpm typecheck,pnpm check(2 warnings + 2 infos, all pre-existing on main),pnpm test4958 passed,git diff --check. Not run: the app itself, so the user-visible lag improvement is inferred from the measurement above rather than observed in the UI.