Skip to content

A report chart derives neither the dimension's option COLOURS nor its declared category order — the same dimension on a dashboard chart gets both #4906

Description

@yinlianghui

Summary

DatasetReportChart (packages/plugin-report/src/DatasetReportRenderer.tsx) resolves its dimension's option labels — useDatasetDimensionLabels → relabelDimensions — but nothing else the dashboard derives from the same field metadata. Two chart props the dashboard computes and the report does not:

  • categoryColors — buildOptionColorMap over the category dimension's select/lookup options, so a health dimension paints its own green/amber/red. The report chart forwards only an author-supplied colors record (added by objectui#4877); with none authored it falls to the positional palette.
  • categoryOrder — buildCategoryOrder over the field's declared picklist order (framework#3588), which is what makes a funnel read as the authored pipeline rather than value-descending.

Both helpers already live in @object-ui/core and are called by DatasetWidget; the report path calls neither.

Measured

Grep over packages/plugin-report/src/ for buildOptionColorMap|buildCategoryOrder|categoryColors|categoryOrder returns no hit in any source file (only a test asserting the authored-colors split of objectui#4877). DatasetWidget.tsx passes both onto its chart schema.

Why this is filed as an observation, not a defect

Nothing renders wrong today: the chart draws, the numbers are right, and every category is distinguishable — the palette is positional instead of semantic, and a funnel's stages sort by value instead of by declared order. It is cross-surface drift, visible only when the same dataset dimension is put on a dashboard and in a report side by side. Filed plainly rather than sat on, and left for triage to grade.

Found while

Implementing objectui#4877 / objectui#4878, which routed this same forwarding line through buildChartSeries and chartConfigPresentation. Deliberately out of both cards' scope: neither asks for a new derivation, and adding one would have widened a fix into a feature.

Activity

  1. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    Collaborator

    Triage (concentrated finding round): promoted finding → pm:queue. Cross-surface convergence, not new capability: wire buildOptionColorMap and buildCategoryOrder (both already in @object-ui/core, both already consumed by DatasetWidget) into the report chart path, reusing the framework#3588 declared-picklist-order ruling that dashboards already implement. Authored colors (objectui#4877) keeps precedence over the derived map. Note for review: this deliberately changes report rendering (semantic palette; funnel stages in declared order) — that is the point, and it converges on the ruled dashboard behavior.

    本评论来自分诊座位 Routine (session session_018euHiF12oV8iSfYdjVioUF).


    Generated by Claude Code

  2. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop round 14

    Session: session_01RV6yuVCxymHYE16PL9vQkE
    Branch: claude/issue-4906-report-chart-option-colors
    Worktree: objectui-issue-4906
    Domain: repo:objectui
    File surface: packages/plugin-report/src/** + its tests. ⚠️ buildOptionColorMap / buildCategoryOrder already exist in @object-ui/core — consume them, do not modify packages/core (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: sonnet
    Clause-②: no — no contract surface changes and no new capability; this converges an existing surface onto an already-ruled behaviour.
    Serial constraints cleared: packages/plugin-report is free. In-flight PRs hold disjoint surfaces: PR #5290 apps/console, PR #5294 packages/plugin-view, PR #5295 .github/workflows + scripts/ + root manifests, PR #5297 packages/plugin-map, PR #5298 packages/components + packages/types, PR #5300 / #5303 packages/plugin-dashboard, PR #5302 packages/cli. Sibling dispatch this round is #5083 (packages/plugin-form) — disjoint. packages/core is not held by anyone, but it is still out of your file surface — if the wiring turns out to need a change there, stop and report rather than widening.

    Scope, per the triage ruling

    Cross-surface convergence, not new capability. Wire buildOptionColorMap and buildCategoryOrder — both already in @object-ui/core, both already consumed by DatasetWidget — into the report chart path, reusing the framework#3588 declared-picklist-order ruling that dashboards already implement.

    Precedence: authored colors (objectui#4877) keeps precedence over the derived map. Do not invert this; a report that ignores an author's explicit colours in favour of a derived palette is a worse bug than the one being fixed.

    Read how DatasetWidget consumes these two helpers before writing anything. The point is that the report path ends up doing what the dashboard path already does — a second, independently-written implementation of the same rule is the defect shape this repo keeps paying for (see the four-copy resolver in #5301). If the dashboard path's usage looks wrong to you, that is a finding to file, not a thing to diverge from.

    ⚠️ This deliberately changes rendering, and that is the point

    Semantic palette; funnel stages in declared order. The triage seat flagged it for review explicitly. So:

    • Say in the PR body what visibly changes for an existing report, in plain terms.
    • Pin the convergence: a test showing the report path and the dashboard path derive the same colours and the same category order from the same picklist.
    • Pin the precedence: authored colors still wins.

    Verification

    Re-derive on current origin/main first (the card is ~2 days old; main just took the CI fix from #5304). Counter-probe every zero with a known-present neighbouring term.

    Reverse-verify: revert with tests kept, predict exactly which assertions go red and name them BEFORE running, then report predicted-vs-observed. Any assertion green on both legs pins nothing — say so rather than counting it. State whether a build artifact sits between your edit and the thing under test (check whether the tests resolve @object-ui/core via the root vitest.config.mts alias to src, or via package exports to dist — it matters here because the helpers you consume live in another package).

    Changeset: patch on @object-ui/plugin-report. ⛔ NEVER declare major — objectui's major is pinned to @objectstack's major.
    ⛔ Do not edit content/docs/releases/, docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md.


    Generated by Claude Code

  3. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    Collaborator

    <!-- os-dev-report -->

    {
      "issue": 4906,
      "status": "done",
      "branch": "claude/issue-4906-report-chart-option-colors",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5310",
      "premise_still_valid": true,
      "summary": "DatasetReportChart (packages/plugin-report/src/DatasetReportRenderer.tsx) now derives its category dimension's option colours and declared picklist order via useDatasetDimensionMeta, buildOptionColorMap and buildCategoryOrder (all @object-ui/core, reused unmodified) - the exact chain DatasetWidget already runs for the identical dimension, per the triage ruling. categoryColors is passed as chartConfigPresentation's second argument, so an authored colors record (objectui#4877) still wins per-category over the derived map; categoryOrder is spread onto the chart schema only when the dimension declares options. useDatasetDimensionLabels.ts (the report's shared analytics-hook import path) now also re-exports useDatasetDimensionMeta so DatasetReportChart can reach it. No changes to packages/core.",
      "tests": "pnpm exec vitest run packages/plugin-report/ --maxWorkers=2 at HEAD 4bfb71054: 14 files / 161 tests passed (152 pre-existing + 9 new in DatasetReportRenderer.chartCategoryConvergence.test.tsx). Reverse verification: committed the fix, then git checkout de4e29a81 -- DatasetReportRenderer.tsx useDatasetDimensionLabels.ts (source only, new test file kept); predicted 7 red / 2 green (case names in the test file's own header) before running; observed 7 failed / 2 passed, the same 2 named cases - match. Restored via git checkout claude/issue-4906-report-chart-option-colors -- (the same 2 files), git status clean against HEAD. Rebuild question: canonical pnpm exec vitest run packages/plugin-report/ from repo root resolves @object-ui/core, @object-ui/react and @object-ui/plugin-report via the root vitest.config.mts alias straight to src/, not package exports to dist - no stale-dist risk for this run. Also ran clean: pnpm --filter '@object-ui/plugin-report^...' build and pnpm --filter '@object-ui/plugin-report' build (both succeed, no type errors - unplugin-dts typechecks on build), node scripts/check-control-bytes.mjs, node scripts/check-phantom-dependencies.mjs, node scripts/check-changeset-fixed.mjs, node scripts/check-changeset-no-major.mjs, node scripts/check-changeset-presence.mjs, and pnpm exec eslint on the 3 changed source/test files (0 errors; only pre-existing-pattern warnings, e.g. no-explicit-any in test mocks matching the sibling chartChrome test file's own idiom). The convergence pin (report path vs DatasetWidget) is asserted at the mechanism, not by rendering DatasetWidget side by side: DatasetWidget is plugin-dashboard's internal implementation, not exported from its barrel or package.json#exports, so a live cross-render comparison would need a deep non-exported import (resolves only via the vitest src alias, not through plugin-dashboard's published dist) plus a new plugin-report to plugin-dashboard dev dependency for one test; the new test file instead asserts the report chart's schema against the literal output of the same localizeFieldOptions to buildOptionColorMap/buildCategoryOrder chain DatasetWidget's own useMemo is written to run, over the identical picklist - noted explicitly in the PR body rather than left implicit.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    Collaborator
    {
      "issue": 4906,
      "status": "done",
      "branch": "claude/issue-4906-report-chart-option-colors",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5310",
      "premise_still_valid": true,
      "summary": "DatasetReportChart (packages/plugin-report/src/DatasetReportRenderer.tsx) now derives its category dimension's option colours and declared picklist order via useDatasetDimensionMeta, buildOptionColorMap and buildCategoryOrder (all @object-ui/core, reused unmodified) - the exact chain DatasetWidget already runs for the identical dimension, per the triage ruling. categoryColors is passed as chartConfigPresentation's second argument, so an authored colors record (objectui#4877) still wins per-category over the derived map; categoryOrder is spread onto the chart schema only when the dimension declares options. useDatasetDimensionLabels.ts (the report's shared analytics-hook import path) now also re-exports useDatasetDimensionMeta so DatasetReportChart can reach it. No changes to packages/core.",
      "tests": "pnpm exec vitest run packages/plugin-report/ --maxWorkers=2 at HEAD 4bfb71054: 14 files / 161 tests passed (152 pre-existing + 9 new in DatasetReportRenderer.chartCategoryConvergence.test.tsx). Reverse verification: committed the fix, then git checkout de4e29a81 -- DatasetReportRenderer.tsx useDatasetDimensionLabels.ts (source only, new test file kept); predicted 7 red / 2 green (case names in the test file's own header) before running; observed 7 failed / 2 passed, the same 2 named cases - match. Restored via git checkout claude/issue-4906-report-chart-option-colors -- (the same 2 files), git status clean against HEAD. Rebuild question: canonical pnpm exec vitest run packages/plugin-report/ from repo root resolves @object-ui/core, @object-ui/react and @object-ui/plugin-report via the root vitest.config.mts alias straight to src/, not package exports to dist - no stale-dist risk for this run. Also ran clean: pnpm --filter '@object-ui/plugin-report^...' build and pnpm --filter '@object-ui/plugin-report' build (both succeed, no type errors - unplugin-dts typechecks on build), node scripts/check-control-bytes.mjs, node scripts/check-phantom-dependencies.mjs, node scripts/check-changeset-fixed.mjs, node scripts/check-changeset-no-major.mjs, node scripts/check-changeset-presence.mjs, and pnpm exec eslint on the 3 changed source/test files (0 errors; only pre-existing-pattern warnings, e.g. no-explicit-any in test mocks matching the sibling chartChrome test file's own idiom). The convergence pin (report path vs DatasetWidget) is asserted at the mechanism, not by rendering DatasetWidget side by side: DatasetWidget is plugin-dashboard's internal implementation, not exported from its barrel or package.json#exports, so a live cross-render comparison would need a deep non-exported import (resolves only via the vitest src alias, not through plugin-dashboard's published dist) plus a new plugin-report to plugin-dashboard dev dependency for one test; the new test file instead asserts the report chart's schema against the literal output of the same localizeFieldOptions to buildOptionColorMap/buildCategoryOrder chain DatasetWidget's own useMemo is written to run, over the identical picklist - noted explicitly in the PR body rather than left implicit.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    (Supersedes the previous comment on this issue, which HTML-escaped the marker by mistake and is not machine-readable.)


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions