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
{{ message }}
Repository navigation
spec: a report chart whose seriesBy cannot split (single-series type, or the same dimension as xAxis) is refused at authoring time, not on the page #28424
A report author splits a chart by a second dimension (chart.seriesBy, delivered by #28206 / #28305) and publishes it. Two combinations parse today and then fail on the page the business user opens:
A single-series chart type with seriesBy.pie, donut, funnel (and treemap and sankey) draw one series. Such a report parses cleanly, but the renderer draws the one-series refusal panel (ui/packages/plugin-charts/src/AdvancedChartImpl.tsx, "A {family} draws one series, and this chart carries N"). So the sales manager sees an error box where the pipeline chart should be.
seriesBy equal to xAxis. The split repeats the category, so every series has exactly one point. The chart looks broken, and nothing tells the author why.
Both are authoring mistakes with no valid reading. The author should hear about them from os build, Studio save or os lint, not from a user. Dashboards already refuse the same thing for their own spelling: checkDashboardWidgetChartMeasureArity in packages/spec/src/ui/dashboard.zod.ts refuses a declared dimension with several measures on a type in SINGLE_SERIES_CHART_TYPES (objectui#8894 ruling D). The report spelling of that split arrived after that rule and is not covered.
Source: ui seat 2's landing note on #28206 (comment 6544899074). It covers rider S1, the seriesBy === xAxis warning in packages/lint/src/validate-chart-bindings.ts, which triage dropped from the ui card, and the single-series finding.
Scope
Single-series arm. Refuse report.chart.seriesBy on a type in SINGLE_SERIES_CHART_TYPES in the spec, with the same set (one source, not a copy). Name the type, the split, and what to write instead (a bar-family type, or drop seriesBy). This mirrors ruling D's dashboard arm.
Same-dimension arm. Report seriesBy === xAxis at authoring time, in the spec refusal or as the lint warning that rider S1 named. The dispatch decides which.
Both arms apply only to non-joined reports, since a joined report has no chart.
Out of scope
Renderer changes. The runtime refusal panel stays as the last line of defence.
Claim: PM loop round 8 · 2026-10-31T14:51Z
Session: session_01L9qibwb6hBqszPTYJobitm
Account: os-tesla
Branch: claude/project-thread-xfdmx2 (card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead of claude/issue-28424-<slug>)
Worktree: objectstack-issue-28424
Domain: domain:spec
Seat: domain:spec#1
Card thread: session session_01L9qibwvHraeucX94Rvvzrk; the dispatch order is in the seat's project, frame + card file.
File surface: packages/spec/src/ui/report.zod.ts, packages/spec/src/ui/dashboard.zod.ts (export of SINGLE_SERIES_CHART_TYPES only, or a shared chart module) + generated artefacts, tests (plus a lint test fixture if one now refuses at parse), changeset (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT (spec narrowing, so a contract review is owed), effort: high
Clause-②: yes (narrowing)
Metadata-protocol: narrowed
Responsibility: a report chart with seriesBy on a single-series type, or seriesBy equal to xAxis, parses and then fails on the page | spec refusals on the report chart, using the dashboard's one single-series type set | report authors and the business users who open their reports
Thread-read: 6544899074
Premise: holds. seriesBy landed on main with #28305. SINGLE_SERIES_CHART_TYPES is a non-exported const in dashboard.zod.ts. ReportChartSchema has no refine.
Serial constraints cleared: none. The dashboard set is read, not changed.
{
"issue": 28424,
"status": "done",
"branch": "claude/project-thread-xfdmx2",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28439",
"session": "session_01L9qibwvHraeucX94Rvvzrk",
"premise_still_valid": true,
"summary": "ReportSchema's refinement now refuses chart.seriesBy on a non-joined report in two exclusive arms at path chart.seriesBy: a type in SINGLE_SERIES_CHART_TYPES (pie/donut/funnel/treemap/sankey; message names report, type, split, prescribes bar/column/horizontal-bar or dropping seriesBy) and seriesBy === xAxis (must name a different dimension). SINGLE_SERIES_CHART_TYPES is exported from dashboard.zod.ts and imported by report.zod.ts (no second list). The check sits in the report-level superRefine, so ReportChartSchema stays an unrefined extend for its .extend/.shape readers. Rider S1's lint warning is superseded by the spec refusal (stated in the PR body).",
"tests": "head 1707dd00. packages/spec/src/ui/report.test.ts new describe, 7 cases (pie/donut/funnel refused naming type; bar seriesBy===xAxis refused; controls bar/line distinct split + pie without split parse; joined report untouched, single issue at chart; one-source equality with SINGLE_SERIES_CHART_TYPES over every ChartTypeSchema member). spec test: VERDICT command-exit 0, Test Files 773/773, Tests 22837 passed + 1 todo. spec typecheck + lint validate-chart-bindings.test.ts: VERDICT command-exit 0, 80/80. Ablation via scripts/ablation-replace.mjs (src-resolved suite, no dist leg): single-series arm anchor 1 to 0, blob 4c78418e to ca603b9e, 4 failed (pie, donut, funnel, one-source); same-dimension arm anchor 1 to 0, blob to b4975efc, 1 failed; both restored to HEAD blob, git diff HEAD empty.",
"gates": "dispatch-gates --commands at 1707dd00: 104 lines, all ':: exit 0' (record /mnt/project-files/spec-seat-1/r2026-10-31/out/28424-gates-ran-1707dd00.list), after prerequisite build turbo packages/** + dogfood^... with dts (VERDICT command-exit 0). --ran reconciliation exit 0: 104 derived, 104 run, 0 NOT-MEASURED, 0 UNRUN. spec check:generated: 3 stale before --fix (api-surface, export-origins, docs), 14/14 after. CI check-runs: in_progress at report time.",
"dogfood_battery": "1707dd00 · os-verify-lock: VERDICT command-exit 0 · Test Files 361 passed | 3 skipped (364) · Tests 2917 passed | 28 skipped (2945) · no failures",
"mcp_calls": "3 — mcp__github__issue_read (get, get_comments x2); 0 write tools",
"api_writes": "2 — relay pr_create (objectstack#28439, run 41218252746) + relay os-dev-report comment on #28424 via post-stamped.mjs",
"line_budget": "167 changed lines (+158/-9, 7 files) vs 3000 threshold",
"files_changed": [
".changeset/28424-report-chart-series-split.md",
"content/docs/references/ui/report.mdx",
"packages/spec/api-surface/ui.json",
"packages/spec/export-origins/ui.json",
"packages/spec/src/ui/dashboard.zod.ts",
"packages/spec/src/ui/report.test.ts",
"packages/spec/src/ui/report.zod.ts"
],
"deviations": [
"the first three commits (wip) carry no Co-Authored-By/Claude-Session trailer pair; the branch is not claude/issue-* so it is shared under AGENTS.md section 3 and was not rewritten; the squash merge drops them",
"no lint rule added: rider S1 superseded by the spec refusal per the dispatch ruling"
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed — objectui Studio report editor runs its own .shape mirror and keeps accepting both shapes until it chains a check; the author meets the refusal at save/publish (same position as the dashboard arm)"
]
}
Activity
objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
Claim: PM loop round 8 · 2026-10-31T14:51Z
Session:
session_01L9qibwb6hBqszPTYJobitmAccount:
os-teslaBranch:
claude/project-thread-xfdmx2(card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead ofclaude/issue-28424-<slug>)Worktree:
objectstack-issue-28424Domain:
domain:specSeat:
domain:spec#1Card thread: session
session_01L9qibwvHraeucX94Rvvzrk; the dispatch order is in the seat's project, frame + card file.File surface:
packages/spec/src/ui/report.zod.ts,packages/spec/src/ui/dashboard.zod.ts(export ofSINGLE_SERIES_CHART_TYPESonly, or a shared chart module) + generated artefacts, tests (plus a lint test fixture if one now refuses at parse), changeset (stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT(spec narrowing, so a contract review is owed),effort: highClause-②: yes (narrowing)
Metadata-protocol: narrowed
Responsibility: a report chart with
seriesByon a single-series type, orseriesByequal toxAxis, parses and then fails on the page | spec refusals on the report chart, using the dashboard's one single-series type set | report authors and the business users who open their reportsThread-read: 6544899074
Premise: holds.
seriesBylanded onmainwith #28305.SINGLE_SERIES_CHART_TYPESis a non-exported const indashboard.zod.ts.ReportChartSchemahas no refine.Serial constraints cleared: none. The dashboard set is read, not changed.
objectstack-fleet commentedon Oct 31, 2026
domain:spec#1 · os-tesla · session_01L9qibwvHraeucX94Rvvzrk
os-dev-report
{ "issue": 28424, "status": "done", "branch": "claude/project-thread-xfdmx2", "pr": "https://github.com/objectstack-ai/objectstack/pull/28439", "session": "session_01L9qibwvHraeucX94Rvvzrk", "premise_still_valid": true, "summary": "ReportSchema's refinement now refuses chart.seriesBy on a non-joined report in two exclusive arms at path chart.seriesBy: a type in SINGLE_SERIES_CHART_TYPES (pie/donut/funnel/treemap/sankey; message names report, type, split, prescribes bar/column/horizontal-bar or dropping seriesBy) and seriesBy === xAxis (must name a different dimension). SINGLE_SERIES_CHART_TYPES is exported from dashboard.zod.ts and imported by report.zod.ts (no second list). The check sits in the report-level superRefine, so ReportChartSchema stays an unrefined extend for its .extend/.shape readers. Rider S1's lint warning is superseded by the spec refusal (stated in the PR body).", "tests": "head 1707dd00. packages/spec/src/ui/report.test.ts new describe, 7 cases (pie/donut/funnel refused naming type; bar seriesBy===xAxis refused; controls bar/line distinct split + pie without split parse; joined report untouched, single issue at chart; one-source equality with SINGLE_SERIES_CHART_TYPES over every ChartTypeSchema member). spec test: VERDICT command-exit 0, Test Files 773/773, Tests 22837 passed + 1 todo. spec typecheck + lint validate-chart-bindings.test.ts: VERDICT command-exit 0, 80/80. Ablation via scripts/ablation-replace.mjs (src-resolved suite, no dist leg): single-series arm anchor 1 to 0, blob 4c78418e to ca603b9e, 4 failed (pie, donut, funnel, one-source); same-dimension arm anchor 1 to 0, blob to b4975efc, 1 failed; both restored to HEAD blob, git diff HEAD empty.", "gates": "dispatch-gates --commands at 1707dd00: 104 lines, all ':: exit 0' (record /mnt/project-files/spec-seat-1/r2026-10-31/out/28424-gates-ran-1707dd00.list), after prerequisite build turbo packages/** + dogfood^... with dts (VERDICT command-exit 0). --ran reconciliation exit 0: 104 derived, 104 run, 0 NOT-MEASURED, 0 UNRUN. spec check:generated: 3 stale before --fix (api-surface, export-origins, docs), 14/14 after. CI check-runs: in_progress at report time.", "dogfood_battery": "1707dd00 · os-verify-lock: VERDICT command-exit 0 · Test Files 361 passed | 3 skipped (364) · Tests 2917 passed | 28 skipped (2945) · no failures", "mcp_calls": "3 — mcp__github__issue_read (get, get_comments x2); 0 write tools", "api_writes": "2 — relay pr_create (objectstack#28439, run 41218252746) + relay os-dev-report comment on #28424 via post-stamped.mjs", "line_budget": "167 changed lines (+158/-9, 7 files) vs 3000 threshold", "files_changed": [ ".changeset/28424-report-chart-series-split.md", "content/docs/references/ui/report.mdx", "packages/spec/api-surface/ui.json", "packages/spec/export-origins/ui.json", "packages/spec/src/ui/dashboard.zod.ts", "packages/spec/src/ui/report.test.ts", "packages/spec/src/ui/report.zod.ts" ], "deviations": [ "the first three commits (wip) carry no Co-Authored-By/Claude-Session trailer pair; the branch is not claude/issue-* so it is shared under AGENTS.md section 3 and was not rewritten; the squash merge drops them", "no lint rule added: rider S1 superseded by the spec refusal per the dispatch ruling" ], "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed — objectui Studio report editor runs its own .shape mirror and keeps accepting both shapes until it chains a check; the author meets the refusal at save/publish (same position as the dashboard arm)" ] }