Skip to content

docs(types,components,app-shell): declare the page-kind to node-type channel - #9705

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-9642-page-kind-node-discriminator-coupling
Sep 17, 2026
Merged

os-sales merged 1 commit into
mainfrom
claude/issue-9642-page-kind-node-discriminator-coupling

Conversation

@os-sales

@os-sales os-sales commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #9642

Clause-②: no — re-derived, not inherited. This branch adds prose and one test. No
ComponentRegistry.register call is added, removed or renamed; no Zod arm gains or loses a key;
no accept set moves; nothing joins a published barrel (the new symbols are a test file's locals,
and packages/types' SchemaRegistry map is untouched — adding a page-kind key there would widen
keyof SchemaRegistry = the published ComponentType union, which the map's own docblock calls a
ruling, so it is declared in a comment instead). The upstream enum lives in the sibling repository
and was read there on origin/main, never edited. ⇒ recording a coupling that already exists
neither relaxes an accept set nor enlarges a public surface.


What the coupling actually is — and one place the card's own framing is wrong

Measured on objectui 92fba11eb and objectstack a7e9a66, 2026-09-17T16:30Z UTC (clock read, not typed).

@objectstack/spec's PageTypeSchema.options reads record, home, app, utility, list — five kinds,
and page is refused by it. The PageRenderer registrations read page, app, utility, home, record.

⇒ They are not "the five page kinds." Four kinds are registered; list is not; and page —
which is not a kind at all — is the fallback the same two-line mapping writes for a stored document
carrying no type. list is absent because it is ADR-0047 interface mode: PageView branches on
interfaceConfig?.source and renders InterfaceListPage directly, so those documents never reach
SchemaRenderer. Every stored list page in the showcase carries that key (5/5 files).

The registry resolution was read directly rather than inferred (probe run, then deleted):

key resolves to
page app home record utility PageRenderer
list a different renderer (defined, ⛔ not undefined)
zzz (absent-token control) undefined

Two controls on one instrument: list reading defined-but-not-PageRenderer separates "served
elsewhere" from "unregistered", and the absent token proves a zero out of this probe is absence
rather than a dead query.

Where the declaration went, and why an auditor from each direction meets it

Two seats reasoned from a comment that was already there — the one at the WRITING end, in
PageView.tsx — and both got it wrong, because neither was reading that end. So the declaration is
placed at the READING ends, one per direction, plus one thing that cannot silently stay true.

file what it carries
packages/types/src/registry.ts Node-type-vocabulary auditor. This map's own docblock makes its key set "the Single Source of Truth for component type lookups", so "is app a declared node type?" is answered here, with no. The note sits at the page entry and says why the gap is not the "registered but never declared" defect, and why adding keys is ⛔ not the remedy. This is the exact question both mis-framed cards asked.
packages/types/src/zod/layout.zod.ts Page-kind-vocabulary auditor. SpecPageFields' type omission bullet already said spec's type is the kind and objectui's is the discriminator — and stopped there, reading as though the collision were resolved. It is not: the node that reaches the registry carries type: 'app', which PageNodeSchema's z.literal('page') would refuse. The bullet now states that.
packages/components/src/renderers/layout/page.tsx Registry-file auditor. The block sits directly above the registrations an auditor is looking at when the wrong conclusion forms.
packages/app-shell/src/views/PageView.tsx Writing end. Twelve lines pointing at the two reading ends and the pin, so the next editor of that mapping knows what goes red and why.
packages/components/src/__tests__/page-kind-node-type-channel-9642.test.tsx The mechanical half. New; 5 cases. A comment cannot fail — this can, and its failure text names the channel instead of looking like a component bug.
packages/components/src/__tests__/page-single-h1.test.tsx Fixture-editing auditor. Header note only. ⚠️ Verified on today's tree: this fixture still reads type: 'app' — the edit to 'page' was never merged, so its signal is intact. The note says the value is evidence about a real stored document and points at the pin.
.changeset/page-kind-node-type-channel-9642.md Empty frontmatter — the explicit "not shipping" declaration.

⚠️ Measured, and worth knowing before assuming the comments ship: // line comments do not
survive into the published .d.ts (0 // hits in dist/registry.d.ts against 3 surviving
JSDoc blocks in the same file as the lit control), and the SpecPageFields docblock never projected
either — its own pre-existing phrase "genuinely collide" reads 0 in dist/zod/layout.zod.d.ts
against 29 surviving JSDoc blocks there. ⇒ these declarations reach a contributor reading source,
⛔ not a consumer reading the published types, and published bytes do not move.

