@@ -161,11 +161,51 @@ never needs the LLM). **Dereferencing a `query_ref` (peek, re-run, stat-binding
161161always executes as the DEREFERENCING caller** — a shared panel refuses per-viewer, never
162162replays the author's scopes. NL→query is ` POST /api/v1/ask ` (Phase 2, additive).
163163
164+ ** Shipped L2 query refs (2026-07-13):** every successful structured execution persists its
165+ request, placeholder SQL, columns, timing, and authorizing scope set under the returned ref.
166+ ` GET /api/v1/query/:query_ref ` peeks that provenance and
167+ ` POST /api/v1/query/:query_ref/rerun ` executes the stored structured request through the current
168+ caller's RLS scopes (and returns a new ref). Because the record contains filter values and may span
169+ several grants, peek/rerun requires the caller to hold the ** complete originating scope set** (a
170+ strict superset is allowed); otherwise it is indistinguishable from a missing ref (404). The
171+ originating grants are never replayed implicitly. Structured ` sum ` requires counter/delta semantics,
172+ and ` avg ` over a counter is rejected as ` agg_mismatch ` . Registered all-event/relationship views
173+ expose only their declared pseudo-fields; dynamic type fields require querying that statistic type.
174+ The request schema reserves ` rate ` , ` fill: zero|previous ` , and ` coverage ` , but this build refuses
175+ those honestly (` bad_agg ` /` unsupported_fill ` /` unsupported_coverage ` ) rather than fabricating data.
176+
164177### 3.2 The statistics catalog — ` GET /api/v1/catalog `
165178
166179The semantic layer, readable, scope-filtered: ` schemas/entities/catalog-entry.schema.json `
167180(type, per-field dimension/measure typing, cardinality, last_emit, emit rate, observed scopes).
168181
182+ L2 is live: ` GET /api/v1/catalog ` returns the shared read envelope (` freshness ` , ` items ` , always-
183+ present opaque ` next_cursor ` , and ` truncated ` ) with a 1 MiB server cap. Byte clipping resumes at the
184+ first omitted type; if one entry alone exceeds the cap, the response explicitly lists it in
185+ ` omitted_types ` and advances, so pagination always makes progress without silently losing a row.
186+ Field descriptors and relationship joins derive transactionally from accepted
187+ emissions; bounded hashed-value sampling classifies dimension cardinality without storing raw
188+ dimension values. Every caller-visible registry projection, cardinality set, and statistic search
189+ document is keyed to one exact scope; the cross-scope aggregate is writer-only coordination state.
190+ Consequently, overlapping access can never reveal field names, joins, or cardinality learned in a
191+ different scope. Conflicting dimension types or measure kind/unit declarations do not silently
192+ rewrite established semantics: the event remains durable and a scoped ` registry_drift ` curation
193+ proposal is created. Producer registrations carry configurable ` max_emit_per_min ` (default 6000)
194+ and ` max_new_types_per_hour ` (default 20); over-cap new types are metadata-only quarantined and
195+ proposed for curation, while same-id retries return the durable rejection without consuming rate
196+ budget until its stored eligibility time; the same body can then be admitted in the new window.
197+ Single-emission cap responses are HTTP 429 with ` Retry-After ` , ` retryable: true ` , and
198+ ` retry_after_s ` ; batch item errors carry ` retryable: true ` .
199+
200+ ` GET /api/v1/catalog/search?q=<text>&limit=<1..32> ` returns the scope-filtered hybrid retrieval
201+ slice (` schemas/semantic-search-result.schema.json ` ) over a normalized 75% pgvector cosine / 25%
202+ PostgreSQL full-text score. The corpus contains catalog definitions, registered views, and successful query
203+ structures; query filter values never enter searchable text. Embeddings are currently the hermetic
204+ 384-dimension ` feature-hash-v1 ` provider. Registered structured-query views are ` events ` (the
205+ raw+archive lake) and ` relationships ` (statistics joined to materialized edges). Governed custom
206+ views publish their direct dimension/measure descriptors in ` semantic_views.fields ` ; validation and
207+ aggregation use those descriptors, and undeclared columns are not addressable.
208+
169209### 3.3 Typed entity reads — ` GET /api/v1/<entity> `
170210
171211Every read returns the ` read-envelope ` (freshness + items + pagination). ** Every entity item
0 commit comments