You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Core reporting in the metamodel: entities declare dimensions, measures (aggregate, ratio, derived) and segments; an object.report names a fixed combination and compiles to a SQL view that every port can read. A full semantic layer is delegated to established tools through reference exporters (Cube first, dbt MetricFlow second). A MetaObjects query-time engine is parked with a re-entry trigger.
Additive vocabulary: metamodelVersion 1.0 → 1.1 (a MINOR on every registry).
Bound by FR-037 R5's cross-backend admission rule; no SQL strings in the metamodel.
measure.derived depends on FR-037 R5 wave 1 (arithmetic fn members).
Open decisions (D1–D6, spec §8):segment as its own type; object.report subtype vs attributes on object.projection; week start; time-dimension field naming; second exporter timing; Search-backend capability gate for exact distinct.
Decisions D1–D6 resolved 2026-10-03 (all as recommended), and the ADR-0023 vocabulary list agreed. The spec now carries the per-item justifications in §3.1 (a7802c7). Changes from the draft: the report's @window is dropped in favour of the existing @filter; @dimensions items are strings (name or name:grain); MetricFlow export waits for first adopter demand. Next: implementation plan for phase 1 (metamodel 1.1 vocabulary in five ports + TS view lowering).
The reporting vocabulary (the ADR-0023 list in spec §3.1) is registered and validated at load in all five ports, with metamodelVersion 1.1.
The rule table is enforced rule-for-rule with identical message text across ports: 20 rules (D1–D4, M1–M6, S1, R1–R7, F1–F2), covered by new shared fixtures/conformance/ cases.
Relative-date filter values load only on reporting hosts (segment, measure.aggregate, object.report).
Reports are inert for now: every generator, migrate and meta docs skip object.report, and a no-churn corpus proves existing output is byte-identical.
Next is Plan 2: TypeScript view lowering for object.report and relative-date values, plus persistence-conformance reads in every port. measure.derived stays out until FR-037 R5 lands (#393).
A view-backed object.report (one declaring source.rdb with @kind: view) now lowers to a SQL view on Postgres, SQLite/D1 and MySQL, including relative-date filter values. A sourceless report stays inert.
MySQL SQL ships through buildReportViews plus a documented recipe (no CLI surface); time bucketing and now are UTC in v1.
Dimension @via joins follow the existing projection rule unchanged.
Shared persistence-conformance read scenarios for reports pass in every port (TypeScript, C#, Java, Kotlin, Python). C# and Kotlin generate a report's typed row; the TypeScript, Java and Python generators keep skipping reports until Plan 3.
The metaobjects-authoring skill, docs and changelog now cover reporting.
Next is Plan 3: generated read routes and the api-contract report/ corpus in five ports.
A view-backed object.report is now served over the generated read API in all five ports: list route with filter, sort and paging over every derived field, at the standard pluralized route segment. No /{id} route is mounted for a report.
The api-contract corpus gains a report/ sub-corpus that every port runs.
Reports appear in meta docs (a sourceless report gets a "not served" model page).
No client-tier output (hooks, grids) is generated for reports; that waits for Plan 5.
Named behaviour changes for existing projections, recorded in the changelog: a view with no id column answers 404 on /{id} instead of the first row; idColumn is emitted when the key field is not id; read-only projection API docs list only mounted routes; TypeScript types a view decimal as the string it is; Kotlin decimal/float filters no longer fail.
Follow-up in progress: make projection/report read-route behaviour identical across all five ports and pin it with shared api-contract cases. Next plan is Plan 4 (Cube exporter).
Activity
docs(roadmap): link FR-044 to its tracking issue #391
dmealing commentedon Oct 3, 2026
Decisions D1–D6 resolved 2026-10-03 (all as recommended), and the ADR-0023 vocabulary list agreed. The spec now carries the per-item justifications in §3.1 (a7802c7). Changes from the draft: the report's
@windowis dropped in favour of the existing@filter;@dimensionsitems are strings (nameorname:grain); MetricFlow export waits for first adopter demand. Next: implementation plan for phase 1 (metamodel 1.1 vocabulary in five ports + TS view lowering).dmealing commentedon Oct 4, 2026
FR-044 Plan 1 has landed in #397.
metamodelVersion1.1.fixtures/conformance/cases.segment,measure.aggregate,object.report).migrateandmeta docsskipobject.report, and a no-churn corpus proves existing output is byte-identical.Next is Plan 2: TypeScript view lowering for
object.reportand relative-date values, plus persistence-conformance reads in every port.measure.derivedstays out until FR-037 R5 lands (#393).dmealing commentedon Oct 4, 2026
FR-044 Plan 2 has landed in #399.
object.report(one declaringsource.rdbwith@kind: view) now lowers to a SQL view on Postgres, SQLite/D1 and MySQL, including relative-date filter values. A sourceless report stays inert.buildReportViewsplus a documented recipe (no CLI surface); time bucketing andnoware UTC in v1.@viajoins follow the existing projection rule unchanged.metaobjects-authoringskill, docs and changelog now cover reporting.Next is Plan 3: generated read routes and the api-contract
report/corpus in five ports.dmealing commentedon Oct 6, 2026
FR-044 Plan 3 has landed in #407.
object.reportis now served over the generated read API in all five ports: list route with filter, sort and paging over every derived field, at the standard pluralized route segment. No/{id}route is mounted for a report.report/sub-corpus that every port runs.meta docs(a sourceless report gets a "not served" model page)./{id}instead of the first row;idColumnis emitted when the key field is notid; read-only projection API docs list only mounted routes; TypeScript types a view decimal as the string it is; Kotlin decimal/float filters no longer fail.Follow-up in progress: make projection/report read-route behaviour identical across all five ports and pin it with shared api-contract cases. Next plan is Plan 4 (Cube exporter).