The scope note's sentence, and where it landed

The director's scope note adds one sentence: AppComponentSchema's app and the spec page kind
app are two vocabularies sharing one token. It landed in three places, primary first:

  1. packages/types/src/registry.ts — primary, because that is where the token's absence from the
    declared key set is read, and AppComponentSchema lives in the same package.
  2. packages/components/src/renderers/layout/page.tsx — beside the app registration itself.
  3. The pin's registryAppKeyServesThePageKind case — the mechanical half of the sentence, asserting
    that the registry key app answers with PageRenderer (the page kind) and carrying the sentence
    in its failure message.

Reverse verification of the pin

Committed first, then ablated, per the repo's rule. Mutation: the app registration replaced with a
marker line in page.tsx.

  • on-disk proof, ⛔ not the editor's exit code — app registration count 1 -> 0, injected marker count 0 -> 1, blob 48fb716 -> 78f2858
  • run: exit 1, Tests 3 failed | 2 passed (5), failing with the channel's own words: "page kind 'app' ... ComponentRegistry must answer it with PageRenderer. It does not. Either the registration was removed — every stored 'app' page then renders OBJUI-001 instead of the page ..."
  • restore leg, verified by state and ⛔ not by exit code: trap '... checkout HEAD -- PATH' EXIT INT TERM; afterwards blob back to 48fb716, marker count 0, git diff HEAD empty
  • no build step is involved: the pin imports ../renderers and ../renderers/layout/page as relative source, so no dist sits between the mutation and the reading

⛔ Not exercised, stated rather than implied: the "upstream enum grows a kind nothing serves" leg
would need the installed @objectstack/spec mutated, which was not done.

Gates — every exit code

Run at 5b293107f unless noted. Heavy legs went through ../objectstack/scripts/pm/os-verify-lock.sh.

