Skip to content

Report

Definition

A Report is a user-owned, pointer-only saved collection of Block references. It stores how to re-fetch each block (the query/tool and its params), not the block data itself — so opening a report re-runs the underlying queries against live sources rather than showing a stale snapshot. This is the deliberate contrast with an Edition: a Report is a lightweight, shareable "saved view" with no sealing, hashing, or attestation; an Edition is the immutable decision record. Reports are for "let me keep and share this set of things I was looking at," not "this is the record of a decision."

Command logic: cortex/cortex/report.py and cortex/cortex/tools/report.py. Persistence: a UDS DAO over the shared Elasticsearch intelligence index under the report alias, id report-{uuid.hex}. Schema (aspirational): cortex/server/api/schema/intelligence.yaml:560.

Note a schema-vs-runtime divergence: the OpenAPI Report schema lists insight_ids[], status, shared_with[], visibility, but the document report_create actually writes (tools/report.py:43) is id, title, description, blocks[] (the block references), username, visibility — i.e. block references, not insight ids, and no status.

Lifecycle

Minimal — there is no freeze/seal/render state machine. The schema's status enum (draft | published | archived) is defined but never set or transitioned in code. Real state is just visibility: a Report is created PRIVATE, and report_share flips it to SHARED (adding users to shared_with[]) or PUBLIC (report.py:83). Public is the broadest and overrides the share list.

Journey through the code

MCP tools report_create, report_list, report_get, report_share (cortex/cortex/tools/report.py, registered via cortex.tools.registry). Each calls its command function, which writes Report().update(with_visibility(strip_none(doc)), uid=report_id) to the report alias; REST exposes /report (intelligence.yaml:1208). On render, the stored block references are re-fetched from their original sources (tools/report.py:30). A separate generic export_data (report.py:112) renders arbitrary result rows to CSV/JSON/HTML/Markdown via cortex/cortex/export/export_utils.py — it takes raw rows, not a report id, so it is not currently wired to report rendering.

Data shape

Runtime required: id, title, username, visibility. Optional: description, blocks[] (each a reference: query_hash / tool / params), shared_with[], updated_at. Schema-only / not populated by code: insight_ids[], status. Storage: intelligence index, report alias; UDS metadata (uds.visibility, create_ts, …) via the base.

Invariants

  • Pointer-only — a Report stores block references and re-fetches on render; it never holds frozen block data.
  • Ownership-scoped sharing — only the owner may report_share (tools/report.py:194); PUBLIC overrides the share list.
  • product.block — a Report references Blocks (by query, not block_id) and re-fetches them live.
  • product.edition — distinct from a Report: the Edition is the sealed, attestable decision artifact; the Report is the lightweight shareable pointer collection.
  • product.insight — the schema claims an insight_ids[] link, but the code does not populate it.

Open questions

  • Schema vs runtime golden shape — is the contract insight_ids[] + status (schema) or blocks[] + no status (code)? They disagree.
  • Render path — is there a real report-render/PDF path? None found; export_data is generic row-rendering, not wired to a report id.
  • Dead status lifecycle and an ownership check in report.py that is a documented no-op (enforced only in the tools/report.py variant).

Realized by: component.cortex.intelligence