When a platform makes it easy to publish an insight, a dashboard or a data API, the next question from the people who run the company is not "how?" but "who published what, who is calling it, and who said they could?" If the platform cannot answer those three from one screen, it is not ready for the board pack. This is the screen.

One catalog, four kinds

The Catalog lists every published object regardless of kind — insights, data APIs, dashboards, collections — with its owner, current version, consumer endpoint, how many calls it has taken and from how many callers, and when it was last called. Search by name or description; filter by kind; change the usage window. It is the same list a consumer would build by reading /api/v1, with the usage added.

Catalog
The Catalog tab: a count by kind — 2 insights, 66 data APIs, 6 dashboards, 1 collection — and rows for each published object with owner, version and date, the /api/v1 endpoint, calls over 30 days with the number of callers, and the last call.
Unused things are visible as unused. That is most of what a catalog is for.

Every call, in a ledger

Every request to a consumer endpoint is recorded: what was called, by whom (a person's session, an API key, an anonymous caller of a public API), through what, the HTTP status, how many rows, how long, whether it was a cache hit — and refusals as well as successes, because "who tried and was refused" is a security question too. The ledger is filterable by kind and by object, and each catalog row's usage is computed from it.

Ledger
The Ledger tab: a list of consumer calls, newest first, each with its kind, object, caller, how it authenticated, status, rows, duration and whether it was served from cache.
Successes and refusals, side by side. A 403 that someone reports is the point.

Authenticated is not entitled

A key or a person that can sign in is thereby allowed to call nothing. Entitlement is a grant, and a grant names what it opens:

A grant saysMeaning
Insights, data APIs, dashboards, collectionsLists of what may be called. An empty list for a kind means all of that kind; no grant means none.
Scope limitsWhich values of a scope axis the caller is confined to — one broker group, one region. A request for another value is refused, never quietly narrowed.
AskWhether the caller may ask free-form questions of the engine at all. Off unless a consumer genuinely needs it.
UnmaskedWhether masked columns are shown in clear. Off by default.
Calls per minute, calls per dayRate and daily quota; the quota answers 429 with when to retry.

Grants attach to an API key — or to a directory group. That second form is what an enterprise deployment actually wants: sign in through Okta or Entra ID with a group claim, map groups to roles for what people may do, and grant groups for what they may see. A person in several groups gets the union. Nobody maintains a per-person list, and leaving a group in the directory removes the access on the next sign-in.

Keys & grants
The Keys and grants tab: API keys and directory groups, each with the insights, data APIs, dashboards and collections it may call, its scope limits, whether it may ask, whether it sees masked columns, and its per-minute and per-day limits.
A key and an Okta group are granted the same way. The key is for a system; the group is for people.
flowchart LR
  subgraph WHO ["Who is calling"]
    K["API key"]
    P["Person signed in
via Okta / Entra"] end P --> G["Directory groups
from the token's group claim"] G --> R["Roles
admin · curator · member"] K --> GR["Grants
what may be called, at what scope,
masked or clear, how often"] G --> GR GR --> C{"The call"} C -->|allowed| L["Ledger entry · rows (masked unless granted)"] C -->|refused| L2["Ledger entry · 403 / 429"] style GR fill:#e6f7f2,stroke:#9fd8c9 style L2 fill:#fdecec,stroke:#e8a0a0
Roles decide what a person may do in the product; grants decide what any caller may read through it. Both are written down, and both are read on every call.

Masking that survives the cache

A data API can mark columns to be masked — redacted, hashed, last four, or nulled — for any caller whose grant does not say unmasked. The detail that matters: masking is applied on the way out, after the cache. A result computed for a privileged caller and reused for an ordinary one is still masked for the ordinary one. We mention it because that is exactly the kind of shortcut a cache invites.

A publish is a decision

Members can build anything and publish nothing. What they get instead is Request publish: the request lands under Requests in the catalog with a note for the reviewer, and a curator or admin approves or rejects it there. Approval runs the object's own publish with its own gates — the untraced figures check for an insight, the breaking-change check for a data API, the draft-query and unused-filter checks for a dashboard. Nobody approves their own request unless they are an admin, and the decision and the reviewer are kept on the request.

Requests
The Requests tab: publish requests with the object, its kind, who asked and when, the note for the reviewer, and for a reviewer the Approve and publish or Reject actions; decided requests show the reviewer and the decision.
The person who built it and the person who vouches for it are usually different people. The product keeps them apart.

Definitions have an audit trail

The things that change meaning — an accepted metric, a confirmed term binding, a golden question, a conventions edit, a schema review decision — are written only by curators and admins, and every write is recorded with who, when, what and the payload. Because the engine records which definitions each generated query used, a reviewer can go from "we changed the definition of earned premium on the 2nd" to the list of answers that predate it, and the cache retires them.

Audit
The Audit tab: definition changes newest first — kind, what changed, the actor, the time and the payload — for metric acceptances, term confirmations, schema reviews and example edits.
Not who viewed what; who changed what a word means. Different log, different audience.

Who may do what

RoleMayMay not
MemberAsk, read the catalog, build drafts, collections and notebooks, request a publish.Publish, change definitions, see set-up or admin pages, approve.
CuratorEverything a member may, plus accept metrics and terms, review schemas, index sources, publish, and approve others' requests.Manage people, providers or keys; approve their own request.
AdminEverything, including people, identity providers, keys and grants.Escape the ledger.

Roles can come from the directory too: a provider carries a group claim and a list of group=role rules, applied on every sign-in. A person removed from the curators' group in Okta is a member at their next login, with nothing to revoke by hand.

What this does not replace

It does not replace your warehouse's own row-level security — the engine runs as the service identity you gave it, inside the tables you indexed, read-only and row-capped. It does not replace your identity provider; it defers to it. And it does not make a judgement call about what should be published; it makes sure a person did, and writes down who.

The principle

Governance that lives in a document is advice. Governance that lives in the product — a grant that is read on every call, an approval that runs the real checks, a ledger nothing can skip — is a fact.

Read next

One number, one definition: governing AI-written SQL — the serving path underneath all of this, where no model runs. An insight that shows its work — what the untraced-figures gate is checking.