gate exit
pnpm exec vitest run packages/components/ packages/types/ packages/app-shell/ (locked) 0 — Test Files 1190 passed (1190), Tests 14405 passed / 1 skipped
turbo run type-check --filter=@object-ui/types --filter=@object-ui/components --filter=@object-ui/app-shell (locked) 0 — 32/32 tasks
turbo run build --filter=@object-ui/console... --concurrency=2 (locked) 0 — 35/35 tasks
pnpm exec eslint over the 6 touched files (the repo's own lint form) 0 — 0 errors, 17 warnings, all pre-existing no-explicit-any
check-changeset-presence 0
check-control-bytes 0
check-new-cross-file-line-citations 0
check-registry-bare-name-collisions 0
check-sdui-registration-pins 0 after the console build (first run was exit 2, "No console build to weigh" = PREREQUISITE NOT MET, ⛔ not a red)
check-comment-mask-corpus 0
check-changeset-claims 0 (report-only; its 10 findings answered below)
check-pending-changeset-literals 0
check-test-path-roots 0
check-component-surface-parity 0
check-spec-symbol-derivation 0
check-doc-component-types 0
check-unreferenced-sources 0
check-vi-mock-specifiers 0
check-handler-key-read-sites 0
check-governed-queue-guard --test (7 paths) 0 — NOT GOVERNED, none of the 5 surfaces matched

Narrowing declared: the test leg was scoped to the three packages this diff touches rather than
pnpm test repo-wide, and the gate list was derived from this repository's own package.json and
.github/workflows/ — scripts/pm/dispatch-gates.mjs lives in the sibling repository and refuses
objectui paths by design, so there is no --commands output to quote here. It is stated, ⛔ not
substituted. pnpm install WAS run in the worktree, so no reading was lost to a missing install.
A repo-wide eslint . was not run: the repo's lint is per-package via turbo, and the six touched
files were linted directly.

⚠️ --no-inline-config is not this repository's lint form and reported one spurious error
(react-hooks/static-components at a pre-existing line that carries its own eslint-disable-next-line);
re-run in the repo's own form it is 0. Recorded because the wrong form reads as a real finding.

check:changeset-claims — ten verdicts, read by paragraph

The gate is report-only and exits 0. 10 pending entries name a file this diff touches. Verdict
per entry, each with the reading behind it. ⛔ Nothing was corrected: this diff falsifies none of them.

The decisive instrument, covering the eight "claims about code"

Every one of the five modified files is byte-identical to its base after comment stripping —
stripped through the TypeScript scanner (SingleLineCommentTrivia / MultiLineCommentTrivia
dropped), sha256 compared:

file stripped sha (base == head) stripped bytes
packages/app-shell/src/views/PageView.tsx 3e8a4778f747 5009
packages/components/src/__tests__/page-single-h1.test.tsx 77005bcb825e 4649
packages/components/src/renderers/layout/page.tsx a5af90104700 20919
packages/types/src/registry.ts 7c86c6a7aa64 3691
packages/types/src/zod/layout.zod.ts 45dff251cb6a 25925

Positive control: the stripper genuinely removes comments (page.tsx 32152 raw -> 20919 stripped).
Negative control: the same instrument reports DIFFERS when handed two genuinely different files.
⇒ ⛔ No claim about a .default() population, an accept set, a schema arm, a key, a registration,
a .describe() string or any symbol count can be moved by this diff.

⚠️ The two entries whose claims are counts over FILE CONTENT — a docblock IS file content

These are the ones the strip proof does not cover, so each was probed directly.

  • .changeset/8871-page-node-refuses-breadcrumbs.md — claims \.breadcrumbs is "exit 0 over
    4 files — every hit one of this branch's own four files (this changeset, the refusal pin,
    layout.ts, zod/layout.zod.ts)"
    . Probed tree-wide at base 92fba11eb and at head
    5b293107f: 4 files at both, and they are exactly the four named. Lit control on the same
    instrument, \.breadcrumb\b: 16 files at both — which is also the number that paragraph
    states for head. Absent-token control exits 1. And git diff base..head | grep -ci breadcrumb
    is 0 — this diff adds no mention of the token in any spelling. STILL TRUE; ⛔ nothing corrected.
  • .changeset/8478-describe-line-addresses.md — claims certain line addresses in
    layout.zod.ts are out of scope. layout.zod.ts carries exactly 1 line-address citation at
    base and 1 at head: `page.tsx:521`. My insertion into page.tsx begins at line 708,
    so 521 is not shifted — verified by content, not arithmetic: lines 519-523 of page.tsx are
    byte-identical at base and head. ⭐ And that address sits in a JSDoc block, not a
    .describe() string
    , so the entry's claim (which is about published .describe() descriptions)
    does not reach it at all. Two independent reasons. STILL TRUE of this diff; ⛔ nothing corrected.

The other eight

Each is covered by the strip proof; two also carry a probe over a file this diff touches, and both
probes were re-run rather than reasoned about.

  • 7926-page-node-refuses-actions.md — "git grep -ni action on page.tsx returns only the
    PageVariableActionBridge import and its render"
    . Re-run at base and at head: byte-identical
    hit sets, 4 lines each, same line numbers
    . Its second claim (3 actions author sites, all in
    content/docs/guide/layout.md) is over a file this diff does not touch. STILL TRUE.
  • page-source-tailwind-prose-retraction-5469.md — claims a specific kind === 'html'
    dispatch-arm comment in page.tsx does not project into dist. Mine is a different comment
    and likewise does not project (0 hits in dist/renderers/layout/page.d.ts after a real build).
    STILL TRUE.
  • 6951-text-value-retired.md (TextSchema.value tombstone; "the value?: string members of
    TextSpanSchema and TabsSchema in the same file are other schemas' contracts and are
    unchanged"
    ) · 7735-zod-mirrors-stop-authoring-defaults.md (41 .default() call sites
    removed, layout.zod.ts 22) · 8478-zod-pins-form-layout.md · 8499-node-slot-registered-arms.md
    (four named arms) · 8505-grid-columns-breakpoint-narrowing.md (GridSchema.columns) ·
    8516-8556-mirror-partial-record-narrowing.md (the mirror-narrowing table) — every claim is
    about a schema member, an arm, a call-site population or an accept set, and the stripped-source
    identity above says none of those can have moved. None names a comment. ALL STILL TRUE.

