Skip to content

feat(types): derive and export the strict authoring twin of the node face - #8642

Draft
os-warren wants to merge 4 commits into
mainfrom
claude/issue-8345-strict-authoring-twin
Draft

feat(types): derive and export the strict authoring twin of the node face#8642
os-warren wants to merge 4 commits into
mainfrom
claude/issue-8345-strict-authoring-twin

Conversation

@os-warren

@os-warren os-warren commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Part of #8345 — the strict face itself, under the #5250 ruling (director comment 5534418546, maintainer 2026-09-04, decision batch #25, option 2). ⛔ No consumer is wired: objectui validate, the JSON-fence gate and objectui check are devx's half and are ruled to come after.

Attribution, in prose because a body edit downgrades the footer: written by Claude Code, seat session session_01Jmxdo7bmeqCQHLSfmLVX9w.

Notation. Generic parameters and placeholders are written as UPPERCASE words rather than in their real angle-bracket spelling, because GitHub deletes tag-shaped fragments on save — backticks and fences included.


Patch round at 8e9b563 — the contract review returned FAIL, and it was right

The ceiling-tier review (verdict 5591195581) found a real defect underneath every passing pin. It is fixed here, and the two prerequisites it named are now pinned.

The defect

The walker's type guard was typeof value === 'object'. Zod 4.4.3 builds some objects through $ZodObjectJIT, and those instances are CALLABLE — they answer typeof 'function', their constructor prints as a bound ZodObject, their traits read ZodObject/$ZodObjectJIT/$ZodObject/$ZodType, and they parse like any other object. 20 of them are reachable on this face, all through @objectstack/spec-derived subtrees. The guard handed each one straight back, so the whole subtree beneath went unwalked.

Measured on the built dist, before and after, by the same probe:

reading at ad99bee at 8e9b563
function-typed nodes on the tolerant face 20 20
objects on the forced strict twin 302 300
objects still OPEN on the twin 6 0
REPRO-A — invented key at page.interfaceConfig.sort[] strict accepted, key silently dropped strict refused, unrecognized_keys names inventedDeepKey
control, same document, invented key at the root refused and named refused and named
tolerant face on REPRO-A accepted accepted
pipes reachable on the face 1 4

The six that were open: page.interfaceConfig.sort[], page.slots.header[0].in.visibleWhen[1] and its .meta, page.slots.header[0].in.dataSource.filter(lazy).right (all zod strip mode), and list-view.bulkActionDefs[].params[] with …params[].options[] (both catchall: unknown, i.e. passthrough).

⛔ The claim was not weakened to match the walker. The walker was fixed so the published sentences — in the changeset, the README and this body — became true. All three are unchanged.

⭐ Why nothing here could have caught it, and the pin that now does

Two instruments shared the defect with the thing they were measuring.

  1. The corpus is structurally blind. No document among the 556 carries an undeclared key inside those six objects. Re-derived after the fix: whole-tree strict is 174 / 556, red-today 46, base equals head in every cell, and the shipped-face agreement check still reads 174 / 556identical to the pre-fix run. ⇒ ⛔ The corpus is not evidence this fix worked. REPRO-A and the population pin are. The corpus is reported below only as the unchanged-accept-set statement it was always good for.
  2. The pin file's own census began typeof node !== 'object' — the identical blind spot. That is why "39 closed, identical before and after" read clean.

⇒ The new pin is over the population, not over a sample document: walk the forced twin and require every object in it to carry catchall: never. Its non-vacuity control is the one whose absence let this through — functionTyped must be greater than zero, so a census that cannot see callable nodes fails loudly instead of reporting a graph it never entered. Both halves are ablated below.

The cycle invariant, now pinned

The review measured the module cycle under four bundlers. Node, Vite/rolldown and Next 16.3.1 Turbopack are green in both entry orders. rollup 4.62.2, deep-module-first with a namespace import used as a value, is REDReferenceError: Cannot access 'StrictAnyComponentSchema' before initialization, from the namespace object rollup synthesizes ahead of the deep module's body. Named imports in the same order are green; barrel-first is green.

