Repository navigation
feat(spec)!: a report chart's seriesBy that cannot split (single-series type, or the xAxis dimension) is refused at authoring time - #28439
Conversation
…s for the seriesBy split refusal Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibwvHraeucX94Rvvzrk
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin faf8b9f6fbd29880bc2d2b098a2e1a457f24e08a && git checkout faf8b9f6fbd29880bc2d2b098a2e1a457f24e08a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 630b4078daf45d41c2d0c19ece48661163dc6418 1707dd00edb420d45edcb08d6c842a5b9aa437a0 && git checkout -B drift-repro 630b4078daf45d41c2d0c19ece48661163dc6418 && git merge --no-ff 1707dd00edb420d45edcb08d6c842a5b9aa437a0
node scripts/docs-audit/affected-docs.mjs --json 630b4078daf45d41c2d0c19ece48661163dc6418
|
|
triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract-review-claim: |
|
triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract reviewServed-tier: ① Derived judgments
② Rulings cited
③ Narrowing / widening
④ Behaviour / flags
Implemented-by: |
|
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm 维护者速读
席位核对 · ACCEPT ·
|
Requested by Tesla · project thread
Fixes #28424
Clause-②: yes (narrowing)
Metadata-protocol: narrowed
domain:spec#1 · os-tesla · session_01L9qibwvHraeucX94Rvvzrk
维护者速读
seriesBy拆分在两种拆不开的写法下,发布前就被 spec 拒收——饼图/环形图/漏斗/树图/桑基这类单系列图,和seriesBy与xAxis同一维度。os build/Studio 保存/os lint时就听到,而且仪表盘早已对同类写法拒收。seriesBy);仓内示例与夹具零命中。回滚 = 撤这个 PR。packages/spec/src/ui/report.zod.ts的checkReportChartSeriesSplit;packages/spec/src/ui/dashboard.zod.ts只是把SINGLE_SERIES_CHART_TYPES导出;packages/spec/src/ui/report.test.ts末尾新 describe。pnpm --filter @objectstack/spec exec vitest run src/ui/report.test.ts -t "cannot split",预期 7 个用例全绿。What changes
ReportSchema's refinement now callscheckReportChartSeriesSpliton every non-joinedreport. It refuseschart.seriesBywith onecustomissue atchart.seriesBy, in two arms:chart.typeis inSINGLE_SERIES_CHART_TYPES(pie/donut/funnel/treemap/sankey). The message names the report, the type and the split, and says what to write instead: a bar-family type (bar/column/horizontal-bar) for one bar per split value, or dropseriesBy.seriesBy === xAxis. The message saysseriesBymust name a different dimension thanxAxis, or be dropped.The arms are exclusive. On a single-series type the first one answers, since dropping
seriesByfixes both.One source for the type set.
SINGLE_SERIES_CHART_TYPESindashboard.zod.tschanges from a module-privateconstto an export, and its docblock now names the report as a reader.report.zod.tsimports it, and so does theseriesBy.describe(). No second list exists.Where the check sits. It runs in the report-level
superRefine, not onReportChartSchema. That gives thechart.seriesBypath and the report's name, and it leavesReportChartSchemaan unrefinedChartConfigSchema.extend(...). Its downstream.extend/.shapereaders (ui/packages/typesSpecReportChartSchema,chart.test.ts) are untouched.Rider S1 superseded. S1 named a lint warning in
packages/lint/src/validate-chart-bindings.tsforseriesBy === xAxis. This spec refusal supersedes it, so no lint rule is added.validateChartBindingsstill owns whetherseriesBynames a dimension the dataset declares, which this schema cannot see.Generated:
api-surface/ui.jsonandexport-origins/ui.json(the new export), pluscontent/docs/references/ui/report.mdx(the.describe()text).Tests
A new describe block, ReportSchema refuses a chart seriesBy that cannot split, in
packages/spec/src/ui/report.test.ts, 7 cases:pie,donutandfunnelwithseriesByare refused atchart.seriesByascustom. Each message names the report,type: 'TYPE', the split and the bar-family prescription.barwithseriesBy === xAxisis refused, and its message says the split must name a different dimension.barandlinewith a distinctseriesByparse and keep it.piewithoutseriesByparses.piechart split by its ownxAxisgets exactly one issue, atchart(the existing joined refusal), and none atchart.seriesBy.ChartTypeSchemamember, the set this refusal fires on equalsSINGLE_SERIES_CHART_TYPES.Lint fixtures: every
seriesByfixture invalidate-chart-bindings.test.tsisbarwith a distinct split, so none refuses now. No fixture changed. The suite stays green (80/80).Acceptance notes
git grep seriesByoverexamples/**,packages/qa/**andui/**, plus the hotcrm checkout: every hit is abarwith a distinct split. Zero hits on either refused shape, at 5da3a8c..shapemirror, so it keeps accepting these two shapes until it chains a check. The author then meets the refusal at save or publish, the same position the dashboard arm is in. Noted, not filed.wip(...)commits at the base of the branch carry no trailer pair. The branch is notclaude/issue-*, so it is shared under AGENTS.md §3 and was not rewritten. The squash merge drops them.Verification
All readings are at head
1707dd00unless noted.Ablation, one per arm (src-resolved suite, so no build leg). Mutation through
scripts/ablation-replace.mjs, restored to the HEAD blob each time.if (typeof type === 'string' && (SINGLE_SERIES_CHART_TYPES …).includes(type)) {replaced withif (false) {. Anchor count went 1 → 0, blob4c78418e→ca603b9e. Result: 4 failed (pie, donut, funnel, one-source) and 3 passed. Restored, blob equals HEAD.if (seriesBy === xAxis) {replaced withif (false) {. Anchor count went 1 → 0, blob →b4975efc. Result: 1 failed (same dimension) and 6 passed. Restored, blob equals HEAD.Package runs
pnpm --filter @objectstack/spec build(declarations on): VERDICT command-exit 0.pnpm --filter @objectstack/spec check:generated: 3 stale before--fix(api-surface, export-origins, docs). After--fix, all 14 are up to date.pnpm --filter @objectstack/spec typecheck+pnpm --filter @objectstack/lint exec vitest run src/validate-chart-bindings.test.ts: VERDICT command-exit 0, 80/80.pnpm --filter @objectstack/spec test: VERDICT command-exit 0, Test Files 773 passed (773), Tests 22837 passed + 1 todo.pnpm --filter @objectstack/dogfood test(owed once for the(narrowing)arm, at 1707dd0, closure built first): VERDICT command-exit 0, Test Files 361 passed + 3 skipped (364), Tests 2917 passed + 28 skipped.Derived gates (
dispatch-gates.mjs --commands, 104 lines, each run with stdin closed, exit captured before any pipe)Prerequisite build first:
turbo run build --filter='./packages/**' --filter='@objectstack/dogfood^...'with declarations (VERDICT command-exit 0). Then all 104 lines ran, and every one is:: exit 0. Thecheck:entry-nameabilitylog prints its standing NOT MEASURED line forapi-assembled/qa, which have no callable export; that line is unrelated to this diff.dispatch-gates.mjs --repo objectstack-ai/objectstack --ran: "104 derived famil(ies) accounted for — 104 run, 0 NOT-MEASURED (a DERIVED zero — all 104 recorded an exit code and none of them is 3)", exit 0.The record is at
/mnt/project-files/spec-seat-1/r2026-10-31/out/28424-gates-ran-1707dd00.listin the seat's project folder. Every other family is CI's: see this PR's check-runs.🤖 Generated with Claude Code
https://claude.ai/code/session_01L9qibwvHraeucX94Rvvzrk
Generated by Claude Code