⛔ Already false before this branch existed — reported, ⛔ not corrected

  • 8478-describe-line-addresses.md says the remaining addresses are "held by in-flight PR
    objectui#8763"
    . That PR is merged (read from the API), so the present-tense clause is stale;
    its companion 8478-zod-pins-form-layout.md carries the same shape — but for PR
    objectui#8799 (merged), not objectui#8766. ⚠️ Corrected by the PM against the file itself:
    objectui#8766 appears in 8478-describe-line-addresses.md, already in the past tense and
    accurate there ("cleared when that PR merged during this round"), so it needs no repair.
    Both stale present-tense claims are now carded as objectui#9706. Its cardinal has moved too: the three files it names carry 2 / 1 / 7 line-address
    citations today (form.zod.ts / layout.zod.ts / complex.zod.ts), identical at base and head.
    ⇒ falsified by other branches' merges, ⛔ not by this diff, and ⛔ not this card's to repair.
  • Recorded because it looks like a finding and is not: my 40-line insertion into
    packages/types/src/registry.ts shifts a pre-existing citation (`renderer.tsx:256`,
    the chatbot note) from host line 264 to 304. The cited line is in
    packages/plugin-chatbot/src/renderer.tsx, which this diff does not touch, so the address still
    points where it did. No changeset names registry.ts.

