Summary
GET /v1/stream?table=T only emits events for rows written via POST /v1/ingest (which publishes to NATS ingest.<table>; the SSE hub subscribes ingest.>). If T is the target table of a ClickHouse MATERIALIZED VIEW — rows land in T via the MV, not the ingest API — no NATS event is published and the stream is silently empty (no error).
Why it surprised us
A natural WaveHouse pattern is: ingest raw rows into a base table, expose a derived/projection table via an MV (e.g. a column-masked positions_public), and stream the projection to public clients. That projection never streams — the base table does, but not the MV target.
(Distinct from the already-tracked row-filter drift in applyStreamPolicy, which is about which columns/rows an event carries. This is about MV-written rows producing no event at all.)
Repro
CREATE TABLE base (...), CREATE TABLE derived (...), CREATE MATERIALIZED VIEW mv TO derived AS SELECT ... FROM base.
GET /v1/stream?table=derived (subscribe).
POST /v1/ingest?table=base a row that the MV projects into derived.
- → the row appears in
derived via /v1/query, but the derived stream receives nothing.
Impact
Live dashboards built on derived/projection tables silently receive zero updates — easy to misdiagnose as a client/auth problem. We only found it by testing each surface.
Workaround
Stream the base (ingest-API-written) table directly and rely on the JWT column policy to mask columns per role.
Suggested
- At minimum, document prominently that SSE/live-query only covers ingest-API-written tables (not MV/derived targets).
- Optionally, a mechanism to surface MV/derived-table changes to the SSE hub (opt-in re-publish of an MV target to NATS, or CDC).
Found building the SCC 2026 tracker pilot against a self-hosted WaveHouse.
Summary
GET /v1/stream?table=Tonly emits events for rows written viaPOST /v1/ingest(which publishes to NATSingest.<table>; the SSE hub subscribesingest.>). IfTis the target table of a ClickHouseMATERIALIZED VIEW— rows land inTvia the MV, not the ingest API — no NATS event is published and the stream is silently empty (no error).Why it surprised us
A natural WaveHouse pattern is: ingest raw rows into a base table, expose a derived/projection table via an MV (e.g. a column-masked
positions_public), and stream the projection to public clients. That projection never streams — the base table does, but not the MV target.(Distinct from the already-tracked row-filter drift in
applyStreamPolicy, which is about which columns/rows an event carries. This is about MV-written rows producing no event at all.)Repro
CREATE TABLE base (...),CREATE TABLE derived (...),CREATE MATERIALIZED VIEW mv TO derived AS SELECT ... FROM base.GET /v1/stream?table=derived(subscribe).POST /v1/ingest?table=basea row that the MV projects intoderived.derivedvia/v1/query, but thederivedstream receives nothing.Impact
Live dashboards built on derived/projection tables silently receive zero updates — easy to misdiagnose as a client/auth problem. We only found it by testing each surface.
Workaround
Stream the base (ingest-API-written) table directly and rely on the JWT column policy to mask columns per role.
Suggested
Found building the SCC 2026 tracker pilot against a self-hosted WaveHouse.