From 669578acccb42e55a77247a098fe0bb257945e18 Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Sat, 25 Jul 2026 11:44:26 +0800 Subject: [PATCH 1/2] feat(spec)!: prune dead aria/performance from ReportSchema + dogfood the live report chart (report-liveness close-out) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to the #3463 report cleanup, closing out the 2026-06 ReportSchema liveness audit. That audit flagged `aria` and `performance` as dead — declared on ReportSchema (editable in the Studio report form) but read by no renderer. - spec: removed ReportSchema.aria (AriaPropsSchema) + ReportSchema.performance (PerformanceConfigSchema) and the now-orphan imports. Both schemas stay exported (still used by views/pages/charts); ReportChart keeps its own aria from ChartConfigSchema. No manifest/export change; report.mdx regenerated. Ships minor per the launch-window breaking-as-minor policy. - showcase: added `showcase_hours_by_status_chart` — a summary report with a `chart` block (est_hours by status, bar) + an Analytics nav item. This dogfoods the live DatasetReportChart path (chart.xAxis/yAxis over the bound dataset), which had no showcase coverage; browser-verified rendering. - docs/audits: the 2026-06 report-liveness audit is refreshed with a resolution banner (chart = WIRED not dead, aria/performance pruned, re-exports removed, joined preview fixed), and the audits README section 2 annotates the resolved report slice while leaving the open chart-view/dashboard debt untouched. Co-Authored-By: Claude Fable 5 --- .changeset/prune-report-aria-performance.md | 26 +++++++++++++++++++ content/docs/references/ui/report.mdx | 2 -- .../2026-06-reportschema-property-liveness.md | 7 +++++ docs/audits/README.md | 4 ++- examples/app-showcase/src/ui/apps/index.ts | 1 + examples/app-showcase/src/ui/reports/index.ts | 21 +++++++++++++++ packages/spec/src/ui/report.zod.ts | 9 +------ 7 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 .changeset/prune-report-aria-performance.md diff --git a/.changeset/prune-report-aria-performance.md b/.changeset/prune-report-aria-performance.md new file mode 100644 index 0000000000..189c5d9daa --- /dev/null +++ b/.changeset/prune-report-aria-performance.md @@ -0,0 +1,26 @@ +--- +"@objectstack/spec": minor +--- + +feat(spec)!: prune the dead `aria` / `performance` props from ReportSchema (report-liveness close-out) + +Follow-up to the #3463 report cleanup. The 2026-06 ReportSchema liveness audit +flagged `aria` and `performance` as dead — declared on `ReportSchema` (and +editable in the Studio report form) but read by **no renderer**. This removes +them. Every other finding from that audit is now closed too: `chart` turned out +to be **live** (`DatasetReportRenderer` plots `chart.xAxis`/`yAxis` via +`DatasetReportChart`), and the obsolete sub-schemas / naming-drift / joined-preview +items were resolved by #3463 and earlier work. + +- Removed `ReportSchema.aria` (`AriaPropsSchema`) and `ReportSchema.performance` + (`PerformanceConfigSchema`), dropping the now-orphan imports. Both schemas + remain exported and are still used by other metadata types (views, pages, + charts) — only the report's use of them is removed. `ReportChart` keeps its + own `aria` (inherited from `ChartConfigSchema`). +- No manifest key or public export changes (`aria`/`performance` were properties, + not schemas); `report.mdx` regenerated. + +**Migration**: nothing an author writes changes — no first-party or example +report set `aria`/`performance`. Reports carry no ARIA/performance overrides; +use the dataset/view surface for those concerns. Ships as `minor` per the +launch-window breaking-as-minor policy. diff --git a/content/docs/references/ui/report.mdx b/content/docs/references/ui/report.mdx index 8688e53b47..a15f2289c2 100644 --- a/content/docs/references/ui/report.mdx +++ b/content/docs/references/ui/report.mdx @@ -60,8 +60,6 @@ const result = JoinedReportBlock.parse(data); | **runtimeFilter** | `any` | optional | Render-time scope filter | | **drilldown** | `boolean` | ✅ | Click-through to underlying records | | **chart** | `{ type: Enum<'bar' \| 'horizontal-bar' \| 'column' \| 'line' \| 'area' \| 'pie' \| 'donut' \| 'funnel' \| 'scatter' \| 'treemap' \| 'sankey' \| 'gauge' \| 'solid-gauge' \| 'metric' \| 'kpi' \| 'bullet' \| 'radar' \| 'table' \| 'pivot'>; title?: string; subtitle?: string; description?: string; … }` | optional | Embedded chart configuration | -| **aria** | `{ ariaLabel?: string; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes | -| **performance** | `{ lazyLoad?: boolean; virtualScroll?: object; cacheStrategy?: Enum<'none' \| 'cache-first' \| 'network-first' \| 'stale-while-revalidate'>; prefetch?: boolean; … }` | optional | Performance optimization settings | | **blocks** | `{ name: string; label?: string; description?: string; type: Enum<'tabular' \| 'summary' \| 'matrix'>; … }[]` | optional | Sub-reports for type=joined | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this report. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | diff --git a/docs/audits/2026-06-reportschema-property-liveness.md b/docs/audits/2026-06-reportschema-property-liveness.md index e17f2b5e73..a421ee5230 100644 --- a/docs/audits/2026-06-reportschema-property-liveness.md +++ b/docs/audits/2026-06-reportschema-property-liveness.md @@ -2,6 +2,13 @@ **Date**: 2026-06-15 · **Scope**: `packages/spec/src/ui/report.zod.ts` (ADR-0021 single-form). **Live path**: `objectui` `ReportRenderer`→`DatasetReportRenderer` (dataset-bound). Pre-9.0 object/columns-query renderers retired; old JSON limps through the lossy `specReportToPresentation` bridge. +> **✅ Fully resolved — 2026-07-25** (#3463 + follow-up). Every finding below has since been actioned; the dated body is kept as the point-in-time snapshot. +> - **`chart` — WIRED, not dead.** `DatasetReportRenderer` now plots `report.chart.xAxis`/`yAxis` over the bound dataset via `DatasetReportChart` (`DatasetReportRenderer.tsx:429-465,773-786`); #3441 corrected the `.describe()`, and the showcase gained a `chart`-bearing report (`showcase_hours_by_status_chart`) so the path is dogfooded. +> - **`aria`, `performance` — PRUNED** from `ReportSchema` (2026-07 report-liveness close-out). +> - **`ReportColumnSchema` / `ReportGroupingSchema` (+ objectui `SpecReportColumn*`/`SpecReportGrouping*` re-exports) — REMOVED** (#3463 → framework #3488 / objectui #2816). +> - **`ReportChartSchema` naming drift — RESOLVED**: the legacy `ReportViewer` chart branch that read `xAxisField`/`yAxisFields` was retired (objectui #2816); the live renderer reads the spec's `xAxis`/`yAxis`; the unread `groupBy` was pruned (#3488). +> - **Studio joined preview — FIXED**: `ReportPreview` branches on `dataset || blocks` (`isJoinedWithBlocks`). + ## LIVE & well-wired (dataset shape — the canonical path) `name`, `label`, `description`, `type` (summary/tabular/matrix/joined), `dataset`, `rows`, `columns` (matrix-across only, matches spec), `values`, `runtimeFilter` (`?? filter`, ANDed via `mergeFilters`), `drilldown` (default-on; cells clickable), `blocks` (joined, per-block dataset/rows/columns/values/runtimeFilter). Evidence: `DatasetReportRenderer.tsx:486-575`, `:493-543`. Wired types: tabular/summary/matrix (true cross-tab + server totals + drill)/joined. diff --git a/docs/audits/README.md b/docs/audits/README.md index f5cde6eb0c..821c8f63e3 100644 --- a/docs/audits/README.md +++ b/docs/audits/README.md @@ -38,7 +38,9 @@ The most serious cluster — properties that imply a security boundary but enfor - **Role `parent`** / **SharingRuleSchema** — manager rollup & spec sharing rules disconnected from the live engine. ### 2. 🔴 ADR-0021 analytics migration debt -Spec moved to `dataset`+`values`/`dimensions`, but: the **chart view variant** + **dashboard renderer + Studio WidgetConfigPanel** still read the *removed* legacy `object/valueField/categoryField/aggregate` shape; **report `chart`** is dead; `ReportColumn`/`ReportGrouping` are obsolete re-exports. (Same debt that invalidated the showcase dashboard/report seeds.) +Spec moved to `dataset`+`values`/`dimensions`, but: the **chart view variant** + **dashboard renderer + Studio WidgetConfigPanel** still read the *removed* legacy `object/valueField/categoryField/aggregate` shape. (Same debt that invalidated the showcase dashboard/report seeds.) + +**✅ Report slice resolved (#3463 + 2026-07 close-out).** `report.chart` is **wired** (`DatasetReportRenderer` plots `chart.xAxis`/`yAxis` via `DatasetReportChart`, now dogfooded by the showcase `…_chart` report); `ReportColumn`/`ReportGrouping` (+ objectui `SpecReport*` re-exports) and the unread `chart.groupBy` + dead `aria`/`performance` are **removed**; the legacy `ReportViewer` chart fallback is **retired**. See [`2026-06-reportschema-property-liveness.md`](./2026-06-reportschema-property-liveness.md). The **chart-view / dashboard / WidgetConfigPanel** legacy-shape readers above remain open. ### 3. 🟠 Naming drift → silent no-ops (spec key ≠ consumed key) field `maxLength`/`minLength`/`referenceFilters`/`maxRating`; page `type`→`pageType` & `label`→`title` & `visibility`; dashboard `title` vs `label`; app `accentColor`/`badgeVariant`/`separator` (renderer reads, **not in spec**); action `disabled`→`enabled`; flow `http` vs `http_request`; skill `requiredPermissions` vs `permissions`; agent `knowledge.{topics→sources}`; webhook `object`→`object_name`, `isActive`→`active`. diff --git a/examples/app-showcase/src/ui/apps/index.ts b/examples/app-showcase/src/ui/apps/index.ts index f00477d6b6..71c1e1f6ce 100644 --- a/examples/app-showcase/src/ui/apps/index.ts +++ b/examples/app-showcase/src/ui/apps/index.ts @@ -95,6 +95,7 @@ export const ShowcaseApp = App.create({ { id: 'nav_charts', type: 'dashboard', dashboardName: 'showcase_chart_gallery', label: 'Chart Gallery', icon: 'layout-dashboard' }, { id: 'nav_report_tabular', type: 'object', objectName: 'showcase_task', viewName: 'tabular', label: 'Task List', icon: 'table' }, { id: 'nav_report_summary', type: 'report', reportName: 'showcase_hours_by_status', label: 'Hours by Status', icon: 'sigma' }, + { id: 'nav_report_chart', type: 'report', reportName: 'showcase_hours_by_status_chart', label: 'Hours by Status (Chart)', icon: 'bar-chart-3' }, { id: 'nav_report_matrix', type: 'report', reportName: 'showcase_status_priority_matrix', label: 'Status × Priority', icon: 'grid-3x3' }, { id: 'nav_report_joined', type: 'report', reportName: 'showcase_task_overview', label: 'Task Overview', icon: 'layers' }, ], diff --git a/examples/app-showcase/src/ui/reports/index.ts b/examples/app-showcase/src/ui/reports/index.ts index a8d27a7798..1054fbd9a0 100644 --- a/examples/app-showcase/src/ui/reports/index.ts +++ b/examples/app-showcase/src/ui/reports/index.ts @@ -68,8 +68,29 @@ export const TaskOverviewReport = defineReport({ ], }); +/** 5 ── Summary with an embedded chart. Exercises the live `DatasetReportChart` + * path: `chart.xAxis`/`yAxis` name the bound dataset's dimension/measure and + * are plotted via a second `queryDataset` call (ADR-0021). */ +export const HoursByStatusChartReport = defineReport({ + name: 'showcase_hours_by_status_chart', + label: 'Hours by Status (Chart)', + description: 'Estimated hours by status, plotted as a bar chart.', + type: 'summary', + drilldown: true, + dataset: 'showcase_task_metrics', + rows: ['status'], + values: ['est_hours'], + chart: { + // Chart type from ChartConfig; xAxis = dataset dimension, yAxis = measure. + type: 'bar', + xAxis: 'status', + yAxis: 'est_hours', + }, +}); + export const allReports = [ HoursByStatusReport, StatusPriorityMatrixReport, TaskOverviewReport, + HoursByStatusChartReport, ]; diff --git a/packages/spec/src/ui/report.zod.ts b/packages/spec/src/ui/report.zod.ts index db88acba94..09b9d09eec 100644 --- a/packages/spec/src/ui/report.zod.ts +++ b/packages/spec/src/ui/report.zod.ts @@ -6,8 +6,7 @@ import { MetadataProtectionFields } from '../kernel/metadata-protection.zod'; import { FilterConditionSchema } from '../data/filter.zod'; import { ChartConfigSchema } from './chart.zod'; import { SnakeCaseIdentifierSchema } from '../shared/identifiers.zod'; -import { I18nLabelSchema, AriaPropsSchema } from './i18n.zod'; -import { PerformanceConfigSchema } from './responsive.zod'; +import { I18nLabelSchema } from './i18n.zod'; /** * Report Type Enum @@ -126,12 +125,6 @@ export const ReportSchema = lazySchema(() => z.object({ /** Visualization */ chart: ReportChartSchema.optional().describe('Embedded chart configuration'), - /** ARIA accessibility attributes */ - aria: AriaPropsSchema.optional().describe('ARIA accessibility attributes'), - - /** Performance optimization settings */ - performance: PerformanceConfigSchema.optional().describe('Performance optimization settings'), - /** * Joined report blocks — only meaningful when `type: 'joined'`. * From fa227763e63aaba550681da8febef73cbb04c232 Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Sun, 26 Jul 2026 15:23:08 +0800 Subject: [PATCH 2/2] test(showcase): bump report-count assertion to 4 for the new chart report seed.test.ts hardcoded 3 reports; the new showcase_hours_by_status_chart makes it 4 (summary, chart, matrix, joined). Co-Authored-By: Claude Fable 5 --- examples/app-showcase/test/seed.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/app-showcase/test/seed.test.ts b/examples/app-showcase/test/seed.test.ts index 8d359a0458..714c24e6e9 100644 --- a/examples/app-showcase/test/seed.test.ts +++ b/examples/app-showcase/test/seed.test.ts @@ -22,9 +22,9 @@ describe('showcase stack', () => { expect((stack.views ?? []).length).toBeGreaterThan(0); expect((stack.dashboards ?? []).length).toBeGreaterThan(0); // ADR-0021 single-form: the former flat `tabular` TaskListReport was - // reclassified as a ListView (a flat list is a row lens, not analytics), - // leaving 3 dataset-bound analytics reports. - expect((stack.reports ?? []).length).toBe(3); + // reclassified as a ListView (a flat list is a row lens, not analytics). + // Four dataset-bound analytics reports: summary, chart, matrix, joined. + expect((stack.reports ?? []).length).toBe(4); expect((stack.flows ?? []).length).toBeGreaterThan(0); // Nine flat positions (contributor/manager/exec/auditor/ops/ // field_ops_delegate/client_portal_user, plus finance/legal for the v16