Acceptance notes

  • ⭐ A premise on the card is wrong and is worth carrying forward. The card and the letter-E
    ruling both describe the registrations as "the five page kinds". They are four kinds plus the
    untyped-document fallback page; the fifth kind, list, is served by the interface-mode branch
    and is registered elsewhere, to a different renderer. Nothing in the ruling turns on this — E
    stands either way — but a declaration that repeated the card's wording would have been wrong on
    its face, so the wording above is the measured shape instead.
  • ⚠️ The card says "No test in this repository renders a stored page document through the real
    SchemaRenderer."
    Read narrowly about PageView's own test that is right; read as written it is
    not. page-single-h1.test.tsx renders a stored-page-shaped document with type: 'app' through
    the real SchemaRenderer — which is why removing the app registration reddens it. What was
    missing is not coverage but attribution: it goes red for a reason that reads as a heading bug.
    The new pin supplies that, ⛔ and no rendering suite was built as this card's deliverable.
  • PageNodeSchema pins type to z.literal('page') while the node PageView actually emits
    carries the kind. Noted, ⛔ not filed and ⛔ not repaired: it is the same undeclared channel this
    card exists to declare, and reconciling it is the render-path change the card fences off.
  • The showcase census re-derived here agrees with the ruling's R2 (home 8, app 6, list 5,
    record 3, utility 0) on the same instrument shape — but that instrument undercounts: one
    file defines seven pages sharing one spread type: 'list' as const base, so 22 page-level type
    hits stand against 28 definePage( calls. The utility zero stands beside a home 8 firing
    control and an absent-token zero on the same instrument. Reported, ⛔ not filed: no disposition
    here depends on the cardinal.
  • Not done, deliberately: no registration added/removed/renamed, PageTypeSchema untouched, the
    render path untouched, no name added to a published barrel, no label or ready flip, no
    auto-merge, no labels touched.

维护者速读

改了什么 — 六个源文件加了注释、一个新的 pin 测试、一个空 frontmatter 的 changeset。零行为改动:没有增删改任何
ComponentRegistry.register,没有动任何 Zod arm,没有动上游枚举(它在兄弟仓,只读)。

为什么改 — 存储的页面文档的 type 就是 spec 的页面 KIND,PageView 把它原样写进
ComponentRegistry 用来分发的节点判别符。于是 PageRenderer 上那几个注册项是因为这一行才存在的。
过去没有任何地方声明这件事,所以审计注册表的人看到「注册了但没有 schema 声明」——这在本仓是一个真实的缺陷
形态。这个误读已经产出两张方向错误的卡,其中一张走到了 draft PR,若落地会让六个已发布的 showcase 页面停止渲染
(页面位置画出 OBJUI-001)。现在这条通道在两个审计入口各写了一份声明,并由一个失败时会指名这条通道的测试钉住。

风险与代价(含回滚) — 风险极低:注释不参与编译语义,且实测不进入已发布的 .d.ts;唯一的可执行新增是一个
只读注册表、不渲染任何东西的测试。代价是这个 pin 会在有人改动这条通道时变红——这正是它存在的意义,⛔ 不要靠改
fixture 把它弄绿。回滚:git revert 这一个 commit 即可,没有迁移、没有数据形态变化、没有发布面变化。

你要做的 — 判两件事。① 声明放的位置对不对:packages/types/src/registry.ts 的 page 条目(节点类型词汇表
的审计入口)与 packages/types/src/zod/layout.zod.ts 的 SpecPageFields 注释(页面 KIND 词汇表的审计入口),
是否真的是两个方向的审计者各自会撞上的地方。② 卡面「五个注册项就是五个页面 KIND」这个说法实测不成立(是四个
KIND + 一个无 type 文档的兜底 page,第五个 KIND list 走 interface 模式、由别的渲染器注册),本 PR 按实测
措辞而非按卡面措辞落笔——请确认这个取舍。


🤖 Generated with Claude Code

https://claude.ai/code/session_01UanLVj6xvbS6puBCewLr8L


Generated by Claude Code


Generated by Claude Code

…channel

A stored page document's `type` is the spec page KIND, and PageView writes it
verbatim into the SchemaNode discriminator ComponentRegistry dispatches on. The
PageRenderer registrations exist because of that line, but nothing said so at
either place an auditor arrives, so two cards read them as "registered but never
declared" and one reached a draft PR that would have stopped every stored
kind-`app` page rendering.

Declared at both reading ends (the SchemaRegistry map's `page` entry, and the
registrations themselves), at the page-kind vocabulary's own face
(SpecPageFields' `type` omission bullet), and at the writing end. Pinned by a
new test that names the channel when it breaks, including that the registry key
`app` serves the spec page kind and not AppComponentSchema's app-level document
-- two vocabularies sharing one token.

No registration is added, removed or renamed; no accept set moves; no name joins
a published barrel; the upstream enum is read and never edited.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UanLVj6xvbS6puBCewLr8L
@github-actions

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 10 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/6951-text-value-retired.md

  • names layout.zod.ts → packages/types/src/zod/layout.zod.ts — edited by this change

    Two published faces, one retirement. The TypeScript interface TextSchema (@object-ui/types, layout.ts) declares value?: never; the Zod mirror TextSchema (@object-ui/types/zod, layout.zod.ts) declares value as a retirementTombstone(), so the key stays DECLARED and is refused BY NAME — a plain deletion would have let an authored value ride BaseSchema's .passthrough() into a silent blank, which is worse than the tolerated fallback it replaces. The value?: string members of TextSpanSchema and TabsSchema in the same file are other schemas' contracts and are unchanged.

.changeset/7735-zod-mirrors-stop-authoring-defaults.md

  • names layout.zod.ts → packages/types/src/zod/layout.zod.ts — edited by this change

    What changed. All 41 .default() call sites under packages/types/src/zod/ are removed — layout.zod.ts 22, crud.zod.ts 11, form.zod.ts 5, views.zod.ts 2, app.zod.ts 1. @object-ui/components reconciles the third face objectui#8229 found: flex's registration defaultProps.align seeded 'center', the value its own renderer never applies, so a designer-made node laid out differently from a hand-authored one; it now seeds 'start'.

.changeset/7926-page-node-refuses-actions.md

  • names packages/components/src/renderers/layout/page.tsx → packages/components/src/renderers/layout/page.tsx — edited by this change

    Accept-set change, deliberately. A page document carrying actions used to parse GREEN and render nothing. PageNodeSchema never declared the key and PageRenderer never read it — git grep -ni action on packages/components/src/renderers/layout/page.tsx returns only the PageVariableActionBridge import and its render — so the array survived purely through BaseSchema's .passthrough(). Measured through the real SchemaRenderer: a page node with actions: [{type:'button',label:'Add Product'}, …] drew 0 buttons and the label appeared nowhere in the DOM, while the SAME two buttons in body drew 2. Until objectui#7933 the array also reached the wrapper element as actions="[object Object],[object Object]".

.changeset/8478-describe-line-addresses.md

.changeset/8478-zod-pins-form-layout.md

.changeset/8499-node-slot-registered-arms.md

  • names zod/layout.zod.ts → packages/types/src/zod/layout.zod.ts — edited by this change

    • SemanticElementSchema (zod/layout.zod.ts) — the seven HTML sectioning tags renderers/layout/semantic.tsx registers: aside main header nav footer section article. - HtmlElementSchema (zod/layout.zod.ts) — the 37 safe flow/inline tags renderers/basic/html-elements.tsx registers (h1…h6, p, a, ul, img, …), plus the per-tag keys that module forwards to the DOM (href, target, rel, title, src, alt, width, height, dateTime, cite). - InputShorthandSchema (zod/form.zod.ts) — email / password, the two aliases renderers/form/input.tsx registers onto the input renderer with inputType pinned. inputType is deliberately NOT declared on this arm: the wrapper spreads its own value last, so an authored one is overwritten. - UiCalendarSchema (zod/form.zod.ts) — ui:calendar, the date-picker primitive renderers/form/calendar.tsx registers under exactly that key (skipFallback, because bare calendar belongs to the plugin-calendar view).

.changeset/8505-grid-columns-breakpoint-narrowing.md

.changeset/8516-8556-mirror-partial-record-narrowing.md

  • names zod/layout.zod.ts → packages/types/src/zod/layout.zod.ts — edited by this change

    | key | mirror was | mirror is | | :-- | :--------- | :-------- | | GridSchema.columns (zod/layout.zod.ts) | z.record(z.string(), z.number()) | a PARTIAL record over the six breakpoints | | ReportComponentSchema.exportConfigs (zod/reports.zod.ts) | z.record(z.string(), ReportExportConfigSchema) | a PARTIAL record over ReportExportFormat |

.changeset/8871-page-node-refuses-breadcrumbs.md

  • names zod/layout.zod.ts → packages/types/src/zod/layout.zod.ts — edited by this change

    What was measured, on this branch's base 93127bd6f. Zero readers, with a point-access probe rather than a bare word: on that base \.breadcrumbs scores 0 tree-wide (exit 1) against \.breadcrumb\b's 12 files tree-wide (10 under packages/) as the lit control. At head the same two probes read 16 and 13 and \.breadcrumbs is exit 0 over 4 files — every hit one of this branch's own four files (this changeset, the refusal pin, layout.ts, zod/layout.zod.ts) quoting the probe string, and the pin's own exclusions put head back at exit 1. The base reading is the measurement; the head reading is this branch's echo of it. The bare word would have lied — it also names Sentry's own unrelated concept (app-shell/src/observability/sentry.ts) and appears in two comments listing UI surfaces (core/src/utils/record-title.ts, layout/src/NavigationRenderer.tsx), so a bare probe reports five readers that do not exist.

.changeset/page-source-tailwind-prose-retraction-5469.md

  • names src/renderers/layout/page.tsx → packages/components/src/renderers/layout/page.tsx — edited by this change

    • @object-ui/react-runtime: README.md is published to npm (npm includes README.md in the tarball regardless of files). Its "no sandbox" callout is the paragraph that routes untrusted-author work to the html tier, and it carried the retracted framing line-wrapped across :17-18. It also gains the §Styling section it was missing — the absence is why the framing survived here. - @object-ui/sdui-parser: the corrected header of src/types.ts projects verbatim into the published dist/types.d.ts. - @object-ui/components: the corrected header of src/renderers/basic/html-elements.tsx projects verbatim into the published dist/renderers/basic/html-elements.d.ts. The kind === 'html' dispatch-arm comment in src/renderers/layout/page.tsx does not project (it is inside a function body) and is included here only because the same package already owes an entry.

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 claim that was born false (a changeset this change adds is excluded by construction), 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 2923cea16 (merge-base with origin/main): 6 file(s) changed outside .changeset/, read against 1126 pending declaration(s) that publish a body (1635 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3049.0 KB 3104.5 KB
Main entry chunk (gzip) 145.7 KB 350 KB
Entry file index-CqfP7f5i.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 545.85KB 130.67KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 215.98KB 59.97KB
fields (index.js) 249.27KB 62.92KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.83KB 10.95KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.92KB 14.22KB
plugin-charts (index.js) 71.49KB 19.99KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.44KB 34.65KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 253.29KB 65.88KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.71KB 34.16KB
plugin-gantt (index.js) 167.62KB 41.26KB
plugin-grid (index.js) 212.64KB 57.91KB
plugin-kanban (index.js) 46.41KB 14.49KB
plugin-list (index.js) 112.73KB 27.69KB
plugin-map (index.js) 21.48KB 6.99KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 85.04KB 21.01KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 104.82KB 34.67KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.04KB 5.36KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-sales
os-sales marked this pull request as ready for review September 17, 2026 17:31
@os-sales
os-sales added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 396a1c1 Sep 17, 2026
38 checks passed
@os-sales
os-sales deleted the claude/issue-9642-page-kind-node-discriminator-coupling branch September 17, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants