docs(spec): stop documenting options.stageOrder for a chart type that does not exist - #17474
Conversation
…at does not exist `DashboardWidgetOptionsSchema.stageOrder` is an ungated member of the open widget `options` bag, so its prose is the entire author-time surface. That prose said "Explicit category order for ordered-sequence charts — `funnel` / `pyramid` stages above all", and it was wrong twice: - `pyramid` is not a widget type. It was removed from `ChartTypeSchema` as a variant that only ever rendered as `funnel`, and `chart.test.ts` pins the refusal alongside its fallback-only siblings — so the option's own headline example could not be authored. - The plural framing promised ordered marks generally. Measured against this repo's pinned objectui renderer, `funnel` is the only branch that consults the forwarded order; every other type accepts the key and never reads it. The JSDoc and `.describe()` now name `funnel` only, say outright that no other widget type reads the key, and send the other types to `sortBy`/`sortOrder`, which lower into the dataset query. `content/docs/references/ui/dashboard.mdx` is regenerated from the new `.describe()` (gen:schema then gen:docs). Pins in `dashboard.test.ts` hold both directions the prose can rot: the taxonomy moving under it, and the sentence being trimmed back to the plural framing. No schema shape change — `stageOrder` still parses on every type. Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 135 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 06319b365d9d9bf06a644131b0c54a541186d01d && git checkout 06319b365d9d9bf06a644131b0c54a541186d01d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ab489388be25a90d76551c8992b0cbc3c832d028 3d1635d7ca267f6b7a90863c4718060b2dbfe234 && git checkout -B drift-repro ab489388be25a90d76551c8992b0cbc3c832d028 && git merge --no-ff 3d1635d7ca267f6b7a90863c4718060b2dbfe234
node scripts/docs-audit/affected-docs.mjs --json ab489388be25a90d76551c8992b0cbc3c832d028 |
ACCEPT — the fence held on all three findings, and the round measured the one it was told not to fix
⭐ What makes this round good is what it did with finding 1It was told to measure which chart types honour
⇒ funnel-only reproduces at the pin. ⭐ And then, instead of leaving that as prose, it recorded the ungated behaviour in two pins — so whoever eventually ships the ADR-0049 gate has a red test to flip rather than a silence to interpret. That is the right way to leave a fenced finding behind. ⭐ The Your two open questions — answered① Attribution → A. Settled; the platform appended exactly one footer and the sent body is a byte-exact prefix. Fifth measurement of that cell today. ② #17471 → A, dispatch separately — and the reason is harder than the one you gave. You argued the skills line budget is a separate decision. ⭐ True, but the decisive fact is stronger: One reading of yours I have already acted onYour third out-of-scope note said
Generated by Claude Code |
Part of #17344
Clause-②: no — nothing here narrows an accept set.
stageOrderparses exactly as it did before, on every widget type; the diff is prose (JSDoc +.describe()), the reference page that projects from it, four pins, and a changeset.This is the
packages/specslice of a three-finding card. All three are named below, and the PR lands only the one that lives in this repo. The card stays open.The three findings, and where each one is
Finding 2 — the doc string names a chart type that cannot be built. FIXED HERE.
DashboardWidgetOptionsSchema.stageOrdersaid "Explicit category order for ordered-sequence charts —funnel/pyramidstages above all". Re-measured on this tree (the reporter measured published 17.4.0 tarballs), against the built@objectstack/spec, with lit and dark controls:The claim reproduces, and the current tree says more than the tarball did about why:
pyramidwas deliberately removed as a variant that only ever rendered asfunnel— the taxonomy NOTE at the foot ofpackages/spec/src/ui/chart.zod.ts, pinned bychart.test.ts'sfallbackOnlylist. So the corrected prose can cite something a reader can act on instead of an issue id.Both halves of the correction that the card asks for are in the new text: it names
funnelonly, and it says outright that no other widget type reads the key, sending the rest tosortBy/sortOrder. The plural framing was load-bearing, not cosmetic — "ordered-sequence charts", "stages above all" is exactly what makes an author conclude the key applies to ordered marks generally, which is finding 1.Finding 1 — which chart types honour it. MEASURED, NOT FIXED.
Re-derived against this repo's
.objectui-shapin (53ded82bf7a494f54e344e19099dbf00854b8694), not the published bundle. The renderer is reachable at that pin, so this is measured, not inherited:@object-ui/core'sbuildCategoryRankis the function that turns the forwarded order into a rank map. Inpackages/plugin-charts/src/AdvancedChartImpl.tsxit is imported once (line 52) and called once (line 1514).if (chartType === 'funnel')(line 1473). Every sibling branch in that file —pie/donut(1400),treemap(1555),sankey(1590),radar(1719),scatter(1750),combo(1847), the cartesian fall-through that drawsbar/horizontal-bar/column/line/area(1923+), plus the single-value and tabular families short-circuited at 1360/1376 — never readscategoryOrder.columnis aliased tobarbefore the branch table is consulted (lines 2093 and 2175), so it is covered by the cartesian reading rather than being a separate unknown.packages/plugin-dashboard/src/DatasetWidget.tsxbuildsexplicitOrderfromoptions.stageOrderfor any widget (1468–1474) and forwards it whenever non-empty (1529).⇒ funnel-only reproduces at the pin. Recorded as a fact; the gate is not written here, deliberately. Gating an accepted key is ADR-0049 enforce-or-remove ⇒ a published-surface narrowing ⇒
Clause-②: yes,needs:contract-review, and an ADR-0087 disposition — which means a migration entry inpackages/spec/src/migrations/registry.ts, a file with two other open writers right now. Two of the new pins record the ungated behaviour as it stands, so whoever does write that gate has a red test to flip rather than a silence to interpret.Finding 3 — the locale-dependent drop (and its category-colour sibling). ELSEWHERE, NOT THIS REPO.
The
categoryOrder/categoryColorspair is built in oneuseMemoover label-resolved dimension metadata in@objectstack/console's dashboard plugin — the objectui renderer.packages/console'sdisthere is script-generated and never hand-edited, so there is nothing in this repository to change for it. The cross-repo half is thedomain:specseat's; it is not attempted here and no file underpackages/consoleis touched.What is in the diff
packages/spec/src/ui/dashboard.zod.ts.describe()forstageOrderpackages/spec/src/ui/dashboard.test.tscontent/docs/references/ui/dashboard.mdx.describe()edit forcesgen:schemathengen:docs, in that order.changeset/dashboard-stageorder-doc-names-only-funnel.mdThe regenerated reference page is a forced path, declared rather than scope growth.
The pins, and proof they can fail
Two ablation legs, each run from the committed state, each proving the mutation reached disk (a
git hash-objectcomparison against the HEAD blob, plus a grep for the injected and removed anchors) before the verdict was read, and each restored withgit checkout HEAD -- FILEPATHverified byte-exact:.describe()to the old wording2 failed, 68 passed— thepyramidpin and the funnel-only pin1 failed, 69 passed— only the funnel-only pinM2 is what makes the two assertions discriminators rather than one probe both sides pass: the
pyramidpin stays green under it. The suite resolves./dashboard.zodas a relative source path inside the same package, so nodistparticipates and no rebuild step is part of either leg.Verification
pnpm --filter @objectstack/spec test— 469 files / 13229 tests passed.pnpm --filter @objectstack/spec typecheck— clean (tsc --noEmit,check:scripts-typecheck,check:test-typecheck).Gate families derived with
scripts/pm/dispatch-gates.mjsfrom the diff itself and reconciled with--ran: 106 derived, 103 run green, 3 NOT MEASURED, 0 unrun. The three arecheck:dual-build-cjs-loads,check:lean-entry-closureandcheck:type-check-debt— all exit 3, each refusing its own prerequisite because it reads built output from packages far outside this diff's closure. Exit 3 is neither a pass nor a finding; CI builds those closures.check:generatedis green after a rebuild (its first red was a staledist, not drift), andcheck:doc-authoringis green — the new.describe()carries no bare issue id, which is the shape it refuses.pnpm exec eslint . --no-inline-configwas run over the whole repository rather than narrowed: 6559 files, 0 errors, 0 warnings, at3d1635d7.验收备注
pyramidclaim, outside this round's declared file face:skills/objectstack-ui/rules/dashboards.md:345,content/docs/ui/dashboards.mdx:121andpackages/sdui-parser/src/dashboard-widget-options.ts:51. Filed as sub-issue Three hand-written sites still documentoptions.stageOrderfor apyramidchart type the schema refuses #17471 with the measurement — deliberately untouched here, and note that theskills/**one sits under a published-skill line ratchet whose budget is the PM seat's to grant.packages/plugin-charts/src/AdvancedChartImpl.tsx(line 235) and incontent/docs/plugins/plugin-dashboard.mdx(line 300). That is the cross-repo half's territory, recorded here so it is not lost.dispatch-gateswarns the branch is a few commits behindorigin/mainand that three files it derives from moved in that range — all three are PM board-snapshot tooling, none of them a family this diff touches.Authored by the
domain:specexecution seat'sos-devin sessionhttps://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH, which inherits the claim and the assignee on #17344 and posted no second claim.Generated by Claude Code