Unreachable today, and that is the point: my stated reason for safety — "read only inside the lazy getters" — is true and not sufficient. The load-bearing invariant is the barrel is the sole entry into the cycle, and it now has a pin covering both routes a caller has:

  • the published exports map has no wildcard subpath and no entry reaching the deep module (so nothing outside the package can deep-link it);
  • no module anywhere in this repository imports the deep module except the barrel — a scan of 4,523 source files under packages, apps, examples, scripts, e2e, matched on import specifiers so that scripts/measure-strict-authoring-face.mjs does not read as an importer merely by sharing the words in its own name.

⚠️ The vitest alias table maps @object-ui/types to packages/types/src by prefix, so inside this repo a deep specifier resolves even though the exports map blocks it for consumers. The repo scan is the half that covers that route; the manifest assertion alone would not.

Two censuses moved, exactly as the review predicted

Opaque limits. Re-derived over the published face, forced through one document parse: custom 71 · function 4 · transform 4 = 79 (was 71 · 4 · 1 = 76 at ad99bee). The old count was a census of what the walker visited, not of the face. The shipped walker and the prototype each reported exactly one transform, and they were different ones: mine at a pipe's out under report.exportOptions, the prototype's a preprocessor-shaped pipe under page.interfaceConfig.filterBy[] that my walker could not reach because the filterBy array element is function-typed. Both are now visited.

Pipes. The pipe arm's own comment said "one pipe reachable, in an array and out the transform" — a reading taken through the blind guard, and therefore false. Re-derived: four pipes, one transform into enum (the preprocessor) and three into a transform from object, string and array. The comment now states the measurement. ⇒ Today no OBJECT sits on an out side, so walking both sides still moves no accept set; it is there so the first preprocessor wrapping an object does not open a hole.


What lands

Three values and two types, published from @object-ui/types/zod:

export what it is
StrictAnyComponentSchema the document-root twin of AnyComponentSchema
StrictSchemaNodeSchema the child-slot twin of SchemaNodeSchema
deriveStrictAuthoringSchema(schema, options) the derivation, so no consumer writes a second walker
StrictAuthoringLimit, DeriveStrictAuthoringOptions types for the onOpaqueShape report

Derived, never hand-written. Every reachable object is closed through unions, discriminated unions, arrays, tuples, records, intersections, optionals, nullables, defaults, both sides of a pipe, z.lazy, and — since the patch round — callable JIT object nodes. Objects are cloned by patching a copy of their own def and calling their own constructor — ⛔ never rebuilt with a fresh object literal, which drops def.checks and would make the twin under-report red. A callable node clones through its own bound constructor and comes back object-typed: a difference in representation, not in behaviour, and the population pin measures behaviour.

The rendering face's passthrough is not flipped. This adds a face; it does not change the existing one — pinned, not promised.

⚠️ Re-derived; ⛔ no figure is inherited from the card body

All at 8e9b563, zod 4.4.3, corpus 556 documents / 2099 nodes (catalog + docs + authored). The card's 176/553 and 184/2099 are pinned at 5505aec1 and are not these numbers.

reading at c4326fe (base) at head
documents refused, whole-tree strict 174 / 556 174 / 556
documents refused by the face as shipped 46 / 556 46 / 556
nodes refused under strict 179 / 2099 179 / 2099
— of those, green today, red only under strict 127 127
— already red under the face as shipped 52 52
component types declared / seen / strict-clean 107 / 94 / 62 107 / 94 / 62
registry collisions · arms with no literal type 0 · 0 0 · 0

Base and head are identical in every cell — the corpus-scale statement that this PR moves nothing about the existing face. ⚠️ And, as above, the same table was identical before the guard fix, which is exactly why it cannot stand as evidence that the face is closed.

Agreement with the prototype, with the script's own whole-tree twin swapped for the shipped StrictAnyComponentSchema (scratch copy, never committed): 174 / 556, red-today control 46 — identical.

The blocker's property, re-read on this tree

The old 294/553 blow-up is gone: whole-tree strict (174) now sits beside per-node strict (179 of 2099) instead of an order of magnitude above it, because since #8344 a child slot resolves to the component union rather than the base keys. That is the error #7935 existed to prevent.

Where the module lives — ruled A by the seat (5590686191), not reopened

