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.

Beads: islandflow-yza Surface: apps/web terminal Validation: tests + prod build

## 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.tsx` to 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.ts` for 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.

Historical packet context was already present. The terminal simply was not selecting it unless the packet id happened to be the first evidence ref.

## 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.ts` passed with 72 tests.
- `bun --cwd=apps/web run build` passed 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_refs` for simpler downstream consumers.
- Optional: add a small integration test around alert drawer selection if the web app gains component-level interaction tests later.