ADORSYS-GIS / ADORSYS-GIS/lightbridge-authz

[Story]: Per-grain query APIs with source as a dimension (grain guard; closes the scope-ownership and multi-scope gaps)

Open
#586 4 comments 0 reactions 1 assignee Claimed by @benie-joy-possi View on GitHub
user-story
Dominant language
Rust
Stars
0
Forks
1
Avg merge
6h 42m
Merged PRs (30d)
246

Description

Parent epic: #581

### Story Statement

As a dashboard consumer, I query each telemetry grain through its own closed, typed endpoint with `source` as a first-class filter and group-by — and a query that would mix grains does not typecheck.

### Real Intent

Extend the ADR-0022 closed-query contract from one endpoint over one table to one endpoint per grain, making the audit's F3 failure (optional grain filter defaulting to off ⇒ every KPI double-counts) structurally impossible, and closing #570/#578 while the surface is open.

### Background and Context

`/usage/v1/usage/query` today: four-value scope enum, eight optional exact-match filters, eight-value group-by enum, double-gated bucket interval, `FROM usage_events` hardcoded. governance#183 names this contract the shape to copy; governance#187 demands the grain guard ("preferably unrepresentable in the request type"); governance#186 lists the execution-grain drill-downs; governance#188 demands NULL cost survive to the wire.

### Source of truth (links)

ADR-0027 Decision 5 · ADR-0022 · governance#183 · governance#186 · governance#187 · governance#188 · #570 · #578

### Acceptance Criteria

1. Per-grain endpoints (`requests`, `executions`, `facts`, `seats` query routes), each with its own request type; no shared table/grain parameter exists — cross-grain aggregation is unrepresentable. Each endpoint declares its authoritative table in exactly one place.
2. `source` added as filter + group-by on every grain; enum-or-bind-bound like every other field (no free-text SQL fragment).
3. #570 closed: `scope_id` ownership verified — a caller reading another tenant's scope gets 403, not data; two-tenant integration test proves it.
4. #578 closed: multi-scope (`scope_ids`) or owner-scoped queries, ownership-checked per item; the LIMIT-drops-newest-buckets bug fixed (order or window such that truncation never silently drops the most recent buckets).
5. NULL money survives serialization as `null` (never 0, never omitted); aggregates report unknown-count alongside totals; no `unwrap_or(0)` on any monetary path (governance#188).
6. The budget spend-reader contract (`/usage/v1/spend/query`, `Option` micro-USD) is byte-stable — its existing integration tests still pass unmodified.
7. OpenAPI updated for every new route; contract tests assert publication.

### Out of Scope

Continuous aggregates (sibling story); dashboard/console wiring (#508); latency percentile changes.

### Dependencies and Blockers

Grain tables landed (execution + day/seat stories). #570's ownership check needs an authority for scope→tenant resolution — decide (shared DB lookup vs authz-api call) in implementation, fail-closed either way.

### Assumptions

The mTLS split-listener posture stays; ownership check is defense-in-depth on top of it, not a replacement.

### Implementation Notes

Reuse `append_dimension`/`date_bin` builder patterns per grain; keep `validate_bucket_interval`'s regex+allowlist double gate. Per-grain repos share the fixed-row-shape trick (unselected dims as `NULL::text`).

### Test Expectations

Two-tenant 403 test (fail-first); per-grain group-by/filter integration tests mirroring the existing `repo_it_tests.rs` coverage; newest-bucket-truncation regression test; NULL-cost wire-shape test.

### Verification evidence

To be attached on the implementing PR.

### Human accountable owner

Stephane Segning Lambou

### AI Usage
AI-assisted (Claude): research and drafting. Reviewed and owned by Stephane Segning Lambou.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.