__tests__/zod-mirror-parity.test.ts runs a census closed over the export consts of src/zod/*.zod.ts, and that file is fenced this round (PR #8553). So the derivation module lives at packages/types/src/strict-authoring-face.ts, outside the mirror directory, and the barrel re-exports from it. The collision is measured, not predicted — ablation leg 1 below. B (move it in, add an EXCLUSIONS row) is recorded as a follow-up for after #8553 lands.

The pins

packages/types/src/__tests__/strict-authoring-face-8345.test.ts25 tests.

  • (a) a known-good card with button and text children parses under the strict face, and under the tolerant one.
  • (b) one invented top-level key ⇒ refused, unrecognized_keys naming exactly that key; the same document accepted by the tolerant face.
  • (c) the tolerant face is unchanged: a five-row verdict table read after the strict derivation is forced, plus a non-mutation reading (closed-object count and open-path count both identical before and after a twin is built and forced).
  • the population is closed — every object reachable on the twin carries catchall: never; plus the callable-node control; plus a discriminator control showing the tolerant face is not closed.
  • REPRO-A — an invented key deep inside a spec-derived subtree is refused and named, with the root-level control in the same document.
  • the recursion point — an invented key on a CHILD is refused and named; a child's own variant / size are ACCEPTED.
  • checks survive the clone — synthetic refinement still fires, with the rebuild caricature as a control; and the live chatbot body clause still refuses a record body one slot down while the root form is accepted, on both faces.
  • the limits are enumerated, not claimed — every reported kind is one of the three recorded opaque kinds, the census is non-vacuous, and a synthetic control pins that the reporter recognises all three; plus the preprocessor pin for the out side of a pipe.
  • the barrel is the sole entry into the cycle — the two halves above.

⚠️ The type-level pins are read by tsc -p tsconfig.test.json and by nothing else — vitest does not typecheck. Non-vacuity with --listFiles: the test program lists the pin file (1 hit), the emitting program does not (0), both list the source.

Ablations — each proved on disk, each restored under a trap

Every leg: blob hash before and after (a byte-identical mutation aborts the leg as a no-op), an EXIT INT TERM trap with absolute paths, and a restore verified by the hash returning to the HEAD blob and git diff HEAD being empty. Every leg printed its RESTORED-OK line.

leg mutation instrument result
1 · census collision one export const appended to zod/index.zod.ts (b866917 to fb5e6a4) vitest, parity file 1 failed / 31 passed, naming index.zod.ts#__StrictAuthoringCensusProbe
2 · rebuild caricature object clone replaced by a rebuilt object literal vitest EXIT 1 — the refinement pin
3 · no out walk the pipe's out branch deleted vitest EXIT 1 — 2 failed
4 · deriver return type widened generic return replaced by the base schema type tsc -p tsconfig.test.json EXIT 1 — TS2741 at the type pin
5 · the same mutation (as above) vitest EXIT 0, 19 passed — vitest is blind
E · the guard regressed walker guard back to object-only (f3a8397 to cd8a54b) vitest EXIT 1 — 2 failed: the population pin, expected [ …(6) ] to deeply equal [], and REPRO-A
F · the census blinded the PIN FILE's census back to object-only, walker left correct (4f24ec9 to 98de385) vitest EXIT 1 — only the callable-node control fires. ⭐ The population assertion goes vacuously green: this is the leg that shows an instrument sharing a defect with what it measures is not a control
G · manifest assertion the deep-module name pointed at one the exports map does reach (4f24ec9 to 4cb80b4) vitest EXIT 1 — the exports-map half
H · a new deep importer a file added under packages/core/src importing the deep module vitest EXIT 1 — the sole-entry scan; restore verified by git status --porcelain empty

Gates

All at 8e9b563 (the readings were taken at 75d31cb and re-run at head; the intervening commit changes one comment and no code); each exit code captured before any pipe.

gate exit
pnpm exec vitest run packages/types/ 0 — 152 files, 2902 tests
pnpm --filter @object-ui/types type-check (all three programs) 0
pnpm --filter @object-ui/types lint 0 — 219 files linted by eslint's own config, 0 errors, pre-existing warnings only, none in the changed files
pnpm --filter @object-ui/types build 0 — 126 emitted files
check:control-bytes · check:published-tsconfig-exclude · check:side-effects-array · check:esm-specifiers · check:self-import 0
check:dist-completeness · check:published-dist 0
check:doc-fences · check:doc-snippets · check:doc-types · check:doc-examples 0
check:governed-queue-guard 0; --test on all five changed paths: NOT GOVERNED
node scripts/check-changeset-presence.mjs 0 — "3 source file(s) of 1 released package(s) … declares 1 changeset"
targeted grep -naP control-byte self-scan of the changed files no match
check:node-esm-load, plain 1 — RED
check:node-esm-load --force-build 0 — GREEN, 37 of 37 … built by this tree, 34 of 39 … imported and evaluated, 5 by design

⚠️ Correction to what I wrote last round about that gate. The provenance root-cause stands and the review confirmed it: turbo shares one .turbo/cache across every worktree of this checkout, and the plain run refuses two entries it did not build — this time @object-ui/auth and @object-ui/react-runtime replayed from the reviewer's own scratch worktree, the side effect the review disclosed. Neither package is in this diff and @object-ui/types was built by this tree in both runs. But my sentence "on CI the refusal cannot arise" implied a coverage CI does not provide. node-esm-load-gate.yml runs on a nightly cron and on push to main; only check:esm-specifiers runs per PR. ⇒ the load leg is unmeasured by anyone on a PR head — ⛔ not "left to CI". The --force-build run above is the only reading of it that exists for this head.

⚠️ Carrier label. needs:contract-review was on this PR, then read back MISSING after the first body edit — something else wrote the label set whole. I re-hung it; I did not clear it and ⛔ will not clear it.

Not measured, stated rather than implied: the repo-wide turbo run lint and the full pnpm test (CI's, and those genuinely do run per PR); esbuild/tsup bundling of the cycle; any browser or runtime rendering (nothing renders this face); import-time cost in a bundled app (the derivation is deferred behind z.lazy, so it is not paid unless the face is parsed).

Scope

Changeset: @object-ui/types minor — a new published face on a published entry point; grade confirmed by the review against AGENTS.md 238–240 and the precedents. Five files: the derivation module, the barrel re-export block, the pin file, the package README, the changeset. ⛔ No fenced file is touched: not packages/types/package.json (the cycle pin reads it, never writes it), not the package's build configuration, not src/record-components.ts, not __tests__/zod-mirror-parity.test.ts.

Falls off the back, as ruled: wiring any consumer; repairing any of the 174; the TypeScript authoring face (#7927); closing the opaque validators.

Carrier: needs:contract-review is on the card and on this PR. ⛔ Not to be cleared here — only the PM seat clears it, on a transcript-verified pass.

…face

Publish `StrictAnyComponentSchema`, `StrictSchemaNodeSchema` and
`deriveStrictAuthoringSchema` from `@object-ui/types/zod` — a derived twin of
the node face that closes every declared object at every depth.

Additive: the rendering face keeps its `.passthrough()`, no accept set moves,
and no consumer is wired to the new face.

The twins are derived, never hand-written. Objects are cloned by patching a
copy of their own def so `.refine()` / `.superRefine()` checks survive; a twin
rebuilt with `z.object(shape)` would drop them and under-report red. Both sides
of a pipe are walked, so a `z.preprocess`'s real schema is closed too.

Part of #8345

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
The snippet used `ButtonSchema` without importing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
@github-actions github-actions Bot added documentation Improvements or additions to documentation package: types tests labels Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3477.4 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-CUuu9hOC.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) 15.67KB 5.75KB
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) 498.93KB 114.12KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 198.39KB 55.29KB
fields (index.js) 243.73KB 61.53KB
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) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
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.84KB 10.94KB
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) 11.71KB 4.29KB
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) 5.12KB 1.74KB
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) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 194.53KB 46.34KB
plugin-dashboard (index.js) 131.43KB 34.44KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 251.10KB 64.96KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.30KB 56.63KB
plugin-kanban (index.js) 55.44KB 15.73KB
plugin-list (index.js) 112.73KB 27.69KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.54KB 20.84KB
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) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
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.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
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) 11.72KB 4.48KB
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

…e population

The walker's type guard was `typeof value === 'object'`. Zod 4.4.3 builds some
objects through `$ZodObjectJIT`, whose instances are CALLABLE — 20 of them are
reachable on this face, all through `@objectstack/spec`-derived subtrees. The
guard handed each one back untouched, so the subtree beneath went unwalked and
6 objects stayed open on the twin: an invented key inside one of them was
accepted and silently dropped, while the same key at the root was refused and
named.

Nothing could catch that. No document in the 556-document corpus carries an
undeclared key inside those 6 objects, and the pin file's own census began
`typeof node !== 'object'` — it shared the blind spot with what it measured.

Both guards now admit callable nodes, and the pin that was missing is here: a
POPULATION pin requiring every object reachable on the twin to carry
`catchall: never`, with the function-typed count asserted non-zero so the
control cannot silently regress. REPRO-A is pinned as a document too, and the
cycle's real invariant — the barrel is the sole entry — is pinned in both of
its halves.

Part of #8345

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

Copy link
Copy Markdown
Contributor

Contract review (claude-fable-5-1, isolated seat) — PR #8642 @ ad99bee

Verdict: FAIL — one blocking defect in the exported face, independently re-measured on this head (not inherited from the card thread). The three owed pins hold; the published contract text does not.

Ruling implemented: objectui#5250, director comment 5534418546, provenance maintainer, live PM chat, 2026-09-04, decision batch #25, option 2. Operative clause, verbatim: "each node schema gets a derived strict variant; objectui validate and the doc-snippet gates run strict; renderer props keep the tolerant face unchanged", with "⛔ The rendering face's .passthrough() is not flipped." Card #8345 (priced on #7935; blocked on #8344, landed as PR #8501 841dd2b7) scopes this PR to the derivation + export + pins (a)(b)(c), no consumer wired. Scope as ruled: the PR adds a face, wires nothing, flips nothing — confirmed by diff (base.zod.ts:417 still .passthrough(); src/zod/ differs from merge-base c4326fe only in the barrel's appended re-export block).

Governed paths touched: NO (AGENTS.md, CLAUDE.md, .claude/**, docs/adr/**, content/docs/releases/** all absent from the 5-file diff). packages/types/package.json untouched; "sideEffects": false intact; exports has ./zod and no wildcard — the deep module is unreachable by specifier.
Clause-②: yes (new export) — three values + two types on the published @object-ui/types/zod entry; mechanical floor. Carriers: needs:contract-review on PR and on card — present on both.

Readings (own worktree-free build: git archive of ad99bee into scratch, sibling-install toolchain zod 4.4.3 / spec 17.3.0, tsc -p tsconfig.json exit 0 → 88 dist files incl. strict-authoring-face.{js,d.ts}; tsc -p tsconfig.test.json exit 0)

reading value
pins (a) known-good / (b) root key refused + named / (b) tolerant accepts / (c) 5-row tolerant table after forcing true / false + ["inventedTop"] / true / all 5 rows unchanged
child slot (recursion point live): invented child key refused + named; child's own variant/size accepted ["inventedChild"]; true — R4 shape, not R2
StrictSchemaNodeSchema: bare string accepted / text + nope refused true / false
corpus (scripts/measure-strict-authoring-face.mjs --json against my scratch dist) 556 docs · 174 whole-tree strict · 46 red today · 2099 nodes · 179 refused (127 strict-only / 52 red) · 107 / 94 / 62 · collisions 0 · arms w/o literal type 0 — identical to every cell the PR quotes
plausibility vs card tables card R4 = 176/553 @ 5505aec, R2 = 294/553; this head 174/556 sits on the R4 line, the R2 blow-up is gone. Controls present (red-today, collisions, arms-without-literal).
opaque census (onOpaqueShape, one forced parse) custom 71 · function 4 · transform 1 = 76
ZodError on the strict path (#8498 cliff, closed by #8544) one invented leaf key at depth 0/1/2/4/6 → flat issues 1/12/23/45/67, JSON 111 B → 9,177 B, ≤0.5 ms/parse — linear, not the 25×/level cliff; cloneWithDef preserves the discriminator, so #8544's fix carries into the twin
tolerant face non-mutation (function-aware census) closed objects reachable from AnyComponentSchema: 58 before and after forcing both twins
module cycle, Node on dist deep-module-first: same object as barrel's, nested key refused; barrel-first: same object, export present. No load-time derivation (createStrictWalker() = one empty Map, two z.lazy wrappers). New edges: strict-authoring-face.tszod/index.zod.ts only — no edge from base.zod.ts (the refused getter-binding route is not taken; base.zod.ts is byte-identical to base).

Findings

1. BLOCKER — the strict twin does not close every reachable object; 6 stay open, and an off-spec key inside them is silently accepted and dropped.
src/strict-authoring-face.ts:141-142: isZodType = (value) => typeof value === 'object' && value !== null && '_zod' in value. On this face 20 zod 4.4.3 schema nodes are typeof 'function' (def kinds: object 15, enum 3, record 1, pipe 1; they parse normally). The guard returns each one unwalked, so its whole subtree keeps the tolerant shape. Function-aware census of the forced StrictAnyComponentSchema: 302 objects, 296 closed, 6 openpage.interfaceConfig.sort[] (strip), page.slots.header[0].in.visibleWhen[1] + its .meta (strip), page.slots.header[0].in.dataSource.filter(lazy).right (strip), list-view.bulkActionDefs[].params[] and …params[].options[] (catchall: unknown, i.e. passthrough).
Reproducer: { type:'page', interfaceConfig:{ source:'x', sort:[{ field:'a', order:'asc', inventedDeepKey:1 }] } } → tolerant true, strict true, no unrecognized_keys, strict output {"field":"a","order":"asc"} (key dropped). Control, same document + inventedTopKey at root → strict false, ["inventedTopKey"] named.
Fix ablation (scratch copy, guard admits typeof value === 'function'): 300 objects / 300 closed / 0 open; reproducer → strict false, ["inventedDeepKey"]; known-good still true; list-view.…params[0].bogus now named alongside the pre-existing required-value issues. The prototype's guard (if (!schema?._zod) return schema;, script line 260) does not have this hole — the shipped walker regressed coverage relative to the prototype on exactly this class.
Expectation: admit function-typed nodes in isZodType; add a pin that walks the forced twin with a function-aware visitor and asserts every reachable object def has catchall.type === 'never' (with a non-vacuity assertion that ≥1 function-typed node was visited); add the reproducer above as a pin, both directions.

2. MAJOR — the published contract text is false at those six depths. Changeset: "refusing any undeclared key at any depth with an unrecognized_keys issue that names it"; README: "closes every declared object, at every depth"; PR body: "Every reachable object is closed". The changeset is the payload that ships. Expectation: make the text true (finding 1) — do not soften the text instead.

3. MINOR (latent) — the walker's default: arm swallows container def kinds silently and reports nothing. Synthetic probe: z.set(obj), z.map(k, obj), obj.prefault(…) → strict twin accepts {a:'x', bogus:1} inside them, inner objects 0 closed, and no onOpaqueShape call — so the "complete limit list = custom/function/transform" claim holds only for kinds the switch names. None of these kinds is on the face today (after the finding-1 fix the census reads 0 open), so no accept set moves now. Controls: catchall: obj and z.record(k, obj) are walked correctly (strict refuses). Expectation: add set/map/prefault/promise arms, or make default: report unknown non-leaf kinds through onOpaqueShape so the limit list is measured rather than enumerated by hand.

4. MINOR — the pin file's instrument shares the defect. closedObjectCount (test file, bottom) starts with typeof node !== 'object', so the "identical before and after" reading and the "39 closed" figure could not see the six open objects; the corpus is blind too (no document among the 556 carries an undeclared key inside those objects — base, head and the swapped-in shipped face all read 174 regardless). Expectation: function-aware counter; the pin in finding 1 is the control the file is missing.

5. INFO — the module cycle's real invariant is "the barrel is the sole entry", and nothing pins it. "Read only inside the lazy getters" is true of the shipped source (import at line 84, runtime reads only at 300/312) and is what makes both Node orders green — but rollup's synthesized namespace on a deep-first entry is the shape #8344 paid for, and the only thing keeping it unreachable is the exports map plus the fact that no file but the barrel imports strict-authoring-face. Build Docs on this head is the skip path (12 s, "No docs-related files changed") and says nothing about Turbopack. Expectation (non-blocking): a source-scan pin that no module other than zod/index.zod.ts imports strict-authoring-face.

6. INFO — check:node-esm-load is not a per-PR gate. node-esm-load-gate.yml triggers on schedule (17 4 * * *) and on push for its own two paths; only check:esm-specifiers runs per PR. So "cannot arise on CI" is true only because CI never runs the load leg on a PR. The provenance explanation is plausible and not this diff, but the PR should state the --force-build re-read rather than lean on CI.

7. INFO — placement (option A) and the census collision, reproduced. Unmutated: pin file 19/19 and parity file 32/32 under vitest. Appending one export const to zod/index.zod.tsTests 1 failed | 31 passed (32), failure naming index.zod.ts#__StrictAuthoringCensusProbe. zod-mirror-parity.test.ts is unchanged vs base (fence honoured); the zod-lazy-getter-identity-7918 row lives in its own test file, also unchanged. Seat ruled A on the card; nothing here is a maintainer item.

8. INFO — the claim comment on #8345 (5590024076) carries no Container & model: line. Tier stated: none. (The dispatch comment says "built at TIER_DEFAULT"; the claim itself does not carry the line.) Commit trailers: both commits carry Co-Authored-By + Claude-Session; commit 1 carries Part of #8345. RULE 2: satisfied.

Changeset verdict

.changeset/8345-strict-authoring-face.md: '@object-ui/types': minorgrade correct (additive export, nothing removed, no BREAKING). Text false at the six depths in finding 1; must be corrected with the fix, not reworded around it.

Tests

19 pins pass; no .skip/.only/.todo; both directions pinned (strict refuses root and child invented keys and names them; tolerant control accepts the same documents; five-row tolerant table after forcing); revert reddens (the exports do not exist at base). What is missing is the whole-graph closure pin (finding 1/4).

CI on ad99bee

33 check runs, all completed, none in progress: Type Check ✓ (19:33:19) · Build Docs ✓ (skip path, 12 s) · Bundle Analysis ✓ (types (strict-authoring-face.js) 11.72 KB / 4.48 KB gz; console eager closure 3477.4 KB under the 3512.7 KB budget) · Test (shard 1/4 … 4/4) all ✓ · Lint ✓ · Changeset Bump Policy / Declaration / Fixed Group / Overwrite ✓ · README Export Check ✓ · Governed Surface Queue Guard ✓. mergeable_state: unknown at read (draft; 8 commits behind origin/main 4dc80d0f).

Maintainer-only merge: no — non-governed additive export under a maintainer-ruled programme; every finding above is implementer-floor. Carrier needs:contract-review stays on PR and card until finding 1 is fixed and re-reviewed.


Generated by Claude Code

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3477.5 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-DqTtGmW_.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) 15.67KB 5.75KB
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) 498.93KB 114.12KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 198.39KB 55.29KB
fields (index.js) 243.73KB 61.53KB
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) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
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.84KB 10.94KB
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) 5.12KB 1.74KB
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) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 194.53KB 46.34KB
plugin-dashboard (index.js) 131.43KB 34.44KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 251.25KB 65.00KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.30KB 56.63KB
plugin-kanban (index.js) 55.44KB 15.73KB
plugin-list (index.js) 112.73KB 27.69KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.54KB 20.84KB
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) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
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.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
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) 13.66KB 5.25KB
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

The `pipe` arm's comment said "one pipe reachable, `in` an array and `out` the
transform". That reading was taken through the object-only guard. With callable
nodes admitted, four pipes are reachable — including a preprocessor under
`page.interfaceConfig.filterBy[]` that the old walker could not see at all.

No code changes; the comment now states what the tree measures.

Part of #8345

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

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3477.5 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-DqTtGmW_.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) 15.67KB 5.75KB
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) 498.93KB 114.12KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 198.39KB 55.29KB
fields (index.js) 243.73KB 61.53KB
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) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
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.84KB 10.94KB
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) 5.12KB 1.74KB
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) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 194.53KB 46.34KB
plugin-dashboard (index.js) 131.43KB 34.44KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 251.25KB 65.00KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.30KB 56.63KB
plugin-kanban (index.js) 55.44KB 15.73KB
plugin-list (index.js) 112.73KB 27.69KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.54KB 20.84KB
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) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
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.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
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.27KB 5.47KB
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

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants