Skip to content

docs(skills): type three marked fences' schema as SchemaRendererProps['schema'] (objectui#11543) - #11558

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-11543-skill-fences-v1
Oct 3, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-11543-skill-fences-v1

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11543
Clause-②: no

What

Three marked (os:check) tsx fences in the published objectui skill guides declared schema: BaseSchema and passed it to SchemaRenderer:

  • skills/objectui/guides/auth-permissions.md (the ContactsPage fence)
  • skills/objectui/guides/data-integration.md (the Prototype fence)
  • skills/objectui/guides/schema-expressions.md (the Page fence)

V1 (objectui#11466, PR #11512) narrows the schema prop to the declared-node union, which refuses a BaseSchema with TS2322. So Skill Example Check is red on PR #11512.

This PR is the card's route B, exactly. Each fence now declares the prop's own type, imported as a type from @object-ui/react:

import type { SchemaRendererProps } from '@object-ui/react'

declare const schema: SchemaRendererProps['schema']

It replaces import type { BaseSchema } from '@object-ui/types' and declare const schema: BaseSchema. BaseSchema had no other use in any of the three fences, so its import goes. The type compiles on main today and after V1 lands, and it follows the prop by reference.

  • Line-neutral: 3 files, +6 / −6.
  • ⛔ No os:check marker was removed or altered. Per file, the marker count is equal at the base and at the head: 6, 9 and 32.
  • No other file is touched.

Measured (head 2f2205315, base 154075ab1)

The skill-example gate is node scripts/check-skill-examples.mjs (pnpm check:skill-examples, the Skill Example Check job in skill-examples.yml). Each leg first built the packages the gate's own --build-filter names (turbo, 29 of 29 tasks), so the fences were judged against the built dist/*.d.ts. The gate's RESOLUTION control confirmed that.

leg tree gate verdict
control main 154075ab1, unchanged exit 0, Semantic phase: 18 of 18 ts fence(s) judged, 0 failed.
this PR main plus this change (2f2205315) exit 0, Semantic phase: 18 of 18 ts fence(s) judged, 0 failed.
probe control PR #11512's head fab635a2d, unchanged exit 1, Semantic phase: 18 of 18 ts fence(s) judged, 3 failed. These are the three TS2322 failures, one in each of the three guides.
probe PR #11512's head fab635a2d plus this change exit 0, Semantic phase: 18 of 18 ts fence(s) judged, 0 failed.
  • The probe ran in a throwaway detached worktree. The change was applied as this commit's patch, and on disk BaseSchema read 0 and SchemaRendererProps['schema'] read 1 in each file. Afterwards the probe was restored with git checkout HEAD (git diff HEAD read 0 bytes) and removed without --force. Nothing from it was pushed.
  • --self-test on main: exit 0, 60 cases pass. --list at the head shows all three fences as marked pass.
  • Tests that read these guides, taken from node scripts/markdown-test-inputs.mjs (all three paths are recorded test inputs), plus two more that git grep names. They ran from the repo root at 2f2205315: Test Files 14 passed (14), Tests 394 passed (394).
  • Every one of these gates exits 0:
    • check-skills-paths
    • check-control-bytes
    • check-shell-escape-residue
    • check-skill-eval-tokens
    • check-new-cross-file-line-citations (0 new)
    • check-doc-fence-languages
    • check-doc-links
    • check-changeset-presence ("no changeset is owed": skills/** is no released package's source)
  • Governed-queue guard predicate, node scripts/check-governed-queue-guard.mjs --test on the three paths: exit 3, GOVERNED — 3 of 3 path(s) are on a governed surface (skills/**, the published skills catalog). The control path packages/react/src/index.ts reads NOT GOVERNED, exit 0.
  • Skills line readings:
    • Per file, base → head: auth-permissions.md 409 → 409, data-integration.md 515 → 515, schema-expressions.md 639 → 639.
    • Whole package: all skills/**/SKILL.md 142 → 142 (one file), and all of skills/objectui/** 5418 → 5418.
    • objectui carries no line ratchet over skills/**. objectstack's check-skill-line-ratchet.mjs covers objectstack's own instruction files only.

Governed landing

skills/** is a governed surface, so this PR stays a draft until an authorized approval (os-zhuang / hotlong). The claiming seat lands it through the merge queue. The author of this draft does not flip it ready, request reviews, arm auto-merge or merge it.

Sequencing, from the card:

维护者速读(草稿)

改了什么

  • 三份对外发布的 objectui 技能指南(权限、数据集成、表达式)里,各有一段受门禁检查的示例代码。
  • 这三段示例把传给 SchemaRenderer 的 schema 的类型标注,从 BaseSchema 换成渲染器自身的入参类型 SchemaRendererProps['schema']。
  • 每段只改两行(换一个 import、换一个类型),三个文件合计 +6 / −6,行数不变。
  • 门禁标记一个没动,其它文件一个没碰。

为什么改

风险与代价(含回滚)

  • 只改文档示例,不改任何发布包的源码,不发版,不需要 changeset。
  • 风险很低。代价是示例的读者看到的是 SchemaRendererProps['schema'] 这种索引类型写法,比 BaseSchema 稍微抽象一些。
  • 回滚:revert 这一个提交即可。但只要 V1 已经落地,回滚就会让这三段示例重新编译报错。

席位意见

你要做的

  • 读一遍上面三处两行的改动。认可就在本 PR 上留一条 APPROVED review(os-zhuang 或 hotlong 账号)。
  • 批准之后,由认领席位把它翻成 ready 并入合并队列落地,你不需要再做别的。

Acceptance notes

Implemented by an os-dev run dispatched from the director seat, session session_016tKoy8NJa35Yih1FdzrVmn.


Generated by Claude Code

…['schema'] (objectui#11543)

Three `os:check` fences in the objectui skill guides (auth-permissions,
data-integration, schema-expressions) declared `schema: BaseSchema` and
passed it to `SchemaRenderer`. V1 (objectui#11466) narrows that prop to
the declared-node union, which refuses a `BaseSchema` with TS2322, so the
Skill Example Check goes red on V1's branch.

Each fence now declares the prop's own type, `SchemaRendererProps['schema']`,
imported as a type from `@object-ui/react`. It compiles on main today and
after V1 lands, and it follows the prop by reference. The `os:check`
markers are untouched; the edit is line-neutral.

Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 1 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/5120-retire-data-table-name-alias.md

  • names skills/objectui/guides/data-integration.md → skills/objectui/guides/data-integration.md — edited by this change

    The two published skill guides that taught the name spelling (skills/objectui/guides/data-integration.md, schema-expressions.md) migrate in this same release, so the platform never refuses a spelling it still ships.

  • names schema-expressions.md → skills/objectui/guides/schema-expressions.md — edited by this change

    The two published skill guides that taught the name spelling (skills/objectui/guides/data-integration.md, schema-expressions.md) migrate in this same release, so the platform never refuses a spelling it still ships.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with d0097af2e (merge-base with origin/main): 3 file(s) changed outside .changeset/, read against 2097 pending declaration(s) that publish a body (2732 pending in total). · run

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读

From the director seat, summon #32 (session_016tKoy8NJa35Yih1FdzrVmn), claim 5970147074 on objectui#11543.

改了什么

  • 三份对外发布的 objectui 技能指南(权限、数据集成、表达式)里,各有一段受门禁检查的示例代码。
  • 每段示例把传给 SchemaRenderer 的 schema 的类型标注,从 BaseSchema 换成渲染器自己的入参类型 SchemaRendererProps['schema']。
  • 每段只改两行,换一个 import、换一个类型。三个文件合计 +6 / −6,行数不变。
  • 门禁标记一个没动,其它文件一个没碰。

为什么改

风险与代价

  • 只改文档示例,不动任何发布包的源码,不需要 changeset。
  • 回滚是 revert 这一个提交;但 V1 落地后再回滚,这三段示例会重新编译报错。

席位意见:建议批准。

  • 这是 V1 落地前唯一的阻塞。
  • 改动严格按 spec 席位裁定的路线 B 执行,没有删除任何门禁标记(不走路线 C),也没有把 skills 文件混进 V1 的 PR(不走路线 A)。
  • ① 长远:示例跟随渲染器自己的类型,不会再和契约脱节。② 拉动:V1 等它。③ 防 AI:AI 照着指南写出的代码在 V1 下也能编译。④ 不扩散:不新增门禁,行数不变。

你要做的

  • 读一遍三处、每处两行的改动。认可就在本 PR 上用 os-zhuang 或 hotlong 账号留一条 APPROVED review。
  • 批准之后,由本席位改成 ready,送进合并队列落地,你不需要再做别的。

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 3, 2026 23:01
@os-zhuang
os-zhuang enabled auto-merge October 3, 2026 23:01
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit 5cde2c6 Oct 3, 2026
40 of 41 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-11543-skill-fences-v1 branch October 3, 2026 23:30
hotlong pushed a commit that referenced this pull request Oct 3, 2026
…ctui#11466)

Brings in objectui#11543 (PR #11558: the three skill fences typed as
SchemaRendererProps['schema']) and the fifteen other squash commits that
landed after d0c0c7f: objectui#11556, #11541, #11550 (three), #11536,
#11544, #11553, #11562, #11216, #10380, #10872, #11572, #11574 and
#11576. No textual conflict.

Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Oct 7, 2026
…rer's `schema` prop take the declared-node union, V1; the dashboard producers name declared nodes and an envelope's object-metric retires (objectui#11466) (objectstack-ai#11512)

Fixes objectstack-ai#11466

This PR carries ruling ① (V1) and the card's residue, with `main` merged
in, the plugin-dashboard producers closed, and the maintainer's ruling A
on the last inline metric form (comment 5966278275). The census reads 0
lines across all 88 workspace type-check programs, with `BaseSchema`'s
index signature present.

Clause-②: yes (narrowing)

**objectui#11543 (governed PR objectstack-ai#11558) has landed** as `5cde2c6fe`.
`Skill Example Check` is green at `cae2224d5`: 18 of 18 ts fences
judged, 0 failed. All 43 check-runs on this head are green or expected
skips.

## What changes

- `@object-ui/types` exports `DeclaredNode`. It is the discriminated
union, keyed by the literal `type`, of:
- every component schema `AnySchema` declares, minus its `BaseSchema`
arm (whose `type` is `string`) and minus the app-level document, which
is left out by `{ type: 'app' }` (`AppSchemaRenderer` reads that
document structurally and `ComponentRegistry` never dispatches it);
  - every spec-declared `AuthoringNode`;
- every entry of the new `CustomNodeRegistry` interface. An entry joins
under its KEY: the arm is the entry intersected with `{ type: KEY }`, so
even a loose entry adds no `type: string` arm.
- `SchemaNode` is `DeclaredNode | string | number | boolean | null |
undefined`. It was `BaseSchema | string | number | boolean | null |
undefined`.
- `SchemaRendererProps['schema']` is `DeclaredNode | string | null |
undefined`. It was `BaseSchema | AuthoringNode | string | null |
undefined`. `toRenderableSchema` follows by reference.
- `@object-ui/core`'s schema builder takes `DeclaredNode` where it took
`BaseSchema`: `.child()` and `.children()` on the grid and flex
builders, and the card builder's `.content()`.
- `@object-ui/components`' `kind: 'html'` page crosses its
runtime-parsed tree into `DeclaredNode` at ONE documented boundary,
right after `validateTree` reports no error (`page.tsx`, objectui#11479
Q2 A). No other cast to `DeclaredNode` exists under `src/`.
- `@object-ui/test-support` gains `undeclaredNode`, the one crossing for
deliberately undeclared test input (objectui#11479 Q3 A). It has 25 call
sites in 15 test files, and none outside tests.
- **`@object-ui/plugin-dashboard`:**
- `plugin-dashboard:metric` is declared through `CustomNodeRegistry`
(objectui#11479 Q1 A). `DashboardMetricNodeSchema`, a new export, is the
node `MetricWidget` renders under that key, with the keys it reads off
the node, typed by `MetricWidgetProps`. `widgetDispatch.ts` enters it in
the registry beside `DASHBOARD_NODE_TYPES`, whose values are now literal
types (a string-keyed view serves the by-type lookup). The package entry
exports the type, so its published typings load the declaration.
- Both surfaces' node builders (`getComponentSchema` in
`DashboardRenderer` and `DashboardGridLayout`) return
`SchemaRendererProps['schema']`, so each node is checked against its
declared type where it is built. The metric arms narrow `widgetType` for
the required label; `classifyWidgetType` answers `metric` only for a
named type, so no verdict moves.
- `DashboardGridLayout`'s static `pivot` node states the keys
`PivotTable` draws (its `PivotTableSchema` keys, and `className`), read
from `options`, instead of spreading `options` whole, so it names
`PivotTableSchema` with no cast.
- The casts before `SchemaRenderer` are gone: `as BaseSchema | string |
null | undefined` in `DashboardGridLayout` and `as BaseSchema` in
`DashboardRenderer`. No new cast.
- **An `object-metric` node in a widget's legacy `component` envelope
draws `LEGACY_RETIRED_WIDGET_SCHEMA` on both surfaces** (the
maintainer's ruling A on objectui#11466, extending ruling C on
objectui#11525), under its bare key and under
`plugin-dashboard:object-metric`, and sends no query. One shared
detector, `isRetiredEnvelopeNode` in `legacyRetiredWidget.ts`, is read
by both surfaces before the envelope pass-through, and the placeholder
is the same imported object the metric and pivot arms return.
`object-metric` leaves the filter broadcast's `FilterableComponentType`
/ `FILTERABLE_COMPONENT_TYPES`, so the flat-`filter` write the declared
`object-metric` node refuses is gone. The broadcast now covers
`object-chart` and `object-data-table`, built by the renderer or written
in an envelope.
- Not here: a `type: string` arm, an index signature, a transitional
`BaseSchema` arm, `BaseSchema`'s own index signature, and the
`component` slot's `BaseSchema` fallback (all objectui#8347's). Every
zod face and every TypeScript authoring face of `object-metric` stays as
it was, and so does the authored `object-metric` block on a page. Two
runtime moves, both in `@object-ui/plugin-dashboard`: an option key the
static pivot does not state no longer reaches its node, and an
envelope's `object-metric` draws the rebind prompt.

## The accept set, before and after (TypeScript face only)

Judged by `packages/types/src/__tests__/node-slot-union-11466.test.ts`,
by the react prop pin, and by the premise probes below.

- **Undeclared `type`, nested or at the prop**, e.g. `{ type: 'card',
children: [{ type: 'txt' }] }`. Before: compiles through the
`BaseSchema` arm. After: TS2322.
- **A value typed `BaseSchema`** at the prop or in a slot. Before:
compiles. After: refused, because it names no declared type.
- **A misspelled key on a closed node type** (an `AuthoringNode`, or a
closed `CustomNodeRegistry` entry), nested at any depth. Before:
compiles through the `BaseSchema` arm. After: refused, because the slot
discriminates on `type`.
- **A misspelled key on a node type that extends `BaseSchema`.** Before:
compiles. After: still compiles, through that type's own index
signature, until objectui#8347 removes it. Measured below as the
signature-present control leg.
- **A missing REQUIRED key.** Before: compiles through the `BaseSchema`
arm. After: refused. Examples: a stored `home` page without `label`, a
`data-table` without `columns`, a static `pivot` without its axes.
- **A registered custom type.** Before: any `type` compiled. After: it
compiles once declared in `CustomNodeRegistry`; an unregistered one is
refused.
- **A `plugin-dashboard:metric` node.** Before: compiled through the
`BaseSchema` arm, like any string. After: in a program that loads
`@object-ui/plugin-dashboard`'s typings it is a declared node, checked
against `DashboardMetricNodeSchema` (which extends `BaseSchema`, so a
misspelled key still compiles until objectui#8347); in one that does
not, it is refused as undeclared.
- **Narrowing on `type`.** `'app'` narrows to `PageDocumentNode` (the
stored page kind) and `'list'` to `ListSchema`. `PageDocumentNode`
excludes the interface-mode `list` kind, which `PageView` renders
through `InterfaceListPage` and never hands to `SchemaRenderer`.
`SchemaByType` reads `AnySchema` and does not move.

## The merge of `main`

- **Measured first with `git merge-tree` against `main` at `160c6c6e`:**
one conflict, `packages/types/src/__tests__/zod-mirror-parity.test.ts`,
as expected. `content/docs/api/schema-reference.md`,
`packages/core/src/builder/schema-builder.ts`,
`packages/plugin-detail/README.md` and `packages/types/src/index.ts`
auto-merged. The merge is the merge commit `c7c37b73`; no rebase, no
force-push.
- **The resolution is the union**, re-derived on today's `main`.
`WiderThanDeclared` holds main's objectui#11515 entry
(`app.zod.ts#AppSchemaRendererNodeSchema::schema`, one SCHEMA-NODE arm)
and this branch's two objectui#11466 entries
(`complex.zod.ts#DashboardComponentSchema::widgets` and
`complex.zod.ts#DashboardWidgetSchema::component`, two CONCRETE arms
each). The header bullet reads the union's figures, with both histories
in landing order; the file's own pin 'the WIDER ledger's header figures
are derived from its ARMS' re-derives them from `WIDER_ARMS` and the
mirrors, and the type-level ratchet confirms each entry against the
mirrors (types `tsconfig.test.json` and vitest, both green).
objectui#11514's `KnownDrift` move (`type` left
`complex.zod.ts#DashboardWidgetSchema`'s entry) merged without conflict.
- **`MeasuredArmDrift11466`** (`node-recursion-point-8344.test.ts`)
drops `detail-section`, `app-schema-renderer` and `cloud:plan-status`,
which objectui#11515 twinned and joined to `AnySchema`. On the merged
tree before that edit the two-way ratchet read red (TS2344 at
`NodeRecursionPointDeclarationDrift`), which is what the ratchet is for;
a dated note records the reconciliation.

- **Landing-prep round (director seat, claim `5970151706`; dev report
`5970915352`):** two more merge commits, both conflict-free, with `pnpm
install` leaving the lockfile unchanged.
- `5afa0269a` merges `main` `154075ab1`: objectui#11533, the
`@objectstack/spec` 17.6.0 bump objectui#11531, objectui#11547, objectstack-ai#11539,
objectstack-ai#11542, objectui#11344 and objectui#11068.
  - `cb687dfad` merges `d0c0c7fe9`, objectui#10813.

  `main` brought no new V1 producer.

- **Final landing round (report `5974814539`):**
- `318447867` merges `main` `0a53c67f9` (16 squash commits,
objectui#11543 among them). There is no conflict and no
conflict-resolution edit inside this PR's 88 files, and the lockfile is
unchanged. The merge brought 105 files, two of them shared with this PR
(`schema-reference.md`, `zod-mirror-parity.test.ts`), both auto-merged
with only `main`'s change.
- `cae2224d5` corrects `MeasuredArmDrift11466`'s docblock (contract
review R1, prose only): the `app` / `record` / `home` / `utility` /
`page` / `dashboard` drifts are recorded for objectui#8347's family, not
carried by their own cards.

## H1: the cycle

- **Before**, with the V1 candidate on the first base (`tsc -p
packages/types/tsconfig.json`), there were 9 errors: TS2456 on
`FlexBlockNode`, `AuthoringNode`, `DeclaredNode` and `SchemaNode`;
TS4109 in `zod/base.zod.ts`; TS7022 on `FlexSchema`,
`FLEX_BAG_CHILDREN`, `FlexPropsBag` and `FlexBlockSchema`.
- **The spelling:** `FlexBlockNode` is an interface that extends the
closed arm input of `FlexBlockSchema`, with no members of its own;
`zod/base.zod.ts` writes the node slot's zod type out through two type
aliases (`SchemaNodeZodType`, `NodeSlotZodType`). The schema objects do
not change.
- **After:** 0 errors in `tsconfig.json` and in
`tsconfig.examples.json`, on the merged tree as well.

## H3: premise ②, re-run on the merged tree

> **Superseded reading (contract review R3):** the figures below were
taken at `b13093d6`. Re-measured at `cb687dfad` under the objectui#8347
mutation: types 39/40 and react 15/15. The one row is f02, the flex
bag's ARRAY child list, which is `unknown[]` on the TS face and carried
by objectui#11564. See the corrected acceptance note.

Throwaway probe files, never committed: 40 type-level rows in
`@object-ui/types` and 15 in `@object-ui/react`, each labelled OK (must
compile) or REFUSE (must error), each run on two legs at `b13093d6`.

- **objectui#8347's P1 mutation** (`BaseSchema`'s index signature
deleted; restore proven by blob `c0d9ad44` equal before and after,
signature lines back to 2): types 40 of 40 as labelled, react 15 of 15,
with no error on an unlabelled probe line. So (a) a nested misspelling
is refused at every slot depth and at the prop, and (b) a registered
custom type is authorable, its misspelling refused, and its keys do not
escape onto a declared type.
- **Signature present** (the control, and what lands now): types 29 of
40, react 9 of 15, the same rows as at the first fork. Every row that
does not pass is a misspelling on a node type that extends `BaseSchema`,
which is the signature objectui#8347 removes. Undeclared types,
wrong-value keys, the tombstone, `AuthoringNode` bag misspellings and
unregistered custom types are refused on both legs.
- **(c) timing**, `main` at `160c6c6e` against this branch at
`b13093d6`. Instantiations are deterministic (one value across 3 runs
each); seconds are medians of 3 on a shared box, so read them as ratios:

| program | instantiations (main → V1) | check time (median) |
|---|---|---|
| types `tsconfig.json` | 1,377,922 → 1,381,453 (+0.26%) | 3.21 s → 3.05
s |
| types `tsconfig.examples.json` | 1,191,109 → 1,195,701 (+0.39%) | 2.97
s → 3.58 s |
| types `tsconfig.test.json` | 3,395,239 → 3,409,600 (+0.42%) | 13.24 s
→ 13.43 s |
| react `tsconfig.json` | 367,923 → 454,978 (+23.66%) | 1.66 s → 2.02 s
|
| react `tsconfig.test.json` | 467,312 → 554,995 (+18.76%) | 3.02 s →
3.47 s |
| components `tsconfig.json` | 853,561 → 913,643 (+7.04%) | 5.53 s →
4.80 s |
| components `tsconfig.test.json` | 1,655,321 → 1,753,308 (+5.92%) |
10.56 s → 9.29 s |

The first fork read +23.95% (react src), +19.01% (react tests) and
+6.48% / +5.83% (components). Memory medians moved between 0.0% and
+6.7%.

## H2: the census

The instrument is objectui#11479's census, copied: all 88 workspace
type-check programs, each run on its own, after a full build.
`BaseSchema`'s index signature is present on every reading.

- **On the merged tree, before any other edit (`c7c37b73`):** 9 lines in
3 of 88 programs. plugin-dashboard `tsc --noEmit` 4 and
`tsconfig.test.json` 4 (the four `SchemaRenderer` render sites, two per
surface, fed by the two casts); types `tsconfig.test.json` 1
(`MeasuredArmDrift11466`).
- **At `f90ba8d2` (the previous round):** 2 lines in 2 of 88 programs,
both the return of `DashboardRenderer`'s filter merge, whose
`object-metric` member wrote a flat `filter` onto an `object-metric`
node. Those programs read a plugin-dashboard `dist` built with a
census-only cast at that line, restored blob-equal before the census.
- **At `cae2224d5` (this head, the final round):** 0 lines across all 88
programs, with the signature present (2 lines in src, 2 in dist) and no
cast added.
- **At `cb687dfad` (after the landing-prep merges):** 0 lines across all
88 programs, the same at `5afa0269a`. `BaseSchema`'s index signature is
present (2 lines in src, 2 in dist), and this round adds no cast.
- **At `fab635a2` (the previous head):** 0 lines; all 88 programs exit
0. No census-only cast: plugin-dashboard's own build, which fails on a
type error in its declaration program, passes.

## The corpus, re-judged

- **Type pins restated:** `SchemaRenderer.propsResolution` (the prop
equality, and `BaseSchema` is not an arm); `node-recursion-point-8344`
(the measured set of zod arms no declared node type admits, now `app`,
`record`, `home`, `utility`, `page`, `dashboard` and the retired kanban
arm); `overlay-trigger-union-7081`, `overlay-node-slot-doc-types-7082`
and `page-body-arity-8310`; `zod-mirror-parity`'s Wider ledger (the
union above); `authoring-nodes-11364` (dated note); new
`node-slot-union-11466`.
- **Test fixtures:** react suites that register test-only types declare
them in `CustomNodeRegistry` (13 files); deliberately undeclared input
crosses `undeclaredNode` (15 files); stored page fixtures gained the
required `label`; the plugin-gantt and plugin-map bag fixtures are
annotated with their declared node types.
- **Docs:** the plugin-dashboard README and
`content/docs/plugins/plugin-dashboard.mdx` name the one retired
envelope node and what still draws. 14 documents name the declared node
type; a registered custom type is shown declared in `CustomNodeRegistry`
(`core/schema-renderer.mdx`). The two blocks held at the first round
(`vscode-extension.mdx`, the plugin-detail README) now compile, answered
by their owner card (objectui#11515).
- **Pending changesets:** 13 pre-existing entries carry 15 append-only
dated notes (0 lines removed): `11364`, `8331`, `8908`,
`schema-input-bridge-permanent-4622`, `7767`, `11479`, `8572`, `8310`
(twice: the prop's annotation, and the root README's example authors
`children`, not `body`), `11354`, `10528-grid-object-table-fetch` and
`11514-dashboard-slot-entry-types` (their "unchanged" / "draws as
before" readings of the grid's static pivot), and for the envelope
retirement `11525-inline-metric-retired` (its envelope `object-metric`
"still receives the dashboard filter bar's values"),
`11348-dashboard-widget-reads` (the broadcast's guard over "the same
three `object-*` types", now two) and `11514-dashboard-slot-entry-types`
again (an envelope "draws under its card heading as before" whatever it
held). New entries: `.changeset/11466-node-slot-union.md` (types, react
and core `minor`; components `patch`),
`.changeset/11466-dashboard-metric-node.md` and
`.changeset/11466-envelope-object-metric-retired.md` (plugin-dashboard
`minor` each, the second stating before, now and the fix: bind a
dataset). Each states its breaking meaning in the body, because objectui
never declares `major`.

## The envelope's `object-metric` (the maintainer's ruling A)

The previous round held one line: the filter broadcast kept
`object-metric` in its filterable set for a node in a widget's legacy
`component` envelope (objectui#11525 kept it), and wrote a flat `filter`
that the declared `object-metric` node (the spec's `properties` bag,
`ObjectMetricBlockNode`) refuses by name on both faces. The maintainer
ruled A (comment 5966278275): that envelope node is the last inline
metric form, retired as ruling C retired the rest.

- **Measured basis (from the report):** an `object-metric` inside a
`component` envelope appears in 1 file across objectui and objectstack,
the objectui#11525 pin itself, against a control of 3 files holding an
envelope of another type. Stored customer dashboards are unmeasured, the
gap ruling C accepted.
- **The pin.** `inlineObjectMetricRetired-11525.test.tsx` carries a
dated note in its header. Its envelope case flips: on both surfaces,
under both keys, the envelope node yields the placeholder object
(checked by identity), the prompt is on screen, and no `aggregate` or
`find` call is made. A new control keeps the broadcast on the envelope's
`object-chart` and `object-data-table`, which still receive the filter
bar's value.
- **Reverse verification**, run on the committed fix (`20fb2278`) with a
trap-restored mutation. `isRetiredEnvelopeNode` was forced false (anchor
hit once, marker on disk 1, blob `71c7335c` to `c2706404`). Expected
direction: the four retired-envelope cases red and everything else
green. Read: "Tests 4 failed | 30 passed (34)", exactly those four (both
keys on both surfaces). Restore: blob `71c7335c` equals HEAD, `git diff
HEAD` 0 bytes, marker 0.

## Gates

HEAD is `cae2224d5` (final round, report `5974814539`; CI 40 success, 3
skipped, 0 failure). The readings below were taken at `fab635a2` unless
the report re-measured them at `cb687dfad`. Toolchain: the container's
Node v22.22.0 (the merged lockfile carries objectui#11366's lowered
jsdom floor). Heavy runs went through the shared verify lock.

- **type-check, all 88 workspace programs** (the census): 88 exit 0, 0
lines.
- **vitest, run from the worktree root with repo-relative paths:**
- `packages/plugin-dashboard/`, every reader test of the dashboard
README, guide and touched changesets, and the changeset-reading script
suites, at `fab635a2`: 182 files passed (2,325 tests, 6 skipped).
- `packages/types/`, `packages/react/`, `packages/core/src/builder/`,
every reader test of a doc, README or changeset the earlier rounds
touched, and the changeset suites, at `f90ba8d2`, before the last round,
whose diff touches plugin-dashboard's sources, its README and guide, and
changesets, all re-read by the run above: 542 files and 14,116 tests
passed.
- **Doc gates:** `check:doc-snippets` exit 0, "777 of 777 block(s)
judged, 0 failed"; `check:doc-examples` exit 0; `check:doc-types` exit
0.
- `check-changeset-no-major` 0, `check-changeset-presence` 0 (3
changesets declared), `check-changeset-fixed` 0,
`check:pending-changeset-literals` 0, `check-changeset-overwrite` 0
(report-only), `check:changeset-claims` 0 (report-only),
`check:new-line-citations` 0 (0 new), `check:control-bytes` 0,
`check:component-surface-parity` 0.
- **eslint, narrowed** to each round's changed `.ts`/`.tsx` files: 0
errors, and the same warning count per file as before the change (the
last round's four files against `f90ba8d2`; the previous round's six
against `main` and `ff7f748e`). `eslint.config.js` sets no parser
`project`, so linting is not type-aware and these diffs cannot move the
verdict on an untouched file. The repo-wide lint is CI's.
- **Not measured:** `check:sdui-registration-pins`, which needs a
console build (exit 2, prerequisite); no registration input moved.

## Acceptance notes

- **Corrected (landing-prep round, report `5970915352`):** the flex
bag's child list is `unknown[] | SchemaNode` on the TS face. A SINGLE
child is checked, and under the objectui#8347 mutation a misspelled key
on it is refused (the earlier f03). An ARRAY of children is `unknown[]`
and unchecked (probe f02 compiles under the mutation, at `cb687dfad` and
at `fab635a2`). That comes from `FLEX_BAG_CHILDREN`'s
`z.array(z.unknown())` arm, which is on `main` and untouched here. With
the signature present, no reading moves today. The arm is carried by
objectui#11564, ordered before objectui#8347's removal PR (seat ruling A
on the report's open question).
- **Premise H3, re-measured at `cb687dfad`:** under the P1 mutation,
types reads 39/40 (f02, the array arm above) and react 15/15. The
control leg reads 29/40 and 9/15.
- `DeclaredNode` has same-`type` pairs that are intended: `flex`
(`FlexSchema` and `FlexBlockNode`) and the `object-*` renderer faces
next to their authored bag nodes.
- The static pivot's runtime move: an option key it does not state (a
host prop of `PivotTable`'s such as `rowLabels`, or a `BaseSchema` node
key other than `className` such as `id`, `style` or `hidden`) no longer
reaches the node. Each stated key draws as before;
`DashboardGridLayout.objectProviderFetch-10528` and
`DashboardGridLayout.datasetPath` pass.
- `DashboardGridLayout.tsx` keeps twelve stale cross-file line
addresses, none in a paragraph this PR edits, so they are listed on the
card for a later edit of that file rather than repaired here: four in
the `dataSource` prop's docblock (into `DashboardRenderer`,
`DatasetWidget`, and `SchemaRenderer` twice) and eight in the
render-site comments (five into `DashboardRenderer`, three into
`legacyRetiredWidget`).

---
_Generated by [Claude
Code](https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants