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
Report chart: split a series by a second dataset dimension #27974
Filing gate: ③ triage-directed. The order on #27430 (rows 2–4) said: TAKE what is ui-only, CARD the rest. The card thread measured each row on origin/mained0e71db (report 6515939841, out_of_scope_findings). Row 2 is taken in PR #27972.
Reach: any report that wants a bar per X split by Y. HotCRM opportunity_funnel_owner_stage (a bar per owner, split by stage); hotcrm#2379 turned it into an owner × stage matrix as the workaround (#27430 row 4).
Reader who acts: domain:spec first (the key; Metadata-protocol added), then domain:ui (plugin-report).
Duplicate search: search_issues "report chart series second dimension groupBy stacked bar ReportChartSchema" → #27563 and #15734, both closed and about other gaps.
Observed
ReportChartSchema (packages/specui/report.zod.ts) extends ChartConfig with one xAxis dimension and one yAxis measure, and DatasetReportRenderer queries exactly chart.xAxis × chart.yAxis. A report therefore cannot draw a bar per owner split by stage. The dashboard dataset path already pivots a second dimension into grouped series (buildChartSeries in ui/packages/core), so the renderer half can reuse it.
Wanted
A declared series dimension key on ReportChartSchema (for example series or groupBy, a dimension name validated against the report's dataset). The report query is widened to it, and the renderer pivots through buildChartSeries. The ui half follows as a domain:ui card once the key ships.
Dedupe words: report chart series, second dimension, groupBy series, stacked bar report, ReportChartSchema.
Claim: PM loop round 2
Session: session_01L9qibx5r5nhDMwpRs4SL6D
Account: os-tesla
Branch: claude/project-thread-1rmsao (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-27974
Domain: domain:spec
Seat: domain:spec#2
File surface: packages/spec/src/ui/report.zod.ts (ReportChartSchema, one series dimension) and the dataset-dimension check that validates xAxis (named in the report), tests, regenerated spec artefacts and reference docs, changeset (@objectstack/spec minor). The ui half is a follow-up domain:ui card the seat files when the key lands; ⛔ no ui/** and no governed path (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT (Clause-②: yes ⇒ default judgment tier to build; the contract review at CONTRACT_REVIEW_TIER is the seat's own, on the maintainer's 「你有 fable,可以自己契约复审」), effort: high
Clause-②: yes
Metadata-protocol: added
Responsibility: n/a — not a defect card
Thread-read: none
Premise: holds (re-read at origin/main9f13ee81; the declaration named on the card still lacks the key)
Serial constraints cleared: none (no open PR touches report.zod.ts)
Ruling-ref: none on the shape; dispatch authority = the maintainer's 「p3 也可以开发」 (2026-10-30T12:41Z) and 「每个座位并发可以5」 (2026-10-30T15:04Z); the card's filing gate ③ (triage-directed)
Dispatched 2026-10-30T15:10Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
{
"issue": 27974,
"status": "done",
"branch": "claude/project-thread-1rmsao",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28191",
"session": "session_01L9qibxKEFRdVkHHwAWLUSE",
"premise_still_valid": true,
"summary": "ReportChartSchema declares one optional key, seriesBy: a second dimension of the report's bound dataset that splits the one yAxis measure into a series per value (the report spelling of a dashboard widget's two-entry dimensions selection). validateChartBindings (packages/lint/src/validate-chart-bindings.ts, the check that resolves chart.xAxis) resolves chart.seriesBy through the same dimensionRef, so a misspelled one is chart-dimension-unknown at os validate / os build / the report publish door; with seriesBy set, chart.series[].name overrides name dimension values and are not judged against the measure. Liveness: the report chart row now drills (childrenDefault live), seriesBy is planned with authorWarn, the walked aria tombstone is dead, and the three nested containers drilling surfaced are recorded in the undrilled baseline in place of report/chart. Spec half only; no ui/** edits.",
"tests": "head 061a780d. spec vitest src/ui + scripts/liveness: Test Files 176/176, Tests 6227/6227. lint test (full): Test Files 178/178, Tests 7646/7646. typecheck spec and lint: lock VERDICT command-exit 0. Ablations via scripts/ablation-replace.mjs (lint suite reads src, no dist): seriesBy dimensionRef line deleted -> 1 failed/80; seriesBy series guard reverted -> 1 failed/80; file restored, hash-object == HEAD blob. Author-warning probe: lintLivenessProperties gives one liveness-planned-property finding on a report setting chart.seriesBy, none on the control.",
"gates": "dispatch-gates --commands at 061a780d: 106 families, run with stdin from /dev/null, exit codes recorded before any pipe (record: /mnt/project-files/spec-seat-2/r2026-10-30/out/27974-gates-ran-061a780d.list). --ran: 106 derived, 106 run, 0 NOT MEASURED, 0 unrun, 0 red. First pass exit 3 on four, re-run after the prerequisite, all exit 0: check-plugin-teardown-shape --self-test (pinned control 621a4876 fetched into the shallow clone), spec check:skill-examples, check:dual-build-cjs-loads, check:lean-entry-closure (after a full packages/** build). spec check:generated: 14/14 up to date; check:liveness exit 0. CI check-runs on #28191: in_progress at report time.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"line_budget": "+135 / -8 across 12 files vs merge base 9f13ee81",
"files_changed": [
".changeset/27974-report-chart-series-by.md",
"content/docs/references/ui/report.mdx",
"packages/lint/src/rule-explanations.ts",
"packages/lint/src/validate-chart-bindings.test.ts",
"packages/lint/src/validate-chart-bindings.ts",
"packages/spec/authorable-surface/ui.json",
"packages/spec/liveness/report.json",
"packages/spec/liveness/state-counts/report.md",
"packages/spec/scripts/liveness/undrilled-containers.baseline.json",
"packages/spec/src/ui/chart.test.ts",
"packages/spec/src/ui/report.test.ts",
"packages/spec/src/ui/report.zod.ts"
],
"deviations": [
"Changeset moves @objectstack/lint minor beside @objectstack/spec minor (the order names spec only): the lint diff adds a finding on a new key, so it publishes.",
"Liveness ledger edits beyond the order's file surface (report.json chart drill, undrilled-containers baseline swap of report/chart for its three nested containers, state-counts regen): the chart row's blanket live verdict would otherwise vouch for seriesBy, which no renderer reads yet.",
"Assignee/reviewer not written on the PR (FRAME forbids it; the session prompt's best-effort assign step skipped)."
],
"decision_for_maintainer": "Shape: a new optional seriesBy key. Not taken: reusing ChartConfig `series` (already the per-series presentation override array), `groupBy` (the X-axis category on the react ObjectChart aggregate and the lane field on kanban), widening xAxis to a list (changes a one-string key every reader uses), reusing the report's `columns` (ties the chart split to the matrix table).",
"mcp_calls": "3 — mcp__github__issue_read (get, get_comments x2); 0 writes",
"api_writes": "2 — relay pr_create (objectstack-ai/objectstack#28191, read back identical) and this os-dev-report comment via post-stamped",
"open_questions": [],
"out_of_scope_findings": [
"ui half of #27974 · carrier: the seat — DatasetReportChart (ui/packages/plugin-report/src/DatasetReportRenderer.tsx) queries [xAxis] x [yAxis] and passes one dimension to buildChartSeries; add seriesBy to the query dimensions, pass [xAxis, seriesBy], match chart.series[].name against the pivoted series keys, flip the chart.seriesBy liveness row to live · dedupe words: report chart seriesBy renderer, DatasetReportChart split series",
"Skills-docs follow-up · carrier: the seat — skills/objectstack-ui/rules/dashboards.md report example teaches chart xAxis/yAxis; teach seriesBy with the renderer half",
"noted, not filed: report/chart liveness note still says sub-key `groupBy` stays experimental; ReportChartSchema has no groupBy key (stale prose in the row, left untouched)"
]
}
Activity
objectstack-fleet commentedon Oct 30, 2026
domain:spec#2 · os-tesla · session_01L9qibx5r5nhDMwpRs4SL6D
Claim: PM loop round 2
Session:
session_01L9qibx5r5nhDMwpRs4SL6DAccount:
os-teslaBranch:
claude/project-thread-1rmsao(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27974Domain:
domain:specSeat:
domain:spec#2File surface:
packages/spec/src/ui/report.zod.ts(ReportChartSchema, one series dimension) and the dataset-dimension check that validatesxAxis(named in the report), tests, regenerated spec artefacts and reference docs, changeset (@objectstack/specminor). The ui half is a follow-updomain:uicard the seat files when the key lands; ⛔ noui/**and no governed path (stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT(Clause-②: yes⇒ default judgment tier to build; the contract review atCONTRACT_REVIEW_TIERis the seat's own, on the maintainer's 「你有 fable,可以自己契约复审」),effort: highClause-②: yes
Metadata-protocol: added
Responsibility: n/a — not a defect card
Thread-read: none
Premise: holds (re-read at
origin/main9f13ee81; the declaration named on the card still lacks the key)Serial constraints cleared: none (no open PR touches
report.zod.ts)Ruling-ref: none on the shape; dispatch authority = the maintainer's 「p3 也可以开发」 (2026-10-30T12:41Z) and 「每个座位并发可以5」 (2026-10-30T15:04Z); the card's filing gate ③ (triage-directed)
Dispatched 2026-10-30T15:10Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.
objectstack-fleet commentedon Oct 30, 2026
domain:spec#2 · os-tesla · session_01L9qibxKEFRdVkHHwAWLUSE
os-dev-report
Draft PR #28191 at head
061a780d.{ "issue": 27974, "status": "done", "branch": "claude/project-thread-1rmsao", "pr": "https://github.com/objectstack-ai/objectstack/pull/28191", "session": "session_01L9qibxKEFRdVkHHwAWLUSE", "premise_still_valid": true, "summary": "ReportChartSchema declares one optional key, seriesBy: a second dimension of the report's bound dataset that splits the one yAxis measure into a series per value (the report spelling of a dashboard widget's two-entry dimensions selection). validateChartBindings (packages/lint/src/validate-chart-bindings.ts, the check that resolves chart.xAxis) resolves chart.seriesBy through the same dimensionRef, so a misspelled one is chart-dimension-unknown at os validate / os build / the report publish door; with seriesBy set, chart.series[].name overrides name dimension values and are not judged against the measure. Liveness: the report chart row now drills (childrenDefault live), seriesBy is planned with authorWarn, the walked aria tombstone is dead, and the three nested containers drilling surfaced are recorded in the undrilled baseline in place of report/chart. Spec half only; no ui/** edits.", "tests": "head 061a780d. spec vitest src/ui + scripts/liveness: Test Files 176/176, Tests 6227/6227. lint test (full): Test Files 178/178, Tests 7646/7646. typecheck spec and lint: lock VERDICT command-exit 0. Ablations via scripts/ablation-replace.mjs (lint suite reads src, no dist): seriesBy dimensionRef line deleted -> 1 failed/80; seriesBy series guard reverted -> 1 failed/80; file restored, hash-object == HEAD blob. Author-warning probe: lintLivenessProperties gives one liveness-planned-property finding on a report setting chart.seriesBy, none on the control.", "gates": "dispatch-gates --commands at 061a780d: 106 families, run with stdin from /dev/null, exit codes recorded before any pipe (record: /mnt/project-files/spec-seat-2/r2026-10-30/out/27974-gates-ran-061a780d.list). --ran: 106 derived, 106 run, 0 NOT MEASURED, 0 unrun, 0 red. First pass exit 3 on four, re-run after the prerequisite, all exit 0: check-plugin-teardown-shape --self-test (pinned control 621a4876 fetched into the shallow clone), spec check:skill-examples, check:dual-build-cjs-loads, check:lean-entry-closure (after a full packages/** build). spec check:generated: 14/14 up to date; check:liveness exit 0. CI check-runs on #28191: in_progress at report time.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "line_budget": "+135 / -8 across 12 files vs merge base 9f13ee81", "files_changed": [ ".changeset/27974-report-chart-series-by.md", "content/docs/references/ui/report.mdx", "packages/lint/src/rule-explanations.ts", "packages/lint/src/validate-chart-bindings.test.ts", "packages/lint/src/validate-chart-bindings.ts", "packages/spec/authorable-surface/ui.json", "packages/spec/liveness/report.json", "packages/spec/liveness/state-counts/report.md", "packages/spec/scripts/liveness/undrilled-containers.baseline.json", "packages/spec/src/ui/chart.test.ts", "packages/spec/src/ui/report.test.ts", "packages/spec/src/ui/report.zod.ts" ], "deviations": [ "Changeset moves @objectstack/lint minor beside @objectstack/spec minor (the order names spec only): the lint diff adds a finding on a new key, so it publishes.", "Liveness ledger edits beyond the order's file surface (report.json chart drill, undrilled-containers baseline swap of report/chart for its three nested containers, state-counts regen): the chart row's blanket live verdict would otherwise vouch for seriesBy, which no renderer reads yet.", "Assignee/reviewer not written on the PR (FRAME forbids it; the session prompt's best-effort assign step skipped)." ], "decision_for_maintainer": "Shape: a new optional seriesBy key. Not taken: reusing ChartConfig `series` (already the per-series presentation override array), `groupBy` (the X-axis category on the react ObjectChart aggregate and the lane field on kanban), widening xAxis to a list (changes a one-string key every reader uses), reusing the report's `columns` (ties the chart split to the matrix table).", "mcp_calls": "3 — mcp__github__issue_read (get, get_comments x2); 0 writes", "api_writes": "2 — relay pr_create (objectstack-ai/objectstack#28191, read back identical) and this os-dev-report comment via post-stamped", "open_questions": [], "out_of_scope_findings": [ "ui half of #27974 · carrier: the seat — DatasetReportChart (ui/packages/plugin-report/src/DatasetReportRenderer.tsx) queries [xAxis] x [yAxis] and passes one dimension to buildChartSeries; add seriesBy to the query dimensions, pass [xAxis, seriesBy], match chart.series[].name against the pivoted series keys, flip the chart.seriesBy liveness row to live · dedupe words: report chart seriesBy renderer, DatasetReportChart split series", "Skills-docs follow-up · carrier: the seat — skills/objectstack-ui/rules/dashboards.md report example teaches chart xAxis/yAxis; teach seriesBy with the renderer half", "noted, not filed: report/chart liveness note still says sub-key `groupBy` stays experimental; ReportChartSchema has no groupBy key (stale prose in the row, left untouched)" ] }