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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
dashboard publishes only columns/gap/className as inputs — widgets, title, header, globalFilters, dateRange, refreshInterval all draw unknown-prop while the renderer honours them #5742
Found while implementing the #5709 census (out-of-scope there; recorded, not touched). Same class as the shipped #4668 / #5091 cards: keys the renderer honours that the registration never publishes, so the authoring manifest warns an author off keys that work.
Measured on origin/main at 8689166f6
The dashboard registration (packages/plugin-dashboard/src/index.tsx, the ComponentRegistry.register('dashboard', DashboardRenderer, ...) call) declares exactly three inputs: columns, gap, className. Its defaultProps even carries widgets: [] — but widgets is not an input.
DashboardRenderer (same package) reads all of these off the schema:
schema.widgets — the entire widget tree (read throughout; e.g. the schema.widgets ?? [] reads in the layout pass)
schema.title / schema.label — header title (spec-canonical label per framework#1878)
Consequence for an author: validateTree over the live manifest reports unknown-prop on every one of those keys on an inline dashboard node — including widgets itself, the key the new #5709 unconsumed-options warning descends into. The two diagnostics side by side read incoherently: the validator disclaims the prop and then reasons about its contents.
dashboard is in PUBLIC_BLOCKS (packages/core/src/registry/public-blocks.ts), so this is contract surface, serialized into sdui.manifest.json and sdui-intrinsics.d.ts.
What this is not
Not a request to blanket-declare everything: #5091 settled that some honoured keys are deliberately non-author surface, per-key, by ruling. The ask is the same per-key triage for the dashboard block: declare the authored ones (at minimum widgets, which every example in content/docs/plugins/plugin-dashboard.mdx authors), and pin the deliberate exclusions the way gridNonAuthorKeys.test.tsx does.
Landing: packages/plugin-dashboard/src/index.tsx — the ComponentRegistry.register('dashboard', …) call that publishes three inputs while DashboardRenderer honours seven. packages/core/src/registry/public-blocks.ts is the reference surface, not the fix site.
Graded pm:queue rather than finding: the body names the landing call, and the remedy is the one already shipped twice for this exact class (#4668 / #5091) — publish the inputs the renderer reads. No open question.
objectui three-stream split (maintainer 2026-08-21). Routed via the maintainer direct-dispatch channel, this session, verbatim: 「objectui 有 79 张卡在车道视图之外(占该仓 35%),你帮我分批处理」 · 「继续 批 2 批 3」. PM session session_0124Qg8rLvpXnQDwCmpKUmaJ. Not a Routine triage fire — the triage seat may re-grade.
Claim — domain:ui execution seat. PM round 28, session session_01EuPCi56cnGyykygi3z9w4m, branch claude/issue-5742-dashboard-declare-honoured-inputs. Dispatching at contract-review tier (clause ②: dashboard is in PUBLIC_BLOCKS, so its input list is serialized into sdui.manifest.json and sdui-intrinsics.d.ts — publishing an input widens the accept surface).
Taken on the triage grading's own reasoning: the body names the landing call and the remedy is the one already shipped twice for this class (#4668 / #5091), so there is no open question to route back.
⚠️ The one thing that is not mechanical, restated for the dev: #5091 settled that some honoured keys are deliberately non-author surface, decided per key — so this is not "declare all seven". Each honoured key gets a decision, and the deliberate exclusions get pinned the way gridNonAuthorKeys.test.tsx pins them, rather than being left as a silent gap that reads identically to an oversight. widgets is the floor (every example in content/docs/plugins/plugin-dashboard.mdx authors it, and #5709's unconsumed-options warning already descends into it).
⛔ packages/core/src/registry/public-blocks.ts is the reference surface, not the fix site.
{
"issue": 5742,
"status": "done",
"branch": "claude/issue-5742-dashboard-declare-honoured-inputs",
"pr": "https://github.com/objectstack-ai/objectui/pull/5829",
"premise_still_valid": true,
"summary": "Per-key triage shipped on the #4668/#5091 line (declare only what the renderer reads AND the strict spec DashboardSchema accepts). Declared 7 new inputs on the `dashboard` registration — widgets (array), label + description (string|locale-map unions), header, globalFilters, dateRange (objects/array), refreshInterval (number) — with author-facing descriptions; columns/gap/className untouched. Pinned two deliberate exclusions gridNonAuthorKeys-style: `title` (legacy spelling, spec rejects by name, the schema.title||schema.label read STAYS and is render-pinned) and `aria` (spec tombstone from the #3896 audit close-out; measured correction to the issue body: this package has ZERO schema.aria read sites, so there is no 'still reads it' leg for it). Docs Schema API block and a minor changeset included. One honoured key (`name`) raised as an open question instead of guessed.",
"tests": "New pin file packages/plugin-dashboard/src/__tests__/dashboardAuthoredInputs.test.tsx (30 tests: author-reach with unknown-prop/type-mismatch controls, exclusion pins with spec verdicts + declared controls + render legs, and the generated-artifact face via the same manifestFromConfigs/generateDts pair gen-manifest.ts uses — the manifest artifacts are build-time codegen, not checked in, so the change to them is pinned through their own generators). Union at final HEAD 6a1e9040e, repo root: pnpm exec vitest run packages/plugin-dashboard/ + the 5 console registry gates (registry-inputs-spec-parity, public-contract, ga-honoured-inputs-author-reach, component-input-union-specimens, public-block-binding-reach) => 'Test Files 81 passed (81) / Tests 836 passed (836)', lock VERDICT command-exit 0. pnpm --filter @object-ui/plugin-dashboard type-check && lint => exit 0 (0 errors) after building the dependency closure. Script gates all exit 0 with verdict lines read from their own output: check-changeset-presence ('declares 1 changeset'), check-phantom-dependencies (new @object-ui/sdui-parser devDep declared), check-control-bytes, check-doc-component-types, check-doc-snippet-types ('Every covered documentation snippet compiles against the built types' — ran after building its --build-filter package set; my mdx edit adds only a plaintext block), check-changeset-fixed, check-changeset-no-major. Reverse verification against the commit (no dist rebuild involved: root vitest aliases @object-ui/* to src, so the runs read the mutated source directly; mutation = git checkout HEAD~1 -- packages/plugin-dashboard/src/index.tsx, confirmed by the run itself flipping and by git status; restore confirmed by git diff HEAD --stat empty): 20 of 30 red on the reverted registration (all 9 author-reach rows back to unknown-prop, all 7 off-arm rows, both not-published control legs, both artifact legs), then 30/30 green restored. Non-discriminating legs, by design: reachability + probe-key control, the five spec-verdict legs (they pin the spec, not the registry), unknown-prop on title/aria (true on both legs), and the two render legs (read sites untouched). CI status at report time: in_progress (report delivered at draft-PR time per standing rule).",
"open_questions": [
{
"question": "Should the inline `dashboard` node publish `name`? The renderer reads schema.name (keys the dashboards.{name}.* translation lookups) and the spec ACCEPTS name (requires it on the document form) — the shipped 'spec accepts + renderer reads => declare' line would put it in. But it is the document identity key written by the stored-dashboard path (DashboardView hands the loaded document to the renderer), no docs example authors it inline, and no sibling registration anywhere declares a `name` input. Its absence is marked pending (not ruled) in the registration comment and the pin test docblock.",
"options": [
"A — declare it (string input, description steering authors to the stored-document identity), consistent with the reverse-parity principle that spec-declared keys must be discoverable",
"B — rule it non-author for the inline node and pin it with producer evidence (DashboardView / document loader), leaving the read untouched"
],
"recommendation": "B — on the four axes: no measured inline-authoring pull (every docs example and both in-repo hosts reach name via the stored document); identity keys belong to documents, not inline nodes; publishing it teaches AI authors to fabricate identities that mostly resolve no translations (silent inert key); startup scope stays tight. The cost of B is that the pin cannot use the 'spec rejects by name' leg (spec accepts name), so it rests on producer evidence alone — which is why this is raised rather than decided."
}
],
"out_of_scope_findings": [
"filed as #5830: DashboardComponentSchema.aria in @object-ui/types declares a key the spec tombstoned and no renderer reads, under a stale 'Aligned with @objectstack/spec AriaPropsSchema' comment (finding label, unassigned)"
]
}
(The comment above is this same report whose HTML-comment marker the body sanitizer stripped — objectui#5581's known behavior; this one leads with the literal marker text so the PM scan finds it. Content identical.)
{
"issue": 5742,
"status": "done",
"branch": "claude/issue-5742-dashboard-declare-honoured-inputs",
"pr": "https://github.com/objectstack-ai/objectui/pull/5829",
"premise_still_valid": true,
"summary": "Per-key triage shipped on the #4668/#5091 line (declare only what the renderer reads AND the strict spec DashboardSchema accepts). Declared 7 new inputs on the `dashboard` registration — widgets (array), label + description (string|locale-map unions), header, globalFilters, dateRange (objects/array), refreshInterval (number) — with author-facing descriptions; columns/gap/className untouched. Pinned two deliberate exclusions gridNonAuthorKeys-style: `title` (legacy spelling, spec rejects by name, the schema.title||schema.label read STAYS and is render-pinned) and `aria` (spec tombstone from the #3896 audit close-out; measured correction to the issue body: this package has ZERO schema.aria read sites, so there is no 'still reads it' leg for it). Docs Schema API block and a minor changeset included. One honoured key (`name`) raised as an open question instead of guessed.",
"tests": "New pin file packages/plugin-dashboard/src/__tests__/dashboardAuthoredInputs.test.tsx (30 tests: author-reach with unknown-prop/type-mismatch controls, exclusion pins with spec verdicts + declared controls + render legs, and the generated-artifact face via the same manifestFromConfigs/generateDts pair gen-manifest.ts uses — the manifest artifacts are build-time codegen, not checked in, so the change to them is pinned through their own generators). Union at final HEAD 6a1e9040e, repo root: pnpm exec vitest run packages/plugin-dashboard/ + the 5 console registry gates (registry-inputs-spec-parity, public-contract, ga-honoured-inputs-author-reach, component-input-union-specimens, public-block-binding-reach) => 'Test Files 81 passed (81) / Tests 836 passed (836)', lock VERDICT command-exit 0. pnpm --filter @object-ui/plugin-dashboard type-check && lint => exit 0 (0 errors) after building the dependency closure. Script gates all exit 0 with verdict lines read from their own output: check-changeset-presence ('declares 1 changeset'), check-phantom-dependencies (new @object-ui/sdui-parser devDep declared), check-control-bytes, check-doc-component-types, check-doc-snippet-types ('Every covered documentation snippet compiles against the built types' — ran after building its --build-filter package set; my mdx edit adds only a plaintext block), check-changeset-fixed, check-changeset-no-major. Reverse verification against the commit (no dist rebuild involved: root vitest aliases @object-ui/* to src, so the runs read the mutated source directly; mutation = git checkout HEAD~1 -- packages/plugin-dashboard/src/index.tsx, confirmed by the run itself flipping and by git status; restore confirmed by git diff HEAD --stat empty): 20 of 30 red on the reverted registration (all 9 author-reach rows back to unknown-prop, all 7 off-arm rows, both not-published control legs, both artifact legs), then 30/30 green restored. Non-discriminating legs, by design: reachability + probe-key control, the five spec-verdict legs (they pin the spec, not the registry), unknown-prop on title/aria (true on both legs), and the two render legs (read sites untouched). CI status at report time: in_progress (report delivered at draft-PR time per standing rule).",
"open_questions": [
{
"question": "Should the inline `dashboard` node publish `name`? The renderer reads schema.name (keys the dashboards.{name}.* translation lookups) and the spec ACCEPTS name (requires it on the document form) — the shipped 'spec accepts + renderer reads => declare' line would put it in. But it is the document identity key written by the stored-dashboard path (DashboardView hands the loaded document to the renderer), no docs example authors it inline, and no sibling registration anywhere declares a `name` input. Its absence is marked pending (not ruled) in the registration comment and the pin test docblock.",
"options": [
"A — declare it (string input, description steering authors to the stored-document identity), consistent with the reverse-parity principle that spec-declared keys must be discoverable",
"B — rule it non-author for the inline node and pin it with producer evidence (DashboardView / document loader), leaving the read untouched"
],
"recommendation": "B — on the four axes: no measured inline-authoring pull (every docs example and both in-repo hosts reach name via the stored document); identity keys belong to documents, not inline nodes; publishing it teaches AI authors to fabricate identities that mostly resolve no translations (silent inert key); startup scope stays tight. The cost of B is that the pin cannot use the 'spec rejects by name' leg (spec accepts name), so it rests on producer evidence alone — which is why this is raised rather than decided."
}
],
"out_of_scope_findings": [
"filed as #5830: DashboardComponentSchema.aria in @object-ui/types declares a key the spec tombstoned and no renderer reads, under a stale 'Aligned with @objectstack/spec AriaPropsSchema' comment (finding label, unassigned)"
]
}
PM ruling on the open question — option B: name is NOT an author input on the inline dashboard node.domain:ui execution seat, session session_01EuPCi56cnGyykygi3z9w4m.
I am ruling B, but on a stronger ground than the report's balance-of-axes, and the difference matters for the pin's wording.
The shipped heuristic does not fire here — this is not a close call
The line is "spec accepts + renderer reads ⇒ declare". The report reads the first clause as satisfied because "the spec ACCEPTS name". But it accepts it on the document form, where it is required — not on the inline node. The shape the spec is accepting name on is not the shape this registration publishes inputs for.
So the premise of the heuristic is not met, and B wins without needing the four axes at all. title and aria were excluded because the spec rejects them; name is excluded because the spec's acceptance is about a different shape. Those are two different exclusion reasons and the pin should say which one it is — a future reader who sees name excluded next to title will otherwise assume "spec rejects it" and be wrong.
The axis that would have decided it anyway
Publishing name as an inline input would teach authors — human and, more to the point, AI — to fabricate a dashboard identity inline. Per the report's own measurement, that identity keys dashboards.{name}.* translation lookups, so a fabricated one resolves nothing and fails silently. That is a newly manufactured silently-inert key: precisely the defect class this card exists to remove. Curing seven instances while minting an eighth is not a trade worth making.
Carry the cost forward honestly
The report names it and it must survive into the code: this pin cannot use the "spec rejects by name" leg, because the spec does accept name. It rests on producer evidence alone — DashboardView / the document loader hands the loaded document to the renderer. That makes it a weaker pin than the title / aria ones, and the docblock should say so, so nobody later reads its silence as the same strength of guarantee. ⛔ Do not paper over that by asserting a spec rejection that does not exist.
Concretely: replace the "pending (not ruled)" marker in the registration comment and the pin test docblock with this ruling, stating (a) that the spec accepts name on the document form only, (b) that the read stays untouched, and (c) that the pin's evidence is the producer, not a spec verdict.
On the rest of the card
The per-key work is right. Declaring seven and pinning two exclusions gridNonAuthorKeys-style is exactly the #5091 line, and ⛔ the schema.title || schema.label read correctly stays while title leaves the published surface — advertised and honoured are different questions, and the render leg pins that.
The measured correction to the issue body is the more valuable half and is accepted: the body implies aria is a "renderer honours it" key, and the measurement found zero schema.aria read sites in this package, so there is no "still reads it" leg for it at all. Recording that rather than inheriting the body's framing is the right instinct — and #5830 (the DashboardComponentSchema.aria declaration in @object-ui/types, under a stale "Aligned with @objectstack/spec AriaPropsSchema" comment) is the correct place for the residue, filed unassigned for triage rather than folded in.
(Amendment run. Leading with both marker spellings in one comment: the body sanitizer strips short <...> fragments on this repo, which is what forced a duplicate report comment on the first run of this card.)
{
"issue": 5742,
"status": "done",
"branch": "claude/issue-5742-dashboard-declare-honoured-inputs",
"pr": "https://github.com/objectstack-ai/objectui/pull/5829",
"premise_still_valid": true,
"summary": "AMENDMENT to the existing PR #5829 — comment-only, no re-implementation. New head 77295c734 (was 6a1e9040e); PR still open, still draft, 2 commits, no second PR. Recorded the PM ruling (option B: `name` is NOT an author input on the inline `dashboard` node) in the two places that carried the 'pending (not ruled)' marker: the registration comment in packages/plugin-dashboard/src/index.tsx and the docblock of packages/plugin-dashboard/src/__tests__/dashboardAuthoredInputs.test.tsx. Each now states all three required points: (a) the exclusion is NOT a spec rejection — the spec ACCEPTS `name`, but on the DOCUMENT form where it is required, not on the inline node, so the shipped 'spec accepts + renderer reads => declare' heuristic never fires here (its premise is about a different shape), with an explicit instruction not to carry `title`'s 'the spec rejects it' over to this key; (b) the `schema.name` read STAYS untouched and still keys the `dashboards.{name}.*` lookups; (c) the evidence is PRODUCER-side alone (DashboardView / the document loader hands the loaded document to the renderer), stated plainly as a WEAKER pin than the `title`/`aria` ones which each assert a re-checkable spec verdict — no spec rejection is asserted for `name` anywhere. Both places also carry the supporting reason (publishing `name` inline would teach authors, AI authors especially, to fabricate a dashboard identity resolving no translations and failing silently — a newly manufactured silently-inert key, the defect class this card removes). Nothing else touched: the seven declared inputs, the `schema.title || schema.label` read, the `title`/`aria` exclusion pins, the tests and #5830 are all untouched — `git diff` shows every changed line is a comment line (48 insertions / 14 deletions across exactly those 2 files). One deviation to flag: the dispatch asked for a fresh worktree ../objectui-5742-amend, but git refuses ('already used by worktree at /home/user/objectui-5742') because this branch was still checked out in this same session's dedicated worktree from the first run; I worked in that existing dedicated worktree (a linked worktree, not the shared checkout, so worktree-first holds) after re-running pnpm install, since its node_modules had been cleaned up. See the open question about the now-stale PR body.",
"tests": "Comment-only delta, so there is NO behavioural leg and I did not run a reverse verification — saying so rather than reporting one is the honest answer here. Discriminating evidence is the marker removal plus the suite staying green. NEGATIVE CONTROL: `grep -rn -i -E 'pending|not ruled|open question|nor pinned|rather than guessed'` over both files => ZERO hits (grep exit 1). POSITIVE CONTROL: `grep -c 'on the DOCUMENT form'` => 1 in each of the two files; `grep -n 'PRODUCER alone'` and `grep -n 'WEAKER'` each present in both. The edit itself was applied by a script that asserts each splice anchor matches EXACTLY once (it would have thrown otherwise) and reported the real byte counts replaced (index.tsx lines 60-62, 215 chars -> 1290; test docblock lines 43-54, 801 chars -> 1729), so this was not a zero-hit no-op edit. Comment-only scope proved mechanically: `git diff -U0 | grep '^[+-]' | grep -v '^[+-]\\s*(//|\\*|/\\*)'` => zero non-comment changed lines (exit 1). GATES, exit codes captured by redirect-then-capture (never through a pipe), verdict lines quoted from the gates' own output. Run at final HEAD 77295c734, and the tree tested is provably the committed tree: after commit, `git status --porcelain` and `git diff HEAD --stat` are both EMPTY, and no edit occurred between the suite run and the commit. (1) `pnpm exec vitest run packages/plugin-dashboard/ --maxWorkers=2` from the REPO ROOT (not --filter, not from a package cwd), via the shared verify lock: 'os-verify-lock: VERDICT command-exit 0 - held the lock 179s - waited 356s' with 'Test Files 76 passed (76) / Tests 712 passed (712)'. (2) The pin file specifically, re-run post-commit at 77295c734: 'Test Files 1 passed (1) / Tests 30 passed (30)' — the 30 pins from the first run all still green (the aggregate reporter does not name passing files, hence the targeted run as collection proof). (3) `node scripts/check-changeset-presence.mjs` EXIT=0, post-commit, its own verdict line: '2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/dashboard-declare-honoured-inputs.md' — the existing changeset does still cover this delta, confirmed by running the gate rather than assuming. (4) `node scripts/check-control-bytes.mjs` EXIT=0, post-commit: 'check-control-bytes: OK (scanned 4845 tracked text file(s); skipped 85 binary)'. No type widening, no loosened pin, no weakened assertion was needed anywhere. No bare version literal was written into any prose. CI at report time: in_progress — the push restarted the gate window, and per the standing rule I am not polling it.",
"open_questions": [
{
"question": "The PR #5829 BODY still carries the superseded framing and is now falsified by this commit — the `name` row reads '**raised as an open question, not guessed**', and a whole '### The open question: `name`' section says 'Its absence from `inputs` is therefore *pending*, not ruled — stated in the registration comment and the pin test's docblock'. That sentence is now false: those two markers are exactly what this amendment removed. The body's Verification section also still cites `6a1e9040e` as the head. The dispatch scoped me to comments in the two source files ('Nothing else changes ... If you think something else is wrong, report it — do not fix it here'), so I did not edit it. Separately I could not have edited it safely: `gh` is not installed in this container, and the only body copy I can read back through the MCP layer is HTML-escaped (`'`, `"`, `>`), so rewriting a ~10KB body from that copy risks byte corruption of the kind AGENTS.md's body-mutation clause warns about.",
"options": [
"A — PM updates the PR body directly (surgical: the `name` disposition cell, the '### The open question' section retitled to the ruling, and the verification head sha), which needs no container access at all",
"B — dispatch a follow-up amendment with raw-body access (a working `gh`, or an explicit instruction to reconstruct from the escaped copy) to do the same edit",
"C — leave the body as the historical record of what was true when the PR was opened, and let the ruling live only in the issue thread and the code comments"
],
"recommendation": "A — it is a few minutes of PM editing with no tooling risk, and C is not viable: a reviewer reads the PR body first, and it currently points them at two files claiming a 'pending' marker that is no longer there, which is the same silently-misleading-documentation defect class this card exists to remove."
}
],
"out_of_scope_findings": []
}
Activity
os-zhuang commentedon Aug 23, 2026
Triage (first touch):
pm:queue+domain:ui.Landing:
packages/plugin-dashboard/src/index.tsx— theComponentRegistry.register('dashboard', …)call that publishes three inputs whileDashboardRendererhonours seven.packages/core/src/registry/public-blocks.tsis the reference surface, not the fix site.Graded
pm:queuerather thanfinding: the body names the landing call, and the remedy is the one already shipped twice for this exact class (#4668 / #5091) — publish the inputs the renderer reads. No open question.objectui three-stream split (maintainer 2026-08-21). Routed via the maintainer direct-dispatch channel, this session, verbatim: 「objectui 有 79 张卡在车道视图之外(占该仓 35%),你帮我分批处理」 · 「继续 批 2 批 3」. PM session
session_0124Qg8rLvpXnQDwCmpKUmaJ. Not a Routine triage fire — the triage seat may re-grade.Generated by Claude Code
claude commentedon Aug 23, 2026
Claim —
domain:uiexecution seat. PM round 28, sessionsession_01EuPCi56cnGyykygi3z9w4m, branchclaude/issue-5742-dashboard-declare-honoured-inputs. Dispatching at contract-review tier (clause ②:dashboardis inPUBLIC_BLOCKS, so its input list is serialized intosdui.manifest.jsonandsdui-intrinsics.d.ts— publishing an input widens the accept surface).Taken on the triage grading's own reasoning: the body names the landing call and the remedy is the one already shipped twice for this class (#4668 / #5091), so there is no open question to route back.
gridNonAuthorKeys.test.tsxpins them, rather than being left as a silent gap that reads identically to an oversight.widgetsis the floor (every example incontent/docs/plugins/plugin-dashboard.mdxauthors it, and #5709's unconsumed-options warning already descends into it).⛔
packages/core/src/registry/public-blocks.tsis the reference surface, not the fix site.Generated by Claude Code
feat(plugin-dashboard): publish the honoured dashboard inputs, pin th…
os-zhuang commentedon Aug 23, 2026
{ "issue": 5742, "status": "done", "branch": "claude/issue-5742-dashboard-declare-honoured-inputs", "pr": "https://github.com/objectstack-ai/objectui/pull/5829", "premise_still_valid": true, "summary": "Per-key triage shipped on the #4668/#5091 line (declare only what the renderer reads AND the strict spec DashboardSchema accepts). Declared 7 new inputs on the `dashboard` registration — widgets (array), label + description (string|locale-map unions), header, globalFilters, dateRange (objects/array), refreshInterval (number) — with author-facing descriptions; columns/gap/className untouched. Pinned two deliberate exclusions gridNonAuthorKeys-style: `title` (legacy spelling, spec rejects by name, the schema.title||schema.label read STAYS and is render-pinned) and `aria` (spec tombstone from the #3896 audit close-out; measured correction to the issue body: this package has ZERO schema.aria read sites, so there is no 'still reads it' leg for it). Docs Schema API block and a minor changeset included. One honoured key (`name`) raised as an open question instead of guessed.", "tests": "New pin file packages/plugin-dashboard/src/__tests__/dashboardAuthoredInputs.test.tsx (30 tests: author-reach with unknown-prop/type-mismatch controls, exclusion pins with spec verdicts + declared controls + render legs, and the generated-artifact face via the same manifestFromConfigs/generateDts pair gen-manifest.ts uses — the manifest artifacts are build-time codegen, not checked in, so the change to them is pinned through their own generators). Union at final HEAD 6a1e9040e, repo root: pnpm exec vitest run packages/plugin-dashboard/ + the 5 console registry gates (registry-inputs-spec-parity, public-contract, ga-honoured-inputs-author-reach, component-input-union-specimens, public-block-binding-reach) => 'Test Files 81 passed (81) / Tests 836 passed (836)', lock VERDICT command-exit 0. pnpm --filter @object-ui/plugin-dashboard type-check && lint => exit 0 (0 errors) after building the dependency closure. Script gates all exit 0 with verdict lines read from their own output: check-changeset-presence ('declares 1 changeset'), check-phantom-dependencies (new @object-ui/sdui-parser devDep declared), check-control-bytes, check-doc-component-types, check-doc-snippet-types ('Every covered documentation snippet compiles against the built types' — ran after building its --build-filter package set; my mdx edit adds only a plaintext block), check-changeset-fixed, check-changeset-no-major. Reverse verification against the commit (no dist rebuild involved: root vitest aliases @object-ui/* to src, so the runs read the mutated source directly; mutation = git checkout HEAD~1 -- packages/plugin-dashboard/src/index.tsx, confirmed by the run itself flipping and by git status; restore confirmed by git diff HEAD --stat empty): 20 of 30 red on the reverted registration (all 9 author-reach rows back to unknown-prop, all 7 off-arm rows, both not-published control legs, both artifact legs), then 30/30 green restored. Non-discriminating legs, by design: reachability + probe-key control, the five spec-verdict legs (they pin the spec, not the registry), unknown-prop on title/aria (true on both legs), and the two render legs (read sites untouched). CI status at report time: in_progress (report delivered at draft-PR time per standing rule).", "open_questions": [ { "question": "Should the inline `dashboard` node publish `name`? The renderer reads schema.name (keys the dashboards.{name}.* translation lookups) and the spec ACCEPTS name (requires it on the document form) — the shipped 'spec accepts + renderer reads => declare' line would put it in. But it is the document identity key written by the stored-dashboard path (DashboardView hands the loaded document to the renderer), no docs example authors it inline, and no sibling registration anywhere declares a `name` input. Its absence is marked pending (not ruled) in the registration comment and the pin test docblock.", "options": [ "A — declare it (string input, description steering authors to the stored-document identity), consistent with the reverse-parity principle that spec-declared keys must be discoverable", "B — rule it non-author for the inline node and pin it with producer evidence (DashboardView / document loader), leaving the read untouched" ], "recommendation": "B — on the four axes: no measured inline-authoring pull (every docs example and both in-repo hosts reach name via the stored document); identity keys belong to documents, not inline nodes; publishing it teaches AI authors to fabricate identities that mostly resolve no translations (silent inert key); startup scope stays tight. The cost of B is that the pin cannot use the 'spec rejects by name' leg (spec accepts name), so it rests on producer evidence alone — which is why this is raised rather than decided." } ], "out_of_scope_findings": [ "filed as #5830: DashboardComponentSchema.aria in @object-ui/types declares a key the spec tombstoned and no renderer reads, under a stale 'Aligned with @objectstack/spec AriaPropsSchema' comment (finding label, unassigned)" ] }Generated by Claude Code
os-zhuang commentedon Aug 23, 2026
os-dev-report
(The comment above is this same report whose HTML-comment marker the body sanitizer stripped — objectui#5581's known behavior; this one leads with the literal marker text so the PM scan finds it. Content identical.)
{ "issue": 5742, "status": "done", "branch": "claude/issue-5742-dashboard-declare-honoured-inputs", "pr": "https://github.com/objectstack-ai/objectui/pull/5829", "premise_still_valid": true, "summary": "Per-key triage shipped on the #4668/#5091 line (declare only what the renderer reads AND the strict spec DashboardSchema accepts). Declared 7 new inputs on the `dashboard` registration — widgets (array), label + description (string|locale-map unions), header, globalFilters, dateRange (objects/array), refreshInterval (number) — with author-facing descriptions; columns/gap/className untouched. Pinned two deliberate exclusions gridNonAuthorKeys-style: `title` (legacy spelling, spec rejects by name, the schema.title||schema.label read STAYS and is render-pinned) and `aria` (spec tombstone from the #3896 audit close-out; measured correction to the issue body: this package has ZERO schema.aria read sites, so there is no 'still reads it' leg for it). Docs Schema API block and a minor changeset included. One honoured key (`name`) raised as an open question instead of guessed.", "tests": "New pin file packages/plugin-dashboard/src/__tests__/dashboardAuthoredInputs.test.tsx (30 tests: author-reach with unknown-prop/type-mismatch controls, exclusion pins with spec verdicts + declared controls + render legs, and the generated-artifact face via the same manifestFromConfigs/generateDts pair gen-manifest.ts uses — the manifest artifacts are build-time codegen, not checked in, so the change to them is pinned through their own generators). Union at final HEAD 6a1e9040e, repo root: pnpm exec vitest run packages/plugin-dashboard/ + the 5 console registry gates (registry-inputs-spec-parity, public-contract, ga-honoured-inputs-author-reach, component-input-union-specimens, public-block-binding-reach) => 'Test Files 81 passed (81) / Tests 836 passed (836)', lock VERDICT command-exit 0. pnpm --filter @object-ui/plugin-dashboard type-check && lint => exit 0 (0 errors) after building the dependency closure. Script gates all exit 0 with verdict lines read from their own output: check-changeset-presence ('declares 1 changeset'), check-phantom-dependencies (new @object-ui/sdui-parser devDep declared), check-control-bytes, check-doc-component-types, check-doc-snippet-types ('Every covered documentation snippet compiles against the built types' — ran after building its --build-filter package set; my mdx edit adds only a plaintext block), check-changeset-fixed, check-changeset-no-major. Reverse verification against the commit (no dist rebuild involved: root vitest aliases @object-ui/* to src, so the runs read the mutated source directly; mutation = git checkout HEAD~1 -- packages/plugin-dashboard/src/index.tsx, confirmed by the run itself flipping and by git status; restore confirmed by git diff HEAD --stat empty): 20 of 30 red on the reverted registration (all 9 author-reach rows back to unknown-prop, all 7 off-arm rows, both not-published control legs, both artifact legs), then 30/30 green restored. Non-discriminating legs, by design: reachability + probe-key control, the five spec-verdict legs (they pin the spec, not the registry), unknown-prop on title/aria (true on both legs), and the two render legs (read sites untouched). CI status at report time: in_progress (report delivered at draft-PR time per standing rule).", "open_questions": [ { "question": "Should the inline `dashboard` node publish `name`? The renderer reads schema.name (keys the dashboards.{name}.* translation lookups) and the spec ACCEPTS name (requires it on the document form) — the shipped 'spec accepts + renderer reads => declare' line would put it in. But it is the document identity key written by the stored-dashboard path (DashboardView hands the loaded document to the renderer), no docs example authors it inline, and no sibling registration anywhere declares a `name` input. Its absence is marked pending (not ruled) in the registration comment and the pin test docblock.", "options": [ "A — declare it (string input, description steering authors to the stored-document identity), consistent with the reverse-parity principle that spec-declared keys must be discoverable", "B — rule it non-author for the inline node and pin it with producer evidence (DashboardView / document loader), leaving the read untouched" ], "recommendation": "B — on the four axes: no measured inline-authoring pull (every docs example and both in-repo hosts reach name via the stored document); identity keys belong to documents, not inline nodes; publishing it teaches AI authors to fabricate identities that mostly resolve no translations (silent inert key); startup scope stays tight. The cost of B is that the pin cannot use the 'spec rejects by name' leg (spec accepts name), so it rests on producer evidence alone — which is why this is raised rather than decided." } ], "out_of_scope_findings": [ "filed as #5830: DashboardComponentSchema.aria in @object-ui/types declares a key the spec tombstoned and no renderer reads, under a stale 'Aligned with @objectstack/spec AriaPropsSchema' comment (finding label, unassigned)" ] }Generated by Claude Code
claude commentedon Aug 23, 2026
PM ruling on the open question — option B:
nameis NOT an author input on the inlinedashboardnode.domain:uiexecution seat, sessionsession_01EuPCi56cnGyykygi3z9w4m.I am ruling B, but on a stronger ground than the report's balance-of-axes, and the difference matters for the pin's wording.
The shipped heuristic does not fire here — this is not a close call
The line is "spec accepts + renderer reads ⇒ declare". The report reads the first clause as satisfied because "the spec ACCEPTS
name". But it accepts it on the document form, where it is required — not on the inline node. The shape the spec is acceptingnameon is not the shape this registration publishes inputs for.So the premise of the heuristic is not met, and B wins without needing the four axes at all.
titleandariawere excluded because the spec rejects them;nameis excluded because the spec's acceptance is about a different shape. Those are two different exclusion reasons and the pin should say which one it is — a future reader who seesnameexcluded next totitlewill otherwise assume "spec rejects it" and be wrong.The axis that would have decided it anyway
Publishing
nameas an inline input would teach authors — human and, more to the point, AI — to fabricate a dashboard identity inline. Per the report's own measurement, that identity keysdashboards.{name}.*translation lookups, so a fabricated one resolves nothing and fails silently. That is a newly manufactured silently-inert key: precisely the defect class this card exists to remove. Curing seven instances while minting an eighth is not a trade worth making.Carry the cost forward honestly
The report names it and it must survive into the code: this pin cannot use the "spec rejects by name" leg, because the spec does accept
name. It rests on producer evidence alone —DashboardView/ the document loader hands the loaded document to the renderer. That makes it a weaker pin than thetitle/ariaones, and the docblock should say so, so nobody later reads its silence as the same strength of guarantee. ⛔ Do not paper over that by asserting a spec rejection that does not exist.Concretely: replace the "pending (not ruled)" marker in the registration comment and the pin test docblock with this ruling, stating (a) that the spec accepts
nameon the document form only, (b) that the read stays untouched, and (c) that the pin's evidence is the producer, not a spec verdict.On the rest of the card
The per-key work is right. Declaring seven and pinning two exclusions
gridNonAuthorKeys-style is exactly the #5091 line, and ⛔ theschema.title || schema.labelread correctly stays whiletitleleaves the published surface — advertised and honoured are different questions, and the render leg pins that.The measured correction to the issue body is the more valuable half and is accepted: the body implies
ariais a "renderer honours it" key, and the measurement found zeroschema.ariaread sites in this package, so there is no "still reads it" leg for it at all. Recording that rather than inheriting the body's framing is the right instinct — and #5830 (theDashboardComponentSchema.ariadeclaration in@object-ui/types, under a stale "Aligned with@objectstack/specAriaPropsSchema" comment) is the correct place for the residue, filed unassigned for triage rather than folded in.Generated by Claude Code
docs(plugin-dashboard): record the ruling on `name` — non-author inli…
os-zhuang commentedon Aug 23, 2026
os-dev-report
(Amendment run. Leading with both marker spellings in one comment: the body sanitizer strips short
<...>fragments on this repo, which is what forced a duplicate report comment on the first run of this card.){ "issue": 5742, "status": "done", "branch": "claude/issue-5742-dashboard-declare-honoured-inputs", "pr": "https://github.com/objectstack-ai/objectui/pull/5829", "premise_still_valid": true, "summary": "AMENDMENT to the existing PR #5829 — comment-only, no re-implementation. New head 77295c734 (was 6a1e9040e); PR still open, still draft, 2 commits, no second PR. Recorded the PM ruling (option B: `name` is NOT an author input on the inline `dashboard` node) in the two places that carried the 'pending (not ruled)' marker: the registration comment in packages/plugin-dashboard/src/index.tsx and the docblock of packages/plugin-dashboard/src/__tests__/dashboardAuthoredInputs.test.tsx. Each now states all three required points: (a) the exclusion is NOT a spec rejection — the spec ACCEPTS `name`, but on the DOCUMENT form where it is required, not on the inline node, so the shipped 'spec accepts + renderer reads => declare' heuristic never fires here (its premise is about a different shape), with an explicit instruction not to carry `title`'s 'the spec rejects it' over to this key; (b) the `schema.name` read STAYS untouched and still keys the `dashboards.{name}.*` lookups; (c) the evidence is PRODUCER-side alone (DashboardView / the document loader hands the loaded document to the renderer), stated plainly as a WEAKER pin than the `title`/`aria` ones which each assert a re-checkable spec verdict — no spec rejection is asserted for `name` anywhere. Both places also carry the supporting reason (publishing `name` inline would teach authors, AI authors especially, to fabricate a dashboard identity resolving no translations and failing silently — a newly manufactured silently-inert key, the defect class this card removes). Nothing else touched: the seven declared inputs, the `schema.title || schema.label` read, the `title`/`aria` exclusion pins, the tests and #5830 are all untouched — `git diff` shows every changed line is a comment line (48 insertions / 14 deletions across exactly those 2 files). One deviation to flag: the dispatch asked for a fresh worktree ../objectui-5742-amend, but git refuses ('already used by worktree at /home/user/objectui-5742') because this branch was still checked out in this same session's dedicated worktree from the first run; I worked in that existing dedicated worktree (a linked worktree, not the shared checkout, so worktree-first holds) after re-running pnpm install, since its node_modules had been cleaned up. See the open question about the now-stale PR body.", "tests": "Comment-only delta, so there is NO behavioural leg and I did not run a reverse verification — saying so rather than reporting one is the honest answer here. Discriminating evidence is the marker removal plus the suite staying green. NEGATIVE CONTROL: `grep -rn -i -E 'pending|not ruled|open question|nor pinned|rather than guessed'` over both files => ZERO hits (grep exit 1). POSITIVE CONTROL: `grep -c 'on the DOCUMENT form'` => 1 in each of the two files; `grep -n 'PRODUCER alone'` and `grep -n 'WEAKER'` each present in both. The edit itself was applied by a script that asserts each splice anchor matches EXACTLY once (it would have thrown otherwise) and reported the real byte counts replaced (index.tsx lines 60-62, 215 chars -> 1290; test docblock lines 43-54, 801 chars -> 1729), so this was not a zero-hit no-op edit. Comment-only scope proved mechanically: `git diff -U0 | grep '^[+-]' | grep -v '^[+-]\\s*(//|\\*|/\\*)'` => zero non-comment changed lines (exit 1). GATES, exit codes captured by redirect-then-capture (never through a pipe), verdict lines quoted from the gates' own output. Run at final HEAD 77295c734, and the tree tested is provably the committed tree: after commit, `git status --porcelain` and `git diff HEAD --stat` are both EMPTY, and no edit occurred between the suite run and the commit. (1) `pnpm exec vitest run packages/plugin-dashboard/ --maxWorkers=2` from the REPO ROOT (not --filter, not from a package cwd), via the shared verify lock: 'os-verify-lock: VERDICT command-exit 0 - held the lock 179s - waited 356s' with 'Test Files 76 passed (76) / Tests 712 passed (712)'. (2) The pin file specifically, re-run post-commit at 77295c734: 'Test Files 1 passed (1) / Tests 30 passed (30)' — the 30 pins from the first run all still green (the aggregate reporter does not name passing files, hence the targeted run as collection proof). (3) `node scripts/check-changeset-presence.mjs` EXIT=0, post-commit, its own verdict line: '2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/dashboard-declare-honoured-inputs.md' — the existing changeset does still cover this delta, confirmed by running the gate rather than assuming. (4) `node scripts/check-control-bytes.mjs` EXIT=0, post-commit: 'check-control-bytes: OK (scanned 4845 tracked text file(s); skipped 85 binary)'. No type widening, no loosened pin, no weakened assertion was needed anywhere. No bare version literal was written into any prose. CI at report time: in_progress — the push restarted the gate window, and per the standing rule I am not polling it.", "open_questions": [ { "question": "The PR #5829 BODY still carries the superseded framing and is now falsified by this commit — the `name` row reads '**raised as an open question, not guessed**', and a whole '### The open question: `name`' section says 'Its absence from `inputs` is therefore *pending*, not ruled — stated in the registration comment and the pin test's docblock'. That sentence is now false: those two markers are exactly what this amendment removed. The body's Verification section also still cites `6a1e9040e` as the head. The dispatch scoped me to comments in the two source files ('Nothing else changes ... If you think something else is wrong, report it — do not fix it here'), so I did not edit it. Separately I could not have edited it safely: `gh` is not installed in this container, and the only body copy I can read back through the MCP layer is HTML-escaped (`'`, `"`, `>`), so rewriting a ~10KB body from that copy risks byte corruption of the kind AGENTS.md's body-mutation clause warns about.", "options": [ "A — PM updates the PR body directly (surgical: the `name` disposition cell, the '### The open question' section retitled to the ruling, and the verification head sha), which needs no container access at all", "B — dispatch a follow-up amendment with raw-body access (a working `gh`, or an explicit instruction to reconstruct from the escaped copy) to do the same edit", "C — leave the body as the historical record of what was true when the PR was opened, and let the ruling live only in the issue thread and the code comments" ], "recommendation": "A — it is a few minutes of PM editing with no tooling risk, and C is not viable: a reviewer reads the PR body first, and it currently points them at two files claiming a 'pending' marker that is no longer there, which is the same silently-misleading-documentation defect class this card exists to remove." } ], "out_of_scope_findings": [] }Generated by Claude Code
feat(plugin-dashboard): publish the honoured dashboard inputs, pin th…
fix(dashboard): retire the dashboard-root `title` read on all five su…