Problem
In @wavehouse/sdk LiveQuery.next, messages still buffered in NATS retention are replayed through the same next: callback as truly-live events. The next: payload is just event.data — no event.replayed, no server-side delivered_at, no separate replay: stream — so a consumer can't gate replayed rows out of latency math without a heuristic.
Any consumer that subscribes with a non-trivial since window (the recommended way to get a smooth backfill) and experiences a brief disconnect→reconnect, or has retention containing messages emitted before the client connected, will see replayed rows arrive through next: indistinguishable from live arrivals. For latency monitoring (event-to-browser timing) this fabricates large recv_ts - emit_ts deltas that aren't real wire latency — observed downstream as AVG-LATENCY cards showing hundreds of seconds with a line decaying linearly toward zero as the page stays open.
Proposed Solution
Add a server-known signal to the next: path so consumers can separate replay from live. Any one of:
event.replayed: boolean on next: payloads — minimal surface, the server already knows the distinction.
- Server-side
delivered_at timestamp per event — lets a consumer compute delivered_at - emit_ts (server-side propagation) and now() - delivered_at (wire latency) separately. Most expressive.
- Separate
replay: callback distinct from next: — clearest separation, biggest API change.
Recommend (2) for monitoring use cases, or (1) as the smallest change that unblocks all latency-monitoring consumers.
Alternatives Considered
- Consumer-side threshold heuristic (drop rows where
recv_ts - emit_ts > ~5s) — current downstream workaround; self-contained but blunt, and wrong whenever real latency or real backfill age crosses the threshold.
Additional Context
From nas-observability WHissues.md, 2026-05-08. Note #87 (MVP cuts) keeps "stream raw events as received" as the surviving live path — i.e. exactly the liveQuery surface this issue hardens — so this is complementary to that scoping, not in tension with it. Unrelated to #33/PR #83 (Pipes KV watcher) despite the shared "real-time" framing — different subsystem.
Problem
In
@wavehouse/sdkLiveQuery.next, messages still buffered in NATS retention are replayed through the samenext:callback as truly-live events. Thenext:payload is justevent.data— noevent.replayed, no server-sidedelivered_at, no separatereplay:stream — so a consumer can't gate replayed rows out of latency math without a heuristic.Any consumer that subscribes with a non-trivial
sincewindow (the recommended way to get a smooth backfill) and experiences a brief disconnect→reconnect, or has retention containing messages emitted before the client connected, will see replayed rows arrive throughnext:indistinguishable from live arrivals. For latency monitoring (event-to-browser timing) this fabricates largerecv_ts - emit_tsdeltas that aren't real wire latency — observed downstream as AVG-LATENCY cards showing hundreds of seconds with a line decaying linearly toward zero as the page stays open.Proposed Solution
Add a server-known signal to the
next:path so consumers can separate replay from live. Any one of:event.replayed: booleanonnext:payloads — minimal surface, the server already knows the distinction.delivered_attimestamp per event — lets a consumer computedelivered_at - emit_ts(server-side propagation) andnow() - delivered_at(wire latency) separately. Most expressive.replay:callback distinct fromnext:— clearest separation, biggest API change.Recommend (2) for monitoring use cases, or (1) as the smallest change that unblocks all latency-monitoring consumers.
Alternatives Considered
recv_ts - emit_ts> ~5s) — current downstream workaround; self-contained but blunt, and wrong whenever real latency or real backfill age crosses the threshold.Additional Context
From nas-observability
WHissues.md, 2026-05-08. Note #87 (MVP cuts) keeps "stream raw events as received" as the surviving live path — i.e. exactly theliveQuerysurface this issue hardens — so this is complementary to that scoping, not in tension with it. Unrelated to #33/PR #83 (Pipes KV watcher) despite the shared "real-time" framing — different subsystem.