Skip to content

fix(plugin-report): a matrix report with columns draws its declared chart beside the cross-tab (objectui#10964) - #11043

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-10964-matrix-report-chart
Sep 29, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-10964-matrix-report-chart

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #10964

Clause-②: no

What

A matrix report that declares columns now draws its declared chart below the cross-tab. ReportSchema accepts that shape, but the cross-tab branch of DatasetReportRenderer returned DatasetMatrixTable before the only report.chart read, so the chart parsed and drew nothing.

The non-joined presentations now share one wrapper and one chart slot. DatasetReportChart runs its own chart.xAxis × chart.yAxis dataset query, so it binds the same way next to a cross-tab as next to a grouped table: xAxis names a dataset dimension (a matrix rows or columns dimension) and yAxis a dataset measure. The chart still comes before a tabular or summary table (and before a matrix without columns, which degrades to the grouped table), and it comes after the cross-tab. The ruling on objectstack-ai/objectstack#20293 places it "beside or below the cross-tab", and below needs no new layout option.

Landing site: packages/plugin-report/src/DatasetReportRenderer.tsx, as the card and the claim name it.

Premises measured on objectui origin/main 3ad61001b

  • Mechanism assumption 1 holds: the presentation === 'matrix' && across.length > 0 branch returned before the chartCfg / report.chart read.
  • Mechanism assumption 2 holds, so the stop valve did not fire. DatasetReportChart queries [chart.xAxis] × [chart.yAxis] over report.dataset through useDatasetRows, independent of the table next to it, and scopeOrder already narrows report.order to that pair. No new binding rule is involved. On the spec side, objectstack's validate-chart-bindings (packages/lint) already treats a chart on every non-joined report as drawn (drawsChart is report.type !== 'joined') and binds chart.xAxis to a dataset dimension and chart.yAxis to a dataset measure: the binding this renderer now honours on the matrix arm too.
  • Mechanism assumption 3 holds: no example carries a matrix report with both columns and a chart, so the pin builds its own document.

Also changed, because this round made it false

  • The out-of-spec chart-type notice said "the grouped table below carries this report's numbers". On a matrix the notice now sits after the cross-tab, so it names no position: "the report's table carries its numbers". Code comments that said the table sits "beneath" the chart slot now say "beside".
  • The matrix wrapper now carries the same flex flex-col gap-3 classes and data-report-presentation attribute the other non-joined presentations carry. git grep finds no reader of data-report-presentation outside the renderer.
  • Docs (AGENTS.md commandment 2): the "Embedded chart" sections of packages/plugin-report/README.md and content/docs/plugins/plugin-report.mdx say where the chart draws for each type. Prose only, no fenced block.

Tests

New pin packages/plugin-report/src/__tests__/DatasetReportRenderer.matrixChart-10964.test.tsx:

  • a matrix report with columns and a chart draws both, with the chart after the cross-tab in document order, from its own ['status'] × ['est_hours'] query;
  • the control, the same report without chart, draws the cross-tab only and issues exactly one query (the cross-tab's);
  • an xAxis naming the ACROSS dimension binds the same way;
  • an out-of-spec chart type on a matrix reaches the visible notice, after the cross-tab.

Reverse verification. The implementation was committed first (cad6b4745). The renderer file was then checked out from BASE 3ad61001b with the pin kept, under a trap-guarded restore. After the mutation the on-disk blob equals the BASE blob c362912eb and the fix-marker count went from 3 to 0. The run gave Tests 3 failed | 1 passed (4): the three chart cases red and the control green, as predicted in the pin's header. After the restore the on-disk blob equals the HEAD blob 9560f4d4b and git diff HEAD is 0 bytes.

Gates, at HEAD ec7caad07:

  • pnpm exec vitest run packages/plugin-report/: Test Files 23 passed (23), Tests 232 passed | 7 skipped (239). The 7 skips are the describe.runIf(DRIVEN) blocks of formatValue.dateOnlyZone-10844.test.ts.
  • pnpm --filter @object-ui/plugin-report type-check (tsc --noEmit && tsc -p tsconfig.test.json): exit 0. tsc -p tsconfig.test.json --listFilesOnly includes the pin. The dependency closure was built first with turbo run build --filter='@object-ui/plugin-report^...'.
  • pnpm exec eslint on the two changed .tsx files: 2 files linted, 0 errors, 5 warnings. The BASE renderer carries the same 5 warnings under the same rules, shifted 3 lines by the new doc lines, so none is new.
  • Exit 0: check-changeset-presence, check-control-bytes, check-new-cross-file-line-citations, check-changeset-no-major, check-changeset-fixed, check-changeset-claims, check-changeset-overwrite, check-pending-changeset-literals, check-doc-links, check-doc-fence-languages, check-test-path-roots, check-unreferenced-sources, check-vi-mock-specifiers.
  • check-readme-exports: exit 1 on this checkout because 24 unrelated packages are unbuilt and it cannot judge them. With plugin-report built, its README has 0 findings.
  • NOT MEASURED: check-sdui-registration-pins, reason: it needs a console build (apps/console/dist/assets), and the diff touches no registration and no sideEffects. Declared to CI.

ESLint narrowing, declared. (1) The population is read from eslint itself: the .md / .mdx files in this diff answer "File ignored because no matching configuration was supplied". (2) The file count is read from --format json: 2. (3) Invariance: eslint.config.js enables no type-aware linting (no projectService, no parserOptions.project), so this diff cannot move a verdict on an untouched file. The repo-wide pnpm lint is CI's.

Acceptance notes

  • objectstack packages/spec/src/ui/report.zod.ts: the doc comment on ReportSchema.chart says the chart is plotted "above the report's table". That still holds for tabular and summary reports. On a matrix with columns the chart now draws below the cross-tab, per the ruling. It is a doc-comment word with no accept-set change, so it is not filed. Carrier: the spec seat on [finding] A type: 'matrix' report with columns and a chart parses, and the pinned renderer never draws the chart objectstack#20293, when that coordination card wraps up.
  • The notice and "Loading chart…" strings in DatasetReportChart are English literals outside the i18n catalogue. That predates this PR and is unchanged in kind. Not filed; carrier: none.

Generated by Claude Code

…hart beside the cross-tab (objectui#10964)

The cross-tab branch of DatasetReportRenderer returned DatasetMatrixTable
before the only report.chart read, so a matrix report with columns and a
chart (which ReportSchema accepts) parsed the chart and drew nothing.

The non-joined presentations now share one wrapper and one chart slot:
DatasetReportChart runs its own chart.xAxis x chart.yAxis dataset query,
so it binds the same way beside a cross-tab as beside a grouped table.
The chart follows the cross-tab (ruling on objectstack-ai/objectstack#20293:
beside or below) and still precedes the grouped / flat table.

The out-of-spec chart-type notice no longer says the table is below it.

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…d of any (objectui#10964)

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation plugin tests labels Sep 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3105.5 KB 3149.4 KB
Main entry chunk (gzip) 149.4 KB 350 KB
Entry file index-Che5iZz_.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.72KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.92KB 133.97KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.62KB 63.16KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.53KB 4.89KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.02KB 14.87KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.56KB 36.67KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.49KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 163.08KB 42.10KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.59KB 22.47KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: ec7caad0787e67bcfc5e01ef281f7b445d9ae1fe
Local-runs: none

Inputs: card #10964 (body; comments 5869441894 triage grade, 5883122669 claim, 5883473426 os-dev-report), PR #11043 (body, the 5-file list, the net diff against main), and the check-runs on the head with filter=latest: 43 runs, 40 success, 3 skipped (dependabot, Test (coverage), the unexpanded Test (coverage shard …/4) matrix entry), 0 failure. Two context reads of the renderer at the head by contents/…?ref=ec7caad…; nothing built, run or re-run.

① Derived judgments

  1. The card's demanded behaviour — right. A matrix report with non-empty columns and a chart now draws the cross-tab AND the chart. The early return of DatasetMatrixTable (base :1616–:1629) is gone; crossTab is a boolean, chartCfg is read for every non-joined presentation, and the wrapper emits {crossTab ? table : chart} then {crossTab ? chart : table}. This is the acceptance line "draws report.chart for a matrix report with columns, beside or below the cross-tab".
  2. Placement below — right, inside the ruling. #20293 5859529768 note 2 says "beside or below"; the diff chooses below (the chart after the cross-tab in document order) and the pin asserts it with compareDocumentPosition. The PR title's "beside" is the ruling's umbrella word, not a different placement.
  3. Binding path — right; the stop valve did not fire. Read at the head: DatasetReportChart (:923) calls useDatasetRows(dataset, [xAxis], [yAxis], runtimeFilter, dataSource, undefined, order) at :951, one dataset dimension times one dataset measure, the same call the summary arm has always made. The diff adds no matrix-aware branch to it, no new prop and no new rule: the matrix arm is handed the very same DatasetReportChart element the summary arm gets. xAxis may name a rows or a columns dimension because both are dataset dimensions; the pin's third case exercises the across dimension. #20293 note 3 is satisfied, and the PR's "mechanism assumption 2" reads correctly off the code.
  4. Control unchanged — right. Without chart, chartCfg is null, chart is null, and only DatasetMatrixTable mounts; the pin's second case asserts exactly one dataset query. A matrix without columns still degrades to the grouped table with the chart above it; summary and tabular keep the chart above the table. The changeset's "as before" sentence is true of the diff.
  5. Hook order — right. No hook call sits between readOrder(report.order) and the return in the head file (:1618–:1691), so removing the early return moves no hook; the structural change is a JSX reshuffle only.
  6. Public surface — no export, prop or type change. DatasetReportRendererProps and ReportChartPlan are untouched except in doc comments. Three DOM-observable changes, each named and each right for a patch: (a) the matrix wrapper now carries flex flex-col gap-3 and data-report-presentation="matrix", the classes and attribute the other non-joined wrappers already carried (base :1646–:1650), so the presentations are now uniform; (b) the out-of-spec chart-type notice drops "the grouped table below", which became false on the matrix arm, for the position-neutral "the report's table carries its numbers", with its data-testid unchanged; (c) the data-testid="dataset-report" wrapper and data-report-name are unchanged. The head's Test, its eight shards and Test (dist pins) are green, so no existing pin depended on the old wrapper shape or the old string.
  7. Docs — right and truthful. packages/plugin-report/README.md and content/docs/plugins/plugin-report.mdx gain one prose paragraph each stating the per-type placement and the binding; no fenced block, so README Export Check and the doc gates have nothing new to judge and are green. The file-level doc comment and the ReportChartPlan comments now say "beside" or name both positions instead of "beneath", matching the code.
  8. Pin — right in shape. New packages/plugin-report/src/__tests__/DatasetReportRenderer.matrixChart-10964.test.tsx, four cases covering both acceptance lines (matrix with columns and chart draws both; the control draws the cross-tab only) plus the across-axis binding and the notice slot. It imports ../DatasetReportRenderer from src, not dist. The report's reverse verification (3 red, control green against the base renderer) is the predicted shape and agrees with the pin's header.

Nothing in the diff is judged wrong.

② Semver level

  • Changeset .changeset/10964-matrix-report-chart.md: '@object-ui/plugin-report': patch, the level the claim (5883122669) named. Right. The diff publishes no new export, prop, option or type, removes nothing, and starts honouring a key the spec already accepted; the card is graded bug. Every changeset gate on the head is green: Changeset Declaration, Changeset Bump Policy, Changeset Claim Re-read, Changeset Fixed Group Check, Changeset Overwrite Report.
  • Each claim in the changeset text is borne out by the diff: below-the-cross-tab placement, the same binding as the summary chart, the other types unchanged, the notice wording.
  • Clause-②: no. Matches the claim's Clause-②: no and the PR body. The diff touches no spec package and moves no accept set; ReportSchema already admits the shape (5856458831 per the card), and the renderer is the only side that changes.

③ Boundary flags

open_questions: []. Nothing to answer.

Deviations, each answered:

  1. Docs files added to the file surface (README, content/docs): accepted. objectui AGENTS.md commandment 2 makes them follow the behaviour change; prose only.
  2. Notice text change: accepted. A direct consequence of the new placement (①.6b).
  3. Matrix wrapper classes and data-report-presentation: accepted. Brings the cross-tab wrapper to the shape the other presentations already had (①.6a); the dev's git grep finds no reader, and the head's test runs agree.
  4. Commit-trailer form (the AGENTS.md pair rather than the harness reminder): not a contract matter. The diff is what is judged, and the repo's own AGENTS.md governs trailer form.
  5. check-sdui-registration-pins NOT MEASURED locally, check-readme-exports judged for plugin-report only: answered by the head. README Export Check is green on ec7caad. No check-run on the head is named for SDUI registration pins, but the diff touches no registration, no index.ts and no sideEffects, and Build & E2E, Test (dist pins) and Bundle Analysis are green, so the gate has nothing in this diff to fire on. Not escalated.
  6. Worktree removal after the PR opened: housekeeping, no bearing on the head.

out_of_scope_findings, each with a carrier or a stated none:

  1. objectstack packages/spec/src/ui/report.zod.ts doc comment "above the report's table" is now inexact for a matrix with columns: carrier named (the spec seat on #20293 at wrap-up), doc-comment only, no accept-set change. Escalation noted; nothing for this PR.
  2. English literals in DatasetReportChart outside the i18n catalogue: pre-existing, unchanged in kind, carrier none. Noted; nothing for this PR.

Stop valve (#20293 note 3): did not fire, and the head's code confirms it needed not to (①.3).

Not graded here: the PR is a draft, which is the seat's to lift. The PR body measured its premises on 3ad61001b; the diff judged is the net diff against main at the PR's current base 2eaf5be27, the same base the head's check-runs ran against, and mergeable_state is clean.

Implemented-by: claude/issue-10964-matrix-report-chart
Reviewed-by: session_011p7ikEivgXefNDaE5S5Uec

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 29, 2026 04:27
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit 49f7672 Sep 29, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10964-matrix-report-chart branch September 29, 2026 04:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation plugin tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

reports: DatasetReportRenderer draws the declared chart for a matrix report with columns (objectstack-ai/objectstack#20293, ENFORCE)

2 participants