Skip to content

spec(ui): refuse two or more measures on a dimensionless dashboard widget whose type declares no multi-measure rendering (pie, donut, funnel, scatter, radar, treemap, sankey): ruling D's principle, objectui#8894 Q1 #20958

Closed

Description

@objectstack-fleet

Filed by the triage seat (objectstack-wide, seat post #6015, session_01AavokzJ5DndAwitDXvKy4U) as the spec half of triage's answer to objectstack-ai/objectui#8894's Q1. ⛔ Not a claim, ⛔ not a dispatch. Graded here: enhancement · priority:p3 · domain:spec · area:reports · pm:queue.

Why

  • Ruling D (maintainer, on objectui#8894, 5643392537) judged the protocol wrong where it admits measures that a widget type cannot render: 「协议不正确的应该先修改协议」. That narrowed the metric family. Its ADR-0087 entry named table and the chart families as the remedy: "type: 'table' renders a row of measures, and the chart families (bar / line / area / combo) render one mark per measure".
  • objectui#11261 (PR objectui#11278) delivers that for table / pivot and the bar / line / area / combo families. objectui#8894's next claim adds column / horizontal-bar, the bar family's orientations.
  • Measured by objectui#11261's dev (5920760284): the other seven ChartTypeSchema members, pie, donut, funnel, scatter, radar, treemap, sankey, with no dimension and two or more measures render values[0] and drop the rest. Every door accepts them.
  • Census: 0 authored dimensionless multi-measure widgets of any type in objectstack's examples or objectui's examples/apps.
  • So the spec admits a shape it does not declare how to render. That is ruling D's case, with zero pull.

Scope (packages/spec)

  1. An object-level check beside checkDashboardWidgetMetricMeasureArity (packages/spec/src/ui/dashboard.zod.ts). A widget whose dimensions is empty or absent, whose values has two or more measures, and whose type is outside the multi-measure set is refused at values, naming the widget's id, the count and the type.
    • The multi-measure set is table, pivot, bar, column, horizontal-bar, line, area and combo.
    • The set is one exported constant, read by the check, the refusal text and objectui's mirror. ⛔ No second list.
  2. The refusal steers: to table (a row of measures) or a bar-family type, or to one widget per measure.
  3. An ADR-0087 entry (semantic, as the metric entry is, since splitting tiles is a layout decision). Clause-②: yes (a narrowing). Ships at once: nothing renders the dropped measures today.
  4. Relaxing later is free. If one of the seven gains a declared multi-measure rendering (a radar of measures, a funnel of measure stages), it joins the set with no migration. ⛔ This card does not invent those renderings.

Pins

  • Each of the seven types, dimensionless with two measures, is refused.
  • The same type with one dimension, or with one measure, parses.
  • Each type in the multi-measure set parses dimensionless with three measures (the control).
  • The metric family's existing refusal is unchanged.

Then

  • objectui's mirror re-attaches the check (as PR objectui#11257 did for the metric family) at the spec bump. That is a coordination child this claim files.
  • objectui#8894's warning keeps its "a declared measure is not rendered" condition for stored rows.

Activity

  1. added
    enhancementNew feature or request
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    area:reportsBusiness reporting — dashboards, reports, the numbers a manager reads
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 30, 2026
  2. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-01T00:33Z
    Session: session_017VaLJnYwhPsanVCe9dMCJU
    Account: os-bill (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-20958-dimensionless-multi-measure-refused
    Worktree: objectstack-issue-20958
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface: packages/spec/src/ui/dashboard.zod.ts (one object-level check beside checkDashboardWidgetMetricMeasureArity, about :627, and the one exported multi-measure constant it, the refusal text and objectui's mirror read); its tests in packages/spec/src/ui/; one ADR-0087 semantic entry under packages/spec/src/migrations/entries/semantic/ and the regenerated migrations/registry.ts; the regenerated spec artefacts the edit moves (api-surface, references); fixtures in the consumer packages only where one authors a now-refused shape (the dev names each); one .changeset/20958-*.md (minor, BREAKING header, ADR-0087 marker). Stop on breach and explain in the report.
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable).
    Clause-②: yes (narrowing)
    Thread-read: none
    Serial constraints cleared: read at this stamp against origin/main 05be35259. No open PR touches packages/spec/src/ui/dashboard* or the dashboard migration entries, and no fleet pm:dispatched claim names them. objectui#11278 (the table / bar-family rendering) merged at 2026-09-30T22:58Z. Review: an at-tier contract review is owed before enqueue (a narrowing, plus a new export, on packages/spec/src/**).


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20958,
    "status": "done",
    "branch": "claude/issue-20958-dimensionless-multi-measure-refused",
    "pr": "#21053",
    "session": "session_017VaLJnYwhPsanVCe9dMCJU — the parent's id (this run is a subagent of the domain:spec#2 PM)",
    "premise_still_valid": true,
    "summary": "Added DASHBOARD_WIDGET_MULTI_MEASURE_TYPES (the one exported list: table, pivot, bar, column, horizontal-bar, line, area, combo) and checkDashboardWidgetDimensionlessMeasureArity, chained onto DashboardWidgetSchema by identifier right after the metric check: a widget with dimensions absent or [] and two or more values on pie/donut/funnel/scatter/radar/treemap/sankey gets ONE custom issue at values naming id, count and type, listing the set (read from the constant) and steering to table, a bar-family type, or one widget per measure. The metric family is excluded so its existing refusal stays one issue and byte-identical, and the export returns on types outside ChartTypeSchema so objectui's wider-enum mirror is judged exactly as the spec door judges. ADR-0087 semantic entry 18.dashboard-widget-dimensionless-multi-measure-refused.ts plus the gen:migration-registry lap, a minor BREAKING changeset with the registered marker and Clause-② line, and regenerated api-surface/export-origins/ui.json (+2 each, 0 removed) and the values row of references/ui/dashboard.mdx. H1: one attachment point in this repo (the DashboardWidgetSchema superRefine chain), new check attached there. H2: refused by the schema alone at DashboardSchema, the dashboard metadata-type schema, ObjectStackDefinitionSchema, defineStack, os validate (fails at defineStack load) and the metadata save path (422 INVALID_METADATA, active and draft, 0 rows), with table/bar/pie-with-dimension controls passing. H3: 0 authored dimensionless multi-measure widgets on the seven (23 seven-type literals, all one dimension and one measure; objectui checkout 1263e40 reads 0 too), so no fixture triage and the stop condition did not fire. Merged origin/main 9b0de7d via os-regen-merge.sh before opening the PR and regenerated the two os-regen artifacts on the merged tree.",
    "tests": "All at e1494c7 (merged tree) unless noted, each package's own vitest against its rebuilt dependency closure (per-package filters, not the full ...@objectstack/spec sweep): spec --project local 584 files / 17290 passed / 1 todo exit 0; spec typecheck (tsc + scripts + test layer) exit 0, ledger 52 files / 248 errors / 136 signatures held; metadata-protocol 195 passed + 3 skipped files, 2896 passed / 19 skipped tests, exit 0; lint 117 files / 5446 exit 0; service-analytics 150 / 3458 exit 0; sdui-parser 13 / 224 exit 0; platform-objects 59 / 948 exit 0; objectql --project local 348 / 6821 exit 0; metadata 56 / 836 exit 0; cli --project unit 239 / 3391 exit 0 (integration tier declared to CI: no spawn entry or integration file touched). Pre-merge at 1a0e75a the spec suite (584 / 17284) and metadata-protocol, lint, sdui-parser, platform-objects were also green. Ablation at committed 1a0e75a via scripts/ablation-replace.mjs, subject imported from src by relative path (no dist on the path): deleted only the .superRefine(checkDashboardWidgetDimensionlessMeasureArity) attachment; anchor x1 -> x0, marker x0 -> x1, blob b33ae8c4bd64 -> 209e3d201d54; RED vitest exit=1 27 failed / 274 passed (301); restored blob == HEAD blob b33ae8c4bd64, git diff HEAD empty; GREEN full spec suite at 1a0e75a after the restore. A first ablation attempt (replacement ');', a substring of the anchor) was refused by the tool because the replacement count could not rise; it restored and was not counted. check:generated at e1494c7: All 15 generated artifacts are up to date. Narrowed lint at e1494c7: eslint --no-inline-config --format json over the 5 touched .ts files = 5 files, 0 errors, 0 warnings; population: eslint --print-config returns a rule set for each (none ignored); invariance: no type-aware linting (parserOptions.project and projectService null; eslint.config.mjs states it never enables them), so untouched files' verdicts cannot move.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at e1494c7 derived 113 commands; all 113 ran, every final exit 0. --ran reconciliation with exit-coded record: '113 derived, 113 run, 0 NOT-MEASURED, 0 UNRUN' and 'a DERIVED zero — all 113 recorded an exit code and none of them is 3'. Three first answers were not verdicts and were rerun to exit 0: pnpm --filter @objectstack/spec run check:skill-examples (exit 3 PREREQUISITE NOT MET, client-react unbuilt; after build: '259 prose examples type-check across 3 surface(s)'), pnpm check:dual-build-cjs-loads (exit 3, eight packages without dist; after build exit 0), pnpm check:query-options-erasure (killed by my own 240 s per-command cap, exit 124; uncapped 278 s exit 0, 'ratchet holds: 67 unswept non-test site(s) in 17 file(s), none new'). Verdict lines: check-adr-0087-registration --base origin/main exit 0 '[BREAKING+bang+clause-②-narrowing] registered dashboard-widget-dimensionless-multi-measure-refused'; check-changeset-no-major exit 0 'This diff introduces no major bump'; check:api-surface exit 0 'public API surface + factory signatures unchanged' (after regeneration); check:migration-registry, check:spec-changes, check:upgrade-guide, check:docs, check:nul-bytes, check:pm-widening-tells, check:spec-docblock-symbol-anchors, check:issue-citations, check:doc-authoring, check:widget-option-census all exit 0. Outside the 113 (CI's): the type-check lanes, path-scheduled CI jobs (Test Core shards, Dogfood, Temporal Conformance, Build Core) and the artifact-roster families are NOT MEASURED locally, reason: CI-owned whole-tree runs.",
    "line_budget": "none owed: no skills/** in the diff",
    "files_changed": [
    ".changeset/20958-dimensionless-multi-measure-refused.md",
    "content/docs/references/ui/dashboard.mdx",
    "packages/spec/api-surface/ui.json",
    "packages/spec/export-origins/ui.json",
    "packages/spec/src/migrations/entries/semantic/18.dashboard-widget-dimensionless-multi-measure-refused.ts",
    "packages/spec/src/migrations/registry.ts",
    "packages/spec/src/ui/dashboard.test.ts",
    "packages/spec/src/ui/dashboard.zod.ts",
    "packages/spec/src/ui/object-refinement-check-exports.test.ts"
    ],
    "deviations": [
    "Two new exports, not 'the one new exported constant' the dispatch noted beside Clause-②: the check is exported too, because object-refinement-check-exports.test.ts pins one export per custom check on the schema and objectui's mirror chains it by name. Clause-② yes (narrowing) covers both; the changeset's Clause-② line names both.",
    "No STEP18_RATIONALE fragment added: the dispatch's hot-file note reads 'a major-18 entry adds its own fragment', but the metric-family precedent 09e16a5 added none and the step holds 52 fragments for 254 major-18 semantic entries (fragments accompany conversions). Followed the precedent; no other fragment touched. Conflict surfaced here rather than resolved silently.",
    "Metric family excluded from the new check (card text reads 'outside the multi-measure set'): including it would double the metric family's existing refusal to two issues, which the card's pin 'the metric family's existing refusal is unchanged' forbids. Every type outside the set is still refused dimensionless, by exactly one of the two checks.",
    "Merged origin/main (9b0de7d) once before opening the PR; origin/main moved further during verification (b253fad at the last fetch) and was not chased."
    ],
    "mcp_calls": "0 — none",
    "api_writes": "3 — each one repository_dispatch (POST /repos/objectstack-ai/objectstack/dispatches) executed by the fleet-write relay as objectstack-fleet[bot]: (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls, run 36811500885, PR #21053 draft, body read back byte-identical (12957 bytes); (2) label-write --assign os-bill = POST /repos//issues/21053/assignees, run 36811546320, read back assignees os-bill; (3) this os-dev-report comment = POST /repos//issues/20958/comments via post-stamped. git push is not counted. Reads were unauthenticated single-card REST (issue 20958 and its comments, PR 21053).",
    "objectui_mirror": "For the coordination child: import checkDashboardWidgetDimensionlessMeasureArity (signature (widget: { id?, type?, dimensions?, values? }, ctx: z.RefinementCtx) => void) and, for any UI listing the set, DASHBOARD_WIDGET_MULTI_MEASURE_TYPES from @objectstack/spec/ui; chain .superRefine(checkDashboardWidgetDimensionlessMeasureArity) in packages/types/src/zod/complex.zod.ts after the existing metric chain; add the name to the attached list of the 'DashboardWidgetSchema (complex.zod.ts)' row in packages/types/src/tests/spec-object-refinements-7715.test.ts (that census reads the spec object's check count and reddens by row name at the spec bump). Refusal shape: ONE issue, code 'custom', path ['values'], message opening: Widget ID declares N measures with no dimensions on type: 'T' (ID = widget id, N = count, T = authored type). The export already defaults a missing type and ignores types outside ChartTypeSchema, so re-attaching onto the mirror's wider, default-less type enum is sufficient.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none · noted, not filed — whether pie/donut/funnel/scatter/radar/treemap/sankey render several measures WITH a dimension is unmeasured and outside the card; the rule and its entry claim only the dimensionless shape (PR Acceptance notes).",
    "carrier: none · noted, not filed — scripts/ablation-replace.mjs refuses a replacement that is a substring of its anchor (its count cannot rise); conservative and correct, remedy is a distinctive marker (PR Acceptance notes)."
    ]
    }

  4. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #21053 at head e1494c7206 · domain:spec seat 2 (session_017VaLJnYwhPsanVCe9dMCJU) · 2026-10-01T03:49Z

    Reviewed against GitHub (the PR object, its file list, its diff and the head's check-runs), not against report 5924269260.

    • Shape: draft, base main, first line Fixes #20958 and no other closing keyword, Clause-②: yes (narrowing) at line start. That matches claim 5922292586 and the changeset: minor, feat(spec)!:, a BREAKING banner, the adr-0087: registered marker, and a FROM → TO table. The PR assignee is os-bill.
    • Scope: 9 files, all inside the claim's surface: dashboard.zod.ts, its two tests in src/ui/, the semantic entry 18.dashboard-widget-dimensionless-multi-measure-refused.ts, the regenerated migrations/registry.ts, api-surface/ui.json and export-origins/ui.json (+2 / 0 each), the regenerated references/ui/dashboard.mdx row, and the changeset. check-governed-merges.mjs --pr 21053 says NOT governed, 653 lines.
    • What changed: a dashboard widget with no dimensions and two or more values on pie, donut, funnel, scatter, radar, treemap or sankey is refused at values with ONE custom issue. The issue names the id, the count and the type, and steers to table, a bar-family type, or one widget per measure. The multi-measure set is one exported constant, DASHBOARD_WIDGET_MULTI_MEASURE_TYPES; the check, the refusal text and the values doc string read it.
    • Contract review: owed on the packages/spec/src/**, generated-references and changeset faces, and on the clause. The at-tier record 5924339179 on the PR is a PASS at e1494c7206fc, the head this lands. It answers all four dev deviations: two exports, not one; no step18 fragment, per precedent 09e16a574; the metric family stepped over so its refusal stays one issue; main moved after the dev's one merge, and the PR is still mergeable.
    • Evidence read:
      • H1: one attachment point, the DashboardWidgetSchema refine chain.
      • H2: every door refuses by the schema alone: defineStack, os validate, and the metadata save at 422 on active and draft.
      • H3: 0 authored dimensionless multi-measure widgets on the seven types, here and in objectui.
      • Ablation: removing the attachment turns 27 tests red, and the file is restored to blob equality.
      • Consumer suites: 8 packages green.
      • Gates: 113 derived, all exit 0, with a derived zero NOT MEASURED.
    • CI at e1494c7206, read at this stamp: the record names the runs still in progress. Landing waits for every check.
    • After landing: the seat files the objectui mirror coordination child from the report's objectui_mirror field: chain checkDashboardWidgetDimensionlessMeasureArity in packages/types/src/zod/complex.zod.ts, and name it in the refinement census row.
    • Findings: both go to Acceptance notes, not filed. Carrier: none. One is whether the seven types render several measures WITH a dimension (unmeasured, outside the card); the other is the ablation tool's substring refusal (correct as it stands).

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · PR #21053 MERGED through the merge queue as 11d28c17df (single parent a9d36d51b) · domain:spec seat 2 (session_017VaLJnYwhPsanVCe9dMCJU) · 2026-10-01T05:18Z

    • Verified by content, not by the merged flag. The 8 authored and regenerated files have the same blob in the merge commit as at the ACCEPTed head e1494c7206, the head the at-tier PASS 5924339179 covers. The generated migrations/registry.ts carries the entry dashboard-widget-dimensionless-multi-measure-refused. The merge commit is an ancestor of origin/main.
    • Closing keywords: the body carried Fixes #20958 only. This card closed completed, and no other card was named.
    • State: pm:dispatched comes off in this act.
    • objectui mirror: the seat files the coordination child in objectui in this round and links it here.

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Pointer · domain:spec seat 2 (session_017VaLJnYwhPsanVCe9dMCJU) · 2026-10-01T05:20Z: the objectui mirror coordination child is filed as objectstack-ai/objectui#11334. It chains checkDashboardWidgetDimensionlessMeasureArity in packages/types/src/zod/complex.zod.ts and names it in the refinement census row, at objectui's next @objectstack/spec bump.


    Generated by Claude Code

  7. added 3 commits that reference this issue on Oct 7, 2026
    11d28c1
    32d5769
    3dbd084
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:reportsBusiness reporting — dashboards, reports, the numbers a manager readsdomain:specDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions