Turn Document · 2026-05-20 02:56 EDT
Historical Alert Flow Packets Persist Again
Alert detail drawers now resolve persisted flow packets from ClickHouse-backed historical context instead of assuming the first evidence reference is the packet. This restores packet visibility for replayed and older alerts after their Redis hot-cache entries have aged out.
Summary
The web terminal was assuming alert.evidence_refs[0] always pointed at a flow packet. For compute-generated alerts, the first evidence ref is often the smart-money event id, with the actual packet id later in the list. That made persisted historical packets look missing even when ClickHouse context had already hydrated them successfully.
Changes Made
- Added shared alert helpers in
apps/web/app/terminal.tsxto extract all flow-packet refs from an alert and resolve the first hydrated packet semantically. - Switched the alert drawer's selected packet lookup to use the shared resolver instead of the first evidence ref.
- Updated alert-underlying inference, visible-alert prefetch, pinned-flow retention keys, and classifier-hit-to-alert matching to use the same alert packet semantics.
- Added focused regression coverage in
apps/web/app/terminal.test.tsfor alerts whose packet ref is not the first evidence entry.
Context
Islandflow alert detail views combine live Redis retention with ClickHouse historical hydration. Once a packet leaves the hot cache, the UI must treat ClickHouse-loaded evidence as first-class persisted context, not as a degraded fallback. The bug was in the web client’s interpretation of alert evidence ordering, not in the persistence of the packet itself.
Important Implementation Details
- The fix is backward-compatible with already-persisted alerts because it tolerates existing evidence ordering instead of rewriting stored records.
- The shared resolver centralizes the packet-selection rule so replay, pinning, and alert navigation do not drift apart again.
- The classifier-hit alert matching path now finds alerts by any embedded packet ref, which improves consistency when opening related alert context from signal panes.
Relevant Diff Snippets
apps/web/app/terminal.tsx · alert packet resolution
-const packetId = selectedAlert.evidence_refs[0];
-return packetId ? resolvedFlowPacketMap.get(packetId) ?? null : null;
+return resolveAlertFlowPacket(selectedAlert, resolvedFlowPacketMap);
apps/web/app/terminal.tsx · prefetch and alert matching
-const visiblePacketIds = visibleAlerts
- .map((alert) => alert.evidence_refs[0] ?? null)
- .filter((id): id is string => Boolean(id) && id.startsWith("flowpacket:"));
+const visiblePacketIds = visibleAlerts.flatMap((alert) => getAlertFlowPacketRefs(alert));
-alertsFeed.items.find((item) => item.trace_id === desiredTrace || item.evidence_refs[0] === packetId)
+alertsFeed.items.find(
+ (item) => item.trace_id === desiredTrace || getAlertFlowPacketRefs(item).includes(packetId)
+)
These snippets are rendered client-side with Diffs using the same old/new code blocks shown in the fallback text if the library cannot load.
Expected Impact for End-Users
Older or replayed alerts should now show their persisted flow packet summary in the detail drawer even after the Redis hot cache no longer has that packet. Users investigating signal history should keep the same evidence continuity they get from live data: packet summary, print context, and related alert linkage stay intact.
Validation
bun test apps/web/app/terminal.test.tspassed with 72 tests.bun --cwd=apps/web run buildpassed on Next.js 16.2.6.- The new tests specifically cover alerts where a smart-money event id precedes the packet id in
evidence_refs.
Issues, Limitations, and Mitigations
- This change does not alter how compute persists alert evidence ordering. Instead, it makes the terminal resilient to existing and future mixed evidence lists.
- The Diffs rendering in this document loads from the published package at view time. A plain-text fallback is included directly in the HTML so the document remains readable offline.
- No full monorepo test sweep was run because the change was isolated to the web terminal alert-context path.
Follow-up Work
- No additional Beads issue was required for this fix.
- Optional: audit whether compute should emit packet ids before higher-level event ids in
evidence_refsfor simpler downstream consumers. - Optional: add a small integration test around alert drawer selection if the web app gains component-level interaction tests later.