Skip to content

feat(types)!: BaseSchema loses its index signature, so a typed node literal refuses an undeclared key; the compile-fail pin, both directions (objectui#8347) - #11607

Merged
os-zhuang merged 16 commits into
mainfrom
claude/issue-8347-baseschema-index-signature
Oct 4, 2026
Merged

os-zhuang merged 16 commits into
mainfrom
claude/issue-8347-baseschema-index-signature

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #8347
Clause-②: yes (narrowing)

BaseSchema no longer declares [key: string]: any. A node literal annotated with its node type now refuses a key that no declaration names, a misspelled key included, and the correct spelling still compiles. This executes the objectui#7927 ruling ("the TypeScript face is an executable contract"), with the compile-fail pin that ruling made non-negotiable. ComponentRendererProps keeps its own signature, and a row in the pin notices if it is ever removed. The zod faces and every runtime path are unchanged, except visibleWhen (below).

Governed: this diff touches AGENTS.md and two published-skill files (skills/objectui/guides/architecture.md, skills/objectui/rules/protocol.md), so the PR stays a draft until an authorized approval is on it (node scripts/check-governed-queue-guard.mjs --test answers GOVERNED for each of them). Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ (PM loop round 5, claim 5977679107, amended for patch round 3 by 5979679543).

The maintainer's one open choice: the props alias on the TypeScript face

This PR writes option A: props is not declared on the TypeScript authoring face. The renderer still reads it at runtime (the maintainer's 2026-08-18 ruling binds the runtime and leaves the TS face open). So the two badge literals in components' alias-precedence-cross-channel.test.tsx that author props now carry an @ts-expect-error naming this choice, and AGENTS.md §4's abridged listing drops the props member that BaseSchema never declared.

  • A (written here): not declared. The dev measurement on objectui#11364 found no non-test TypeScript, tracked JSON or objectstack example that authors a node props, and the published skill teaches it as wrong.
  • B: props?: unknown on BaseSchema. AuthoringNode derives from the zod BaseSchema shape, so B also needs a zod mirror row and a parity entry.
  • C: declared on AuthoringNode only.

To flip it, remove the two directives and add the member. Nothing else in this PR depends on the choice.

What changed, class by class (one commit each)

  1. The two src sites. plugin-kanban: ObjectKanban reads the gate-written sort (the binding's dataSource.sort) through GateBoundKanbanSchema, a read type private to the file; ObjectKanbanSchema still declares no sort (objectui#8174). plugin-timeline: TimelineRenderSchema, the private hand-off type, declares the onItemClick slot ObjectTimeline composes; TimelineSchema still declares none. Both compile with the signature present or absent.
  2. The mechanical rows. Two schema-to-record test reads convert through unknown; the gantt and map propertiesBag-10859 fixtures keep operator a literal and type the bag node as its block node.
  3. BaseSchema.visibleWhen, Q6 = B. The TS face is the spec's EvaluatedExpressionInput, by reference. The zod twin is the same accept set (a string, or the spec's own EvaluatedExpressionSchema envelope) with EvaluatedExpressionInputSchema's verdict and without its string transform.
  4. The removal, and everything that can only land with it. The compile-fail pin; the adjudicated probe and ceiling flips; the two props flips; the valueless envelope metric-card pinned refused on the TS face (Q3 = A); envelopeStray and its complex.ts note deleted per the constant's own removal condition; the two object-view-slot-key-lists tripwires flipped; partial-schema-collapse-pin.test.ts deleted per its header, with PartialSchema's docblock describing the alias as it now works; five mirror-parity ledger entries (below); and the prose in those files that described the signature as live.
  5. Docs. The 13 listed doc blocks plus the objectos-integration.mdx page block (now regions, and since round 4 rendered under SchemaRendererProvider); the published passages that described the signature as live; the plugin-calendar README note; the plugin-dashboard README widget-key passage; the examples/dashboard.ts comment; a dated note on the pending 11564 changeset, whose "until objectui#8347 removes it" sentence this release makes false.
  6. AGENTS.md. §5 #0.1 gains the rule as shipped: the TS authoring face is part of the contract, a refused key is declared by reference or fixed at the producer and never cast past, and the fresh-literal bound is named with the pin that measures it. §4 drops props; Add default props to all components to prevent collapse in designer #4's events sentence names the face that still keeps one.
  7. The changeset. minor for @object-ui/types with the breaking note; minor for plugin-timeline (TimelineRenderSchema, the schema prop type of the exported TimelineRenderer, gains one optional member); patch for plugin-kanban.
  8. Patch round 3, after the merge of main at b508ac50. The two published-skill sections (H3 below); the five restored deletion guards and the reworded test strings (Acceptance notes); main merged by a merge commit, with the type-check of every package main moved since the merge base green afterwards.
  9. Patch round 4, doc and comment bytes only. The integration guide's App block installs the adapter through SchemaRendererProvider dataSource (the renderer reads it from SchemaRendererContext; a dataSource prop on SchemaRenderer reaches only the root component), and its system-objects comment names only the provider. The parity ledger's complex.zod.ts#DashboardWidgetSchema component entry says the mirror slot's BaseSchema fallback stays by objectui#8344's decision, with no open card retiring it, instead of reserving it for this card.

The compile-fail pin, both directions

packages/types/src/__tests__/base-schema-closed-face-8347.test.ts, read by tsc -p tsconfig.test.json:

The measurements the dispatch named

H1, the re-census at BASE 2e818d0b5, before any kept edit. Instrument: every package built (turbo, forced: 40 of 40, 0 cached); the six BaseSchema lines deleted and nothing else; types rebuilt (dist keeps one signature, ComponentRendererProps'); then every tsc program the workspace type-check scripts name, one job each (90 jobs, apps/site's generators included, plus the four root programs).

programs red unique errors src tests
BASE, signature removed alone 90 13 81 in 44 files 3 78
BASE control, signature present (the same 13) 13 0 0
final head e0a9af67, removal kept 90 0 0 0 0

The 81 fall exactly into the predicted classes: src 3 (ObjectKanban sort twice, timeline onItemClick); tests 67 adjudicated probe and ceiling flips (types 49; charts xAxisKy twice and objectNme; dashboard bogusKey twice and zzUndeclared7353 four times; grid bogusKeyRefusedNowhere and two Expect wrappers; list visibleWhn twice; map enableClusterng; tree zzplTreeAbsentControl8655, objectNaem; components content on label), 2 props flips, 3 mechanical rows (two schema-to-record casts, one mirror-parity ledger mismatch), and the 6 gantt and map fixture literals. No site needed a contract decision. check:doc-snippets under the removal at BASE: 14 of 777 blocks failed, the 13 listed plus the objectos-integration.mdx page block (BASE control: 0 failed); doc-examples, doc-types and skill-examples stayed green.

The parity ledger. The mismatch was five pairs whose member is typed with an interface (AppSchemaRendererNodeSchema.schema; the reports pairs' report, sections, chart) against a .passthrough() mirror whose z.input carries a string index signature. TypeScript grants an implicit index signature to anonymous and mapped types and never to an interface. Measured: the declared type is refused, and a one-level anonymous copy of it fits the same mirror input. They are ledgered as an artifact of the assignability test, with that reading in each entry's docblock, and the header's derived figures moved with them.

H2, the objectui#11573 headroom pin. AnyComponentSchema's declaration on the compiler's counter: 12260 before, 12974 after (the visibleWhen twin), limit 900000. Read through a trap-deleted copy of the pin that writes its reading.

H3, skill fences. check:skill-examples exits 0 under the removal at BASE and on every head since. Patch round 3 edits the two skills/** files whose prose the removal made false: the architecture guide's "JSON Protocol" section and the protocol rule's "Component Schema Structure" section said the published BaseSchema declares its members plus an index signature, and that props / events / properties reach a node through it. Both now state the two verdicts a key no member declares gets, one per face (a compile error in a fresh typed literal on the TypeScript face, with the fresh-literal bound said as AGENTS.md §5 #0.1 says it; kept and judged by the named reader on the tolerant zod face), and their teaching fences drop the three keys BaseSchema never declared and end on the same no-index-signature line as AGENTS.md §4. props keeps one sentence stating option A, so a flip to B or C is a one-sentence edit. Neither fence is a marked example; check:skill-examples, check:skill-eval-tokens and check:skills-paths stay green.

H4. The flex rows' header and examples/dashboard.ts no longer say "until objectui#8347"; the flex test gains the row that removal promised (a text entry misspelled inside the list is refused, and the well-formed list's text entry compiles).

H5, visibleWhen. visible-when-spec-input-8347.test.ts: the TS member is Equal to the spec's EvaluatedExpressionInput; on 13 probe values the mirror's verdict equals EvaluatedExpressionInputSchema's and PageComponentSchema.visibleWhen's, read in the same run (the probe set holds both verdicts); a blank string is refused with the spec's own sentence; a string parses to the same string, while the spec rewrites it (the control); an envelope parses to itself; and the envelope a spec parse writes is accepted by both component faces, a dialect-less one refused. ⚠️ This is a narrowing as well as a widening on the tolerant face: a blank visibleWhen string used to parse and is refused now, as the spec refuses it.

Gates, on head e0a9af67

The dev's local readings on that head. The gate verdict on the current head is its own check-runs.

  • type-check, every program (the H1 instrument): 90 of 90 exit 0, 0 errors.
  • pnpm --filter @object-ui/types build: exit 0. pnpm --filter @object-ui/types test: exit 0, Test Files 353 passed (353), Tests 9419 passed (9419).
  • vitest over the edited plugin packages (kanban, timeline, gantt, map, charts, dashboard, grid, list, tree), on the same file contents: exit 0, Test Files 819 passed | 1 skipped (820). components: see the report.
  • check:doc-snippets 777 of 777 block(s) judged, 0 failed.; check:doc-examples 35 compile, 87 fail, 87 of those declared; check:doc-types, check:skill-examples, check:readme-exports, check:spec-symbols, check:changeset-claims, check:pending-changeset-literals, check:control-bytes, changeset:check, type-check:coverage: exit 0. check:new-line-citations: 0 new citation(s).
  • check-governed-queue-guard.mjs --test over the changed paths: GOVERNED (AGENTS.md; since patch round 3 also the two skills/** files).

Overlap

PR #11069 (draft) edits content/docs/guide/architecture.md's paragraph on a button's text key. This PR edits the same file's Type Safety block (the button literal writes label). Region-disjoint; whichever lands second merges main.

Acceptance notes (read, not filed)

  • ObjectChartBlock's pre-gate schema prop is BaseSchema (ruling 5810232641). A fresh literal at that prop is now excess-checked against BaseSchema itself, so a correctly spelled objectName is refused there as much as the objectNme probe; in-tree callers pass typed nodes. The flipped probe's comment says so.
  • plugin-grid's RemoveIndexSignature in ObjectGrid.tsx strips nothing now, as its own test predicted; retiring it is cleanup left out of this PR.
  • object-view-slot-key-lists' form Pick list may move back to Omit, per its header's removal condition; not done here.
  • PartialSchema has no consumer outside its declaration (a tracked-files git grep for the name, with SchemaByType as the positive control). The enforce-or-remove card the deleted pin's header asks for is filed: objectui#11608 (Blocked-by: #8347).
  • Source comments, test comments, docs and the published skill that described the signature as live, or said objectui#8347 removes it, are repaired in this PR (patch rounds 2 and 3). The enumerating commands are git grep -n -i "index signature", git grep -n -F '[key: string]: any' and git grep -n 'objectui#8347 remove' over packages/, apps/, examples/, content/docs/ and skills/, CHANGELOGs and release notes excluded as append-only. What they still find is true at the head: other types' own signatures (ComponentRendererProps, AuthUser, FormField, a widget's own props type, the field-widget data- attribute signature, QueryParams' statements), the tolerant zod face's .passthrough(), and past-tense history.
  • The deletion guards the removal silenced are restored (patch round 3). While the signature stood, an @ts-expect-error over a tombstone or a typed member also failed (TS2578) when its member was deleted; since the removal the undeclared key satisfies the directive. object-kanban-card-title-9606, object-grid-default-sort-tombstone-5861, object-grid-show-filters-retired-11068, object-grid-declared-keys-11068 and gantt-flat-config-declared-keys each gain a type-level row that is a compile error when its member is deleted and pins the declared or tombstone type; each was shown red by a trap-restored deletion of its member and green at HEAD (readings on the card). Three test titles and one assertion message that described the signature as live are reworded, assertion logic untouched.

维护者速读(草稿)

改了什么:@object-ui/types 的 BaseSchema 去掉了 [key: string]: any。从此用 TypeScript 写节点时,拼错或未声明的键会直接编译报错,正确拼写照常通过;新增的钉子测试两个方向都钉住,并用"把签名加回去、钉子变红"的消融证明它真能失败。顺带:visibleWhen 改为直接引用 spec 的输入类型(字符串或 { dialect, source } 信封);看板与时间轴两处运行期键改为在各自包内私有类型上声明;一批文档示例与说明改成在新约束下成立;AGENTS.md §5 #0.1 写明"TS 编写面也是契约"。已发布技能包(skills/objectui)里两处讲 BaseSchema 形状的教学文案同步改写——它们原先说该类型带索引签名、props/events 由签名承接,去掉签名后已不成立;因此本 PR 的受管面除 AGENTS.md 外还含 skills/**,同一份批准覆盖两者。

为什么改:这是 objectui#7927 的裁决(TS 面是可执行契约)的落地,也是本卡的全部范围。此前签名让任何拼写都能编译,AI 批量写错元数据时被静默放过。

风险与代价(含回滚):对 TS 使用者是破坏性收窄(按仓规以 minor 发布并在 changeset 写明);运行期与 zod 宽容面不变,唯一例外是 visibleWhen 现在拒绝空字符串、接受 spec 的信封。已知边界:TS 只对"新鲜对象字面量"做多余键检查,经变量转手的值不会再查,已在 AGENTS.md 与钉子里写明。回滚:还原本 PR 即可,无数据迁移。

席位意见:

你要做的:1)裁决 props 别名在 TS 面上的去留:本 PR 按方案 A(不声明)写,B 是在 BaseSchema 上声明 props?: unknown,C 是只在 AuthoringNode 上声明;改选只需删两条 @ts-expect-error 并加成员。2)批准后由认领席落地(受管面,草稿态等你的批准)。


Generated by Claude Code

claude added 7 commits October 4, 2026 07:51
…eir readers take off the node, where those readers live

`ObjectKanban` reads the gate-written `sort` (the binding's `dataSource.sort`,
objectui#10068) through a non-exported read type, `GateBoundKanbanSchema`, and
`TimelineRenderSchema` declares the `onItemClick` slot `ObjectTimeline`
composes. Neither key joins an authoring face: `sort` stays undeclared on
`ObjectKanbanSchema` (objectui#8174) and `onItemClick` stays off
`TimelineSchema` (the objectui#6170 docblock). Both reads compiled only as
`any` through `BaseSchema`'s index signature; this compiles with or without it.

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
…mpiling without `BaseSchema`'s index signature

Two schema-to-record reads convert through `unknown`, and the gantt and map
`propertiesBag-10859` fixtures keep `operator` a literal and type the bag node
as its block node. Each compiles with the signature present too.

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
…put, by reference, on both faces

The TypeScript face is `@objectstack/spec`'s `EvaluatedExpressionInput`; the
zod twin is the same accept set (a predicate string, or the spec's own
`EvaluatedExpressionSchema` envelope) with `EvaluatedExpressionInputSchema`'s
verdict and without its string transform. Both read `string` before, so the
`{ dialect, source }` envelope a spec parse writes into this key was refused
(objectui#8347, ruled Q6 = B). `visible-when-spec-input-8347.test.ts` pins the
type identity, the verdict parity on a probe set read against the spec in the
same run, and that a string parses to itself.

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
…l pin, both directions, and the adjudicated flips

`BaseSchema` declares no `[key: string]: any`, so a node literal annotated with
its node type refuses a key no declaration names (objectui#8347, executing the
objectui#7927 ruling). `ComponentRendererProps` keeps its own signature.

- `base-schema-closed-face-8347.test.ts`: #7927's P5 turned red on a fresh
  literal, the correct spelling compiling, a nested node, the non-fresh bound,
  and `PartialSchema`'s working reading.
- The adjudicated probe and ceiling rows flip: each "an unknown key still
  compiles" row becomes an `@ts-expect-error`, and each `IsAny` fall-through
  control becomes a membership reading with a lit `IsAny<any>` control.
- The `props` alias rows flip (option A, the maintainer's open choice).
- The valueless `metric-card` in the legacy envelope is pinned refused on the
  TS face (Q3 = A); `envelopeStray` and its `complex.ts` note go, per the
  constant's own removal condition.
- `object-view-slot-key-lists` tripwires flip; `partial-schema-collapse-pin`
  is deleted per its header and `PartialSchema`'s docblock describes the alias
  as it now works.
- The mirror-parity ledger records five interface-to-passthrough entries the
  removal surfaces, measured as an artifact of the assignability test.
- Prose in these files that described the signature as live is corrected.

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
The listed doc blocks now compile against the closed face: architecture.md's
button writes `label`; objectos-integration.mdx's page block authors
`regions`, and its object-view nodes drop the adapter written as `dataSource`;
the types README's card writes `children`; plugin-calendar.mdx and
plugin-map.mdx pass their click handlers as component props instead of node
keys. Prose that described `BaseSchema`'s signature as live is corrected
(schema-reference, schema-renderer, ci-cd-pipeline, plugin-form, the
wrapperClass callouts, and the plugin-form, plugin-dashboard,
plugin-calendar and types READMEs), the `examples/dashboard.ts` comment too,
and the pending flex changeset gets a dated note (objectui#8347).

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
…he contract; §4 drops `props`

Describes what shipped with objectui#8347: `BaseSchema` declares no index
signature, a refused key is declared by reference or fixed at the producer,
never cast past, and the fresh-literal bound is stated with the pin that
measures it. §4's abridged listing drops `props`, which `BaseSchema` does not
declare, and #4's `events` sentence names the face that still keeps one.

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

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 331 chunks) 3312.3 KB 3330.4 KB
Main entry chunk (gzip) 151.3 KB 350 KB
Entry file index-BdK4FoGs.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) 17.22KB 6.37KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.89KB 38.62KB
plugin-designer (index.js) 231.41KB 48.84KB
plugin-detail (index.js) 245.74KB 64.59KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.44KB 45.28KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.63KB 64.77KB
plugin-kanban (index.js) 49.60KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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.81KB 3.58KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e0a9af67abc4414d3fc4ad80c80d522392bf49e7
Local-runs: none

Inputs: card #8347 (body and all 26 comments, rulings and earlier records included), PR #11607 (body, 79-file list, net diff against main at the head), and the head's check-runs, re-read at 2026-10-04T09:55Z: 43 runs, 40 success, 3 skipped (the coverage matrix placeholder, Test (coverage), dependabot), 0 failed, none in progress. Type Check, Test (shard 1/8) to (shard 8/8), Doc Snippet Type Check, Governed Surface Queue Guard and every changeset gate are green. Read-only: no worktree, nothing built or run. Faces judged: the Clause-②: yes declaration, the published @object-ui/types faces (TS and zod, per the package exports map: ., ./base, ./zod are the entries this diff touches), and the governed rule text in AGENTS.md.

① Derived judgments

  1. TS authoring face: BaseSchema loses [key: string]: any (packages/types/src/base.ts, published through . and ./base). Every node type that extends it narrows: a fresh typed literal refuses an undeclared key. Breaking. Right — it executes the objectui#7927 ruling as the card scopes it; the H1 re-census at BASE 2e818d0b5 (81 errors, 44 files) falls entirely into classes the fork ACCEPTs 5953788689 / 5977022487 adjudicated, and no site needed a contract decision. ComponentRendererProps keeps its signature (verified at the head; pinned by _RendererPropsKeepTheirs). The pin base-schema-closed-face-8347.test.ts is fresh-literal in both directions on four targets (CalendarViewSchema, BaseSchema, a nested button child, PartialSchema), and pins the bound (a non-fresh value is not re-checked) as a directive-free row, so the file claims no more than tsc delivers. The ablation (signature put back, 52 errors, every refusal row red) is the dev's reading in the report; not re-run here.
  2. TS: BaseSchema.visibleWhen goes from string to the spec's EvaluatedExpressionInput, by reference. Widening. Right — the seat ruled Q6 = B on the card (5953788689); _VisibleWhenIsTheSpecInput pins identity with the spec type, so nothing is restated locally.
  3. Zod tolerant face: BaseSchemaCore.visibleWhen (zod/base.zod.ts, published through ./zod as BaseSchema, AnyComponentSchema, safeValidateSchema, and the derived StrictAnyComponentSchema). It widens (the { dialect, source } envelope a spec parse writes now parses) and it narrows (a blank or whitespace-only string, accepted by the old z.string(), is refused with the spec's sentence). Right — by-reference adoption of the spec's EvaluatedExpressionInputSchema verdict carries the spec's refusals with it, which is what Q6 = B ordered; the transform is correctly withheld (a string parses to itself); verdict parity with the spec and with PageComponentSchema.visibleWhen is pinned on 13 probes holding both verdicts; the narrowing is disclosed in the changeset and the PR body. The card body's "zod face is out of scope (spec(types): derive and export the strict authoring twin of the node face — the #5250 strict face itself, no consumer wired #8345)" is superseded for this one key by the seat's carried item (5948782907, 5953788689), so this is in appetite.
  4. TS: PartialSchema (published alias in index.ts) now declares T's members optional with type required, as its first line always promised. A consequence of item 1, not an edit; pinned (_PartialKeepsTheMembers, a misspelling refused); the collapse pin deleted per its own header's removal condition; the docblock rewritten truthfully. Right. The enforce-or-remove card that header asks for is still owed (see ③).
  5. plugin-kanban: GateBoundKanbanSchema is non-exported; ObjectKanbanSchema, ObjectKanbanComponentProps and both zod faces are unchanged; sort stays undeclared on the authoring face (_KanbanSortStaysUndeclared, now a membership pin plus a fresh-literal refusal). No published change; the read is a widening assignment, not a cast. Right (objectui#8174, and the objectui#6356 hand-off pattern).
  6. plugin-timeline: TimelineRenderSchema gains optional onItemClick. Placement right per the maintainer's objectui#6356 ruling (host-written keys typed where producer and consumer live, never on TimelineSchema). One precision the PR body and changeset miss: the type is not private to the file. index.tsx re-exports ./renderer, whose exported TimelineRenderer takes schema: TimelineRenderSchema, so the member is reachable from the package entry and this is a one-member optional widening of a shipped prop type. Not a contract defect; the word "private" is inexact.
  7. The test-face flips (67 adjudicated probe and ceiling rows, the two props option-A directives, the three mechanical rows, the gantt and map operator literals): each flips a "still compiles" ceiling into an @ts-expect-error refusal while keeping a lit control (_IsAnyCanAnswerTrue or a declared-member control), so no assertion is loosened. The valueless envelope metric-card is pinned refused on the TS face only (Q3 = A, the zod component slot's BaseSchema arm left to the zod-face card); envelopeStray and its complex.ts note are deleted per the constant's own condition; the two object-view-slot-key-lists tripwires are flipped and the Pick lists kept, as the header now says. Right.
  8. Mirror-parity ledger: five new KnownDrift entries, INTERFACE-TO-PASSTHROUGH (AppSchemaRendererNodeSchema.schema and four reports.zod.ts pairs). Right — TypeScript grants an implicit string index to type literals and mapped types, never to an interface, so once BaseSchema's explicit signature is gone an interface-typed member is not assignable to a .passthrough() input; the dev measured that a one-level anonymous copy fits, which isolates the cause to that rule. Ledgered as an artifact of the operator, with the exit condition named; base.zod.ts#BaseSchema joins SPEC_DERIVED_PAIRS because its envelope arm is now a spec reference. The header's derived figures move with the entries.
  9. AGENTS.md (governed, Tier H). §4 drops props from the abridged listing — right, BaseSchema never declared it — and adds the no-index comment. §5 #0.1's new sub-bullet: every claim checks against the head (StrictAnyComponentSchema exists in strict-authoring-face.ts; the named pin file exists and pins both directions and the bound; ComponentRendererProps keeps its signature; the fresh-literal bound is stated per 完善设计器的每一个细节 #9 with the instrument named, not its answer). Add default props to all components to prevent collapse in designer #4's events sentence now names the face that still keeps the bag, which is true. Rule-shaped, no incident narrative. Right.
  10. Docs, READMEs, examples/dashboard.ts, the dated note on .changeset/11564-flex-bag-children-list.md are the prose face, outside the three review faces; read, not graded: the calendar and map handler keys moved to component props that exist at the head (ObjectCalendar.onEventClick / onDateClick, ObjectMap.onMarkerClick), the 11564 note is append-only with its frontmatter byte-identical, and Doc Snippet Type Check is green on the head.
  11. The props alias, option A (not declared on the TS face): a choice the PR body names as the maintainer's, carried by exactly two directives and the §4 listing. Consistent with the 2026-08-18 ruling's scope (runtime bound, TS face open) and the objectui#11364 measurement. Not decided by this record (see ③).

② Semver level

  • Levels. @object-ui/types: minor with the breaking banner and a FROM-to-TO migration — right under this repository's version policy (fixed group, no major; a breaking change ships as minor with the breaking semantics in the body). @object-ui/plugin-kanban: patch — right (nothing published moves). @object-ui/plugin-timeline: patch — see ① item 6: a reachable prop type widens by one optional member; the group's minor carries the version, so patch is tolerable, and minor would be exact. Not blocking.
  • The Clause-②: line — WRONG, and this is the finding. The changeset reads Clause-②: yes (mixed); the PR body reads Clause-②: yes. The arm is a closed pair, (widening) / (narrowing) (scripts/pm/clause2-line.mjs, CLAUSE2_ARMS), and the one reader treats a parenthetical without a widen or narrow stem as ordinary reasoning, so (mixed) is read as no arm: both carriers declare yes with no direction. For a diff whose title carries !, whose changeset says the removal "narrows the TypeScript authoring face of every node type", and whose tolerant zod face narrows too (item 3), that is the fail-open shape the arm was introduced to remove: a declared narrowing that no gate can read. The grammar's spelling for "widens one surface and narrows another" is yes (narrowing) — the spelling this repository's own changesets already use for exactly this mixed shape (.changeset/10859-object-gantt-properties-bag.md, .changeset/10859-object-map-properties-bag.md). Fix: in .changeset/8347-baseschema-closed-face.md replace Clause-②: yes (mixed) with Clause-②: yes (narrowing) (the sentence after it may stay), and in the PR body replace Clause-②: yes with Clause-②: yes (narrowing). Nothing else in ② moves.

③ Boundary flags

Dev deviations (report 5978644114):

  • Census instrument un-chained, not the literal chained pnpm type-check: accepted — the instrument the ACCEPTs 5926169140 and 5953788689 adopted.
  • Parity ledger, five INTERFACE-TO-PASSTHROUGH entries, operator unchanged: accepted (① item 8).
  • visibleWhen refuses a blank string on the tolerant face: accepted as the by-reference consequence of Q6 = B, disclosed on both carriers; the declaration line it points at is the one defect (②).
  • Kanban sort read through a non-exported intersection, no cast: accepted (① item 5).
  • AGENTS.md Add default props to all components to prevent collapse in designer #4 clause changed beside §4 and §5 #0.1: accepted, judged in ① item 9.
  • Four more inert keys fixed in the objectos-integration.mdx page block; handler keys moved to component props: read; prose face, gate green.
  • Single-program tsc probes outside os-verify-lock: a process note, no contract bearing; recorded.
  • Plugin vitest run on file contents equal to the head rather than at the head: superseded by the head's own check-runs (Test (shard 1/8) to (shard 8/8) success).

The open choice: props A / B / C on the TS face — escalated, not decided here. The 2026-08-18 ruling binds the runtime and leaves the TS face open; the PR writes A and names the two directives and the §4 line as the only carriers, so a flip costs one member and two deletions. This is the maintainer's call and the Tier H approval on this PR is where it is made.

Acceptance notes (read, not filed): RemoveIndexSignature in ObjectGrid.tsx now strips nothing and the form Pick list may return to Omit — cleanup, not owed by this card; present-tense "index signature" comments in untouched files — the opportunistic-repair rule applies, no sweep. One item is owed and not yet on the card: the enforce-or-remove card for PartialSchema that the deleted pin's header, the P1 reports and the fork ACCEPTs all name as due "at removal time" — the dispatching seat files it, with the dev's zero-consumer reading (declaration, docblock and the new pin's two rows only; SchemaByType as the positive control) as its evidence.

Carried items, checked against the diff: 5934689950 (props, visibleWhen) carried; 5955722883 (five plugin-map.mdx blocks) carried; 5957048412 (envelopeStray and the complex.ts note) carried; 5959573012 (valueless envelope, Q3 = A) carried as the TS-face pin; 5977022487's re-read list carried in full, grouping and the 6397 note dissolved as recorded; 5865873645 (the two PartialSchema sentences) re-pointed. H2: the objectui#11573 counter 12260 to 12974 against a 900000 limit (dev reading). H3: no skills/** path in the file list.

Gate reading: every check-run on the head is completed; the Governed Surface Queue Guard pull_request leg exits 0 by design and says nothing about approval. This PR is Tier H (AGENTS.md): after the ② fix lands on a new head, a fresh record on that head and the maintainer's APPROVED review are both still required before the owning seat lands it.

Implemented-by: claude/issue-8347-baseschema-index-signature
Reviewed-by: session_01CPvhwGcirXqBGEdPSb72TZ

VERDICT: FAIL

One finding, ② only: the Clause-② arm. Everything in ① and ③ holds; re-record on the head that carries yes (narrowing) on both carriers.


Generated by Claude Code

… plugin-timeline is `minor`

The arm is the closed pair `(widening)` / `(narrowing)`, and `(mixed)` read as
no arm at all; this repository spells the widen-one-surface, narrow-another
shape `yes (narrowing)`. The plugin-timeline bullet now says what ships: an
optional `onItemClick` on `TimelineRenderSchema`, the prop type of the
exported `TimelineRenderer`, so a one-member widening of an exported type and
`minor` (contract review `5978769372`, ② and ① item 6).

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

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 331 chunks) 3312.3 KB 3330.4 KB
Main entry chunk (gzip) 151.3 KB 350 KB
Entry file index-BdK4FoGs.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) 17.22KB 6.37KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.89KB 38.62KB
plugin-designer (index.js) 231.41KB 48.84KB
plugin-detail (index.js) 245.74KB 64.59KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.44KB 45.28KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.63KB 64.77KB
plugin-kanban (index.js) 49.60KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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.81KB 3.58KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 0334c43e025960679ce5616dadee53d2fbe7e155
Local-runs: none

Inputs: card #8347 (body and all 27 comments: the three P1 fork reports, the fork ACCEPTs, the carried items, the two done reports 5978644114 and 5978810507 included), PR #11607 (body as read at 2026-10-04T10:05Z, the 79-file list, the net diff against main at the head, and the one-commit diff e0a9af67..0334c43e), the earlier record 5978769372 (FAIL on this PR's previous head, ② only) as one input among the others, and the head's check-runs (readings below). Read-only: no worktree, nothing built, run or re-run; the one node -e over readClause2Line is a read of two strings, not a gate. Faces judged: the Clause-② declaration on both carriers, the published @object-ui/types faces (TS and zod; the package exports map at main is the published surface, and this diff touches ., ./base, ./zod, and ./complex in docblocks only), and the governed rule text in AGENTS.md. This record stands on its own: every judgment below is re-derived on the new head's full net diff against main, not inherited from 5978769372.

What moved between the two heads: one commit, one file, .changeset/8347-baseschema-closed-face.md (3 insertions, 3 deletions): the Clause-② arm (mixed) to (narrowing), @object-ui/plugin-timeline from patch to minor, and the plugin-timeline bullet rewritten to say the type is the schema prop of the exported TimelineRenderer. The PR body's Clause-② line reads yes (narrowing) as read. No source, test, doc or AGENTS.md byte changed between the heads.

① Derived judgments

  1. TS authoring face: BaseSchema loses [key: string]: any (packages/types/src/base.ts, published through . and ./base; every node interface that extends it narrows with it). A fresh typed literal now refuses an undeclared key, a misspelling included. Breaking narrowing. Right. It executes the objectui#7927 ruling (removal) within the card's appetite: the H1 re-census at BASE 2e818d0b5 (81 unique errors in 44 files, the dev's reading) fell entirely into the classes the fork ACCEPTs 5953788689 and 5977022487 adjudicated, no site needed a contract decision, and the final-head census is 90 programs exit 0 (dev reading; the head's Type Check check-run is the gate verdict, read below). ComponentRendererProps keeps its own signature at the head (read in base.ts; pinned by _RendererPropsKeepTheirs), and the other ten index-signature sites in packages/types/src the card puts out of scope (complex.ts twice, data-protocol.ts, data.ts, designer.ts twice, form.ts, objectql.ts twice, ui-action.ts) are untouched, read by git grep at the head.

    • The compile-fail pin packages/types/src/__tests__/base-schema-closed-face-8347.test.ts is read by tsc -p tsconfig.test.json, chained in the package's type-check script, so an @ts-expect-error that stops matching is itself an error (TS2578). Both directions on fresh literals, four targets: objectui#7927's P5 (titleFieldd refused, titleField compiles, on CalendarViewSchema), the base itself (classNmae against className), a node nested in a slot (labell on a button child, judged at the slot per objectui#11466), and PartialSchema (labell against label). Three declaration-level rows (_BaseSchemaHasNoIndexSignature, _NodeTypesInheritNone, _RendererPropsKeepTheirs) and the bound as a directive-free row (widenedIsNotRechecked: a value that reached its annotation through a wider variable is not re-checked). The dev's ablation (signature put back: the types test program exits 2 with 52 errors, every refusal row red) is the report's reading, not re-run here.
    • The card's P5 is honoured on a fresh literal, not on the README block. The dev measured that objectui#7927's literal P5 on today's plugin-calendar README stays green with or without the signature (the block is a type alias plus two non-fresh assignments), with a lit control that went red. The pin, the BaseSchema docblock, AGENTS.md and the README note all state that bound. Right: the ruling's flip is delivered where TypeScript delivers it, and nothing claims more.
  2. TS: BaseSchema.visibleWhen goes from string to the spec's EvaluatedExpressionInput, by reference (imported from @objectstack/spec/shared; the lockfile resolves @objectstack/spec@17.6.0). Widening: the { dialect, source } envelope a spec parse writes is authorable; inherited by every node type (assertionGalleryInheritsVisibleWhen moved with it). Right: Q6 = B, ruled by the seat in 5953788689; _VisibleWhenIsTheSpecInput pins identity with the spec type, so nothing is restated locally; dialectlessEnvelopeIsRefused pins that this key is narrower than ExpressionWire (objectui#7530), as the ruling accepted.

  3. Zod tolerant face: BaseSchemaCore.visibleWhen (zod/base.zod.ts, published through ./zod as BaseSchema, AnyComponentSchema, safeValidateSchema, and the derived StrictAnyComponentSchema). z.string() becomes VisibleWhenInputSchema: a union of z.string() and the spec's EvaluatedExpressionSchema (through stripImportedDefaults), with a superRefine that hands the value to the spec's EvaluatedExpressionInputSchema and copies its issues. It widens (the envelope parses) and it narrows (a blank or whitespace-only string, which z.string() accepted, is refused with the spec's sentence; a dialect-less envelope and an unknown dialect are refused as the spec refuses them). The spec's string transform is withheld, so a string parses to itself. Right. By-reference adoption of the spec's verdict is what Q6 = B ordered, the transform is correctly withheld (this mirror authors nothing into a parsed document), and the parity is pinned on 13 probes that hold both verdicts, against the spec input schema and against PageComponentSchema.visibleWhen in the same run (visible-when-spec-input-8347.test.ts); imported-defaults-8317.test.ts registers the new crossing; base.zod.ts#BaseSchema joins SPEC_DERIVED_PAIRS. The card body's "the zod face (spec(types): derive and export the strict authoring twin of the node face — the #5250 strict face itself, no consumer wired #8345 owns it)" is superseded for this one key by the seat's carried item (unlock 5948782907: by reference, on both faces; ACCEPT 5953788689: the zod twin is non-transforming), so it is in appetite. The narrowing is disclosed on both carriers.

  4. TS: PartialSchema (published alias in index.ts). Not edited; its behaviour changes as a consequence of item 1: it keeps T's declared members optional with type required, as its first line always promised, where it declared type alone beside a live signature before (objectui#6397). Pinned (_PartialKeepsTheMembers, partialMisspelled refused); the collapse pin partial-schema-collapse-pin.test.ts deleted per its own header's removal condition ("delete this file and, if PartialSchema is still unconsumed at that point, file a fresh enforce-or-remove card"); the docblock rewritten truthfully, with the OmitDeclared caveat for a T that declares its own signature. Right. At the head PartialSchema has no consumer outside its declaration, the new pin and the changeset (tracked-files git grep, CHANGELOGs excluded), so the card that header asks for is owed (③).

  5. plugin-kanban: GateBoundKanbanSchema, a non-exported intersection (ObjectKanbanSchema plus an optional sort of SortConfig[]; SortConfig is an export of @object-ui/types), assigned from the declared prop without a cast (legal: the member is optional). ObjectKanbanComponentProps, ObjectKanbanSchema and both zod faces unchanged; sort stays undeclared on the authoring face (_KanbanSortStaysUndeclared is now a membership pin plus the fresh-literal refusal kanbanAuthoredSort). No published change. Right (objectui#8174; the objectui#6356 hand-off pattern).

  6. plugin-timeline: TimelineRenderSchema gains optional onItemClick. The type is not exported by name, but it is the schema prop type of TimelineRenderer, which index.tsx re-exports from ./renderer, so this is a one-member optional widening of a reachable prop type. TimelineSchema (the authoring face) declares no onItemClick. Placement right per the objectui#6356 ruling (host-written keys typed where producer and consumer live, never on the authoring face); the changeset now describes it exactly and bumps the package minor (②).

  7. The test-face flips: the adjudicated probe and ceiling rows across types, plugin-charts, plugin-dashboard, plugin-grid, plugin-list, plugin-map, plugin-tree and components (misspellings such as visibleWhn, xAxisKy, drillDwn, filtr, colourField, enableClusterng, objectNaem; the zzUndeclared7353 / bogusKey / someProp controls; operators on the grid twin; the retired chatbot keys; onSuccess on the base); the two props option-A directives in alias-precedence-cross-channel.test.tsx; content on a label node in form-renderers.test.tsx; the three mechanical rows (two schema-to-record casts through unknown, the parity ledger); the six gantt and map operator literals (as const, the bag node typed ObjectGanttBlockNode / ObjectMapBlockNode, both exports of @object-ui/types); the two object-view-slot-key-lists tripwires (declaresStringIndex now false, the Pick lists kept and the header saying the form one may return to Omit). Each flips a "still compiles" ceiling into an @ts-expect-error refusal or a keyof membership row, and each keeps a lit control (_IsAnyCanAnswerTrue, a declared-member control, or a picked key), so no assertion is loosened and IsAny cannot go vacuous. Where a key is undeclared rather than tombstoned (operators on ObjectGridSchema, letter C of objectui#9739), a membership row (_OperatorsIsNoMember) keeps "not declared" measurable, since a refusal alone cannot tell an undeclared key from a ?: never tombstone. Right.

    • The valueless envelope metric-card is pinned refused on the TS face only, naming value (Q3 = A, ACCEPT 5977022487), with the value-carrying envelope as the control; the zod component slot's BaseSchema arm is left to the zod-face card, as ruled. envelopeStray and the complex.ts note are deleted per the constant's own removal condition, read in the deleted block. flex-bag-children-list-11564.test.ts gains the text-in-list refusal the removal promised (H4). Right.
  8. Mirror-parity ledger: five new KnownDrift entries, INTERFACE-TO-PASSTHROUGH (app.zod.ts#AppSchemaRendererNodeSchema schema; reports.zod.ts ReportBuilderSchema report, ReportComponentSchema sections, ReportSectionSchema chart, ReportViewerSchema report); header figures 50 / 87 to 55 / 92. Right: TypeScript grants an implicit string index to type literals and mapped types and never to an interface, so once BaseSchema's explicit signature is gone an interface-typed member is not assignable to a .passthrough() mirror's input; the dev measured that a one-level anonymous copy fits, which isolates the cause to that rule. An artifact of the ratchet's assignability test, not a narrowing a document can hit; ledgered with its exit condition.

  9. AGENTS.md (governed; the agents-md row of this repository's GOVERNED_SURFACES, Tier H). §4 drops the props member from the abridged listing (right: BaseSchema never declared it, as P1 report 5926022178 flagged) and adds the no-index comment. §5 #0.1's new sub-bullet: every claim checks against the head (StrictAnyComponentSchema exists in strict-authoring-face.ts; the named pin exists and pins both directions and the bound; ComponentRendererProps keeps its signature; the fresh-literal bound is stated per 完善设计器的每一个细节 #9 with the instrument named and not its answer). Add default props to all components to prevent collapse in designer #4's events sentence now names the face that still keeps the bag, which is true. Rule-shaped. Right. One precision for the approver, not a defect: the sub-bullet names two remedies for a refused key (declare it by reference on the node type that reads it, or fix the producer); the third route this very PR uses for a host-written runtime key (a package-local hand-off type, the objectui#6356 ruling) is not named there, and the ruling stands on its own.

  10. Docs, READMEs, examples/dashboard.ts, the dated note on .changeset/11564-flex-bag-children-list.md: prose face, read and not graded. The calendar and map handler keys moved to component props that exist at the head (ObjectCalendar onEventClick / onDateClick, ObjectMap onMarkerClick); the objectos-integration.mdx page block now authors regions, href, defaultViewType and table.columns and hands the adapter to the renderer, not the node; the five plugin-map.mdx blocks are typed ObjectMapBlockNode; the 11564 note is append-only with its frontmatter byte-identical; the plugin-form README's sentence that FormField keeps its own signature is true at the head. Doc Snippet Type Check is green on the head.

  11. The props alias, option A (not declared on the TS face): carried by two directives, the §4 listing and the changeset's migration sentence. Consistent with the 2026-08-18 ruling's scope (runtime bound, TS face open) and the objectui#11364 measurement (zero non-test authors). Not decided here (③).

② Semver level

  • Changeset .changeset/8347-baseschema-closed-face.md: @object-ui/types: minor with the breaking banner and the FROM-to-TO migration (misspelled: fix it; undeclared: declare it by reference or remove it; never cast past; props to properties). Right under this repository's version policy (fixed group, no major; a breaking change ships as minor with the breaking semantics in the body; Changeset Bump Policy green). @object-ui/plugin-kanban: patch: right, nothing published moves. @object-ui/plugin-timeline: minor: right, and now exact (① item 6). The eight packages whose only changes sit under src/__tests__ publish nothing and ride the fixed group; Changeset Declaration (presence) is green on the head.
  • The Clause-② line, both carriers, read with the fleet reader (readClause2Line from scripts/pm/clause2-line.mjs): changeset yes, arm narrowing; PR body yes, arm narrowing. The grammar's yes (narrowing) is a diff that widens one surface and narrows another, and that is true here on both counts: widens (the visibleWhen envelope on both faces, the timeline prop type) and narrows (the TS authoring face of every node type, a blank visibleWhen string on the tolerant zod face). yes takes at least minor (it does) and (narrowing) is breaking (the title carries !, the body carries the banner and the migration). The ② finding of 5978769372 is discharged on this head. No gate in this repository's check-run set reads an ADR-0087 disposition marker and this repository's AGENTS.md asks for none; not applied.
  • .changeset/11564-flex-bag-children-list.md: a dated, append-only note; its frontmatter and its own Clause-②: yes (narrowing) line are unchanged. Changeset Claim Re-read and Changeset Overwrite Report green.

③ Boundary flags

Dev deviations (report 5978644114), each answered:

  • Census instrument un-chained (90 programs), not the literal chained pnpm type-check: accepted, the instrument the ACCEPTs 5926169140 and 5953788689 adopted; the head's Type Check check-run is the gate verdict.
  • Parity ledger, five INTERFACE-TO-PASSTHROUGH entries, operator unchanged: accepted (① item 8).
  • visibleWhen refuses a blank string on the tolerant face: accepted as the by-reference consequence of Q6 = B, disclosed on both carriers, and now declared (narrowing) on both.
  • Kanban sort through a non-exported intersection, no cast: accepted (① item 5).
  • AGENTS.md Add default props to all components to prevent collapse in designer #4 clause changed beside §4 and §5 #0.1: accepted, a truth repair, judged in ① item 9; Tier H, so the approver reads it.
  • Four more inert keys fixed in the objectos-integration.mdx page block; handler keys moved to component props: read; prose face; gate green.
  • Single-program tsc probes outside os-verify-lock: a process note, no contract bearing; recorded.
  • Plugin vitest run on file contents equal to the previous head rather than at it: superseded by the head's own Test (shard 1/8) to (shard 8/8) check-runs (readings below).

Patch-round report 5978810507: deviations and open_questions are empty; its "CI on 0334c43 NOT MEASURED" is answered by the readings below.

The open choice, props A / B / C on the TS face: escalated, not decided here. The maintainer's call, made on the Tier H approval of this PR. The PR writes A. A flip costs one member, the two directive deletions, and one more sentence than the PR body counts: the changeset's migration line (props is not declared on the TypeScript face, write properties) must move with it.

Owed, and not evidenced in the inputs as filed: the enforce-or-remove card for PartialSchema that the deleted pin's header, the P1 reports and the fork ACCEPTs name as due at removal time (carrier: the dispatching seat, per 5978644114 out_of_scope_findings), with the dev's zero-consumer reading as its evidence.

Acceptance notes (read, not filed), and one correction:

  • ObjectChartBlock's pre-gate schema prop is BaseSchema (ruling 5810232641), so a fresh literal there is now excess-checked against BaseSchema itself and a correctly spelled objectName is refused as much as the probe; in-tree callers pass typed nodes. Not a defect of this diff: the prop's type is plugin-charts' own choice, and retyping it is a separate card if the seat reads it as an authoring trap.
  • RemoveIndexSignature in ObjectGrid.tsx strips nothing now; the form Pick list may return to Omit: cleanup, not owed by this card.
  • Present-tense index-signature prose in shipped source the PR does not touch. The dev's note says "tense only, none became false". That does not hold as written: a git grep at the head over packages/*/src with tests excluded reads 24 docblock sentences still saying BaseSchema carries, closes with, ends in, or still carries [key: string]: any (for example in objectql.ts: "BaseSchema still carries [key: string]: any, so declaring a key buys it"; others in ai.ts, data-display.ts, designer.ts, feedback.ts, form.ts, layout.ts, crud.ts, complex.ts, plugin-tree's ObjectTree.tsx, plugin-charts's ObjectChart.tsx; two of the 24 are about other types), plus the future-tense "which objectui#8347 removes" family. These are TSDoc, outside the three faces, and the tombstone reasoning they carry still holds on the zod side, so they do not move this verdict. Escalated to the seat as one comment-only follow-up card, seeded from the dev's own enumerating command; not a rider on this PR.

Carried items, checked against the diff: 5934689950 (props, visibleWhen) carried; 5945723770 (ActionBarSchema re-read: Q5 = A, nothing to change) carried; 5955722883 (five plugin-map.mdx blocks, and venueMap) carried; 5957048412 (envelopeStray and the complex.ts note) carried; 5959573012 (valueless envelope, Q3 = A) carried as the TS-face pin; 5977022487's re-read list carried in full (grouping and the 6397 note dissolved; the 6397 changeset is absent at the head); 5865873645 (the two PartialSchema sentences) re-pointed. H2: the objectui#11573 counter 12260 to 12974 against a 900000 limit (dev reading). H3: no skills/**, .claude/** or docs/adr/** path in the 79-file list; AGENTS.md is the one governed path.

Gate reading (the head's check-runs, which are the gate verdicts), read three times: at 2026-10-04T10:05Z 42 runs with 13 in_progress; at 10:09Z 42 runs with 10 in_progress (Type Check, Test (shard 1/8) to (shard 8/8), Spec Main Shape Gate); at 10:17Z, the reading this record stands on, 43 runs, every one completed: 40 success, 3 skipped (the coverage matrix placeholder Test (coverage shard), Test (coverage), dependabot), 0 failed, 0 in progress. Type Check (success, 10:10Z), Test (shard 1/8) to (shard 8/8) and the Test rollup (success, the last at 10:16Z), Test (dist pins), Doc Snippet Type Check, Lint, Spec Main Shape Gate, Skill Example Check, README Export Check, Line Citation Gate, every changeset gate (Changeset Declaration, Changeset Bump Policy, Changeset Claim Re-read, Changeset Overwrite Report, Changeset Fixed Group Check) and Governed Surface Queue Guard are success. The queue guard's pull_request leg exits 0 by design on a governed diff and says nothing about approval.

Landing: this PR is Tier H (AGENTS.md). A PASS here is the contract record, ⛔ not the landing authorization: the PR stays draft until an APPROVED review by an account in GOVERNED_APPROVERS is on it, and then the owning seat lands it through the queue; no agent seat approves. The PR reads behind main at this read; the queue rebuilds it.

Implemented-by: claude/issue-8347-baseschema-index-signature
Reviewed-by: session_01CPvhwGcirXqBGEdPSb72TZ

VERDICT: PASS


Generated by Claude Code

…gnature now gone)

Comment and prose bytes only. Every sentence that said `BaseSchema` (or a
node type through it) carries, closes with or ends in `[key: string]: any`,
every future-tense "objectui#8347 removes", and every TS2578 note that
promised a directive goes unused when its member is deleted, now says what
is true at this head: the signature is gone, a deletion is refused on a
fresh literal and still rides a widened value, and the zod face keeps its
`.passthrough()` reasoning, named as the zod face.

AGENTS.md section 5 #0.1 gains the package-local hand-off-type route for a
host-written runtime key (objectui#6356).

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

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 331 chunks) 3312.6 KB 3330.4 KB
Main entry chunk (gzip) 151.4 KB 350 KB
Entry file index-BVtToKYW.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) 17.22KB 6.37KB
app-shell (runtime-config.js) 22.52KB 7.86KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.89KB 38.62KB
plugin-designer (index.js) 231.41KB 48.84KB
plugin-detail (index.js) 245.74KB 64.59KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.74KB 45.38KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.63KB 64.77KB
plugin-kanban (index.js) 49.60KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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.81KB 3.58KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.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

claude added 3 commits October 4, 2026 12:06
…ignature

Patch round 3 on objectui#8347 works on the merged tree: the six PRs main took since the merge base touch no file this branch edits, so the merge is textual-conflict-free; the post-merge type-check of the packages main moved is the check that the merge is also semantically clean.

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
…ipt face (objectui#8347)

The architecture guide's "JSON Protocol" section and the protocol rule's "Component Schema Structure" section taught that the published `BaseSchema` declares its members "plus an index signature", and that `props` / `events` (and `properties`) reach a node through `[key: string]: any`. objectui#8347 removed that signature, so both became false on the TypeScript face.

Both warning paragraphs now give the two verdicts a key no member declares gets, one per face: a compile error in a fresh typed literal on the TypeScript authoring face (with the fresh-literal bound stated as AGENTS.md section 5 #0.1 states it), and kept-then-judged-by-the-named-reader on the tolerant zod / JSON face. The teaching fences drop `props`, `events` and `properties`, which the published type never declared, and end on the same no-index-signature line AGENTS.md section 4 uses; they stay SHAPE copies, not member lists, and the member count in prose is gone (section 5 #9). `props` keeps one sentence of its own, stating option A as shipped (not declared on the TypeScript face, read by the runtime), so a flip to B or C is a one-sentence edit. The "Actions Are Node Types" rule's `events` paragraph no longer points at a fence entry that is gone.

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
…d, and retitle the four pins that described the signature as live

While `BaseSchema` carried `[key: string]: any`, an `@ts-expect-error` over a tombstone or a typed member doubled as a deletion guard: delete the member, the key widened to `any`, the directive went unused, TS2578. Since the removal the deleted key is refused as undeclared (or the indexed access itself errors), the directive stays used, and the deletion goes unnoticed. Each of the five files gains a type-level row that asserts the member EXISTS with its declared or tombstone type: an indexed access on a member that does not exist is a compile error, and `Equal` reddens on a re-typing. `object-kanban-card-title-9606` pins `cardTitle` (and the `titleField` alias the ruling forbids retiring); `object-grid-default-sort-tombstone-5861` pins `defaultSort`; `object-grid-show-filters-retired-11068` pins `showFilters` (and that the list-view and object-view spellings stay live); `object-grid-declared-keys-11068` pins `rowSpecActions` and `bulkSpecActions`, the two tombstones `BaseSchema` does not declare; `gantt-flat-config-declared-keys` pins `staticData`, `filter` and `sort`, the three query keys its derived invariant cannot see. Every existing assertion stays. The header comments name the real guard.

Four strings that described the signature as live are rewritten, the assertion logic untouched: two it-titles (action-callback-retired-7068, timeline-dead-keys-retired-6170), one it.each title (stack-schema-emitted-members) and one assertion message (schema-reference-named-list-view-keys-7923). No baseline, snapshot, allowlist or script references those titles (tracked-files grep, zero hits outside the four files).

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
…tion exposed

The first ablation pass on the restored guards showed that a deleted member also reddens the `zod-mirror-parity` mirrored-undeclared ledger (the zod twin still declares it), the kanban file's two fresh literals, and, for `defaultSort`, the `ObjectGridSlotKey` constraint in `objectql.ts`. The new rows' docblocks say so, and the kanban file's older claim that the ratchet is blind to this deletion is dated to when it was measured, with the re-measurement beside it. Comment bytes only.

Claude-Session: https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ
Co-authored-by: Claude <noreply@anthropic.com>
…y they restate `any`

The `_StaticDataIsDeclared` and `_FilterIsDeclared` rows pin members `objectql.ts` declares as `any[]`; `Equal` is strict, so the row must spell the same type. A per-line disable with that reason replaces the two `no-explicit-any` warnings the lint run reported. Comment bytes only.

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

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 331 chunks) 3312.8 KB 3330.4 KB
Main entry chunk (gzip) 151.4 KB 350 KB
Entry file index-D6zRWH_9.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) 17.22KB 6.37KB
app-shell (runtime-config.js) 22.52KB 7.86KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.89KB 38.62KB
plugin-designer (index.js) 231.41KB 48.84KB
plugin-detail (index.js) 245.74KB 64.59KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.74KB 45.38KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.63KB 64.77KB
plugin-kanban (index.js) 49.60KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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.81KB 3.58KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 09165ac8d78fe269892c7bb6645c3806b7e5336a
Local-runs: none

Inputs: card #8347 (body and all 31 comments: the three P1 fork reports and their ACCEPTs, the carried items, the done report 5978644114, the patch-round reports 5978810507, 5979644768 and 5979995689, the seat ruling 5978976059 and the claim amendment 5979679543), PR #11607 (body as read at 2026-10-04T12:42Z, the 202-file list, and the net diff against main at merge base b508ac50, built read-only in a fetched clone because the diff exceeds the API's size), the two earlier records on this PR (5978769372, FAIL on head e0a9af67, ② only; 5978958580, PASS on head 0334c43e) as inputs among the others, and the head's check-runs (three readings, below). Read-only: no worktree, nothing built, run or re-run; the node -e over readClause2Line is a read of three strings, not a gate, and the comment-versus-code split of the diff is a text read. Faces judged: the Clause-② declaration on both carriers; the published @object-ui/types faces (TS and zod; the package exports map at the head is the published surface, and this diff moves ., ./base and ./zod, with ./complex, ./layout, ./form, ./data-display, ./navigation, ./overlay and ./data touched in docblocks only); the governed rule text in AGENTS.md; and, since patch round 3, the published skill text in skills/objectui/guides/architecture.md and skills/objectui/rules/protocol.md. This record stands on its own: every judgment is re-derived on this head's full net diff against main, not inherited from either earlier record.

What moved since the PASS record's head 0334c43e, read commit by commit: 032b9a2d (round 2: comment and prose bytes in 164 files, plus one clause in AGENTS.md), 774e113b (a merge of main at b508ac50 by merge commit: its combined diff is empty, so no conflict was hand-resolved; the 49 files main brought and the 202 files this branch edits are disjoint, and the branch's own commits touch exactly the 202 files the net diff lists), 50d31423 (the two published-skill files), 2c8709b7 (five deletion guards restored and four test strings reworded), de88092c (guard docblocks) and 09165ac8 (two lint-disable comment lines). The comment-versus-code split over the whole net diff confirms the round-2 claim: of the 39 shipped (non-test) source files in the diff, only four carry a non-comment change, namely packages/types/src/base.ts, packages/types/src/zod/base.zod.ts, packages/plugin-kanban/src/ObjectKanban.tsx and packages/plugin-timeline/src/renderHandoff.ts; the other 35 move comment bytes only.

① Derived judgments

  1. TS authoring face: BaseSchema loses [key: string]: any (packages/types/src/base.ts, published through . and ./base; every node interface that extends it narrows with it, so the ./complex, ./layout, ./form, ./data-display, ./navigation, ./overlay and ./data entries narrow too). A fresh typed literal now refuses a key no declaration names, a misspelling included; the correct spelling compiles. Breaking narrowing. Right. It executes the objectui#7927 ruling (removal) inside the card's appetite: the H1 re-census at BASE 2e818d0b5 (81 unique errors in 44 files, the dev's reading) fell entirely into classes the fork ACCEPTs 5953788689 and 5977022487 adjudicated; no site needed a contract decision; the head's Type Check check-run is the gate verdict and is green. ComponentRendererProps keeps its own signature (read at the head; pinned by _RendererPropsKeepTheirs), and the other index-signature sites the card puts out of scope are untouched (the code split shows no non-comment change outside the four files above).

    • The compile-fail pin packages/types/src/__tests__/base-schema-closed-face-8347.test.ts is read by tsc -p tsconfig.test.json, chained in the package's type-check script (the include of tsconfig.test.json is src/**/*.test.ts and src/**/*.test.tsx, so the new file is in the program), and CI's Type Check job runs pnpm type-check. An @ts-expect-error that stops matching is itself an error (TS2578), so a signature put back turns the refusal rows red. Both directions on fresh literals, four targets: objectui#7927's P5 (titleFieldd refused, titleField compiles, on CalendarViewSchema); the base itself (classNmae against className); a node nested in a slot (labell on a button child, reported at the slot per objectui#11466); and PartialSchema (labell against label). Three declaration-level rows (_BaseSchemaHasNoIndexSignature, _NodeTypesInheritNone, _RendererPropsKeepTheirs) and the bound as a directive-free row (widenedIsNotRechecked: a value that reached its annotation through a wider variable is not re-checked). The dev's ablation (signature put back, the types test program exits 2 with 52 errors, every refusal row red) is the report's reading, not re-run here.
    • P5 is honoured on a fresh literal, not on the README block. The dev measured that objectui#7927's literal P5 on the plugin-calendar README stays green with or without the signature (the block is a type alias plus two non-fresh assignments), with a lit control that went red. The pin, the BaseSchema docblock, AGENTS.md, both skill files and the README note all state that bound, so nothing claims more than tsc delivers. Right.
  2. TS: BaseSchema.visibleWhen goes from string to the spec's EvaluatedExpressionInput, by reference (@objectstack/spec/shared). Widening on the TS face: the { dialect, source } envelope a spec parse writes is authorable, inherited by every node type. Right: Q6 = B, ruled by the seat in 5953788689; _VisibleWhenIsTheSpecInput pins identity with the spec type, so nothing is restated locally; dialectlessEnvelopeIsRefused pins that this key is narrower than ExpressionWire (objectui#7530), as that ruling accepted.

  3. Zod tolerant face: BaseSchemaCore.visibleWhen (packages/types/src/zod/base.zod.ts, published through ./zod as BaseSchema, AnyComponentSchema, safeValidateSchema and the derived StrictAnyComponentSchema). z.string() becomes VisibleWhenInputSchema: a union of z.string() and the spec's EvaluatedExpressionSchema (through stripImportedDefaults), with a superRefine that hands the value to the spec's EvaluatedExpressionInputSchema and copies its issues. It widens (the envelope parses) and it narrows (a blank or whitespace-only string, which z.string() accepted, is refused with the spec's sentence; a dialect-less envelope and an unknown dialect are refused as the spec refuses them). The spec's string transform is withheld, so a string parses to itself. Right. By-reference adoption of the spec's verdict is what Q6 = B ordered; the transform is correctly withheld (this mirror authors nothing into a parsed document); parity is pinned on 13 probes holding both verdicts, against the spec input schema and against PageComponentSchema.visibleWhen in the same run (visible-when-spec-input-8347.test.ts), and both component faces accept the spec-parsed envelope while the strict face refuses a dialect-less one; imported-defaults-8317.test.ts registers the new crossing; base.zod.ts#BaseSchema joins SPEC_DERIVED_PAIRS. The card body's "the zod face (spec(types): derive and export the strict authoring twin of the node face — the #5250 strict face itself, no consumer wired #8345 owns it)" is superseded for this one key by the seat's carried item (unlock 5948782907: by reference, on both faces; ACCEPT 5953788689: a non-transforming twin), so it is in appetite. The narrowing is disclosed on both carriers. One nit, not a finding: the superRefine callback calls stripImportedDefaults on every parse rather than once at module scope; the verdict is unchanged, only an allocation per parse.

  4. TS: PartialSchema (published alias in index.ts). Not edited; as a consequence of item 1 it keeps T's declared members optional with type required, as its first line always promised (it declared type alone beside a live signature before, objectui#6397). Pinned (_PartialKeepsTheMembers, partialMisspelled refused); partial-schema-collapse-pin.test.ts deleted per its own header's removal condition ("THIS FILE IS EXPECTED TO GO RED WHEN objectui#5155 LANDS ... Do not widen the assertion; delete the file"); the docblock rewritten truthfully, with the OmitDeclared caveat for a T that declares its own signature. Right. The enforce-or-remove card that header asks for exists: objectui#11608, open, Blocked-by: #8347, filed by the seat after the PASS record (③).

  5. plugin-kanban: GateBoundKanbanSchema, a non-exported intersection (ObjectKanbanSchema plus an optional sort of SortConfig[]; SortConfig is an export of @object-ui/types), assigned from the declared schema prop without a cast, which is legal because the added member is optional. ObjectKanbanComponentProps, ObjectKanbanSchema, the package's exports map and both zod faces are unchanged; sort stays undeclared on the authoring face (_KanbanSortStaysUndeclared is now a membership row, plus the fresh-literal refusal kanbanAuthoredSort, with _IsAnyCanAnswerTrue as the lit control for the IsAny rows). No published change. Right (objectui#8174; the objectui#6356 hand-off pattern, which AGENTS.md §5 #0.1 now names).

  6. plugin-timeline: TimelineRenderSchema gains optional onItemClick. The type is not exported by name, but it is the schema prop type of TimelineRenderer, which index.tsx re-exports from ./renderer, so this is a one-member optional widening of a reachable prop type on the package's . entry. TimelineSchema, the authoring face, declares no onItemClick. Placement right per the objectui#6356 ruling (host-written keys typed where producer and consumer live, never on the authoring face); the changeset describes it exactly and bumps the package minor (②).

  7. The test-face flips. The adjudicated probe and ceiling rows across types, plugin-charts, plugin-dashboard, plugin-grid, plugin-list, plugin-map, plugin-tree, components and examples/schema-catalog (misspellings such as visibleWhn, xAxisKy, drillDwn, filtr, enableClusterng, objectNaem; the zzUndeclared7353 / bogusKey / someProp controls; operators on the grid twin; the retired chatbot keys; onSuccess on the base as the control of action-callback-retired-7068); the two props option-A directives in alias-precedence-cross-channel.test.tsx; the mechanical rows (two schema-to-record casts through unknown, the parity ledger); the six gantt and map operator literals (as const, the bag node typed ObjectGanttBlockNode / ObjectMapBlockNode, both exports of @object-ui/types); the two object-view-slot-key-lists tripwires (declaresStringIndex now false, the Pick lists kept and the header saying the form one may return to Omit). Each flips a "still compiles" ceiling into an @ts-expect-error refusal or a keyof membership row and keeps a lit control, so no assertion is loosened. Where a key is undeclared rather than tombstoned, a membership row keeps "not declared" measurable, since a refusal alone cannot tell an undeclared key from a ?: never tombstone. Right.

    • The valueless envelope metric-card is pinned refused on the TS face only, naming value (Q3 = A, ACCEPT 5977022487), with the value-carrying envelope as the control; the tolerant zod component slot's BaseSchema arm is left alone, as ruled, and the test says so. envelopeStray and the complex.ts note on widgets are deleted per the constant's own removal condition, read in the deleted block. flex-bag-children-list-11564.test.ts gains the text-in-list refusal the removal promised (H4). Right.
  8. Mirror-parity ledger: five new KnownDrift entries, INTERFACE-TO-PASSTHROUGH (app.zod.ts#AppSchemaRendererNodeSchema schema; reports.zod.ts ReportBuilderSchema report, ReportComponentSchema sections, ReportSectionSchema chart, ReportViewerSchema report); header figures 50 / 87 to 55 / 92. Right: TypeScript grants an implicit string index to type literals and mapped types and never to an interface, so once BaseSchema's explicit signature is gone an interface-typed member is not assignable to a .passthrough() mirror's input; the dev measured that a one-level anonymous copy fits, which isolates the cause to that rule. An artifact of the ratchet's assignability test, not a narrowing a document can hit; ledgered with its exit condition. The WiderThanDeclared entry for complex.zod.ts#DashboardWidgetSchema component is re-worded to say the slot's BaseSchema fallback still stands, since this PR leaves the zod faces alone; what it no longer says is who retires that fallback (③).

  9. Round 3: five deletion guards restored (object-kanban-card-title-9606, object-grid-default-sort-tombstone-5861, object-grid-show-filters-retired-11068, object-grid-declared-keys-11068, gantt-flat-config-declared-keys). The mechanism the dev names is real: while the signature stood, deleting a member widened its key to any, the directive went unused and TS2578 fired; since the removal the deleted key is refused as undeclared, the directive stays used, and the deletion is silent. Each file now carries a type-level row of the form Expect of Equal(the indexed access, the declared or tombstone type): an indexed access on a member that does not exist is a compile error, and Equal reddens on a re-typing. The two any[] rows restate members objectql.ts declares as any[], which strict Equal requires, with a per-line lint disable stating that. The dev's nine trap-restored ablation legs (each red on deletion, green restored) are the report's reading. Three test titles and one assertion message that described the signature as live are reworded with assertion logic untouched, and the PR body's count ("three") matches the commit. Right.

  10. AGENTS.md (governed; the agents-md row of this repository's GOVERNED_SURFACES). §4 drops the props member from the abridged listing (right: BaseSchema never declared it) and adds the no-index comment. §5 #0.1's sub-bullet: every claim checks against the head (StrictAnyComponentSchema exists; the named pin exists and pins both directions and the bound; ComponentRendererProps keeps its signature; the fresh-literal bound is stated per 完善设计器的每一个细节 #9 with the instrument named and not its answer), and since round 2 it names the third remedy this PR itself uses for a host-written runtime key (a package-local hand-off type, objectui#6356), which answers the PASS record's item-9 precision. Add default props to all components to prevent collapse in designer #4's events sentence names the face that still keeps the bag, which is true. Rule-shaped, no incident narrative. Right.

  11. The published skills (governed; the skills-catalog row). architecture.md's "JSON Protocol" section and protocol.md's "Component Schema Structure" section said the published BaseSchema declares its members plus an index signature and that props / events / properties reach a node through it; on the TypeScript face this PR makes every one of those sentences false, so the repair belongs in this PR (the seat's ruling 5978976059, extended by the claim amendment 5979679543). Both warning paragraphs now give the two verdicts a key no member declares gets, one per face, with the fresh-literal bound said as §5 #0.1 says it; both fences drop the three keys the published type never declared and end on the same no-index line as AGENTS.md §4; protocol.md's "Actions Are Node Types" paragraph no longer points at a fence entry that is gone and now mirrors AGENTS.md Add default props to all components to prevent collapse in designer #4's sentence; the member count in prose is gone (完善设计器的每一个细节 #9). Each statement checks against the head: props is read by the runtime and undeclared on the TS face under option A; properties is declared per block on AuthoringNode; events is read by nothing. Neither fence carries an os:check marker (architecture.md has none; protocol.md's first marker sits under the "Bindable Text Keys" rule, below the fence), so check:skill-examples does not compile them, and Skill Example Check, Skill Eval Token Check and Skill Guide Path Check are green on the head. Right. One pre-existing simplification for the skills lane, not this PR's: both fences still spell the slot children?: BaseSchema[] with "the real slot also admits primitives", while since objectui#11466 the object arm is DeclaredNode; the fences are labelled abridged shape copies, the sentence was there before this PR, and the removal does not make it false.

  12. Docs, READMEs, examples/dashboard.ts, the dated note on .changeset/11564-flex-bag-children-list.md: the prose face, read and not graded. The calendar and map handler keys moved to component props that exist at the head (ObjectCalendar's onEventClick / onDateClick, ObjectMap's onMarkerClick; no node-level onMarkerClick remains in plugin-map.mdx, venueMap included); the five plugin-map.mdx blocks are typed ObjectMapBlockNode; the objectos-integration.mdx page block authors regions, href, defaultViewType and table.columns, and the adapter leaves the node; the plugin-calendar README's note now states the fresh-literal bound and the open calendar block; the 11564 note is append-only with its frontmatter byte-identical. Doc Snippet Type Check is green on the head. One precision for the seat on the rewritten objectos-integration.mdx App block (③).

  13. The props alias, option A (not declared on the TS face): carried by the two directives, the §4 listing, the changeset's migration sentence, and now one sentence in each skill file. Consistent with the 2026-08-18 ruling's scope (runtime bound, TS face open) and the objectui#11364 measurement (zero non-test authors). Not decided here (③).

② Semver level

  • Changeset .changeset/8347-baseschema-closed-face.md: @object-ui/types: minor with the breaking banner and the FROM-to-TO migration (misspelled: fix it; undeclared: declare it by reference on the reading type or remove it; never cast past; props to properties). Right under this repository's version policy (fixed group; no major, a breaking change ships as minor with the breaking semantics in the body; Changeset Bump Policy and Changeset Fixed Group Check green). @object-ui/plugin-kanban: patch: right, nothing published moves (an entry is not even owed; it is harmless inside the fixed group). @object-ui/plugin-timeline: minor: right and exact (① item 6). The twelve other released packages in the file list change comment bytes in shipped source, tests, or READMEs only (the comment-versus-code split above), so they publish nothing; Changeset Declaration (presence) is green on the head.
  • The Clause-② line, both carriers, read with the fleet reader (readClause2Line from scripts/pm/clause2-line.mjs): changeset declared, yes, arm narrowing; PR body declared, yes, arm narrowing. The grammar's yes (narrowing) is a diff that widens one surface and narrows another, and that is what this diff does: it widens (the visibleWhen envelope on both faces; the timeline prop type) and it narrows (the TS authoring face of every node type; a blank visibleWhen string on the tolerant zod face). yes takes at least minor (it does) and (narrowing) is breaking (the title carries !, the body carries the banner and the migration). The ② finding of 5978769372 stays discharged on this head. No gate in this repository's check-run set reads an ADR-0087 disposition marker and this repository's AGENTS.md asks for none; not applied.
  • .changeset/11564-flex-bag-children-list.md: a dated, append-only note; its frontmatter and its own Clause-②: yes (narrowing) line are unchanged (read with the same reader). Changeset Claim Re-read and Changeset Overwrite Report green.
  • The dispatch claim 5977679107 declared Clause-②: yes with no arm; the PR's yes (narrowing) is the arm the diff requires, and this record judges the diff, not the dispatch.

③ Boundary flags

Dev deviations, each answered.

Round 1 (5978644114):

  • Census instrument un-chained (90 programs), not the literal chained pnpm type-check: accepted, the instrument the ACCEPTs 5926169140 and 5953788689 adopted; the head's Type Check check-run is the gate verdict.
  • Parity ledger, five INTERFACE-TO-PASSTHROUGH entries, operator unchanged: accepted (① item 8).
  • visibleWhen refuses a blank string on the tolerant face: accepted as the by-reference consequence of Q6 = B, disclosed on both carriers and declared (narrowing) on both.
  • Kanban sort through a non-exported intersection, no cast: accepted (① item 5).
  • AGENTS.md Add default props to all components to prevent collapse in designer #4 clause changed beside §4 and §5 #0.1: accepted, a truth repair (① item 10); Tier H, so the approver reads it.
  • Four more inert keys fixed in the objectos-integration.mdx page block; handler keys moved to component props: read; prose face; gate green.
  • Single-program tsc probes outside os-verify-lock: a process note, no contract bearing; recorded.
  • Plugin vitest run on file contents equal to the then-head: superseded by this head's own Test (shard 1/8) to (shard 8/8) and Test rollup check-runs.

Round 2 (5979644768):

  • The dev did not PATCH the PR body and left the replacement text in the report: accepted; the body as read now carries the seat's edits (the governed paragraph naming the two skill files, H3, the two acceptance-notes bullets, item 8, the 速读 sentence).
  • Its out_of_scope_findings: the published skills (fixed in round 3, ① item 11); the silenced deletion guards (fixed in round 3, ① item 9); the complex.zod.ts#DashboardWidgetSchema component ledger entry, whose reservation "objectui#8347 retires the slot's BaseSchema fallback" now has no owner because this card left the zod faces alone: escalated to the seat. Q3 = A (5977022487) sent the zod component slot's BaseSchema arm to "the zod-face card" and objectui#8344's slot choice; no card number is named in the inputs. The seat names that card, or records that the fallback stays by the objectui#8344 decision, so the ledger entry's exit condition points at something.

Round 3 (5979995689):

  • Worktree attached to a stale local branch of the same name at the remote head rather than created afresh: a process note, recorded.
  • check:doc-snippets not run locally: answered by Doc Snippet Type Check success on this head.
  • Its out_of_scope_findings: skills/objectui/guides/data-integration.md's "common mistakes" bullet contradicts the same guide's paragraph on QueryParams (one says an unprefixed option rides an index signature, the other that it is a compile error): pre-existing, not made false by this PR, published-skill text, so escalated to the skills lane as a one-sentence repair when that guide is next touched (governed, so its own approval). The parity ledger acting as a second deletion guard: informational, recorded in the docblocks.

open_questions is empty in all three rounds.

The open choice, props A / B / C on the TS face: escalated, not decided here. The maintainer's call, made on the Tier H approval of this PR. The PR writes A. For the approver's accounting, a flip touches more than the PR body's "two directives and the member": the two directives, the AGENTS.md §4 listing, the changeset's migration sentence, one sentence in architecture.md and one in protocol.md, and, for B, a zod mirror row with a parity entry (AuthoringNode derives from the zod shape, per 5934689950).

A precision on the prose face, for the seat, not a finding: the rewritten objectos-integration.mdx App block passes the adapter as dataSource on SchemaRenderer itself. That compiles (the renderer's props are SchemaRendererProps intersected with a forwarded Record of string to any), but SchemaRenderer reads its data source from SchemaRendererContext, and an explicit dataSource prop is forwarded to the root page component rather than installed for the nested object-view; AGENTS.md #1 names SchemaRendererProvider as the injection point. The old block was worse (an adapter object inside the node), the gate only type-checks the block, and nothing in the three faces moves, so this is a comment-only doc follow-up (wrap the block in SchemaRendererProvider dataSource) for whoever next touches that page, or a one-line patch round if the seat prefers it in this PR.

The PartialSchema enforce-or-remove card the deleted pin's header asked for is filed: objectui#11608, open, Blocked-by: #8347, with the dev's zero-consumer reading as its evidence. Owed and discharged.

Carried items, checked against the diff: 5934689950 (props, visibleWhen) carried; 5945723770 (ActionBarSchema re-read: Q5 = A, nothing to change) carried; 5955722883 (the five plugin-map.mdx blocks and venueMap) carried; 5957048412 (envelopeStray and the complex.ts note) carried; 5959573012 (the valueless envelope, Q3 = A) carried as the TS-face pin; 5977022487's re-read list carried in full (grouping and the 6397 note dissolved; no 6397 changeset exists at the head); 5865873645 (the two PartialSchema sentences) re-pointed in index.ts, the pin deleted; the seat ruling 5978976059 (prose fixed in this PR; #11608 filed) discharged; the claim amendment 5979679543 (skills limited to the sentences the removal made false; the five guards; the four strings) honoured, with the skill edits confined to the two named sections and the events paragraph that pointed at them. H2: the objectui#11573 counter 12260 to 12974 against a 900000 limit (dev reading; the pin runs in the Test shards, green). H3: check:skill-examples green on this head with the two skill files edited.

Gate reading (the head's check-runs, which are the gate verdicts), read three times: at 2026-10-04T12:42:34Z, 42 runs with 5 in_progress (Test (shard 2/8), (3/8), (7/8), (8/8), Spec Main Shape Gate); at 12:45:35Z, 42 runs with 1 in_progress (Test (shard 2/8)); at 12:47:21Z, the reading this record stands on, 43 runs, every one completed: 40 success, 3 skipped (dependabot, Test (coverage), the coverage shard matrix placeholder), 0 failed, 0 in progress. Type Check (success, 12:41:03Z), Test (shard 1/8) to (shard 8/8) and the Test rollup (success, 12:47:07Z), Test (dist pins), Lint, Doc Snippet Type Check, Spec Main Shape Gate (success, 12:45:17Z), Skill Example Check, Skill Eval Token Check, Skill Guide Path Check, README Export Check, Line Citation Gate, Control Byte Scan, Build & E2E, Build Docs, Bundle Analysis, every changeset gate (Changeset Declaration, Changeset Bump Policy, Changeset Claim Re-read, Changeset Overwrite Report, Changeset Fixed Group Check) and Governed Surface Queue Guard are success. The queue guard's pull_request leg exits 0 by design on a governed diff and says nothing about approval.

Landing: this PR is Tier H on two rows (AGENTS.md, and skills/** since round 3; node scripts/check-governed-queue-guard.mjs --test over the three paths answers GOVERNED, as the PR body says). A PASS here is the contract record, ⛔ not the landing authorization: the PR stays draft until an APPROVED review by an account in GOVERNED_APPROVERS is on it, and then the owning seat lands it through the queue; no agent seat approves. The PR reads draft, mergeable, state blocked at this read, with main merged in at b508ac50; the queue rebuilds it on landing.

Implemented-by: claude/issue-8347-baseschema-index-signature
Reviewed-by: session_01CPvhwGcirXqBGEdPSb72TZ

VERDICT: PASS


Generated by Claude Code

…hrough SchemaRendererProvider; the widget-slot ledger entry names who keeps the fallback (objectui#8347 round 4)

Patch round 4, doc and comment bytes only (seat ruling 5980160589 on contract review 5980141759 ③).

content/docs/guide/objectos-integration.mdx: the App block this PR rewrote handed the adapter as a `dataSource` prop on `SchemaRenderer`. The renderer reads its data source from `SchemaRendererContext` (the `useContext(SchemaRendererContext)` read in SchemaRenderer.tsx), and an explicit prop is only forwarded to the root component, so the nested `object-view` never got the adapter. The block now wraps the renderer in `SchemaRendererProvider dataSource={dataSource}` from `@object-ui/react`, imported the way the other guides import it, with a comment saying why; the "System Objects Integration" comment names only the provider. No other line this PR added hands an adapter to `SchemaRenderer` as a prop (the two plugin-calendar blocks pass `dataSource` to `ObjectCalendar`, which declares that prop itself); the occurrences already on main are left as they are.

packages/types/src/__tests__/zod-mirror-parity.test.ts, the `complex.zod.ts#DashboardWidgetSchema` `component` entry: its exit condition read as a reservation for objectui#8347 to retire the mirror slot's `BaseSchema` fallback. The fallback stays by objectui#8344's decision; objectui#8347's Q3 = A (ACCEPT 5977022487) put the zod face out of that card's scope; no open card retires the arm, and narrowing it is a mirror change. The comment now says exactly that, and that this entry and the `widgets` one above are deleted when a card does retire it. The TypeScript printer with removeComments prints HEAD and this tree identically for the file.

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

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 331 chunks) 3312.8 KB 3330.4 KB
Main entry chunk (gzip) 151.4 KB 350 KB
Entry file index-D6zRWH_9.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) 17.22KB 6.37KB
app-shell (runtime-config.js) 22.52KB 7.86KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.60KB 22.89KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.89KB 38.62KB
plugin-designer (index.js) 231.41KB 48.84KB
plugin-detail (index.js) 245.74KB 64.59KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 175.74KB 45.38KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.63KB 64.77KB
plugin-kanban (index.js) 49.60KB 15.58KB
plugin-list (index.js) 116.46KB 28.93KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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.81KB 3.58KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 89c2138f253dc9daa101f058f417e23d800fd4c0
Local-runs: none

Inputs: card #8347 (body and all 33 comments: the three P1 fork reports and their ACCEPTs, the carried items, the done report 5978644114, the patch-round reports 5978810507, 5979644768, 5979995689 and 5980405578, the seat rulings 5978976059 and 5980160589, the claim 5977679107 and its amendment 5979679543), PR #11607 (body as read at 2026-10-04T13:26Z, the 202-file list over three pages, and the net diff against main at merge base b508ac50, written out of a read-only git diff of the fetched refs because it exceeds the API's size), the three earlier records on this PR (5978769372, FAIL on head e0a9af67, ② only; 5978958580, PASS on head 0334c43e; 5980141759, PASS on head 09165ac8) as inputs among the others, and the head's check-runs (three readings, below). Read-only: no worktree, no checkout, nothing built, run or re-run. Three reads that are not gates: the one node -e over readClause2Line from scripts/pm/clause2-line.mjs on three strings; the comment-versus-code split of the 39 shipped source files in the diff, done by printing each file's base and head blob through the TypeScript printer with comments removed and comparing the text (no program, no type-check, no emit to disk); and git grep / git show against the fetched refs. Faces judged: the Clause-② declaration on both carriers; the published @object-ui/types faces (TS and zod; the package exports map at the head is the published surface, unchanged by this diff, and the diff moves ., ./base and ./zod, with every other subpath that re-exports a BaseSchema extender narrowing through inheritance and touched in docblocks only); the governed rule text in AGENTS.md; and the published skill text in skills/objectui/guides/architecture.md and skills/objectui/rules/protocol.md. This record stands on its own: every judgment is re-derived on this head's full net diff against main; where an earlier record's reading is relied on, it is named and was checked.

What moved since the PASS record's head 09165ac8: one commit, 89c2138f, two files. content/docs/guide/objectos-integration.mdx (46 insertions, 39 deletions in the net, 40 and 33 in the commit): the App block now wraps the renderer in SchemaRendererProvider dataSource={dataSource}, imported from @object-ui/react beside SchemaRenderer, with a comment stating that a dataSource prop on SchemaRenderer reaches only the root component; the schema literal is unchanged; the system-objects comment names only the provider. packages/types/src/__tests__/zod-mirror-parity.test.ts: the complex.zod.ts#DashboardWidgetSchema component entry's docblock, comment bytes only (the TypeScript printer with comments removed prints the base and head text of that file identically). Nothing else moved: no source, no other test, no doc, no changeset, no governed byte. main is still merged in at b508ac50, which is also the PR's base sha, and the branch's 16 commits touch exactly the 202 files the net diff lists.

The comment-versus-code split over the whole net diff: of the 39 shipped (non-test) source files in the file list, exactly four carry a non-comment change (packages/types/src/base.ts, packages/types/src/zod/base.zod.ts, packages/plugin-kanban/src/ObjectKanban.tsx, packages/plugin-timeline/src/renderHandoff.ts); the other 35 move comment bytes only. Every judgment on a published face below is about those four files, the two new test files, the deleted test file, the two changesets, AGENTS.md and the two skill files.

① Derived judgments

  1. TS authoring face: BaseSchema loses [key: string]: any (packages/types/src/base.ts, published through . and ./base; every node interface that extends it narrows with it, so the ./complex, ./layout, ./form, ./data-display, ./feedback, ./navigation, ./overlay and ./data entries narrow too). At the head BaseSchema declares its 21 named members (type, id, name, label, description, placeholder, className, style, data, bind, body, children, visible, visibleWhen, visibleOn, hidden, hiddenOn, disabled, disabledOn, testId, ariaLabel) and nothing else: no props, no events, no properties, no index signature. A fresh typed literal now refuses a key no declaration names, a misspelling included; the correct spelling compiles. Breaking narrowing. Right. It executes the objectui#7927 ruling (removal) inside the card's appetite as the fork ACCEPTs 5953788689 and 5977022487 re-scoped it: the H1 re-census at BASE 2e818d0b5 (81 unique errors in 44 files, the dev's reading in 5978644114) fell entirely into the adjudicated classes (3 src sites, 67 probe and ceiling flips, 2 props flips, 3 mechanical rows, 6 fixture literals), no site needed a contract decision, and the head's Type Check check-run is the gate verdict and is green. ComponentRendererProps keeps its own signature (read in base.ts at the head; pinned by _RendererPropsKeepTheirs). The ten other index-signature sites the card puts out of scope are untouched: git grep at the head still finds a [key: string]: any declaration on KanbanCard and one more interface in complex.ts, in data-protocol.ts, data.ts, twice in designer.ts, in form.ts (FormField), twice in objectql.ts (QueryParams) and in ui-action.ts, and the split above shows no non-comment change in any of those files.

    • The compile-fail pin packages/types/src/__tests__/base-schema-closed-face-8347.test.ts (read in full at the head) is in tsconfig.test.json's include (src/**/*.test.ts) and that program is chained in the package's type-check script (tsc --noEmit, then the examples program, then tsc -p tsconfig.test.json), which CI's Type Check job runs. An @ts-expect-error that stops matching is itself an error (TS2578), so a signature put back on BaseSchema turns every refusal row red. Both directions on fresh literals, four targets: objectui#7927's P5 (titleFieldd refused, titleField compiles, on CalendarViewSchema); the base itself (classNmae against className); a node nested in a slot (labell on a button child, reported at the slot per objectui#11466); and PartialSchema (labell against label). Three declaration-level rows (_BaseSchemaHasNoIndexSignature, _NodeTypesInheritNone, _RendererPropsKeepTheirs), and the bound as a directive-free row (widenedIsNotRechecked: a value that reached its annotation through a wider variable is not re-checked). The dev's ablation (signature put back on the committed head, the types test program exits 2 with 52 errors, every refusal row red) is the report's reading, not re-run here.
    • P5 is honoured on a fresh literal, not on the README block. The dev measured that objectui#7927's literal P5 on the plugin-calendar README stays green with or without the signature (the block is a type alias plus two non-fresh assignments), with a lit control that went red. The pin, the BaseSchema docblock, AGENTS.md §5 #0.1, both skill files and the README note all state that bound, so nothing claims more than tsc delivers. Right.
  2. TS: BaseSchema.visibleWhen goes from string to the spec's EvaluatedExpressionInput, by reference (@objectstack/spec/shared; the lockfile at the head resolves @objectstack/spec@17.6.0). Widening on the TS face: the { dialect, source } envelope a spec parse writes is authorable, inherited by every node type (widget-schema-anchors-6576's assertionGalleryInheritsVisibleWhen moved with it, and the schema-reference.md row says the new type). Right: Q6 = B, ruled by the seat in 5953788689; _VisibleWhenIsTheSpecInput pins identity with the spec type, so nothing is restated locally; dialectlessEnvelopeIsRefused pins that this key is narrower than ExpressionWire (objectui#7530), as that ruling accepted.

  3. Zod tolerant face: BaseSchemaCore.visibleWhen (packages/types/src/zod/base.zod.ts, published through ./zod as BaseSchema, AnyComponentSchema, safeValidateSchema and the derived StrictAnyComponentSchema). z.string() becomes VisibleWhenInputSchema: a z.union of z.string() and the spec's EvaluatedExpressionSchema (through stripImportedDefaults), with a superRefine that hands the value to the spec's EvaluatedExpressionInputSchema and copies its issues. It widens (the envelope parses) and it narrows (a blank or whitespace-only string, which z.string() accepted, is refused with the spec's own sentence; a dialect-less envelope and an unknown dialect are refused, as the spec refuses them and as the old z.string() already did). The spec's string transform is withheld, so a string parses to itself. Right. By-reference adoption of the spec's verdict is what Q6 = B ordered; the transform is correctly withheld (this mirror authors nothing into a parsed document); parity is pinned in visible-when-spec-input-8347.test.ts (read in full) on 13 probes that hold both verdicts, against the spec input schema and against PageComponentSchema.visibleWhen in the same run, with the blank-string sentence compared text for text, the no-transform control, the envelope round trip, and both component faces accepting the spec-parsed envelope while the strict face refuses a dialect-less one; imported-defaults-8317.test.ts registers the new EvaluatedExpressionSchema crossing; base.zod.ts#BaseSchema joins SPEC_DERIVED_PAIRS. The card body's "the zod face (spec(types): derive and export the strict authoring twin of the node face — the #5250 strict face itself, no consumer wired #8345 owns it)" is superseded for this one key by the seat's carried item (unlock 5948782907: by reference, on both faces; ACCEPT 5953788689: a non-transforming twin), so it is in appetite. The narrowing is disclosed on both carriers. One nit, not a finding: the superRefine callback calls stripImportedDefaults on every parse rather than once at module scope; verdict unchanged, one allocation per parse.

  4. TS: PartialSchema (published alias in index.ts). Not edited; as a consequence of item 1 it keeps T's declared members optional with type required, as its first line always promised (it declared type alone beside a live signature before, objectui#6397). Pinned (_PartialKeepsTheMembers, partialMisspelled refused); partial-schema-collapse-pin.test.ts deleted per its own header's removal condition, read in the deleted block ("THIS FILE IS EXPECTED TO GO RED WHEN objectui#5155 LANDS ... delete this file and, if PartialSchema is still unconsumed at that point, file a fresh enforce-or-remove card"); the docblock rewritten truthfully, with the OmitDeclared caveat for a T that declares its own signature. Right. Re-derived at the head: a tracked-files git grep for the word PartialSchema (CHANGELOGs excluded) hits only its declaration in index.ts, the new pin's rows and the changeset, with SchemaByType as the positive control (8 files). The enforce-or-remove card is named filed as objectui#11608 by the seat ruling 5978976059 and the PR body; that card is outside this brief's inputs and was not re-read here.

  5. plugin-kanban: GateBoundKanbanSchema, a non-exported intersection (ObjectKanbanSchema plus an optional sort of SortConfig[]; SortConfig is an exported interface of @object-ui/types), assigned from the declared schema prop (destructured as boardSchema) without a cast, which is legal because the added member is optional. ObjectKanbanComponentProps, ObjectKanbanSchema, the package's exports and both zod faces are unchanged; sort stays undeclared on the authoring face (_KanbanSortStaysUndeclared is now a keyof membership row, plus the fresh-literal refusal kanbanAuthoredSort, with _IsAnyCanAnswerTrue as the lit control for the IsAny rows). No published change. Right (objectui#8174; the objectui#6356 hand-off pattern, which AGENTS.md §5 #0.1 now names).

  6. plugin-timeline: TimelineRenderSchema gains optional onItemClick. The type is not exported by name, but index.tsx has export * from './renderer' and renderer.tsx's exported TimelineRenderer takes schema: TimelineRenderSchema, so this is a one-member optional widening of a reachable prop type on the package's . entry (read at the head). TimelineSchema, the authoring face, declares no onItemClick. Placement right per the objectui#6356 ruling (host-written keys typed where producer and consumer live, never on the authoring face); the changeset describes it exactly and bumps the package minor (②).

  7. The test-face flips. Read file by file over the whole net diff. The adjudicated probe and ceiling rows across types, plugin-charts, plugin-dashboard, plugin-grid, plugin-list, plugin-map, plugin-tree, components and examples/schema-catalog (misspellings such as visibleWhn, xAxisKy, drillDwn, filtr, colourField, enableClusterng, objectNaem, titleFieldd; the zzUndeclared7353 / bogusKey / someProp / bogusUndeclared / notAMember controls; operators on the grid twin; the retired chatbot keys; onSuccess on the base as the control of action-callback-retired-7068; content on a label node in form-renderers.test.tsx); the two props option-A directives in alias-precedence-cross-channel.test.tsx (the runtime alias read is still what those tests measure); the mechanical rows (two schema-to-record casts through unknown; the parity ledger); the six gantt and map operator literals (as const, the bag node typed ObjectGanttBlockNode / ObjectMapBlockNode, both exports of @object-ui/types); the two object-view-slot-key-lists tripwires (declaresStringIndex now false, the Pick lists kept and the header saying the form one may return to Omit). Each flips a "still compiles" ceiling into an @ts-expect-error refusal or a keyof membership row and keeps a lit control (_IsAnyCanAnswerTrue, a declared-member control, a picked key, or a widened-value row), so no assertion is loosened. Where a key is undeclared rather than tombstoned, a membership row keeps "not declared" measurable, since a refusal alone cannot tell an undeclared key from a ?: never tombstone (_OperatorsIsNoMember, the chatbot sibling-face IsMember tuples, the NoMember rows). The two "DELETED row, live" controls (ai-zero-read-members-retired-8178, chatbot-display-mode-retired) now pin both halves of the bound: the fresh literal refused, the widened value still carried. Right.

    • The valueless envelope metric-card is pinned refused on the TS face only, naming value (Q3 = A, ACCEPT 5977022487), with the value-carrying envelope as the control; the tolerant zod component slot's BaseSchema arm is left alone, as ruled, and the test says so. envelopeStray and the complex.ts note on widgets are deleted per the constant's own removal condition, read in the deleted block. flex-bag-children-list-11564.test.ts gains the text-in-list refusal the removal promised (H4). Right.
  8. Mirror-parity ledger: five new KnownDrift entries, INTERFACE-TO-PASSTHROUGH (app.zod.ts#AppSchemaRendererNodeSchema schema; reports.zod.ts ReportBuilderSchema report, ReportComponentSchema sections, ReportSectionSchema chart, ReportViewerSchema report); header figures 50 / 87 to 55 / 92. Right: TypeScript grants an implicit string index to type literals and mapped types and never to an interface, so once BaseSchema's explicit signature is gone an interface-typed member is not assignable to a .passthrough() mirror's input; the dev measured that a one-level anonymous copy fits, which isolates the cause to that rule. An artifact of the ratchet's assignability test, not a narrowing a document can hit; ledgered with its exit condition. The WiderThanDeclared entry for complex.zod.ts#DashboardWidgetSchema component now says the slot's BaseSchema fallback stays by objectui#8344's decision, that objectui#8347's Q3 = A put the zod face out of this card's scope, that no open card retires the arm, and that the entry and the widgets one above are deleted when a card does; its sibling widgets entry carries no reservation. That is what the seat ruling 5980160589 item 2 asked for. Right.

  9. Round 3: five deletion guards restored (object-kanban-card-title-9606, object-grid-default-sort-tombstone-5861, object-grid-show-filters-retired-11068, object-grid-declared-keys-11068, gantt-flat-config-declared-keys). The mechanism is real: while the signature stood, deleting a member widened its key to any, the directive went unused and TS2578 fired; since the removal the deleted key is refused as undeclared, the directive stays used, and the deletion is silent. Each file now carries a type-level row of the form Expect of Equal on the indexed access against the declared or tombstone type: an indexed access on a member that does not exist is a compile error, and Equal reddens on a re-typing. The show-filters file adds two live controls (ListViewSchema and ObjectViewSchema keep showFilters as boolean); the gantt file adds rows for the three query keys its derived invariant cannot see and keeps the two any[] rows that restate members objectql.ts declares as any[], each with a per-line lint disable stating that (Lint green). The dev's nine trap-restored ablation legs are the report's reading. Three test titles and one assertion message that described the signature as live are reworded with assertion logic untouched, and the PR body's count matches the diff. Right.

  10. AGENTS.md (governed; the agents-md row of this repository's GOVERNED_SURFACES, Tier H). §4 drops the props member from the abridged listing (right: BaseSchema never declared it, see item 1's member list) and adds the no-index comment. §5 #0.1's sub-bullet: every claim checks against the head (StrictAnyComponentSchema is exported from strict-authoring-face.ts; the named pin exists and pins both directions and the bound; ComponentRendererProps keeps its signature; the third remedy for a host-written runtime key, the package-local hand-off type of objectui#6356, is named and is the route this PR itself uses twice; the fresh-literal bound is stated per 完善设计器的每一个细节 #9 with the instrument named and not its answer). Add default props to all components to prevent collapse in designer #4's events sentence names the face that still keeps the bag: true, git grep over shipped source at the head finds no read of schema.events, and the zod BaseSchemaCore still ends .passthrough(). Rule-shaped, no incident narrative. Right.

  11. The published skills (governed; the skills-catalog row). architecture.md's "JSON Protocol" section and protocol.md's "Component Schema Structure" section said the published BaseSchema declares its members plus an index signature and that props / events / properties reach a node through it; this PR makes every one of those sentences false on the TypeScript face, so the repair belongs here (seat ruling 5978976059, extended to skills/** by the claim amendment 5979679543). Both warning paragraphs now give the two verdicts a key no member declares gets, one per face, with the fresh-literal bound said as §5 #0.1 says it; both fences drop the three keys the published type never declared and end on the same no-index comment line as AGENTS.md §4; protocol.md's "Actions Are Node Types" paragraph no longer points at a fence entry that is gone and mirrors AGENTS.md Add default props to all components to prevent collapse in designer #4's sentence; the member count in prose is gone (完善设计器的每一个细节 #9). Each statement checks against the head: props is read by the runtime (SchemaRenderer.tsx reads newSchema.props beside properties through propsWithoutCanonicalKeys) and is undeclared on the TS face under option A; properties is declared per block on AuthoringNode (ClosedArmShape closes that member per arm in authoring-nodes.ts); events is read by nothing. Neither fence carries an os:check marker (architecture.md has none; protocol.md's first marker sits under the "Bindable Text Keys" rule, below the fence), so check:skill-examples does not compile them, and Skill Example Check, Skill Eval Token Check and Skill Guide Path Check are green on the head. Right. One pre-existing simplification for the skills lane, not this PR's: both fences still spell the slot children?: BaseSchema[] with "the real slot also admits primitives", while since objectui#11466 the object arm is DeclaredNode; the fences are labelled abridged shape copies, the sentence predates this PR, and the removal does not make it false.

  12. Docs, READMEs, examples/dashboard.ts, the dated note on .changeset/11564-flex-bag-children-list.md: the prose face, read and not graded. The calendar and map handler keys moved to component props (ObjectCalendar's onEventClick / onDateClick, onMarkerClick passed to SchemaRenderer); the five plugin-map.mdx blocks are typed ObjectMapBlockNode, venueMap included; the objectos-integration.mdx page block authors regions, href, defaultViewType and table.columns, the adapter leaves the node and is now installed through SchemaRendererProvider (exported by packages/react/src/context/SchemaRendererContext.tsx, reached from the package root through export * from './context/index.js'; its props are children, dataSource, and optional debug, debugFlags, apiFetch, and the block passes dataSource only); the plugin-calendar README's note states the fresh-literal bound and the open calendar block; the plugin-form and types READMEs and schema-reference.md state the two faces' verdicts; the 11564 note is append-only with its frontmatter byte-identical. Doc Snippet Type Check is green on the head, which is the compile verdict on the rewritten App block (a typescript fence with no fragment marker, per the dev's report). The seat ruling 5980160589 item 1 is discharged on this head.

  13. The props alias, option A (not declared on the TS face): carried by the two directives, the §4 listing, the changeset's migration sentence, and one sentence in each skill file. Consistent with the 2026-08-18 ruling's scope (runtime bound, TS face open) and the objectui#11364 measurement (zero non-test authors). Not decided here (③).

② Semver level

  • Changeset .changeset/8347-baseschema-closed-face.md: @object-ui/types: minor with the breaking banner and the FROM-to-TO migration (misspelled: fix it; undeclared: declare it by reference on the reading type or remove it; never cast past; props to properties). Right under this repository's version policy (fixed group; no major; a breaking change ships as minor with the breaking semantics in the body; Changeset Bump Policy and Changeset Fixed Group Check green). @object-ui/plugin-kanban: patch: right, nothing published moves (the entry is harmless inside the fixed group). @object-ui/plugin-timeline: minor: right and exact (① item 6). The thirteen other released packages in the file list (components, react, plugin-calendar, plugin-charts, plugin-dashboard, plugin-designer, plugin-form, plugin-gantt, plugin-grid, plugin-list, plugin-map, plugin-tree, plugin-view) change comment bytes in shipped source, tests, or READMEs only (the comment-versus-code split above), so they publish nothing semver-visible; Changeset Declaration (presence) is green on the head, and the PR carries no skip-changeset label.
  • The Clause-② line, both carriers, read with the fleet reader (readClause2Line): the PR body reads declared, yes, arm narrowing; the changeset reads declared, yes, arm narrowing. The grammar's yes (narrowing) is a diff that widens one surface and narrows another (CLAUSE2_ARMS' own docblock), and that is what this diff does: it widens (the visibleWhen envelope on both faces; the timeline prop type) and it narrows (the TS authoring face of every node type; a blank visibleWhen string on the tolerant zod face). yes takes at least minor (it does) and (narrowing) is breaking (the title carries !, the body carries the banner and the migration). The ② finding of 5978769372 stays discharged on this head. No gate in this repository's check-run set reads an ADR-0087 disposition marker and this repository's AGENTS.md asks for none; not applied. The dispatch claim 5977679107 declared Clause-②: yes with no arm; the arm the diff requires is the one both carriers now spell, and this record judges the diff, not the dispatch.
  • .changeset/11564-flex-bag-children-list.md: a dated, append-only note; its frontmatter and its own Clause-②: yes (narrowing) line are unchanged (read with the same reader). Changeset Claim Re-read and Changeset Overwrite Report green.

③ Boundary flags

Dev deviations, each answered.

Round 1 (5978644114):

  • Census instrument un-chained (90 programs), not the literal chained pnpm type-check: accepted, the instrument the ACCEPTs 5926169140 and 5953788689 adopted; the head's Type Check check-run is the gate verdict.
  • Parity ledger, five INTERFACE-TO-PASSTHROUGH entries, operator unchanged: accepted (① item 8).
  • visibleWhen refuses a blank string on the tolerant face: accepted as the by-reference consequence of Q6 = B, disclosed on both carriers and declared (narrowing) on both.
  • Kanban sort through a non-exported intersection, no cast: accepted (① item 5).
  • AGENTS.md Add default props to all components to prevent collapse in designer #4 clause changed beside §4 and §5 #0.1: accepted, a truth repair (① item 10); Tier H, so the approver reads it.
  • Four more inert keys fixed in the objectos-integration.mdx page block; handler keys moved to component props: read; prose face; gate green.
  • Single-program tsc probes outside os-verify-lock: a process note, no contract bearing; recorded.
  • Plugin vitest run on file contents equal to the then-head: superseded by this head's own Test (shard 1/8) to (shard 8/8) and Test rollup check-runs.

Patch round 1 (5978810507): deviations and open_questions empty.

Round 2 (5979644768):

  • The dev did not PATCH the PR body and left the replacement text in the report: accepted; the body as read carries the seat's edits (the governed paragraph names the two skill files; H3; the two acceptance-notes bullets; items 8 and 9; the 速读 sentence).
  • Its out_of_scope_findings: the published skills (fixed in round 3, ① item 11); the silenced deletion guards (fixed in round 3, ① item 9); the complex.zod.ts#DashboardWidgetSchema component ledger entry's ownerless reservation (fixed in round 4 per the seat's 5980160589 item 2, ① item 8).

Round 3 (5979995689):

  • Worktree attached to a stale local branch of the same name at the remote head rather than created afresh: a process note, recorded.
  • check:doc-snippets not run locally: answered by Doc Snippet Type Check success on this head.
  • Its out_of_scope_findings: skills/objectui/guides/data-integration.md's "common mistakes" bullet on QueryParams contradicting the same guide's paragraph: pre-existing, not made false by this PR; the seat's 5980160589 item 3 records it as an acceptance note for whoever next edits that guide (governed, so its own approval then); agreed, not a rider here. The parity ledger acting as a second deletion guard: informational, recorded in the docblocks.

Round 4 (5980405578): deviations and open_questions empty. Its one out_of_scope_findings entry: four pre-existing occurrences on main that hand an adapter to SchemaRenderer as a dataSource prop (the same guide's fragment-marked "Unit Tests" block, data-objectstack.mdx's inline sentence, the data-objectstack README quick-start block, two schema-catalog gallery test harnesses). Not this PR's lines and not a face this record judges; escalated to the seat as a candidate for one prose follow-up card (whether a root-component forward is enough for a root object-grid is that card's question), not a rider on this PR.

open_questions is empty in every round.

The open choice, props A / B / C on the TS face: escalated, not decided here. The maintainer's call, made on the Tier H approval of this PR. The PR writes A. For the approver's accounting, a flip touches the two directives, the AGENTS.md §4 listing, the changeset's migration sentence, one sentence in architecture.md and one in protocol.md, and, for B, a zod mirror row with a parity entry (AuthoringNode derives from the zod shape, per 5934689950).

Seat ruling 5980160589, checked item by item on this head: item 1 (the integration guide's injection point) is fixed in 89c2138f; item 2 (the ledger entry's exit condition) is fixed in 89c2138f; item 3 (the data-integration.md bullet) stays an acceptance note; item 4 (props) unchanged. Nothing it asked for is outstanding.

Acceptance notes (read, not filed):

  • ObjectChartBlock's pre-gate schema prop is BaseSchema (ruling 5810232641), so a fresh literal there is now excess-checked against BaseSchema itself and a correctly spelled objectName is refused as much as the objectNme probe; in-tree callers pass typed nodes, and the flipped probe's comment says to hand the shell a typed node. Not a defect of this diff; retyping that prop is a separate card if the seat reads it as an authoring trap.
  • RemoveIndexSignature in ObjectGrid.tsx strips nothing now; the form Pick list in object-view-slot-key-lists may return to Omit: cleanup, not owed by this card.
  • The index-signature prose repaired in rounds 2 to 4: the remaining [key: string]: any mentions in packages/types/src outside tests, read one by one at the head, are either another type's own live signature (ComponentRendererProps, KanbanCard, FormField, QueryParams, the designer catch-all, and the rest of the ten sites) or past-tense history ("carried ... until objectui#8347", "rode", "absorbed"). The KanbanCard mirror's "the declaration carries [key: string]: any" is about that interface's own signature, which stands. Nothing present-tense about BaseSchema remains.

Carried items, checked against the diff: 5934689950 (props, visibleWhen) carried; 5945723770 (ActionBarSchema re-read: Q5 = A, nothing to change) carried; 5955722883 (the five plugin-map.mdx blocks and venueMap) carried; 5957048412 (envelopeStray and the complex.ts note) carried; 5959573012 (the valueless envelope, Q3 = A) carried as the TS-face pin; 5977022487's re-read list carried in full (grouping and the 6397 note dissolved; no 6397 changeset exists at the head); 5865873645 (the two PartialSchema sentences) re-pointed in index.ts, the pin deleted; the seat ruling 5978976059 (prose fixed in this PR; the PartialSchema card named filed) discharged; the claim amendment 5979679543 (skills limited to the sentences the removal made false; the five guards; the four strings) honoured; the seat ruling 5980160589 discharged (above). H2: the objectui#11573 counter 12260 to 12974 against a 900000 limit (dev reading; the pin runs in the Test shards, green). H3: check:skill-examples green on this head with the two skill files edited. H4: the flex list refusal row present. H5: the visibleWhen pin present and in the Test shards.

Gate reading (the head's check-runs, which are the gate verdicts), read three times: at 2026-10-04T13:26:51Z, 42 runs, 29 success, 3 skipped, 10 in_progress (Type Check, Test (shard 1/8) to (shard 8/8), Spec Main Shape Gate); at 13:28:29Z, the same 42 with the same 10 in progress; at 13:36:02Z, the reading this record stands on, 43 runs, every one completed: 40 success, 3 skipped (dependabot, Test (coverage), the coverage shard matrix placeholder), 0 failed, 0 in progress. Type Check (success, 13:31:41Z), Test (shard 1/8) to (shard 8/8) (the last at 13:33:38Z) and the Test rollup (success, 13:33:50Z), Spec Main Shape Gate (success, 13:32:10Z), Test (dist pins), Lint, Doc Snippet Type Check, Doc Component Type Check, Skill Example Check, Skill Eval Token Check, Skill Guide Path Check, README Export Check, Line Citation Gate, Control Byte Scan, Build & E2E, Build Docs, Bundle Analysis, every changeset gate (Changeset Declaration, Changeset Bump Policy, Changeset Claim Re-read, Changeset Overwrite Report, Changeset Fixed Group Check) and Governed Surface Queue Guard are success. The queue guard's pull_request leg exits 0 by design on a governed diff and says nothing about approval.

Landing: this PR is Tier H on two rows (AGENTS.md, and skills/** since round 3). A PASS here is the contract record, ⛔ not the landing authorization: the PR stays draft until an APPROVED review by an account in GOVERNED_APPROVERS is on it, and then the owning seat lands it through the queue; no agent seat approves. The PR reads draft, mergeable, state blocked, no auto-merge, at this read, with main merged in at b508ac50; the queue rebuilds it on landing.

Implemented-by: claude/issue-8347-baseschema-index-signature
Reviewed-by: session_01CPvhwGcirXqBGEdPSb72TZ

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

objectstack-fleet Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor Author

维护者速读

改了什么:@object-ui/types 的 BaseSchema 去掉了 [key: string]: any。用 TypeScript 写节点时,拼错或未声明的键会直接在编写处报错,正确拼写照常通过。新增的钉子测试正反两个方向都钉住了,并做过消融:把签名加回去,钉子就变红,证明它真能失败。同批改动:

  • visibleWhen 改为直接引用 spec 的 EvaluatedExpressionInput(字符串,或 { dialect, source } 信封)。
  • 看板的 sort、时间轴的 onItemClick 改在各自包内的类型上声明。
  • 因签名消失而变假的源码注释、文档示例、README,以及已发布技能包 skills/objectui 里的两处教学文案,一并改写。
  • 原来靠签名才能报警的五处删除守卫,补回了真守卫。
  • AGENTS.md:§4 示例去掉 props;§5 #0.1 写明「TS 编写面也是契约」。

为什么改:落地 objectui#7927 的裁决(TS 面是可执行的契约),也就是 #5250 严格化里 TS 的那一半。此前签名让任何键都能编译,AI 写错元数据时被静默放过。为此已先落地准备卡 #11466、#11573、#11564、#11598。

风险与代价(含回滚):

  • 对 TS 使用者: 破坏性收窄。按仓规以 minor 发布,changeset 写明了迁移方法。
  • 运行期与 zod 宽容面: 运行期渲染不变。zod 宽容面只有 visibleWhen 一处变化:现在接受 spec 的信封,拒绝空字符串。
  • 已知边界: TS 只对新鲜对象字面量做多余键检查,经变量转手的值不会再查。这一点已写进 AGENTS.md、技能包和钉子。
  • 验证: CI 全绿(43 项中 40 项通过、3 项按设计跳过、0 项失败)。
  • 受管面: AGENTS.md 和 skills/**,一份批准覆盖两者。
  • 回滚: revert 本 PR 即可,不涉及数据迁移。

席位意见:建议批准。

  • 达档契约复审在最终 head 89c2138f 上 PASS(记录 5980631123)。
  • 首次复审 FAIL 后修了一轮 Clause-② 声明;首个 PASS 之后又修补三轮,都是席位要求「本 PR 让哪句话变假,就在本 PR 里改」,不是返工。
  • props 别名按方案 A 处理(TS 面不声明,运行期仍按旧别名读取),与 2026-08-18 裁决的范围一致。若改选 B 或 C,要改的有:
    • 加一个成员、删两条 @ts-expect-error;
    • AGENTS.md §4 和 changeset 的迁移句;
    • 技能包里的两句;
    • 选 B 还要另加一行 zod 镜像。
  • 后续卡 objectui#11608(PartialSchema 去留)已立,等本 PR 落地后处理。

你要做的:审阅后在本 PR 上提交 Approve(os-zhuang 或 hotlong 任一即可)。若想把 props 改为 B 或 C,就在审阅意见里写明,席位让 dev 改完再落地。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 4, 2026 13:51
@os-zhuang
os-zhuang enabled auto-merge October 4, 2026 13:51
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 331 chunks) 3313.4 KB 3330.4 KB
Main entry chunk (gzip) 151.4 KB 350 KB
Entry file index-NdnQH7aI.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) 17.22KB 6.37KB
app-shell (runtime-config.js) 22.52KB 7.86KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
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) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 572.97KB 137.34KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 232.57KB 64.51KB
fields (index.js) 261.62KB 66.20KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 35.66KB 9.49KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
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) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
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) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 84.26KB 23.05KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 143.54KB 38.79KB
plugin-designer (index.js) 231.41KB 48.84KB
plugin-detail (index.js) 245.74KB 64.59KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 176.66KB 45.52KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 235.92KB 64.87KB
plugin-kanban (index.js) 50.06KB 15.74KB
plugin-list (index.js) 116.72KB 29.10KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
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.81KB 3.58KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.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

@os-zhuang
os-zhuang added this pull request to the merge queue Oct 4, 2026
Merged via the queue into main with commit b403bb3 Oct 4, 2026
44 of 45 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-8347-baseschema-index-signature branch October 4, 2026 14:22
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Oct 7, 2026
…ys; the snake_case spellings are refused by name (objectui#11610) (objectstack-ai#11614)

Fixes objectstack-ai#11610
Clause-②: yes (narrowing)

The `grid` widget's eight field-level keys become camelCase in one move
across the published type, its zod mirror, the form-field face and every
reader. The snake_case spellings retire at once and are refused by name
on all three faces, each refusal naming the camelCase key. Ground:
objectstack-ai/objectstack#21704 fork 2, ruled B (record `5978663135`);
claim `5979906990` (seat ruling: refuse by name, no load-time
conversion, premised on no stored producer). Dispatch session
`session_01CPvhwGcirXqBGEdPSb72TZ`, `mode:subagent`.

## Premise (measured before any edit): no stored producer outside
objectui's own fixtures

- **objectstack `origin/main` `316be321`** (read through `git grep` on a
private ref, nothing edited): the eight snake_case words occur only in
comments, test strings and one changeset line. `packages/spec`
`component.zod.ts` names them in three comments (the line-items guidance
block, the `customFields` fork note, the master-detail `sortField`
retirement note); the retirement test for `details.sortField` carries
one as a must-not-match judge string; `conversions/registry.ts`,
`migrations/registry.ts` and the retired-key entry for
`details.sortField` carry it in comments. No schema declares or emits
any of the eight as a field's metadata, and the spec's `FieldType` enum
has no `grid` member at all, so the spec cannot store a `grid` field.
The seat's reading is confirmed.
- **objectui at base `b508ac50`** (every tracked file, `git grep` on
that commit), each hit classified:
  - grid field metadata, READERS: `GridField.tsx` (the eight reads).
- grid field metadata, PRODUCERS (in-repo, render-time, not stored):
`MasterDetailForm` and `LineItemsPanel` (both hand the grid an object
cast through `any`), and `apps/console` `DevLookup` (a dev harness).
- grid field metadata, DECLARATIONS: `GridFieldMetadata`, the form-field
face (`FormField`), its zod mirror (`FormFieldSchema`).
- grid field metadata, STORED fixture: `examples/schema-catalog`
`fields-grid/line-items-grid.json` (the only stored document).
- docs: `content/docs/fields/grid.mdx`; the clipboard-paste RFC (states
`max_rows` / `allow_add` as GridFieldMetadata's API in its proposed
wiring); ADR 0001 (reported below, not edited).
- tests: seven `GridField` test files in `packages/fields` (the triage
counted five), the master-detail members test and the line-items total
test in `packages/plugin-form`, three `packages/types` tests (strict
face, form-field coverage, mirror parity comment), the console registry
pin's prose.
- SAME NAME, DIFFERENT READER (not renamed): the `## MAX_ROWS vs
MIN_ROWS` heading-anchor string in `plugin-markdown`'s toc test; the en
locale comment (a comment about the grid's label, updated); every
`CHANGELOG.md` (history, untouched). The master-detail
`details.sortField` the spec retired is a different key on a different
object and stays untouched.
- Existing facts not re-measured: the objectstack#21464 census (0
`customFields` entries) and the triage's hotcrm / cloud reading (0
hits).

## Rename map

| FROM | TO |
| --- | --- |
| `min_rows` | `minRows` |
| `max_rows` | `maxRows` |
| `allow_add` | `allowAdd` |
| `allow_delete` | `allowDelete` |
| `allow_reorder` | `allowReorder` |
| `total_field` | `totalField` |
| `add_label` | `addLabel` |
| `sort_field` | `sortField` |

One list holds it: `GRID_FIELD_RETIRED_KEYS` (new export of
`@object-ui/types`, with its key type `GridFieldRetiredKey`). The zod
arms and the widget both read it; a type-level pin holds its keys equal
to the `never` tombstones and its values equal to the live camelCase
members.

## The retirement form, per face (refused by name, never stripped)

- **TypeScript.** `GridFieldMetadata` and `FormField` each declare the
eight snake_case keys as `never` tombstones with a `@deprecated` note
naming the replacement. `{ type: 'grid', name: 'lines', min_rows: 1 }`
typed `GridFieldMetadata` does not compile; on the docs face the gate's
compile of `grid.mdx` reports `TS2322: Type 'number' is not assignable
to type 'undefined'` for the same key.
- **zod (`@object-ui/types/zod`).** `FormFieldSchema` declares each
snake_case key as an `aliasKeyRefusal` arm. On the mirror, the tolerant
face (`safeValidateSchema`, the `objectui validate` door) and the strict
authoring face, `fields[0].min_rows: 1` answers exactly one issue,
`invalid_type` at `fields.0.min_rows`, whose message leads
``Unrecognized key(s) on this form field: `min_rows`. Did you mean
`min_rows` → `minRows`?`` and goes on to say the value stays the same.
Any value is refused (the refusal is by name). The camelCase key with
the same value parses and is kept on all three doors.
- **The widget (`@object-ui/fields`).** `GridField` is now a thin gate
over the grid body: a field whose metadata carries any snake_case key
(with a defined value) is drawn as `RetiredGridFieldKeys` instead of the
grid, an inline `role="alert"` (`data-testid="grid-field-retired-keys"`)
reading for example ``[object-ui] Grid field `lines` carries retired
snake_case key(s): `min_rows` → `minRows`. …``, plus the same text on
`console.error` once per message. This is `RetiredFieldTombstone`'s
settled shape in this package: nothing thrown, nothing silently
substituted, rows untouched (`onChange` is never called).

Producers move with it: both plugin-form adapters write the camelCase
keys, and their grid object is now `satisfies` Partial of
`GridFieldMetadata` instead of `as any`, so a snake_case key written
there no longer compiles.

## Pins and guards, with ablation readings

All ablations ran through the anchored mutation tool (anchor must hit;
blob change and restore proven on disk; restore leg `git checkout HEAD`,
blob after restore equal to the HEAD blob, `git diff HEAD` empty), from
committed state.

1. **The eight camelCase keys draw**, each through the real `GridField`
with a lit control without the key
(`GridField.retiredSnakeKeys-11610.test.tsx`): `minRows` disables every
Remove at the minimum; `maxRows` disables Add and every Duplicate at the
maximum; `allowAdd: false` removes Add and Duplicate; `allowDelete:
false` removes Remove; `allowReorder: false` removes the drag handles;
`totalField` draws the footer total (30); `addLabel` labels Add;
`sortField` stamps the new indices after a drag. Through the real form
path too: `fields-grid-keys-camelcase-11610.test.tsx` renders the
catalog fixture through `SchemaRenderer` and the form renderer (label
`Add line item`, total `109.97`, two drag handles / Duplicate / Remove,
all enabled), with the snake_case respelling as its control.
2. **A snake_case key is answered by the refusal, never dropped**: per
key, the alert names the key and its replacement, the grid is not drawn,
`console.error` is called once with the alert's text; edges pinned:
several keys in one alert in map order, a snake key beside its camelCase
twin is still refused, an `undefined` value is not refused (as on the TS
and zod faces), a nameless field reads "This grid field", a second mount
logs nothing new.
- ABLATION (widget gate disabled): 12 refusal tests red, the 10 others
(the eight draws, the lit control, the `undefined` row) green. Restored.
3. **zod refusal by name** (`grid-field-keys-camelcase-11610.test.ts`,
three doors × eight keys, plus lit controls and an any-value row).
- ABLATION (delete the `min_rows` arm): 8 tests red (the `min_rows` row
and the any-value row on each of the three doors, and both
`form-field-zod-coverage` rows). Restored.
4. **TS tombstones, each with a deletion guard that does not lean on an
index signature** (same file, read by `tsc -p tsconfig.test.json`): an
`Equal` row per member on both faces, a `keyof` membership row on
`FormField`, and the map-equals-tombstones rows.
- ABLATION A (delete all eight `GridFieldMetadata` tombstones): the
eight `Equal` rows red, `TS2339` naming each key; the two map rows red;
the strict-face lit-control row red; the map's `satisfies` red
(`TS2561`). ⚠️ The eight `@ts-expect-error` rows over fresh
`GridFieldMetadata` literals stayed SILENT: with the member gone the key
is still an excess property and the directive swallows it. That is the
objectui#8347 lesson, reproduced; the `Equal` rows are what catch the
deletion.
- ABLATION A1 (delete `total_field` alone): exactly its `Equal` row
(`TS2339`), the map row and the `satisfies` red.
- ABLATION B (delete all eight `FormField` tombstones): the eight
`Equal` rows and the `keyof` row red, four `TS2578` unused
`@ts-expect-error` (the index signature now accepts the key), the
strict-face by-reference rows red, and the mirror-parity ratchet red on
`FormFieldSchema`.
- ABLATION B1 (delete `sort_field` alone): its `Equal` row, the `keyof`
row, its `TS2578`, the strict-face rows and the parity ratchet red,
naming `sort_field`.
- Every leg restored with blob equal to HEAD; the green `tsc -p
tsconfig.test.json` runs are in the gates below.
5. **Docs face**: respelling one key of `grid.mdx`'s snippet snake_case
turns `pnpm check:doc-snippets` red at that line (`TS2322`), restored
green.

Repo-wide pin sweep: every assertion that read a grid key by its
snake_case spelling now asserts the camelCase key's substance (the
master-detail grid object's exact key set and values, the strict face's
accept and wrong-type rows, the coverage key set, the widget draws). The
rejection rows for genuinely wrong values (a string `minRows`, a numeric
`addLabel`, …) stay, respelled; the guarded surface grows by the eight
refusals.

## Files and landing point

The claim's surface, plus two adjacent files the census named:
`apps/console` `DevLookup.tsx` (a producer) and its registry pin's
prose; `packages/i18n` en locale (one comment naming `add_label`); the
RFC. The landing point is the claim's list; no producer was found in
another package.

## ADR and RFC

- `docs/adr/0001-master-detail-subform.md` (governed, ⛔ not edited)
names the keys in three sentences: "Honors `min_rows` / `max_rows` /
`allow_add` / `allow_delete` from the …", "Drag reorder of lines
(`allow_reorder`), grouping/subtotal rows." and "… **drag-to-reorder**
(a `sort_field` …". Reported for whoever owns that record.
- `content/docs/rfcs/0001-clipboard-paste.md` (status Draft) stated
`max_rows` "from GridFieldMetadata" and wired `field.allow_add` /
`field.max_rows` as the current API, so it is edited to the camelCase
keys.

## Serial and overlap

The claim's serial step is done. objectui#11605's PR objectstack-ai#11612 (`fd060f07`)
and objectui#8347's PR objectstack-ai#11607 (`b403bb36`) both landed. `main` at
`b403bb36` is merged into this branch by merge commit `8b56ef26`. Its
combined diff is empty, so no hunk was hand-resolved.

The four files this branch shares with them carry `main`'s hunks outside
this branch's hunks: `packages/i18n/src/locales/en.ts`,
`packages/types/src/form.ts`, `packages/types/src/index.ts` and
`zod-mirror-parity.test.ts`. The contract review on the merged head
(`5981193754`) reads every hunk of this branch as byte-identical to the
reviewed head. The gate verdict on the merged head is its own
check-runs.

## Gates (the dev's local readings, tree `82b400f9`; the current head's
verdict is its check-runs)

- type-check, package and test program: `@object-ui/types`,
`@object-ui/fields`, `@object-ui/plugin-form`, `@object-ui/i18n`,
`@object-ui/example-schema-catalog`, `@object-ui/console` — all exit 0
(the console run after building `@object-ui/plugin-tree`, which its
import graph needs). The fields and plugin-form test programs list the
touched test files (`--listFilesOnly`).
- vitest, repo-root form: `packages/types/` 353 files / 9482 tests
passed; `packages/fields/` 233 passed + 1 skipped / 3647 passed + 7
skipped; `packages/plugin-form/` 163 / 1889 passed + 1 skipped;
`examples/schema-catalog/` + the console registry pin + `packages/i18n/`
121 / 3807 passed + 13 skipped. The `types` / `fields` / `plugin-form`
runs measured a working tree byte-identical to `82b400f9` (its two
later-committed files, the changeset and the catalog test, were already
on disk); the rest ran at `82b400f9`.
- lint (`eslint` with the root config, as each package's `lint` runs it)
over the 25 touched TS/TSX files, counted from `--format json`: 0
errors; the one finding on a touched line is the pre-existing `as any`
warning in `GridField.test.tsx`'s fixture. Narrowing statement: the
population is every file under the touched packages, read by the one
root `eslint.config.js`; it enables no type-aware linting and no custom
rule reads the filesystem, so this diff cannot move a verdict on an
untouched file. `pnpm lint` itself is CI's.
- `check:doc-snippets` (777 blocks judged, 0 failed),
`check:doc-examples`, `check:readme-exports`, `check:new-line-citations`
(0 new), `check:control-bytes`, `check:spec-symbols`,
`check:designer-field-key-parity`, `check:prompt-keys`,
`check:handler-key-reads`, `check:unreferenced-sources`,
`check:phantom-deps`, `check:self-import`, `check:test-path-roots`,
`check:doc-types`, `check:doc-example-ids`, `check:doc-fences`,
`check:doc-example-readers`, `check:i18n-drift`, `check:i18n-keys`,
`check:esm-specifiers`, `check:side-effects-array`: all exit 0.
- changeset checkers: presence, no-major, fixed, overwrite, claims,
pending-literals: all exit 0. `.changeset/11610-grid-keys-camelcase.md`:
`@object-ui/types` and `@object-ui/fields` `minor`, breaking banner,
FROM → TO for all eight, `Clause-②: yes (narrowing)`.
- Governed surface: `node scripts/check-governed-queue-guard.mjs --test`
over the diff answers NOT GOVERNED.

## Acceptance notes

- ⚠️ Same name, different meaning: the grid's `totalField` names the
CHILD column summed (the value a spec `amountField` carries), while the
spec's own `totalField` on a master-detail subform or
`record:line_items` names the PARENT field the sum is saved to. The
mechanical camelCase of `total_field` lands on that homonym. Every
declaration, the doc page and the changeset say so; the open question in
the report asks the seat whether the spec's runtime form field should
carry it under this name.
- When the spec seat adds the camelCase keys to the runtime form field
(objectstack-ai/objectstack#21704), the three objectstack comments that
still name the snake_case keys can move with it. Carrier: that stage.
- `DevLookup.tsx` keeps its `as any` field (a dev harness; only the key
moved).

The dispatching session is
`https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ`.

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

---------

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

Projects

None yet

3 participants