Found while implementing #5016 (the three fabricated exports in packages/plugin-report/README.md). Filed unassigned, out of that card's scope: #5016 is scoped to the fabricated export names; this is the schema shape the surrounding prose teaches, which is a larger and separately-decidable surface. Measured on origin/main at dc9d651a2c55c10a9e4d30434e429e5fdc5ae968.
What the code says
packages/plugin-report/src/ReportRenderer.tsx:6-20 states the single form and the retirement in as many words:
* ADR-0021 single-form: a 9.0 report is **dataset-bound** — it binds a
* semantic-layer `dataset` and selects its `values` (measure names) grouped
* by `rows` (dimension names). That is the live rendering path.
...
* The pre-9.0 query-form renderers (SpecReportGrid / MatrixRenderer /
* JoinedReportRenderer) were retired with the cutover — stored old-shape JSON
* renders through the lossy {@link specReportToPresentation} bridge until it
* is migrated to a dataset binding.
packages/plugin-report/CHANGELOG.md:1284 records the same removal, and packages/plugin-report/src/index.tsx:33-37 records that useReportData() and its buildAggregateQuery / groupAndAggregate / pivotRows helpers were removed with ADR-0021 because dataset-bound reports aggregate in the semantic layer.
What the docs still teach
1. content/docs/plugins/plugin-report.mdx — names the retired renderers as the live ones. Its "At a glance" table maps each variant to a renderer:
| line | claim |
|---|
:22-25 | tabular / summary renderer is SpecReportGrid; matrix is MatrixRenderer; joined is JoinedReportRenderer |
:79-83 | dateGranularity routes to POST /api/v1/data/:object/query, falling back to applyInMemoryAggregation() |
:85-86 | "MatrixRenderer renders row totals, column totals and grand total automatically" |
All three renderer names and applyInMemoryAggregation are zero-hit in packages/plugin-report/src. Every authoring example on the page (:36-50, :60-72, :92-120) is in the objectName + columns + groupingsDown / groupingsAcross query form.
2. packages/plugin-report/README.md — the same query form, in the sections #5016 does not touch. After PR-for-#5016 lands, the remaining stale surface is:
| line (at that PR's head) | claim |
|---|
:9 | feature bullet: dateGranularity on groupingsAcross / groupingsDown |
:10 | feature bullet: "tabular/summary delegate to ObjectGrid" |
:12 | feature bullet: each joined block owns its own objectName |
:83-146 | the whole "Spec Reports — the four variants" section: ReportInput examples in the query form, plus :145 "each block runs an isolated useReportData() call" |
The dataset-bound shape those should be describing is { name, type, dataset, rows: string[], columns?: string[], values: string[], filter?, order?, drilldown?, chart?, blocks? } — see DatasetReportLike at packages/plugin-report/src/DatasetReportRenderer.tsx:128-158.
Why this is not "just stale prose"
The query form is not rejected, it is silently degraded: ReportRenderer routes a stored isSpecReport document through specReportToPresentation, which its own comment calls "lossy by construction". So an author following either doc gets a report that renders — differently from what the page promises, with no diagnostic. That is the same failure shape as #4600 (the 9 dashboard examples teaching the pre-ADR-0021 widget shape), one corpus over.
Both files are also AI-authoring inputs: the mdx is the published authoring reference, and package READMEs ship to npm.
Open question for triage, not for an implementer
Whether these documents should be migrated to the dataset form or should keep a clearly-labelled "stored pre-9.0 documents" section describing the bridge. That depends on whether the query form is a supported compat arm or a migration waiting room — ReportRenderer.tsx:102-105 says "the proper fix is migrating the stored report to a dataset binding", which reads like the latter, but the decision belongs to whoever owns ADR-0021's migration story. Same enforce-or-retire question #4600 raised for the widget shape.
Recheck
grep -rn "SpecReportGrid\|MatrixRenderer\|JoinedReportRenderer\|applyInMemoryAggregation" packages/plugin-report/src # zero hits
grep -n "SpecReportGrid\|MatrixRenderer\|JoinedReportRenderer" content/docs/plugins/plugin-report.mdx
grep -rn "ReportViewer" packages/plugin-report/src | head # positive control: a name that IS real
Related: #5016 (the export-name half, in flight), #4600 (same class, dashboard examples), #5002 / PR #5021 (the plugin-map precedent for a README rewritten against its code).
Found while implementing #5016 (the three fabricated exports in
packages/plugin-report/README.md). Filed unassigned, out of that card's scope: #5016 is scoped to the fabricated export names; this is the schema shape the surrounding prose teaches, which is a larger and separately-decidable surface. Measured onorigin/mainatdc9d651a2c55c10a9e4d30434e429e5fdc5ae968.What the code says
packages/plugin-report/src/ReportRenderer.tsx:6-20states the single form and the retirement in as many words:packages/plugin-report/CHANGELOG.md:1284records the same removal, andpackages/plugin-report/src/index.tsx:33-37records thatuseReportData()and itsbuildAggregateQuery/groupAndAggregate/pivotRowshelpers were removed with ADR-0021 because dataset-bound reports aggregate in the semantic layer.What the docs still teach
1.
content/docs/plugins/plugin-report.mdx— names the retired renderers as the live ones. Its "At a glance" table maps each variant to a renderer::22-25tabular/summaryrenderer isSpecReportGrid;matrixisMatrixRenderer;joinedisJoinedReportRenderer:79-83dateGranularityroutes toPOST /api/v1/data/:object/query, falling back toapplyInMemoryAggregation():85-86MatrixRendererrenders row totals, column totals and grand total automatically"All three renderer names and
applyInMemoryAggregationare zero-hit inpackages/plugin-report/src. Every authoring example on the page (:36-50,:60-72,:92-120) is in theobjectName+columns+groupingsDown/groupingsAcrossquery form.2.
packages/plugin-report/README.md— the same query form, in the sections #5016 does not touch. After PR-for-#5016 lands, the remaining stale surface is::9dateGranularityongroupingsAcross/groupingsDown:10ObjectGrid":12objectName:83-146ReportInputexamples in the query form, plus:145"each block runs an isolateduseReportData()call"The dataset-bound shape those should be describing is
{ name, type, dataset, rows: string[], columns?: string[], values: string[], filter?, order?, drilldown?, chart?, blocks? }— seeDatasetReportLikeatpackages/plugin-report/src/DatasetReportRenderer.tsx:128-158.Why this is not "just stale prose"
The query form is not rejected, it is silently degraded:
ReportRendererroutes a storedisSpecReportdocument throughspecReportToPresentation, which its own comment calls "lossy by construction". So an author following either doc gets a report that renders — differently from what the page promises, with no diagnostic. That is the same failure shape as #4600 (the 9 dashboard examples teaching the pre-ADR-0021 widget shape), one corpus over.Both files are also AI-authoring inputs: the mdx is the published authoring reference, and package READMEs ship to npm.
Open question for triage, not for an implementer
Whether these documents should be migrated to the dataset form or should keep a clearly-labelled "stored pre-9.0 documents" section describing the bridge. That depends on whether the query form is a supported compat arm or a migration waiting room —
ReportRenderer.tsx:102-105says "the proper fix is migrating the stored report to a dataset binding", which reads like the latter, but the decision belongs to whoever owns ADR-0021's migration story. Same enforce-or-retire question #4600 raised for the widget shape.Recheck
Related: #5016 (the export-name half, in flight), #4600 (same class, dashboard examples), #5002 / PR #5021 (the plugin-map precedent for a README rewritten against its code).