Skip to content

fix(types): one SchemaNode and one label vocabulary — the union wins, labels resolve where the locale lives (#4580) - #4608

Merged
yinlianghui merged 4 commits into
mainfrom
claude/issue-4580-one-schemanode-round2
Aug 13, 2026
Merged

yinlianghui merged 4 commits into
mainfrom
claude/issue-4580-one-schemanode-round2

Conversation

@yinlianghui

@yinlianghui yinlianghui commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #4580.

Executes, as ONE seat with one repo-wide canary, the three pieces #4580's rulings left open: the revised Q1-A label-vocabulary ruling, the SchemaNode reconciliation (original ruling 1), and Q4-B (bridge return types).

The ruling chain

# Ruling Where Status here
1 types' union wins; core re-exports claim comment 5282651398 piece B
Q1-B label/description stay string; bridges resolve comment 5284007579 ⛔ premise measured FALSE by PR #4603
Q1-A label/description widen; resolve at READ time comment 5284973826 (revision) piece A
Q4-B bridge return types annotated BaseSchema comment 5284007579 piece C

The revision is the load-bearing one. Q1-B was ruled first and PR #4603's seat measured its premise false on every leg — the bridge is a plain class method that cannot call a hook, BridgeContext declares no locale, updateContext() has zero callers. The PM revised rather than leaving the reconciliation permanently blocked:

Revised Q1 ruling — option A: BaseSchema.label and .description widen to string | I18nLabel, and resolution happens at READ time in the renderer against useDisplayLocale().

Piece A — the widening, and the inventory it produced

BaseSchema.label and .description are now string | I18nLabel, where I18nLabel is the spec's INLINE locale map. Measured against the installed @objectstack/spec 17.0.0-rc.6 rather than assumed:

declare const I18nLabelSchema: z.ZodUnion< readonly [z.ZodString, z.ZodRecord< z.ZodString, z.ZodString > ] >;
type I18nLabel = z.input< typeof I18nLabelSchema >;

so string | Record< string, string > — a real widening, not a no-op.

⚠️ Note on one character in the quoted compiler output below. GitHub's body sanitizer strips a < that is immediately followed by a letter, treating it as an HTML tag. Published verbatim, tsc's Record + < + string, string + > was stored as bare Record, silently deleting the type argument from three blocks of evidence — caught by reading the body back after publishing. Every such generic quoted in this PR therefore carries one space after the < so it survives at rest. That space is an artifact of the sanitizer, not part of tsc's output.

The compiler inventory IS the audit. The widening turns every blind schema.label-as-string read into a named TS2322. Repo-wide downstream canary, --continue so every package reports:

# File : line What reaches the slot Package
1 components/src/renderers/complex/filter-builder.tsx:29 {schema.label} into a < label > text node @object-ui/components
2 components/src/renderers/navigation/sidebar.tsx:108 {schema.label} into < SidebarGroupLabel > @object-ui/components
3 components/src/renderers/overlay/dropdown-menu.tsx:61 {schema.label} into < DropdownMenuLabel > @object-ui/components
4 plugin-dashboard/src/DashboardGridLayout.tsx:328 {schema.title || schema.label || 'Dashboard'} into < h2 > @object-ui/plugin-dashboard

All four report the identical error, e.g.:

src/renderers/complex/filter-builder.tsx(29,61): error TS2322: Type 'string | Record< string, string >' is not assignable to type 'ReactNode'.

Four sites, one class — well under the card's ~25-site STOP threshold, so piece A shipped. description produced zero read-site errors. Both packages already depend on @object-ui/i18n, so both are i18n-reachable and no packages/layout-style no-i18n-dependency workaround was needed.

Red-first — the harm is a THROW, not [object Object]

Measured on the unfixed source before any edit, by invoking each registered renderer directly. All four sites, byte-identical message:

Objects are not valid as a React child (found: object with keys {en, zh-CN}). If you meant to render a collection of children, use an array instead.

A text node is a position React refuses outright rather than stringifying, so the pre-fix harm is the whole subtree failing to render, not a cosmetic mis-render. This is worth stating because the card predicted [object Object] or a throw; it is the throw.

⚠️ One probe was vacuous and the correction is kept rather than quietly fixed. dropdown-menu first measured as an EMPTY container with no throw — Radix mounts DropdownMenuContent lazily, so the label is unreachable with the menu closed. A case written that way would have shipped looking green while proving nothing. defaultOpen: true is load-bearing in the shipped test for exactly that reason, and the test header says so.

The fixes

Sites 1-3 resolve with the spec's own resolveI18nLabel against useDisplayLocale(), aliased on import following PR #4169's convention (and AppSchemaRenderer.tsx:44's use of it), because this repo has its own resolveKeyedI18nLabel over a different vocabulary. Hooks are legal in these renderers: the registry renders its entries with React.createElement (SchemaRenderer.tsx:621), and elements.tsx:380 already calls useDisplayLocale() in one. Two renderers gained a block body solely to host the hook.

Site 4 deliberately uses pickLocalized against the active UI language instead, and this is a departure from the card's letter that I want reviewed. DashboardGridLayout already resolves the sibling slot — widget.title, the same inline-map vocabulary — with pickLocalized(widget.title, language) seventy lines below. Adding the spec resolver plus useDisplayLocale() would put two resolvers AND two locale channels in one component for one vocabulary, and those channels genuinely disagree: useDisplayLocale() prefers the tenant's regional default over the active UI language, so a heading and the widget titles beneath it could resolve to different languages in the same render. This is not a lenient fallback standing in for the real resolver — pickLocalized is objectui's limb-for-limb twin of resolveI18nLabel (objectstack#6765 aligned them deliberately), differing only in how each spells a miss ('' vs undefined), pinned in plugin-list/src/__tests__/i18nLabel-resolver-parity.test.ts. The || chain is preserved exactly, and a test pins that the 'Dashboard' backstop still fires.

The resolver's documented fallback is pinned, not assumed

Cases cover exact match, base/region (zh-CN ↔ zh), and the last-resort limb ({ 'ja-JP': … } viewed as fr), per the resolver's own doc. A resolver that only ever hits the exact limb is indistinguishable from a lookup that ignores the locale, so the other two limbs are pinned separately. String-passthrough-unchanged is pinned at every site.

PIN MOVED

base-schema-label-vocabulary.test.ts's assertionLabel / assertionDescription pinned label/description as string under Q1-B, and that file's header predicted in advance that "a future card that 'fixes' the bridge defect by widening BaseSchema.label turns them red on purpose." That is exactly what happened, on the very next card. Measured red before the move:

base-schema-label-vocabulary.test.ts(153,38): error TS2344: Type 'false' does not satisfy the constraint 'true'.
base-schema-label-vocabulary.test.ts(154,44): error TS2344: Type 'false' does not satisfy the constraint 'true'.

They now pin the widened unions, annotated PIN MOVED (objectui#4580 revised Q1), with the superseded history kept rather than rewritten. A new assertionVocabulariesAreDistinct pins that label and ariaLabel do NOT collapse into each other — without it, an edit that "simplified" one union into the other would leave both Equal pins green while silently swapping which resolver owns the slot. Every Equal is invariant, for the reason #4593 established: a one-way extends is vacuous for a widening in both directions.

The bridges are untouched by piece A — verified, not asserted

The reverse verification proves this directly. With piece C still applied and ONLY piece A reverted, the two bridge sites go red again at exactly the lines #4593 measured:

src/spec-bridge/bridges/list-view.ts(180,19): error TS2322: Type 'string | Record< string, string >' is not assignable to type 'string | undefined'.
src/spec-bridge/bridges/list-view.ts(224,25): error TS2322: Type 'string | Record< string, string >' is not assignable to type 'string | undefined'.

So it is piece A's widening — not piece C's annotation — that makes node.label = spec.label and node.description = spec.description compile, and both assignment expressions are byte-unchanged.

Piece B — one SchemaNode

packages/core/src/types/index.ts's hand-declared interface SchemaNode becomes export type { SchemaNode } from '@object-ui/types';. No structural copy: a copy reproduces the defect the moment either side moves.

Core's entry surface is unchanged — measured, both rounds: packages/core/dist/index.d.ts is byte-identical across the change (sha256 3d1bf0ff…21fb25 on both trees).

The preserved pin, restored and red-first

Round 1's withdrawn reconciliation pin was preserved byte-identical (sha256 1294d525…8e4d4) and is restored as packages/react/src/__tests__/SchemaNode.reconciliation.test.ts. It lives in @object-ui/react because the collision is only observable from a package resolving BOTH through node_modules; that package's tsconfig.test.json sets "paths": {} precisely so the two dist identities are real.

With piece B reverted, all three of its written-first predictions hold, and the error text names both identities verbatim — the #4548 class:

SchemaNode.reconciliation.test.ts(64,34): error TS2344: Type 'false' does not satisfy the constraint 'true'.
SchemaNode.reconciliation.test.ts(90,9): error TS2322: Type 'import(".../packages/types/dist/base").SchemaNode' is not assignable to type 'import(".../packages/core/dist/types/index").SchemaNode'.
SchemaNode.reconciliation.test.ts(96,19): error TS2345: Argument of type 'import(".../packages/types/dist/base").SchemaNode' is not assignable to parameter of type 'import(".../packages/core/dist/types/index").SchemaNode'.
SchemaNode.reconciliation.test.ts(101,14): error TS2322: Type 'string' is not assignable to type 'SchemaNode'.
SchemaNode.reconciliation.test.ts(102,14): error TS2322: Type 'null' is not assignable to type 'SchemaNode'.
SchemaNode.reconciliation.test.ts(113,11): error TS2322: Type 'string' is not assignable to type 'SchemaNode'.

⚠️ A latent defect in the preserved pin, found and fixed

The pin as preserved could not run under vitest. typesNode and acceptsCoreNode are declared — type-level fictions with no runtime existence — so the top-level export const coreNodeHoldsTypesNode: CoreSchemaNode = typesNode; type-checked correctly but threw on import:

ReferenceError: typesNode is not defined
 ❯ packages/react/src/__tests__/SchemaNode.reconciliation.test.ts:77:55

failing the whole suite before a single case ran (Test Files 1 failed | 44 passed, Tests 604 passed — zero test failures, a load failure). Round 1 only ever type-checked this file, so the defect was invisible there. It is moved into a never-called function, which tsc checks just as thoroughly and which never executes. The pin was then re-verified red against a reverted core after the fix — the errors above are from that second run, so the fix is proven not to have made it vacuous.

Piece C — the bridges return BaseSchema

BridgeFn, SpecBridge.transform / transformListView / transformFormView, and both bridge functions now declare BaseSchema. Both bridges end in a single return node on an object literal (list-view.ts:226, form-view.ts:195), so the union described nothing real while forcing a narrowing at every read.

Reverse verification, piece C alone reverted — 272 errors, matching round 1's measurement exactly, across the same five suites:

Suite Errors
P1SpecBridge.test.ts 108
SpecBridge.test.ts 102
FormViewSpecConformance.test.ts 48
RowHeightDensityAgreement.test.ts 10
ListViewExportOptionsLift.test.ts 4

by class: 134 × TS18049 ('node' is possibly 'null' or 'undefined'), 131 × TS2339 (Property 'formType' does not exist on type 'string | number | boolean | BaseSchema'), 4 × TS2322, 2 × TS2533, 1 × TS7053. Piece C kills all 272 — no residue needed narrowing in test files.

Canary — per class, before and after

Repo-wide, PREFIX filter = the downstream consumers (the direction that matters for a widening):

Class Before After Killed by
SchemaNode collision (#4548's 19-of-35) latent on main; 6 errors when pinned 0 piece B
list-view.ts label/description 2 0 piece A (bridges untouched)
spec-bridge test residue 272 0 piece C
label read sites 4 0 piece A
moved pins 2 0 piece A

Final state, post-merge, all three directions:

Filter Result
...@object-ui/types 77 / 77 successful, 0 errors
...@object-ui/core 72 / 72 successful, 0 errors
...@object-ui/react 67 / 67 successful, 0 errors

The collision class is worth one note: on main today the canary is green, because PR #4578 sidestepped the collision rather than leaving it live. The 19-of-35 figure is #4548's measurement under its option A, and the honest way to show the defect still exists is the pin — which is why the pin, not the canary, carries piece B's red.

Tests

Repo-root vitest run --maxWorkers=2 over the consumption radius, split into four runs (the single combined run exceeded the 600 s cap and was re-run split, not abandoned):

Radius Files Tests
types, core, plugin-dashboard 172 2621 passed
components, layout 135 1223 passed
react 45 605 passed
app-shell 394 3725 passed, 1 skipped
total 746 8174 passed, 1 skipped, 0 failed

Emit discipline

Both trees built with dist/ and every *.tsbuildinfo cleared, through turbo so the dependency closure is built identically on both sides.

Package Emitted JS Note
@object-ui/types byte-identical b9a2769d…41d4cb both sides
@object-ui/core byte-identical 1c4ebaa7…839d042 both sides — piece B proven types-only
@object-ui/react comment-only sole delta is the JSDoc I expanded on transform; executable code byte-identical after comment strip
@object-ui/components 1 import + 3 call sites piece A, enumerated below
@object-ui/plugin-dashboard 1 line piece A

Piece A's runtime footprint is exactly the four inventory sites and nothing else. In the components bundle: one added import and exactly three resolver calls — Bn(e.label, i), Bn(e.label, n), Bn(e.label, r) — against zero in the baseline. The remainder of that bundle's diff is a minifier alpha-rename cascade triggered by the new import shifting the identifier sequence (Bn→Vn→Hn→Un→…), not a semantic change. In plugin-dashboard the entire executable delta is one line:

- children: t.title || t.label || "Dashboard"
+ children: t.title || V(t.label, m) || "Dashboard"

Per-package .d.ts and grading — measured

Package .d.ts differing What changed Grade
@object-ui/types 2 of 54 base.d.ts (the two widened unions + evidence comments); zod/index.zod.d.ts is order-only minor
@object-ui/core 1 of 86 types/index.d.ts — declaration moved to a re-export; entry index.d.ts byte-identical minor
@object-ui/react 2 of 63 spec-bridge/types.d.ts, spec-bridge/SpecBridge.d.ts — return types minor
@object-ui/components 1 of 206 ui/command.d.ts — order-only, unrelated to this change minor
@object-ui/plugin-dashboard 0 of 24 none; the change is runtime minor

types is minor by position analysis: the diff ADDS members to unions on two authored-input-dominant properties, removes nothing, and nothing that type-checked before stops doing so — the #4593/#4603 line. core is minor on #4569 (declaration moved, entry surface intact). react is minor by measurement rather than by rule: the return type is NARROWED (SchemaNode → BaseSchema), which is free for callers reading the result but tightens the contract for anyone implementing a BridgeFn. components / plugin-dashboard are minor as a behavior move on the #4495/#4271/#4479 line. Never major.

Two .d.ts diffs were checked rather than waved away, because an unexplained diff in a published declaration is exactly what a grading claim must not contain:

  • types/zod/index.zod.d.ts — identical as a multiset of lines; pure key-order churn in tsc's zod inference, the same class PR fix(types): ariaLabel declares the keyed vocabulary, disabled accepts the predicate string (#4581) #4603 recorded.
  • components/ui/command.d.ts — two lines, "onChange" | "value" | "type" versus "type" | "onChange" | "value" inside an Omit. Set-identical after sorting union members, and the file mentions none of SchemaNode / BaseSchema / I18nLabel — tsc union-ordering nondeterminism, not reachable from this change.

must-not-change

Verification

  • 11 local gates PASS: control-bytes, phantom-dependencies, changeset-presence, changeset-no-major, changeset-fixed, type-check-coverage, lint-coverage, spec-symbol-derivation, i18n-call-site-keys, i18n-en-drift, doc-links. Re-run after both forward merges, including finding(tooling): rule 2's tie test is symbol-agnostic, so a declaration can cite a retired spec symbol and pass because it references a different, live one #4607's newly tightened spec-symbol gate.
  • eslint: 0 errors both sides. On the 11 pre-existing touched files, 71 → 69 problems, net −2 — both from core/src/types/index.ts, whose hand-declared interface (data?: any plus an index signature) became a re-export. The 3 new files add 2 warnings, 0 errors.
  • Control-byte and NBSP self-scan clean over every file this branch touches, including untracked ones; re-scanned after each edit pass.

Filed, not fixed

Noted for #4605's zod-mirror drift census, per the card: this widening adds label and description to it. packages/types/src/zod/base.zod.ts still declares both as z.string(), now narrower than the TypeScript declarations they mirror — the same class #4603 filed for visible / disabled / ariaLabel. Not touched here: widening a published validator is a contract decision, and for these two slots it is the same INLINE-versus-KEYED question #4605 already holds.


Generated by Claude Code

… labels resolve where the locale lives (#4580)

Piece B: core's hand-declared `interface SchemaNode` becomes a re-export of
`@object-ui/types`' union (ruling 1). Piece A: `BaseSchema.label`/`.description`
widen to `string | I18nLabel`, resolved at READ time against the display locale
(revised Q1-A ruling, comment 5284973826) — the compiler inventory named four
read sites, all one class. Piece C: the spec bridges declare `BaseSchema`
returns instead of the union (ruling Q4-B), a type annotation only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
@vercel

vercel Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 13, 2026 8:10pm

Request Review

…anode-round2

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-CC3mQjmF.js —
Status PASS —

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 38.46KB 10.17KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.35KB 1.07KB
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.02KB 0.88KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 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.65KB 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) 489.48KB 108.55KB
core (index.js) 3.79KB 1.52KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 163.56KB 44.83KB
fields (index.js) 230.37KB 57.17KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.98KB 10.85KB
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.74KB
mobile (index.js) 1.50KB 0.62KB
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.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.86KB 12.91KB
plugin-charts (index.js) 62.10KB 17.67KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 121.05KB 31.57KB
plugin-designer (index.js) 212.58KB 42.83KB
plugin-detail (index.js) 239.93KB 60.01KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 114.72KB 27.70KB
plugin-gantt (index.js) 164.30KB 40.02KB
plugin-grid (index.js) 190.02KB 50.48KB
plugin-kanban (index.js) 52.74KB 14.53KB
plugin-list (index.js) 112.01KB 27.27KB
plugin-map (index.js) 18.16KB 5.81KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.38KB 11.09KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.09KB 20.56KB
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.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 27.64KB 9.44KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.26KB 0.67KB
react (schema-input.js) 1.45KB 0.83KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.05KB 1.52KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
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 (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
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

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-CC3mQjmF.js —
Status PASS —

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 38.46KB 10.17KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.35KB 1.07KB
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.02KB 0.88KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 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.65KB 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) 489.48KB 108.55KB
core (index.js) 3.79KB 1.52KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 163.56KB 44.83KB
fields (index.js) 230.37KB 57.17KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.98KB 10.85KB
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.74KB
mobile (index.js) 1.50KB 0.62KB
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.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.86KB 12.91KB
plugin-charts (index.js) 62.10KB 17.67KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 121.05KB 31.57KB
plugin-designer (index.js) 212.58KB 42.83KB
plugin-detail (index.js) 239.93KB 60.01KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 114.72KB 27.70KB
plugin-gantt (index.js) 164.30KB 40.02KB
plugin-grid (index.js) 190.02KB 50.48KB
plugin-kanban (index.js) 52.74KB 14.53KB
plugin-list (index.js) 112.01KB 27.27KB
plugin-map (index.js) 18.16KB 5.81KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.38KB 11.09KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.09KB 20.56KB
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.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 27.64KB 9.44KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.26KB 0.67KB
react (schema-input.js) 1.45KB 0.83KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.05KB 1.52KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
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 (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
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

claude added 2 commits August 13, 2026 20:01
…4580)

`typesNode` and `acceptsCoreNode` are `declare`d — type-level fictions with no
runtime existence — so the top-level `const coreNodeHoldsTypesNode = typesNode`
type-checked correctly but threw `ReferenceError: typesNode is not defined` the
moment vitest imported the module, failing the suite before any case ran.
Round 1 only ever type-checked this file, so the defect was latent in the
preserved pin. Moved into a never-called function: `tsc` checks the body just as
thoroughly and it never executes. Re-verified that the pin still goes red when
core's re-export is reverted, naming both `dist` identities.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
…anode-round2

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-CC3mQjmF.js —
Status PASS —

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 38.46KB 10.17KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.35KB 1.07KB
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.02KB 0.88KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 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.65KB 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) 489.48KB 108.55KB
core (index.js) 3.79KB 1.52KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 163.56KB 44.83KB
fields (index.js) 230.37KB 57.17KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.98KB 10.85KB
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.74KB
mobile (index.js) 1.50KB 0.62KB
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.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.86KB 12.91KB
plugin-charts (index.js) 62.10KB 17.67KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 121.05KB 31.57KB
plugin-designer (index.js) 212.58KB 42.83KB
plugin-detail (index.js) 239.93KB 60.01KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 114.72KB 27.70KB
plugin-gantt (index.js) 164.30KB 40.02KB
plugin-grid (index.js) 190.02KB 50.48KB
plugin-kanban (index.js) 52.74KB 14.53KB
plugin-list (index.js) 112.01KB 27.27KB
plugin-map (index.js) 18.16KB 5.81KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.38KB 11.09KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.09KB 20.56KB
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.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 27.64KB 9.44KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.26KB 0.67KB
react (schema-input.js) 1.45KB 0.83KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.05KB 1.52KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
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 (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
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

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-CC3mQjmF.js —
Status PASS —

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 38.46KB 10.17KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.35KB 1.07KB
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.02KB 0.88KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 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.65KB 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) 489.48KB 108.55KB
core (index.js) 3.79KB 1.52KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 163.56KB 44.83KB
fields (index.js) 230.37KB 57.17KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 38.98KB 10.85KB
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.74KB
mobile (index.js) 1.50KB 0.62KB
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.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.86KB 12.91KB
plugin-charts (index.js) 62.10KB 17.67KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 121.05KB 31.57KB
plugin-designer (index.js) 212.58KB 42.83KB
plugin-detail (index.js) 239.93KB 60.01KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 114.72KB 27.70KB
plugin-gantt (index.js) 164.30KB 40.02KB
plugin-grid (index.js) 190.02KB 50.48KB
plugin-kanban (index.js) 52.74KB 14.53KB
plugin-list (index.js) 112.01KB 27.27KB
plugin-map (index.js) 18.16KB 5.81KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.38KB 11.09KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.09KB 20.56KB
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.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 27.64KB 9.44KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.26KB 0.67KB
react (schema-input.js) 1.45KB 0.83KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.05KB 1.52KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
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 (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
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

@yinlianghui
yinlianghui marked this pull request as ready for review August 13, 2026 20:23
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit c1d939f Aug 13, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4580-one-schemanode-round2 branch August 13, 2026 20:24
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Aug 17, 2026
…the docs site builds again (objectstack-ai#4617) (objectstack-ai#4621)

`Build Docs` (`next build`, which type-checks apps/site) has failed on every
push to `main` since PR objectstack-ai#4608 landed, with 5x TS2322 at the five call sites
that hand a `SchemaNode` to `SchemaRenderer`'s `schema` prop.

Route all five through `toRenderableSchema`, the adapter objectstack-ai#4548-Q2 kept for
exactly this crossing: `SchemaNode` deliberately includes `number`/`boolean`,
SchemaRenderer's component union deliberately excludes them. Not a prop
widening, not a cast.

Also close the gate gap that let this reach `main` green: apps/site's
type-check script was named `types:check`, so `turbo run type-check` listed it
as `<NONEXISTENT>` and never ran it. Renamed to `type-check`; its
CHECKED_BY_OWN_BUILD exemption retires with the rename, as that gate's own
ratchet requires.


Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3

Co-authored-by: Claude <noreply@anthropic.com>
os-sales pushed a commit that referenced this pull request Aug 21, 2026
…#4622)

The closing paragraph of `toRenderableSchema`'s JSDoc said the two competing
repo-wide `SchemaNode` spellings "have not been reconciled" and that "when it
lands, the call sites using this can go back to forwarding directly". Both
halves went false when PR #4608 merged, and the second half is the harmful one:
it is an instruction whose trigger condition has now fired, sitting directly
above the function a future author is about to call.

The reconciliation (objectui#4580 / PR #4608) resolved the collision in favour
of `@object-ui/types`' union — `packages/core/src/types/index.ts:41` is now
`export type { SchemaNode } from '@object-ui/types';` — while SchemaRenderer's
prop stays deliberately narrow per objectui#4548 ruling Q2
(`schema: BaseSchema | string | null | undefined`, no `number` / `boolean`). So
a `SchemaNode` became LESS assignable to that prop, not more, and the bridge is
a permanent crossing between two intentionally different types.

Following the old instruction has a measured cost, and the new paragraph names
it: five `apps/site` call sites were forwarding directly when PR #4608 landed,
and `Build Docs` was red on `main` for roughly five hours until PR #4621 routed
all five through this function (objectui#4617).

Comment-only. The emitted JavaScript is byte-identical (both revisions of the
file transpiled with `tsc --removeComments`, sha256
ce9ba5c4ce7590dce63e5ca853cfb7a79d55df338d1fd32403b215b39cefda06 on each side),
and no changed line falls outside the JSDoc block. The paragraph does ship,
which is why a patch changeset is owed: this package builds with plain `tsc`,
so the comment is carried into `dist/schema-input.d.ts`.

Fixes #4622

Claude-Session: https://claude.ai/code/session_012u2pRjcqAYtoEjgr3wwhnK

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Aug 23, 2026
…objectstack-ai#4622) (objectstack-ai#5602)

* docs(react): toRenderableSchema's header says the bridge is permanent (objectstack-ai#4622)

The closing paragraph of `toRenderableSchema`'s JSDoc said the two competing
repo-wide `SchemaNode` spellings "have not been reconciled" and that "when it
lands, the call sites using this can go back to forwarding directly". Both
halves went false when PR objectstack-ai#4608 merged, and the second half is the harmful one:
it is an instruction whose trigger condition has now fired, sitting directly
above the function a future author is about to call.

The reconciliation (objectui#4580 / PR objectstack-ai#4608) resolved the collision in favour
of `@object-ui/types`' union — `packages/core/src/types/index.ts:41` is now
`export type { SchemaNode } from '@object-ui/types';` — while SchemaRenderer's
prop stays deliberately narrow per objectui#4548 ruling Q2
(`schema: BaseSchema | string | null | undefined`, no `number` / `boolean`). So
a `SchemaNode` became LESS assignable to that prop, not more, and the bridge is
a permanent crossing between two intentionally different types.

Following the old instruction has a measured cost, and the new paragraph names
it: five `apps/site` call sites were forwarding directly when PR objectstack-ai#4608 landed,
and `Build Docs` was red on `main` for roughly five hours until PR objectstack-ai#4621 routed
all five through this function (objectui#4617).

Comment-only. The emitted JavaScript is byte-identical (both revisions of the
file transpiled with `tsc --removeComments`, sha256
ce9ba5c4ce7590dce63e5ca853cfb7a79d55df338d1fd32403b215b39cefda06 on each side),
and no changed line falls outside the JSDoc block. The paragraph does ship,
which is why a patch changeset is owed: this package builds with plain `tsc`,
so the comment is carried into `dist/schema-input.d.ts`.

Fixes objectstack-ai#4622

Claude-Session: https://claude.ai/code/session_012u2pRjcqAYtoEjgr3wwhnK

Co-authored-by: Claude <noreply@anthropic.com>

* docs(react): correct the emit claim on this branch — the JSDoc does ship as bytes

The changeset on the previous commit said "the emitted JavaScript is byte-identical".
That is FALSE, and the way it became false is worth recording, because it is the same
failure mode this card exists to prevent — a confident claim that does not survive being
checked.

The measurement behind it transpiled both revisions with `tsc --removeComments` and
compared sha256s. That is a correct measurement of a build this repo does not perform:
`tsconfig.base.json:22` sets `"removeComments": false` deliberately, and this package
builds with plain `tsc`, so comments are emitted into `dist/*.js`. The flag measured away
the very thing being measured.

Re-measured by building the package the way the repo builds it, at both revisions, with
`dist/` cleared between runs:

    dist/schema-input.js   1,486 B -> 2,316 B   (1.45 KB -> 2.26 KB)
    gzipped                  850 B -> 1,246 B   (0.83 KB -> 1.22 KB)
                                                +830 B raw, +396 B gzipped

which reproduces CI's bundle-size rows for this PR (2.26 KB / 1.22 KB) and for two
sibling PRs cut from the same merge-base that do not touch this file (1.45 KB / 0.83 KB).

What IS true, and is what the changeset now says: all 18 differing lines in the emitted
file are JSDoc continuations, and the three executable lines are byte-identical, so the
growth is the paragraph and nothing else. The source change remains comment-only — the
`git diff -U0` structural check is unaffected and still holds.

The doc paragraph itself is unchanged: it makes no claim about emitted bytes, and the
size is not being chased. Roughly 0.4 KB gzipped is the deliberate price of not repeating
a five-hour `Build Docs` outage.

Claude-Session: https://claude.ai/code/session_012u2pRjcqAYtoEjgr3wwhnK

Co-authored-by: Claude <noreply@anthropic.com>

* docs(react): scope the union spelling to objectstack-ai#4617's logs, so it cannot go stale

PM ruling on the wording of the TS2322 clause: neither "against this function's return
type" alone nor a bare `string | BaseSchema | null | undefined` alone, but both, with the
literal spelling scoped as a historical quotation.

The reasoning is the axis I had not weighed. Describing the type by its ROLE is
self-updating — if `SchemaRendererProps['schema']` gains or loses a member tomorrow, the
sentence stays true with no edit. Hardcoding today's spelling as a present-tense claim is
NOT self-updating, and would have added a fresh way for this paragraph to go false, which
is the exact defect the paragraph exists to fix. Attributing the spelling to what objectstack-ai#4617's
logs said in August 2026 is a fixed fact that cannot rot however the union evolves, and it
hands a reader with the log open the exact string to match in one hop.

    - `number` against this function's return type — until PR objectstack-ai#4621 routed all five
    - through here (objectui#4617).
    + `number` against this function's return type, spelled
    + `string | BaseSchema | null | undefined` in objectui#4617's logs — until
    + PR objectstack-ai#4621 routed all five through here.

The paragraph grew, so both byte figures in the changeset are re-measured rather than
left stale — the same build, at both revisions, with `dist/` cleared between runs:

    dist/schema-input.js   1,486 B -> 2,377 B   (1.45 KB -> 2.32 KB)   +891 B
    gzipped                  850 B -> 1,266 B   (0.83 KB -> 1.24 KB)   +416 B

previously 2,316 B / 1,246 B for the shorter paragraph. All 19 differing lines in the
emitted file are JSDoc continuations (was 18) and the three executable lines remain
byte-identical, so the growth is still the paragraph and nothing else.

Noted for next time, per the PM: quoting exact byte counts in a changeset couples it to
the comment's length, which is what made this edit cost a re-measure. Still the right
call here — the numbers are the honest replacement for a claim that was wrong — but a
cost to choose deliberately rather than by default.

Claude-Session: https://claude.ai/code/session_012u2pRjcqAYtoEjgr3wwhnK

Co-authored-by: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
os-sales pushed a commit that referenced this pull request Sep 17, 2026
…nce instead of letting it read as live

Three docblocks stated a retired producer's behaviour in the PRESENT tense
("assigns", "already writes"), one of them as the stated factual basis of
objectui#4580's revised Q1 ruling. The producer was removed by objectui#6366
(PR #6632) as a declared BREAKING CHANGE, so the sentences read as live while
being false, which is the shape AGENTS.md #9 forbids.

Established per site at the write-time ref, not per card: the sentences were
TRUE when PR #4608 wrote them on 2026-08-13 — at that commit
`packages/react/src/spec-bridge/bridges/list-view.ts` exported `bridgeListView`
and carried the label and description assignments at exactly the cited
addresses. They are therefore ROTTED, not born false, so each is KEPT, quoted,
dated, and followed by a dated note naming objectui#6366 as the falsifier.
Deleting them would erase that objectui#4580 ever had a stated rationale.

What the docblocks now assert points at instruments rather than at a retired
producer: the declared face is re-derived by
`inline-locale-declared-face-9092.test.ts`, the read side by the renderer pins.
No figure is written down.

Nothing executable moves — the diff is comment-only plus one changeset.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UanLVj6xvbS6puBCewLr8L
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
…e instead of letting it read as live (objectstack-ai#9365) (objectstack-ai#9742)

Fixes objectstack-ai#9365

Clause-②: no

Three docblocks described `bridgeListView` — a producer objectui#6366
retired as a declared BREAKING CHANGE — in the PRESENT tense (`assigns`,
`already writes`), one of them as the stated factual basis of
objectui#4580's revised Q1 ruling. Nothing re-derives those sentences
and nothing can, which is the shape AGENTS.md objectstack-ai#9 forbids. This is a
paper-trail repair: nothing executable moves and objectui#4580 is
**not** re-litigated.

## Per-site verdict — established at the WRITE-TIME ref, per SITE

`git log -S` named one write-time ref for all three sentences:
`c1d939f7f` — "fix(types): one SchemaNode and one label vocabulary"
(objectstack-ai#4580, PR objectstack-ai#4608), 2026-08-13. Reading the tree AT that ref is what
rules BORN FALSE out, and it rules it out byte-exactly.

| site (addressed by symbol) | verdict | established at which ref, and
on what reading | repair taken |
|---|---|---|---|
| `BaseSchema.label` docblock — `packages/types/src/base.ts` |
**ROTTED** | `c1d939f7f`: that tree carries `export const
bridgeListView` in
`packages/react/src/spec-bridge/bridges/list-view.ts`, and the cited
line is exactly `if (spec.label) node.label = spec.label;` | sentence
KEPT, quoted and dated to its write-time ref, followed by a dated note
naming the falsifier; the assertion now points at an instrument |
| `BaseSchema.description` docblock — same file | **ROTTED** |
`c1d939f7f`: the cited line in the same module is exactly `if
(spec.description) node.description = spec.description;` | same |
| header docblock of
`packages/components/src/__tests__/inline-locale-label-read-sites.test.tsx`
| **ROTTED** | `c1d939f7f` — the same commit wrote all three sentences |
same |
| the column-spelling comment in
`packages/plugin-grid/src/ObjectGrid.tsx` | **NOT ROTTED — measured, not
assumed** | read WHOLE on `20b5e361e` | none. "The one in-repo producer
that spoke it, `bridgeListView` in `@object-ui/react`, was migrated in
the same PR" is a PAST-tense account of objectui#5068's migration. It
was true when written and it is true now. |
| the retired-witness comment at the tail of
`packages/plugin-grid/src/__tests__/gridNonAuthorKeys.test.tsx` |
**CORRECT** | read WHOLE on `20b5e361e` | none. It already records the
objectui#6366 retirement in the past tense. |

⇒ the card's "three rotted / two probably fine" split — which the card
itself flagged as a one-line-of-grep-context reading — survives a
whole-docblock re-read. **None of the five is BORN FALSE**, and all
three repairs are the ROTTED route (keep + date + name the falsifier),
not the correction route.

**The falsifier, dated:** `bf283414f` — "refactor(react): retire the
spec-bridge — SpecBridge, bridgeListView, bridgeFormView (objectstack-ai#6366)
(objectstack-ai#6632)", 2026-08-29. `.changeset/retire-spec-bridge-6366.md` declares
it BREAKING and removes the public exports outright, so the producer,
its module and the addresses the sentences cite are all gone.

**What the docblocks assert now.** The declared face is re-derived on
every run by `inline-locale-declared-face-9092.test.ts` in
`packages/types` (both `tsc -p packages/types/tsconfig.test.json` and
vitest read it); the read side by the renderer pins in
`@object-ui/components` and `@object-ui/plugin-dashboard`. No figure is
written down — the instrument is named instead (AGENTS.md objectstack-ai#9). ⛔ No new
gate, probe or citation was added: the only `path:line` addresses in the
diff are the two the dead sentences already carried, kept verbatim
inside the quotation.

## Measurement — the quotation trap, taken head on

⭐ A count is invariant under quotation, and the ROTTED route quotes what
it retires. So the token and the rot PHRASE were each read in ASSERTION
position and in QUOTED position, separately, with a whitespace-tolerant
scanner over whole file contents (` * ` prefixes stripped, line wraps
joined) rather than a line-anchored `git grep`. Corpus: every
git-tracked file under `packages/`, `CHANGELOG.md` excluded.

| reading (source files, CHANGELOG excluded) | BEFORE (assertion /
quoted) | AFTER (assertion / quoted) |
|---|---|---|
| token `bridgeListView` | 5 / 0 | 5 / 3 |
| phrase "bridgeListView assigns" (wrap-tolerant) | **3 / 0** | **0 /
3** |
| phrase "producer already writes" (wrap-tolerant) | **2 / 0** | **0 /
2** |
| **LIT CTRL** token `SchemaRenderer`, same instrument, same corpus |
3473 / 5 | 3473 / 5 |
| **ABSENT CTRL** a minted token | 0 / 0 | 0 / 0 |

Read the bare token row as the trap it is: it goes UP, because the
repair's own dated notes name the three retired exports. The reading
that answers the card is the PHRASE in ASSERTION position: 3 to 0 and 2
to 0, with every one of those occurrences still present in quoted
position, which is the ROTTED route working as intended.

⚠️ And the wrap-tolerance is load-bearing rather than ceremonial: the
test-header sentence wraps between `bridgeListView` and `assigns`, so a
line-anchored probe reads 2 where the truth is 3.

**Whole-tree population.** 11 mentions across 5 files, not the card's 5
across 4. The extra six are all in `packages/react/CHANGELOG.md` —
published release history, past tense, CORRECT, and ⛔ untouched.

## Gates and tests — every exit code captured to a file BEFORE any pipe

| run | exit | reading |
|---|---|---|
| `check-changeset-presence` | 0 | "2 source file(s) of 2 released
package(s) changed, and this change declares 1 changeset(s)" |
| `check-changeset-overwrite` · `check:changeset-claims` ·
`check:pending-changeset-literals` · `check-changeset-no-major` ·
`check-changeset-fixed` | 0 each | — |
| `check:control-bytes` | 0 | — |
| `check:new-line-citations` | 0 | "VERDICT
new-cross-file-line-citations: 0 new citation(s)" — the quoted addresses
are byte-identical, so the multiset does not move |
| `check-governed-queue-guard --self-test` | 0 | and `--test` on the
three paths: "NOT GOVERNED — 3 path(s) checked against 5 governed
surface(s); none matched" |
| `check:doc-component-types` | 0 | it reads
`packages/types/src/base.ts`; "Every documented component type is
registered" |
| `pnpm --filter @object-ui/types type-check` | 0 | `tsc --noEmit` +
`tsconfig.examples.json` + `tsconfig.test.json` |
| `pnpm --filter @object-ui/types test` | 0 | Test Files 203 passed
(203) · Tests 4762 passed (4762) |
| `pnpm --filter @object-ui/components type-check` | 0 | `tsc --noEmit`
+ `tsconfig.test.json`, after building that package's dependency closure
|
| `pnpm exec vitest run
packages/components/src/__tests__/inline-locale-label-read-sites.test.tsx`
| 0 | Test Files 1 passed (1) · Tests 9 passed (9) |
| the three `scripts/__tests__/` suites that read either changed file |
0 | Test Files 3 passed (3) · Tests 57 passed (57) |

Every heavy run went through the container's shared verify lock; each
one printed `VERDICT command-exit 0`.

**NOT MEASURED, with reasons.** `check:doc-example-types` exited **2** =
PREREQUISITE NOT MET: it needs every package's `dist` on disk (a
whole-monorepo turbo build). It is a repo-level scan and CI's run; a
comment-only diff moves no type it reads. `@object-ui/types`'s
dependency closure build is empty — `pnpm --filter
"@object-ui/types^..." build` selects no workspace package with a build
script — so step ① is a no-op for that package and was run for real for
`@object-ui/components`.

**Declared narrowings.** `eslint --no-inline-config` was run on the two
changed files only, from the flat config that owns the population
(`eslint.config.js`, whose lint population is `**/*.{ts,tsx}` minus its
`ignores` block): 2 files linted (count read from `--format json`), 0
errors, 21 warnings, ALL of them pre-existing
`@typescript-eslint/no-explicit-any` — `base.ts` reads 20 warnings both
on `origin/main` and here. No type-aware linting is configured (no
`project` / `projectService` in `eslint.config.js`), so a comment-only
diff cannot move the verdict on any file it does not touch. Repo-wide
`pnpm lint` is CI's run. The full `@object-ui/components` suite is
likewise CI's; the changed file there is a header comment and the file
itself was run.

## ⚠️ One declared deviation from the dispatch word — the changeset is
`patch`, not empty

The dispatch asked for EMPTY frontmatter on the ground that no package
moves. **Measured, it does.** `@object-ui/types` publishes `files:
["dist", ...]`, and after `pnpm --filter @object-ui/types build` the
repaired prose is in `packages/types/dist/base.d.ts` (2 hits for the new
dated note; POSITIVE CONTROL: 2 hits for neighbouring prose known to
ship; ABSENT CONTROL: a minted token, 0 hits, exit 1). Published bytes
therefore move, and `.changeset/9375-base-i18n-vocabulary-docblock.md` —
the same file, the same class of comment-only repair — graded itself
`patch` for exactly this reason. So this PR declares
`'@object-ui/types': patch` and states the conflict rather than picking
a side quietly. The components-side change is a test header, which
reaches no tarball (`tsconfig.json` excludes `**/__tests__/**`), and is
owed no declaration of its own.

## Out of scope, deliberately

- ⛔ The `bridgeFormView` / `SpecBridge` sweep the card names as the
obvious next question was **not** run and is not widened into here.
- ⛔ `packages/react/CHANGELOG.md` is untouched.
- ⛔ No label was added, removed or changed on this PR or on the card.

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

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(types): two competing SchemaNode declarations — core's interface vs types' union

2 participants