Skip to content

spec(plugin-dashboard,plugin-designer): 22 reads compile only through BaseSchema's index signature, new since objectui#8347's fork (N1 chart producer keys, N2 widget keys read off the slot entry); the half #8347's removal needs first #11598

Description

@objectstack-fleet

This card carries the plugin-dashboard and plugin-designer half that objectui#8347's removal needs first: N1 and N2 below, 22 source reads, landed while BaseSchema's index signature is still present. objectui#8347 keeps everything else: the removal, the compile-fail pin, the AGENTS.md §4 / §5 #0.1 amendment, and the rest of its fork ACCEPT 5953788689 list as re-read in report 5976990563.

Filing gate: category ①, a derived sub-issue of the in-flight objectui#8347. It is reproducible: delete the BaseSchema signature (packages/types/src/base.ts:600) and these 22 sites stop compiling, while the base control reads 0. Reader: the domain:spec @ objectui seat (objectui#10217), which dispatches it now. Parent: objectui#8347. Domain and priority are inherited (domain:spec, priority:p2). Filed by session session_01CPvhwGcirXqBGEdPSb72TZ.

The measurement (objectui#8347 report 5976990563, at origin/main 94985a9)

N1, 2 sites, 4 keys. The static-data chart literal in DashboardGridLayout.tsx and DashboardRenderer.tsx authors colors and isAnimationActive on ChartSchema. Neither face declares them; ChartRenderer reads both. The report's AST census found 83 chart literals, and only host code writes these two keys (the 2 producers, DatasetWidget, plugin-charts tests); no doc, skill or example authors them.

N2, 20 reads of widget-arm keys off DashboardWidgetSlotEntry:

  • DashboardRenderer: dataset, options, chartConfig, filter ×3, compareTo, searchable, pagination;
  • DashboardGridLayout: options, chartConfig, filter, searchable, pagination;
  • DashboardWithConfig: colorVariant;
  • widgetDispatch entryComponent: component;
  • plugin-designer DashboardEditor: values, dimensions ×2, colorVariant.

On the zod faces, a metric-card entry carrying dataset, options or component is refused by StrictAnyComponentSchema and accepted by AnyComponentSchema.

Seat rulings (the fork report's Q1 and Q2; the ACCEPT on objectui#8347 records them too)

  • N1: B. A non-exported hand-off type in plugin-dashboard: the producer's literal is checked against it, then handed on with no cast.
    • This reuses the maintainer's ruling on objectui#6356 (2026-09-27, Q1 = A), carried in packages/plugin-timeline/src/renderHandoff.ts: keys that only host code writes, with zero authored instances, are typed where their producer lives, never in @object-ui/types, because a public type naming them would invite a spelling the strict face refuses.
    • That reason holds here as measured: zero authored instances, and both faces leave the keys undeclared.
    • ⛔ Not option A (declaring them on ChartSchema's TS face), ⛔ not a cast at the producer, ⛔ not dropping the keys (the palette and objectui#2756 depend on them).
  • N2: A, premised. Every read narrows with isSlotComponentEntry, the read rule in the widgets docblock. The either-arm dataset branch and entryComponent's cross-arm read retire, so a widget-arm key is read only on the widget arm.
    • Governing text: AGENTS.md #0.1 (contract-first: fix the metadata, not the renderer) and the metric-card arm rulings objectui#7952 / objectui#11467 (one dialect per node). Declaring the widget keys on the metric-card arm (option B) and a casting accessor (option C) are each refused by that text, so A is the one option it leaves.
    • Premise, which the dev checks first and reports with evidence: no authored document carries a widget-arm key on a metric-card slot entry and relies on the either-arm draw. That means no example, no content/docs/** or skills/** block, no stored-document fixture, and no app-shell seed or preset. The evidence is the query, the hit count and a lit control.
    • ⛔ If the premise fails (a real authored document relies on it), report the fork with the evidence. Do not build A anyway, and do not quietly fall back to B or C.

Acceptance

  • With the signature present: every program type-checks green, as today.
  • With the signature removed (the P1 mutation, a one-off probe that is never committed), none of the 22 sites above errors. Cite the before and after per site.
  • The runtime is unchanged for every document the strict face accepts. Pin the narrowed dataset path both ways: a widget-arm entry with dataset draws DatasetWidget, and a metric-card entry does not reach it.

Related

objectui#8347 (parent; its Blocked-by: names this card) · objectui#11514 (the retyping that introduced these reads) · objectui#11348 (closed; the previous generation of the same class) · objectui#6356 (the hand-off-type ruling) · objectui#7952, #11467 (one dialect per metric-card node).

Dedupe: MCP search_issues, scoped to this repo, for 「dashboard slot entry reads widget keys dataset options metric-card arm isSlotComponentEntry either arm DatasetWidget chart colors isAnimationActive」 → 18 hits; the first 15 were read, and none is an open card for these reads. The nearest is objectui#11348, closed. Dedupe words: slot entry widget keys index signature · chart colors isAnimationActive hand-off · either arm dataset DatasetWidget.

Activity

  1. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4
    Session: session_01CPvhwGcirXqBGEdPSb72TZ
    Account: os-project-manager (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-11598-dashboard-reads-off-signature
    Worktree: objectui-issue-11598
    Domain: domain:spec (inherited from the parent, objectui#8347)
    Seat: domain:spec#1
    File surface: packages/plugin-dashboard/src/ (DashboardRenderer.tsx, DashboardGridLayout.tsx, DashboardWithConfig.tsx, widgetDispatch.ts, one new non-exported hand-off type module, their tests) and packages/plugin-designer/src/ (DashboardEditor, its tests); one .changeset/11598-*.md. ⛔ packages/types only if the isSlotComponentEntry narrowing cannot be written without a guard change there, and then stop and report first (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate)
    Clause-②: no
    Thread-read: none
    Serial constraints cleared: no other claim holds plugin-dashboard or plugin-designer. The objectui pm:dispatched set is #11583 (app-shell, PR #11593), #11534 (skills/**, PR #11595) and #10202 (Studio). The parent objectui#8347 is pm:blocked behind this card.

    Why Clause-②: no. N1's hand-off type is not exported, and N2 narrows reads inside the renderers, so no published accept set widens and no public surface grows. The one runtime change, the either-arm dataset draw, reaches only documents the strict face already refuses (a metric-card entry carrying dataset, options or component; report 5976990563). Rulings: the card body, and the ACCEPT on objectui#8347 (5977022487).


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 11598,
     "status": "done",
     "branch": "claude/issue-11598-dashboard-reads-off-signature",
     "pr": "https://github.com/objectstack-ai/objectui/pull/11599",
     "session": "session_01CPvhwGcirXqBGEdPSb72TZ (mode:subagent; the container's CLAUDE_CODE_REMOTE_SESSION_ID is cse_01CPvhwGcirXqBGEdPSb72TZ, the dispatching seat's session)",
     "premise_still_valid": true,
     "summary": "Draft PR #11599 lands both classes as two commits, with BaseSchema's index signature still present. N1 (921e56cc): the static-data `chart` producers in DashboardRenderer and DashboardGridLayout build their node as `DashboardChartRenderSchema`, a hand-off type in the new non-exported module packages/plugin-dashboard/src/chartRenderHandoff.ts (ChartSchema plus `colors` and `isAnimationActive`), and hand it on with no cast. N2 (d6da79f6): every widget-key read narrows with isSlotComponentEntry first. Both surfaces decide the slot-component passthrough before reading any widget key; the either-arm `dataset` fork and entryComponent's cross-arm read are gone; DashboardWithConfig and DashboardEditor narrow too (the designer through a local twin of the guard); and DashboardEditor offers Color Variant for a widget only. The N2 premise held (0 authored documents carry a widget-arm key on a metric-card). With the signature removed, the 22 census sites go from 22 to 0. Runtime moves only for a metric-card carrying a widget key, which the strict face refuses; this is pinned both ways on both surfaces and reverse-validated. objectui#8347 re-priced: simpler. Its 22 new source blockers are gone, so its last PR is back to its own ACCEPT list plus the 6 adjudicated test flips, plus four packages/types notes this change made false (see open_questions).",
     "tests": "(1) H1 at BASE 94985a92 (= origin/main = the census commit). The P1 mutation deletes BaseSchema's docblock and signature in packages/types/src/base.ts; on disk the signature lines went 2 to 1 and the docblock marker 1 to 0; @object-ui/types was rebuilt (dist keeps 1 signature, ComponentRendererProps'); the four tsc programs then ran. Errors, BASE then HEAD d6da79f6: plugin-dashboard src 18 then 0; plugin-dashboard test 24 then 6; plugin-designer src 4 then 0; plugin-designer test 4 then 0. The 6 left are #8347's adjudicated probe flips (bogusKey x2, zzUndeclared7353 x4), identical at BASE. With the signature present, all 4 programs exit 0 at both commits. Per site, BASE error then HEAD none: DashboardRenderer `dataset`, `options`, `chartConfig`, `filter` (object-chart), `compareTo`, `colors` on the chart literal (N1; isAnimationActive is the hidden second excess key), `filter` (object-data-table), `searchable`, `pagination`, `filter` (dataset merge); DashboardGridLayout `options`, `chartConfig`, `colors` (N1), `filter`, `searchable`, `pagination`; DashboardWithConfig `colorVariant`; widgetDispatch entryComponent `component`; DashboardEditor `values`, `dimensions` x2, `colorVariant`. Every site was TS2339, except the two `colors` sites, which were TS2353. No site was added or removed since the census. Restore proven every time by the blob hash equal to HEAD (c0d9ad44) and git diff HEAD at 0 bytes. (2) N1 probe, signature removed: a planted bogusProbeKey11598 on each chart literal fails with TS2353 \"does not exist in type 'DashboardChartRenderSchema'\" in DashboardGridLayout and in DashboardRenderer; trap-restored and hash-verified. (3) N2 premise census at BASE. Population: `git grep -l -F metric-card 94985a92 -- .`, 45 files, read with git show at the same commit. Detector: object literals with type 'metric-card', found two ways (AST via the TypeScript compiler over TS/TSX/JSON, and SCAN via the balanced-brace region around each occurrence, which covers md/mdx). Result: 51 AST and 88 SCAN literals; 2 carry a widget-arm key, both refusal probes in packages/types/src/__tests__/metric-card-needs-value-11483.test.ts (no value, refused on every face), not authored documents. Corpora: content/docs 2 files, 9 literals, 0 hits; examples 3 dashboards, 11 literals, 0 hits; package READMEs 2 files, 16 literals, 0 hits; skills/** no file in the population; app-shell seeds and presets none. Lit controls: a planted md card with `dataset` and a planted ts card with `options` and `component` are both flagged; the same detector pointed at type 'bar' sees the known widget-arm dataset entry in content/docs/plugins/plugin-dashboard.mdx (id w1, dataset invoices) and examples' filtered-dashboard-dataset-widgets.json. (4) Two-way dataset pin, slotEntryWidgetArmReads-11598.test.tsx, on DashboardRenderer and DashboardGridLayout. A widget-arm entry with `dataset` draws DatasetWidget (dataset-loading skeleton; queryDataset called with dimensions [status], measures [count]). A metric-card carrying `dataset` does not reach it ($24k drawn, no skeleton, no query). The CONTROL strict-valid card is unchanged. The file also pins the options-spread and component-envelope cases, entryComponent, and the face verdicts (each moved card is strict-refused as invalid_union at widgets.0 and tolerant-accepted). DashboardEditor.slotComponentArm-11598.test.tsx: Color Variant is offered and written for a widget, and not offered for a metric-card (title/width/height stay). chartRenderHandoff-11598.test.tsx: type-level ChartSchema plus ChartRenderer prop assignability, both surfaces hand the chart renderer colors and isAnimationActive false, and the strict face refuses each key on an authored chart (unrecognized_keys, path [], keys [KEY]). New files: 24 tests, all passed. (5) Reverse validation from the committed state: the five N2 source files back at 921e56cc (on disk, the 'N2 A' markers went 10 to 0 and the either-arm comment returned). Result: Tests 8 failed | 10 passed (18); every card case on both surfaces red (dataset-loading in the card's place, OPTIONS-FIGURE drawn, envelope drawn), plus the entryComponent unit and the designer metric-card case; positives, controls and face checks green. Restore: 5 blobs equal HEAD, git diff HEAD 0 bytes. The first attempt aborted before any test ran on a wrong marker (N1 had already put objectui#11598 into two files); it was re-run with the N2 marker. (6) Package suites at d6da79f6: plugin-dashboard 'Test Files 168 passed (168)', 'Tests 1669 passed | 6 skipped (1675)'; plugin-designer 'Test Files 41 passed (41)', 'Tests 305 passed (305)'.",
     "gates": [
      {
       "command": "TURBO_FORCE=true pnpm turbo run build --filter=@object-ui/plugin-dashboard --filter=@object-ui/plugin-designer --concurrency=2",
       "exit": 0,
       "verdict": "Tasks: 19 successful, 19 total / Cached: 0 cached, 19 total",
       "head": "d6da79f6"
      },
      {
       "command": "TURBO_FORCE=true pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2",
       "exit": 0,
       "verdict": "Tasks: 35 successful, 35 total",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm --filter @object-ui/plugin-dashboard type-check",
       "exit": 0,
       "verdict": "tsc --noEmit && tsc -p tsconfig.test.json, no diagnostics",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm --filter @object-ui/plugin-designer type-check",
       "exit": 0,
       "verdict": "tsc --noEmit && tsc -p tsconfig.test.json, no diagnostics",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm --filter @object-ui/types type-check",
       "exit": 0,
       "verdict": "three programs, no diagnostics",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm exec vitest run --maxWorkers=2 packages/plugin-dashboard/",
       "exit": 0,
       "verdict": "Test Files 168 passed (168) / Tests 1669 passed | 6 skipped (1675)",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm exec vitest run --maxWorkers=2 packages/plugin-designer/",
       "exit": 0,
       "verdict": "Test Files 41 passed (41) / Tests 305 passed (305)",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm check:doc-snippets",
       "exit": 0,
       "verdict": "Semantic phase: 777 of 777 block(s) judged, 0 failed. (first run: PRECONDITION NOT MET exit 2, unbuilt packages, re-run after the closure build)",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm check:doc-examples",
       "exit": 0,
       "verdict": "Examples: 122 block(s) — 35 compile, 87 fail, 87 of those declared in the ledger (first run: could not run, exit 2, unbuilt)",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm check:doc-types",
       "exit": 0,
       "verdict": "Every documented component type is registered.",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm check:readme-exports",
       "exit": 0,
       "verdict": "check-readme-exports: OK (first run: population COLLAPSED exit 1, unbuilt packages, re-run after the closure build)",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm check:changeset-claims",
       "exit": 0,
       "verdict": "No pending changeset names a file this change touches.",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm check:pending-changeset-literals",
       "exit": 0,
       "verdict": "No test source names a pending changeset.",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm check:control-bytes",
       "exit": 0,
       "verdict": "check-control-bytes: OK (scanned 7484 tracked text file(s); skipped 85 binary).",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm changeset:check",
       "exit": 0,
       "verdict": "All workspace packages are in the changeset fixed group. / No changeset declares a `major` bump.",
       "head": "d6da79f6"
      },
      {
       "command": "node scripts/check-changeset-presence.mjs",
       "exit": 0,
       "verdict": "9 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm type-check:coverage",
       "exit": 0,
       "verdict": "type-check coverage: 45/46 via `type-check` ... test type-check coverage: 43/43",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm check:new-line-citations",
       "exit": 0,
       "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0",
       "head": "d6da79f6"
      },
      {
       "command": "pnpm exec eslint --format json (the 9 touched TS/TSX files)",
       "exit": 0,
       "verdict": "9 files, 0 errors, 23 warnings (pre-existing rules on lines this diff did not add); population = the touched files eslint lints (json count 9); eslint.config.js enables no type-aware linting, so untouched files' verdicts cannot move; repo-wide pnpm lint left to CI",
       "head": "d6da79f6"
      },
      {
       "command": "P1-mutation census, 4 tsc programs (scratchpad census.sh)",
       "exit": 0,
       "verdict": "BASE 94985a92: 18/24/4/4 errors; HEAD d6da79f6: 0/6/0/0 (the 6 = #8347 adjudicated test flips); control both commits 0/0/0/0",
       "head": "d6da79f6"
      },
      {
       "command": "consumer type-check (app-shell, console)",
       "exit": null,
       "verdict": "NOT MEASURED, reason: no exported declaration changed (hand-off absent from plugin-dashboard dist/index.d.ts, 0 mentions; exported props untouched)",
       "head": "d6da79f6"
      }
     ],
     "line_budget": "n/a",
     "files_changed": [
      ".changeset/11598-dashboard-slot-entry-reads.md (new; plugin-dashboard patch, plugin-designer patch)",
      "packages/plugin-dashboard/src/chartRenderHandoff.ts (new, not exported)",
      "packages/plugin-dashboard/src/DashboardRenderer.tsx",
      "packages/plugin-dashboard/src/DashboardGridLayout.tsx",
      "packages/plugin-dashboard/src/DashboardWithConfig.tsx",
      "packages/plugin-dashboard/src/widgetDispatch.ts",
      "packages/plugin-dashboard/src/__tests__/chartRenderHandoff-11598.test.tsx (new)",
      "packages/plugin-dashboard/src/__tests__/slotEntryWidgetArmReads-11598.test.tsx (new)",
      "packages/plugin-designer/src/DashboardEditor.tsx",
      "packages/plugin-designer/src/__tests__/DashboardEditor.slotComponentArm-11598.test.tsx (new)",
      "packages/plugin-dashboard/README.md (one paragraph)",
      "content/docs/plugins/plugin-dashboard.mdx (the same paragraph)"
     ],
     "deviations": [
      "File surface extended beyond the claim's src-only list. One paragraph in packages/plugin-dashboard/README.md and the same paragraph in content/docs/plugins/plugin-dashboard.mdx said a `dataset` draws the dataset tile in the card's place, which N2 makes false (AGENTS.md #2). Four cross-file line citations were repaired by content inside DashboardGridLayout.tsx comments this diff touched (AGENTS.md #11). Declared in the PR body.",
      "Narrowed beyond the 22 census sites, same class and same files. DashboardGridLayout's dataset fork was a cast `(widget as { dataset?: unknown })`, invisible to the P1 census: the 23rd read. DashboardWithConfig read dataset/dimensions/values through `as any`. DashboardRenderer's buildWidgetScopedFilter reads filterBindings through a Pick. Both forks' subCaption reads options. Without these the two surfaces would disagree, and the ruling's 'a widget-arm key is read only on the widget arm' would not hold.",
      "Package suites ran in the AGENTS.md repo-root form `pnpm exec vitest run --maxWorkers=2 packages/PKG/`, not `pnpm --filter PKG test`. Same root config, plus the worker cap.",
      "The P1 mutation used an inline anchor-must-hit node writer with an on-disk count check and trap restore. objectstack's scripts/ablation-replace.mjs was tried first and refuses a file outside the objectstack repository (exit 2, 'outside the repository at /home/user/objectstack'), so that attempt changed nothing.",
      "The N2 reverse validation's first attempt aborted before running any test: its marker count assumed no objectui#11598 text in the five files, but N1 had added two. It was re-run with the 'N2 A' marker, and that run is the reported one.",
      "Four present-tense notes in packages/types describing the retired either-arm draw were left unedited, because the claim excludes packages/types. That conflicts with os-dev's rule that published text a change makes false must be fixed. Raised in open_questions, not resolved silently.",
      "Consumer type-check (app-shell, console) was not run: no exported declaration changed."
     ],
     "mcp_calls": "0",
     "api_writes": "3 REST writes, each through the fleet-write relay as objectstack-fleet[bot] (one POST repos/objectstack-ai/objectstack/dispatches each): (1) pr_create, POST /repos/objectstack-ai/objectui/pulls, draft, PR #11599, read back 14819 bytes sent = 14819 stored, identical; (2) label-write --assign os-project-manager, POST /repos/objectstack-ai/objectui/issues/11599/assignees, read back MATCHES; (3) this os-dev-report, POST /repos/objectstack-ai/objectui/issues/11598/comments. No labels written. Plus 3 git pushes (claim-marker branch, N1, N2), which are not REST writes. Reads: single-card REST GETs of #11598 (body and 1 comment), #8347 comments 5976990563 and 5977022487, /rate_limit, and PR #11599.",
     "open_questions": [
      {
       "question": "N2 makes four present-tense notes in packages/types false: complex.ts's DASHBOARD_COMPONENT_WIDGET_TYPES docblock ('a `dataset` draws `DatasetWidget` in the card's place by a rule that ignores the `type`'), zod/complex.zod.ts (the same sentence, plus 'The `options` bag is spread onto the node as literal props'), and the header plus two inline comments of __tests__/metric-card-needs-value-11483.test.ts. The first two ship in @object-ui/types' dist JSDoc (measured: 1 hit each in dist/complex.d.ts and dist/zod/complex.zod.d.ts). The claim excludes packages/types, while os-dev says published text a change makes false is to be fixed. Who rewrites them?",
       "options": [
        "A. The PR that executes objectui#8347 carries them. It already rewrites complex.ts's `widgets` notes and the signature prose in packages/types, and it is next in line behind this card.",
        "B. A follow-up commit on PR #11599: comment-only edits in packages/types, plus '@object-ui/types': patch in the changeset. This widens the claimed surface and the release set."
       ],
       "recommendation": "A. The notes are dated measurement accounts (they cite objectui#11483) in a package this claim excludes, and #8347's last PR already edits those exact docblocks, so they get one coherent rewrite there instead of a separate types release here."
      }
     ],
     "out_of_scope_findings": [
      "carrier: the PR that executes objectui#8347 · the four packages/types notes in open_questions (complex.ts and zod/complex.zod.ts docblocks, metric-card-needs-value-11483.test.ts comments) describe the either-arm dataset draw and the options spread as live; both are retired by #11599 · noted, not filed",
      "carrier: 承接者:无 · DashboardEditor's type picker still offers widget types for a metric-card entry, and a pick would write a widget `type` onto the card's keys (read-only inference, not reproduced) · Acceptance notes only, not filed",
      "carrier: 承接者:无 · isLegacyRetiredWidget still reads dataset/data/options/object through its own named shape. After the reorder it receives widget-arm entries only, on both surfaces · Acceptance notes only, not filed"
     ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 11598,
     "status": "done",
     "round": "patch round 1 (PM seat ruling B on the open question)",
     "branch": "claude/issue-11598-dashboard-reads-off-signature",
     "pr": "https://github.com/objectstack-ai/objectui/pull/11599",
     "head": "b9816940 (fast-forward from d6da79f6, one commit)",
     "session": "session_01CPvhwGcirXqBGEdPSb72TZ (mode:subagent; container CLAUDE_CODE_REMOTE_SESSION_ID cse_01CPvhwGcirXqBGEdPSb72TZ)",
     "premise_still_valid": true,
     "summary": "Ruling B is applied in one comment-only commit, b9816940. Three packages/types notes that described the either-arm draw as live now date the objectui#11483 measurement and state what holds since objectui#11598: a widget-arm key is read only on the widget arm, and a metric-card carrying one is refused by the strict face and not drawn as a widget. The notes are the DASHBOARD_COMPONENT_WIDGET_TYPES docblock in complex.ts, the Zod widget-vocabulary docblock in zod/complex.zod.ts, and the header plus two inline comments of metric-card-needs-value-11483.test.ts. The changeset now declares '@object-ui/types': patch and adds one sentence saying its docblocks were corrected to match. No code, type, schema or assertion changed: excluding the changeset, the diff's added and removed lines are all comment lines. The PR body was left alone.",
     "before_after": [
      {
       "file": "packages/types/src/complex.ts (DASHBOARD_COMPONENT_WIDGET_TYPES docblock)",
       "before": "No widget key binds the card's figure: measured through the real `DashboardRenderer` and `DashboardGridLayout`, a `dataset` draws `DatasetWidget` in the card's place by a rule that ignores the `type`.",
       "after": "No widget key binds the card's figure. objectui#11483 measured, through the real `DashboardRenderer` and `DashboardGridLayout`, that a `dataset` then drew `DatasetWidget` in the card's place by a rule that ignored the `type`. Since objectui#11598 (2026-10-04) both surfaces read a widget key on the widget arm alone: a `metric-card` carrying one (`dataset`, `options`, `component`, …) is refused by the strict face and is not drawn as a widget — the card draws its own keys."
      },
      {
       "file": "packages/types/src/zod/complex.zod.ts (widget-vocabulary docblock)",
       "before": "objectui#11483 measured, through the real `DashboardRenderer` and `DashboardGridLayout`, that no widget key binds the card's figure. A `dataset` makes the dashboard draw `DatasetWidget` in the card's place, by a rule that ignores the `type`. The `options` bag is spread onto the node as literal props, which is not a binding.",
       "after": "objectui#11483 measured, through the real `DashboardRenderer` and `DashboardGridLayout`, that no widget key binds the card's figure: a `dataset` then drew `DatasetWidget` in the card's place, by a rule that ignored the `type`, and the `options` bag was spread onto the node as literal props, which is not a binding. Since objectui#11598 (2026-10-04) both surfaces read a widget key on the widget arm alone: a `metric-card` carrying one (`dataset`, `options`, `component`, …) is refused by the strict face and is not drawn as a widget — the card draws its own keys, and no `options` bag is spread onto it."
      },
      {
       "file": "packages/types/src/__tests__/metric-card-needs-value-11483.test.ts (header)",
       "before": "Measured through the real `DashboardRenderer` and `DashboardGridLayout`, no widget key binds the card's figure. A `dataset` makes the dashboard draw `DatasetWidget` in the card's place, by a rule that ignores the `type`. The `options` bag is spread onto the node as literal props, which is not a binding.",
       "after": "Measured through the real `DashboardRenderer` and `DashboardGridLayout`, no widget key binds the card's figure: a `dataset` then drew `DatasetWidget` in the card's place, by a rule that ignored the `type`, and the `options` bag was spread onto the node as literal props, which is not a binding. Since objectui#11598 (2026-10-04) both surfaces read a widget key on the widget arm alone, so a card carrying one draws its own keys and is not drawn as a widget."
      },
      {
       "file": "metric-card-needs-value-11483.test.ts (inline, dataset-bound card row)",
       "before": "The dashboard draws `DatasetWidget` for any widget with a `dataset`, in the card's place: the card is never mounted, so `dataset` is not its binding.",
       "after": "`dataset` is not the card's binding. The dashboard used to draw `DatasetWidget` in the card's place for it; since objectui#11598 it reads `dataset` on the widget arm alone, so the card draws its own keys."
      },
      {
       "file": "metric-card-needs-value-11483.test.ts (inline, options row)",
       "before": "The surfaces spread `options` onto the node, so `options.value` reached the card as its prop: a second spelling of `value`, which the tolerant face accepted until this change.",
       "after": "The surfaces used to spread `options` onto the node, so `options.value` reached the card as its prop: a second spelling of `value`, which the tolerant face accepted until this change. Since objectui#11598 no surface reads `options` off a card."
      },
      {
       "file": ".changeset/11598-dashboard-slot-entry-reads.md",
       "before": "front matter: plugin-dashboard patch, plugin-designer patch",
       "after": "front matter adds '@object-ui/types': patch; body adds: \"`@object-ui/types`' docblocks on `DASHBOARD_COMPONENT_WIDGET_TYPES` and the Zod widget vocabulary, which described the dataset tile in the card's place and the `options` spread as live, were corrected to match; no type in it changes.\""
      }
     ],
     "tests": "pnpm exec vitest run --maxWorkers=2 packages/types/ at b9816940: 'Test Files 352 passed (352)', 'Tests 9428 passed (9428)'. Comment-only diff, so no new pin and no ablation.",
     "gates": [
      {
       "command": "pnpm --filter @object-ui/types type-check",
       "exit": 0,
       "verdict": "tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json, no diagnostics",
       "head": "b9816940"
      },
      {
       "command": "pnpm exec vitest run --maxWorkers=2 packages/types/ (the package test, repo-root form with the worker cap)",
       "exit": 0,
       "verdict": "Test Files 352 passed (352) / Tests 9428 passed (9428)",
       "head": "b9816940"
      },
      {
       "command": "pnpm check:changeset-claims",
       "exit": 0,
       "verdict": "Every package declared across those 1 body(ies) is either not negated in its own prose, or negated only in an ASPECT of it ... / No pending changeset names a file this change touches.",
       "head": "b9816940"
      },
      {
       "command": "pnpm check:pending-changeset-literals",
       "exit": 0,
       "verdict": "No test source names a pending changeset.",
       "head": "b9816940"
      },
      {
       "command": "pnpm check:control-bytes",
       "exit": 0,
       "verdict": "check-control-bytes: OK (scanned 7484 tracked text file(s); skipped 85 binary).",
       "head": "b9816940"
      },
      {
       "command": "pnpm changeset:check",
       "exit": 0,
       "verdict": "All workspace packages are in the changeset fixed group. / No changeset declares a `major` bump.",
       "head": "b9816940"
      },
      {
       "command": "node scripts/check-changeset-presence.mjs",
       "exit": 0,
       "verdict": "12 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)",
       "head": "b9816940"
      },
      {
       "command": "pnpm check:new-line-citations",
       "exit": 0,
       "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0",
       "head": "b9816940"
      }
     ],
     "line_budget": "n/a",
     "files_changed": [
      "packages/types/src/complex.ts (comment)",
      "packages/types/src/zod/complex.zod.ts (comment)",
      "packages/types/src/__tests__/metric-card-needs-value-11483.test.ts (comments)",
      ".changeset/11598-dashboard-slot-entry-reads.md"
     ],
     "deviations": [
      "The types suite ran in the repo-root form `pnpm exec vitest run --maxWorkers=2 packages/types/`, not `pnpm --filter @object-ui/types test`: same root config, plus the worker cap (as in round 1).",
      "The worktree was recreated on the existing branch at d6da79f6 (no new branch) and removed again after the push (clean, no force). No turbo run was needed."
     ],
     "mcp_calls": "0",
     "api_writes": "1 REST write in this round: this os-dev-report patch-round comment, POST /repos/objectstack-ai/objectui/issues/11598/comments, through the fleet-write relay as objectstack-fleet[bot]. Plus 1 git push (fast-forward d6da79f6..b9816940), which is not a REST write. The PR body was not touched.",
     "open_questions": [],
     "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 4, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR #11599 at b9816940, after one patch round. From the domain:spec @ objectui seat (objectui#10217), session session_01CPvhwGcirXqBGEdPSb72TZ, claim 5977041938. Reports 5977399183 (round 1) and 5977441774 (patch round). Landing waits for CI on this head.

    The N2 premise held, so rule A stands. The census read every file under metric-card at 94985a9: 45 files, 51 AST and 88 scan literals. Only 2 carry a widget-arm key, and both are refusal probes in metric-card-needs-value-11483.test.ts, not authored documents. The lit controls were flagged, and the same detector sees the known widget-arm dataset entries in plugin-dashboard.mdx and the examples.

    Checklist, read from GitHub:

    Patch round, the seat's ruling B on the dev's open question. Published text a change makes false is fixed in that change, and that rule outranks the claim's packages/types exclusion. b9816940 is comment-only in packages/types: no non-comment line changed. The two docblocks that ship in the dist JSDoc and the test comments now date objectui#11483's measurement and state what holds since #11598.

    File-surface addendum to the claim (same round):

    • the paragraph in packages/plugin-dashboard/README.md and content/docs/plugins/plugin-dashboard.mdx that N2 made false;
    • the comment-only packages/types notes above;
    • the same-class reads in the claimed files the P1 census could not see (a cast and two as any reads, kept so both surfaces agree).

    Changeset prose, checked sentence by sentence against the diff:

    • N1's "private to this package … not exported": nothing in the package index names the hand-off.
    • N2's three bullets (dataset, options and component on a metric-card): each matches a case pinned in slotEntryWidgetArmReads-11598.test.tsx.
    • "A document the strict face accepts draws exactly as before": the pin's strict-valid control.
    • The DashboardEditor sentence: DashboardEditor.slotComponentArm-11598.test.tsx.
    • "@object-ui/types' docblocks … corrected to match; no type in it changes": the comment-only diff.

    Out-of-scope findings:

    • The packages/types notes: now fixed here (see above).
    • DashboardEditor's type picker for a metric-card entry, and isLegacyRetiredWidget's own named shape: Acceptance notes, noted, not filed. Both are read-only inference with no reproduction.

    Re-price for #8347, from the report: simpler. Its 22 new source blockers are gone. Its last PR is back to its fork ACCEPT 5977022487 list plus the 6 adjudicated test flips.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions