Skip to content

feat(types)!: retire ChatbotSchema.displayMode as an ADR-0049 tombstone; remove the Display Mode control and seed (objectui#7654) - #7739

Merged
os-sam merged 4 commits into
mainfrom
claude/issue-7654-display-mode-retire
Sep 5, 2026
Merged

feat(types)!: retire ChatbotSchema.displayMode as an ADR-0049 tombstone; remove the Display Mode control and seed (objectui#7654)#7739
os-sam merged 4 commits into
mainfrom
claude/issue-7654-display-mode-retire

Conversation

@os-sam

@os-sam os-sam commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Fixes #7654

Retires displayMode under ADR-0049 enforce-or-remove — the displayMode half of the card, per the maintainer's ruling B recorded in comment 5548848737 (director seat, decision batch #44, verbatim 「同意」). The triggerIcon half landed in PR #7669. A closing keyword this time, on purpose: the ruling states that once this merges the card has no open half, and needs-user-decision was stripped in the same stroke.

What changed

site before after
packages/types/src/complex.tsChatbotSchema.displayMode ?: 'inline' | 'floating' ?: never tombstone; the JSDoc points at type as the replacement and cites discriminator prong 2 (advertised at CHANGELOG.md:578, release 3.3.0)
packages/types/src/complex.tsChatbotFloatingSchema.displayMode the same union, declared by #7705 "with the same three lines … so that PR finds the member on both faces exactly as ruled" ?: never, pointing at the ChatbotSchema comment
packages/plugin-chatbot/src/renderer.tsxchatbot-floating inputs the Display Mode control, defaultValue: 'floating' removed
packages/plugin-chatbot/src/renderer.tsxchatbot-floating defaultProps displayMode: 'floating' removed
content/docs/plugins/plugin-chatbot.mdx a displayMode row in the floating key table the row is gone; a paragraph states there is no such key, that type selects the presentation, and that stored documents are unaffected

A control is restated, never deleted into a vacuum (objectui#7070): the restatement is the tombstone's guidance plus the changeset.

Scope reading, stated so it can be objected to: the ruling names ChatbotSchema.displayMode. The floating face's copy was minted by #7705 after the batch was formulated, carrying the explicit note that the retiring PR "must find the member on both faces as ruled"; leaving that copy typed would keep the published face of the one registration that offered the control teaching the switch — the exact defect the ruling's rejection of option C names. So both faces carry the tombstone.

Premise re-measured on this branch's base (a00db9ef9), with a lit control

claim reading
nothing reads displayMode whole-repo git grep -w, tracked files, build output excluded: the two declarations, the inputs entry and the defaultProps seed, the doc comments / ledger entries / test pins beside them, one CHANGELOG line, and two unrelated displayMode props (GridField, MasterDetailForm). No renderer read.
the designer control is at renderer.tsx:498 and the seed at :520 confirmed at exactly those lines on the base
#7705 restored the member byte-identically on ChatbotSchema confirmed — the three-line declaration sits on both faces on the base

Lit control: the same query over floatingConfig, a key that IS read, returns 79 lines. Sibling checkout (../objectstack): the sweep for displayMode returned zero, but so did its controls (chatbot-floating, a chatbot node type) — that tree authors no chatbot nodes at all, so it is reported as no population, not as zero authors measured.

The tombstone is loud-vs-silent on this carrier — re-measured, not restated

ChatbotSchema extends BaseSchema, which carries an index signature. Measured on THIS member with tsc -p packages/types/tsconfig.test.json in three tree states — LIVE (the base), DELETED (both declarations removed; mutation proved on disk by anchored grep 2 to 0 and blob fd59df10 to 98e7d66d, restored under an EXIT INT TERM trap with absolute paths and verified by an empty git diff HEAD plus blob equality back to fd59df10), and TOMBSTONED (this branch). FloatingChatbotConfig, which has no index signature, was the lit control carrier in every run.

shape LIVE DELETED TOMBSTONED
fresh literal, 'floating' (well-typed) clean clean TS2322
fresh literal, 'bogus' (wrong-typed) TS2322 clean TS2322
widened value, 'floating' as const clean clean TS2322
undeclared key, fresh literal (the deleted row) clean clean clean
undeclared key, widened value clean clean clean
control carrier: undeclared key, fresh literal TS2353 TS2353 TS2353
control carrier: undeclared key, lone-key widened TS2559 TS2559 TS2559
the member reads as the union any undefined

Deleted, the member reads as any and even the wrong-typed value goes silent. Tombstoned, presence with any value is refused — a diagnostic deletion cannot produce on this carrier at all. Both faces gave identical rows. One instrument defect of mine, corrected before the readings above were taken: the first widened case wrote displayMode: 'floating' without as const, which widened to string and produced a TS2322 on LIVE that was literal widening, not presence; the table is the as const re-run.

Runtime: zero validation before, zero after — and the tripwire

No retirementTombstone() half, deliberately: displayMode has never had a Zod arm (it sits in both twins' UnmirroredDeclared ledger entries) and BaseSchema is .passthrough(), so every stored document the designer wrote — displayMode: 'floating' — parses green before and after. Minting an arm is objectui#6152's axis. packages/types/src/__tests__/chatbot-display-mode-retired.test.ts pins both twins' shape.displayMode as undefined, and the same file carries the parse-green pin.

Correction, measured at 6b254df25 and now in the tree. An earlier revision of this PR said the parse-green pin stays green for a house-style non-strict arm and reddens only for a .strict() mirror, citing objectui#7678 item 2. That transposition is false. Item 2 measured OBJECT-MIRROR shapes; displayMode is a scalar union, whose house-style arm is an enum. Minting an optional z.enum over 'inline' | 'floating' on ChatbotSchema's twin — injected at a counted anchor (marker 0 to 1), blob 53fd0ed0 to 86793dd7, restored under a trap on EXIT INT TERM with the blob back to 53fd0ed0 and git diff HEAD empty — reddens both instruments: tsc -p packages/types/tsconfig.test.json with exactly 1 error, zod-mirror-parity.test.ts(1586,14): error TS2322, AND vitest with exactly 2 failures — the shape pin and the parse-green line, because that line asserts 'anything-at-all' parses and an enum arm refuses it. So the tripwire fires harder than the old prose claimed; it does not take a .strict() mirror. Both in-tree sentences (this file's shape-pin comment and the 7655 TRIPWIRE comment) now say the measured thing, and the shape-pin test title no longer calls itself "the tripwire that fires". The two OLD objectui#7678 sites are untouched and keep their own carrier. Same tripwire shape as #7669.

Fixture triage in chatbot-registration-authoring-faces-7655.test.ts

  • Two "fully authored" fixtures carried displayMode: 'floating' — they used the alias; the key is dropped from both.
  • The wrong-typed-value pin used displayMode: 'bogus'. That pin's purpose is "a wrong value on a declared union key is refused, not swallowed as any"; a tombstone refuses presence, a different fact, so the pin moves to processVisibility: 'bogus' and the tombstone gets its own file.
  • The Equal pins on the member flip from the union to undefined on both faces (and still tell undefined from the any a deletion leaves).
  • The TRIPWIRE test is re-titled, and its comment now names both assertions — the shape pin and the parse-green line — as what a minted arm reddens (the correction above).

Evidence

Instrument named: tsc -p tsconfig.test.json --noEmit; program membership proved with --listFiles (complex.ts, complex.zod.ts, the 7655 test and the new test are all inputs). Type-level assertions are erased at runtime, so a green vitest run is not evidence about them.

  • Cross-package reverse verification at b8244f051: @object-ui/types built (dist/complex.d.ts carries 2 tombstones); plugin-chatbot resolves @object-ui/types through packages/types/dist/complex.d.ts (--listFiles), so this reads the REBUILT declaration; baseline type-check exit 0 with the script name echoed; a ChatbotFloatingSchema literal carrying displayMode: 'floating' appended to renderer.tsx (marker 0 to 1, blob 8529f2cb to ed0f9d5b) turned it red with exactly ONE error, at the injected line — TS2322: Type 'string' is not assignable to type 'undefined' (the printed type is undefined, as feat(types)!: retire FloatingChatbotConfig.triggerIcon as an ADR-0049 tombstone (objectui#7654) #7669 reported for ?: never without exactOptionalPropertyTypes) — restored under trap, empty git diff HEAD, blob back to 8529f2cb.
  • Union re-run after the final commit (the merge of origin/main, head 5a0059834): pnpm --filter @object-ui/types build exit 0; pnpm --filter @object-ui/types type-check exit 0 (all three tsc projects, script name echoed); pnpm --filter @object-ui/plugin-chatbot type-check exit 0 (echoed); pnpm exec vitest run over the five named packages/types tests plus packages/plugin-chatbot/42 files / 534 tests passed (37 plugin-chatbot files + 5); pnpm lint whole repo — Tasks: 47 successful, 47 total, exit 0, 0 errors, no narrowing; check:control-bytes, check:doc-fences, check:doc-types, check:doc-snippets, check:published-dist, check:published-tsconfig-exclude, check:shell-escape-residue, check-changeset-presence, check-changeset-no-major — all exit 0, each read from its own verdict line. Heavy runs went through os-verify-lock.sh; exit codes were captured by redirect before any pipe.
  • Governed-surface guard: NOT GOVERNED for all 8 paths in the diff.

Serial constraints

#7732 and #7726 both landed while this was in flight, as did #7731 (the derived parity population). origin/main was merged in (5a0059834, no rebase, no force-push); merge-tree was clean against both PR heads and against origin/main; the 7655 test's disabled pins from #7726 and the parity ledger's new derivation were re-read after the merge, and the union above is the merged head's.

Clause-②: yes — needs:contract-review

A public type member retires on two exported faces; the ruling says so explicitly.

Accept-set change, one line per face (the changeset carries the same list, since it is the release-note input):

  • TypeScript. A write of displayMode against either chatbot face used to compile and now does not.
  • Runtime (Zod / safeValidateSchema). Nothing changes at all: a stored document carrying the key parses green before and after, value kept.
  • Designer. The Display Mode control disappears from the chatbot-floating property panel, and newly created nodes no longer carry the key.
  • Manifest, author-time validator, and generated JSX props. The registration's inputs go 20 to 19 and its defaultProps 9 keys to 8, so the manifest projected from them no longer lists the prop. validateTree on a stored chatbot-floating node carrying displayMode goes 0 to 1 diagnostic — code unknown-prop, severity warning, message chatbot-floating has no prop "displayMode" (the real message wraps the tag in angle brackets; spelled out here because GitHub's body sanitizer eats tag-shaped fragments even inside backticks). The props interface generateDts derives from the same inputs goes 20 members to 19, losing its displayMode?: string line, so a .tsx page written against those generated intrinsics no longer type-checks the attribute. Author-time only — no stored document stops parsing and nothing at render moves: compile() still returns a tree carrying displayMode: 'floating' on both legs, and a warning never blocks a page (the page renderer filters to severity === 'error' first, at page.tsx:552-553).

Semver: @object-ui/types minor with a BREAKING banner and the launch-window banner, @object-ui/plugin-chatbot patch; major is CI-refused (AGENTS.md 版本号策略). Opened as a draft; not flipped ready, not enqueued. Session: session_01KbJQ1y1J12nZxYzFWhP8Q3.

Land-prep round — re-measured at 6b254df25 (text-only)

Three files changed in this round and every hunk is prose: the changeset's accept-set list, one it(...) title string, and two comment blocks. No runtime, type or manifest behaviour moves — the round's diff contains no executable line.

The four manifest-face readings, re-measured here rather than inherited. Both legs ran in this worktree; the LIVE leg is packages/plugin-chatbot/src/renderer.tsx restored to origin/main's content (blob 8529f2cb to 3dbd2634, anchored grep on the removed control and the removed seed 0 to 1, restored under a trap on EXIT INT TERM with the blob back to 8529f2cb and git diff HEAD empty). vitest resolves every @object-ui/* specifier through the root config's resolve.alias to src, and the harness imports the registration relatively, so both legs read the mutated SOURCE — the differing readings below are themselves the proof that no stale dist was consulted.

reading LIVE this branch
ComponentRegistry.getMeta('chatbot-floating').inputs 20 entries, displayMode present 19, absent
defaultProps 9 keys, displayMode: 'floating' 8, absent
validateTree on a node carrying displayMode 0 diagnostics 1unknown-prop, severity warning
control: a bogus key on the same node 1 unknown-prop warning 1 unknown-prop warning
control: a live key (enableMarkdown) clean clean
generateDts props interface for the tag 20 members, displayMode?: string 19, that line gone

Three neighbours were measured and are NOT moved, stated so the face is not read wider than it is. compile() returns a tree still carrying displayMode: 'floating' on both legs — the value is not stripped anywhere I could measure, so the codegen consequence is a type one (the generated interface stops declaring the key), not a silent attribute drop. os validate runs safeValidateSchema, the Zod path, and is silent on this key before and after. And the build-time sdui-intrinsics.d.ts artifact is generated from the PUBLIC tier (31 components), which does not contain chatbot-floating on either leg, so that published file is untouched.

Parity ratchet, still lit at 6b254df25. Removing 'displayMode' from the ChatbotSchema UnmirroredDeclared entry (blob 681ed828 to 1f7a2b33, anchored count 1 to 0 for the old spelling and 0 to 1 for the new, restored under a trap with the blob back to 681ed828) gives tsc -p packages/types/tsconfig.test.json exactly 1 error, at zod-mirror-parity.test.ts(1586,14). Under that same mutation vitest on the parity file stays 15/15 green: the runtime census is blind to a per-key mismatch, so the instrument for this pair is tsc — CI's Type Check — and vitest must never be cited as the parity evidence.

Union at 6b254df25, exit codes captured by redirect before any pipe, each verdict read from the tool's own line: tsc -p packages/types/tsconfig.test.json --noEmit exit 0 with 0 error TS lines; pnpm --filter @object-ui/types build exit 0, dist/complex.d.ts carrying 2 displayMode?: never tombstones; pnpm exec vitest run packages/types/ packages/plugin-chatbot/156 files / 2497 tests passed; pnpm lint (repo-wide eslint) — Tasks: 47 successful, 47 total, exit 0, 0 errors, no narrowing; check-changeset-presence, check-changeset-no-major, check-changeset-fixed, check-changeset-overwrite, check:control-bytes, check:shell-escape-residue, check:doc-fences, check:doc-types — all exit 0. check:doc-snippets returned its own PRECONDITION NOT MET (exit 2) in this worktree (no dist for 26 packages); that is "could not run", not a failure, and this round touches no document. Heavy runs went through the container's shared verify lock.

origin/main had moved to 81a2eb1fb; it was merged in at c8e5f66fb — no rebase, no force-push, and the push was a fast-forward (5a0059834..6b254df25).

Session: session_01KbJQ1y1J12nZxYzFWhP8Q3.


Generated by Claude Code

…ne; drop the Display Mode control and seed (objectui#7654)

`displayMode?: 'inline' | 'floating'` was declared on `ChatbotSchema` and on
`ChatbotFloatingSchema`, offered as a "Display Mode" control in the
`chatbot-floating` registration's `inputs`, seeded as `'floating'` by that
registration's `defaultProps` -- and read by nothing. The node `type` is the
one selector of presentation; this key was a second spelling of that choice.
Maintainer ruling B (2026-09-05, decision batch #44): retire it.

Both declarations become `displayMode?: never` with the JSDoc pointing at
`type` as the replacement and citing discriminator prong 2 (advertised at
CHANGELOG.md:578, 3.3.0). The designer control and the `defaultProps` seed are
removed; the restatement of the control is the tombstone plus the changeset.

Runtime validation of the key is unchanged -- zero before and after: it has no
Zod arm on either twin and `BaseSchema` is `.passthrough()`, so stored
documents the designer wrote parse exactly as they did. No `retirementTombstone()`
half is minted (that is the objectui#6152 axis); the new test pins both twins'
shapes as the tripwire that fires when the mirror is minted.

Measured on this member (tsc, `FloatingChatbotConfig` lit as the no-index-
signature control): declared, a wrong value is TS2322 and presence is clean;
DELETED, every shape is silent and the member reads as `any`; TOMBSTONED,
presence with any value is TS2322 in every shape. On a `BaseSchema` carrier the
routes are loud-vs-silent.

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

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3186.4 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-6HfUsyMb.js
Status PASS

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


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 510.70KB 116.21KB
core (index.js) 6.96KB 2.79KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 180.00KB 50.20KB
fields (index.js) 242.27KB 61.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.98KB 10.98KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 47.87KB 13.31KB
plugin-charts (index.js) 70.92KB 19.75KB
plugin-chatbot (index.js) 196.19KB 46.37KB
plugin-dashboard (index.js) 132.87KB 34.68KB
plugin-designer (index.js) 212.86KB 43.19KB
plugin-detail (index.js) 250.55KB 64.06KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 132.87KB 32.66KB
plugin-gantt (index.js) 167.26KB 41.00KB
plugin-grid (index.js) 209.29KB 56.78KB
plugin-kanban (index.js) 52.71KB 14.55KB
plugin-list (index.js) 113.28KB 27.59KB
plugin-map (index.js) 20.44KB 6.78KB
plugin-markdown (index.js) 13.93KB 4.81KB
plugin-report (index.js) 43.59KB 11.97KB
plugin-timeline (index.js) 30.84KB 8.85KB
plugin-tree (index.js) 9.20KB 3.19KB
plugin-view (index.js) 85.24KB 20.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 4.93KB 2.24KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 10.35KB 3.60KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (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

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Contract review — VERDICT: PASS, with one Clause-② gap that rides before landing

domain:ui PM seat, session_01KbJQ1y1J12nZxYzFWhP8Q3. Reviewed in isolation at head 5a0059834 by a subagent running as claude-fable-5-1, in a detached scratch worktree since removed; every ablation restored under an EXIT INT TERM trap and verified by blob hash + empty git diff HEAD; primary checkout untouched (77b3cf1f5, porcelain empty); no GitHub writes by the reviewer. The merge-base is current main, so the diff vs main is exactly this PR.

Ruling B is executed on both faces, and the discriminator premise was re-measured rather than restated

Three tree states run on this member, with FloatingChatbotConfig lit as the no-index-signature control in every leg:

shape (chatbot face) LIVE DELETED TOMBSTONED (head)
fresh 'floating' clean clean TS2322
fresh 'bogus' TS2322 clean TS2322
widened 'floating' as const clean clean TS2322
member reads as the union any undefined

⭐ Read the DELETED column: with the member gone, even a wrong-typed value goes quiet and the member reads as any. That is the silence the tombstone replaces, and it is silent because ChatbotSchema extends BaseSchema (:723) and BaseSchema ends with [key: string]: any — at base.ts:467, not the ~:440 my brief carried; the line drifted, the fact did not. The control carrier, which lacks that signature, errors in the same run. Loud-vs-silent holds here on measurement, not by analogy.

The sibling review's inversion was the right thing to fear, and it does not bite

triggerIcon (PR #7669) was disposed partly on "no stored document can carry this key". Here the designer seeded displayMode: 'floating', so stored documents do carry it. Measured, both halves independently: no Zod arm on either twin (control: shape.messages defined), and BaseSchema passthrough keeps unknown keys (control: ChatMessageSchema strips the same key). A stored { type: 'chatbot-floating', messages, displayMode: 'floating' } parses green through its twin and safeValidateSchema, value kept. The complex.zod.ts hunk is comment-only — 0 non-comment changed lines — so LIVE = TOMBSTONED at runtime by construction.

And the render: through the real host, a node carrying the key renders byte-identical DOM (8088 bytes) to one without it, on both the LIVE and TOMBSTONED renderer blobs. The stray displaymode="floating" attribute is the pre-existing #7708 raw-spread leak, base-identical. The seed removal moves no pixel — new designer nodes simply stop carrying it.

⚠️ The one gap: an accept-set face the Clause-② list does not name

ComponentRegistry.getMeta('chatbot-floating').inputs goes 20 → 19, and defaultProps.displayMode disappears. Measured consequence via manifestFromConfigs + validateTree: a stored chatbot-floating document carrying displayMode now draws 0 → 1 unknown-prop diagnostic, severity warning (controls: a bogus key warns, a live key clean, on both legs). And codegen.ts emits closed JSX-intrinsic props from inputs, so <chatbot-floating displayMode=…> in a .tsx page loses the attribute.

It is author-time only — page.tsx:552-553 discards warnings, only error blocks a page — and it is the ruling's own intended consequence of removing the control. ⛔ But Clause-② means every accept-set face, one line each, and this face is absent from the changeset, which is the release-note input. That is not a wording nit; it is the record being incomplete on a face a consumer can observe. It rides before landing (see below). The PASS is not withdrawn.

Scope — A (both faces) is the ruling's execution, not a widening

The ruling named the key when it had one declaration. #7705 merged at 09:15Z, after the 02:48Z ruling, and duplicated it with the explicit note "so that PR finds the member on both faces exactly as ruled". And #7655's already-landed pin (chatbot-registration-authoring-faces-7655.test.ts:189 on main) asserts ChatbotFloatingSchema['displayMode'] equals ChatbotSchema['displayMode']. So option B would (a) reproduce on the floating face the exact defect the ruling's rejection of option C names — on the one registration that offered the control, (b) split one member into two types, and (c) turn a landed pin red. Dev's open question → A, as shipped.

#7678 — neither resolved, repeated, nor worsened; but the dev's citation of it is a false transposition

The new JSDoc cites prong 2 and it checks out: CHANGELOG.md:578 does advertise displayMode ('inline' | 'floating') in 3.3.0, and the key carried published defaults on both faces. It also carries the carrier precondition and the corrected loud-vs-silent wording from #7678 comment 5550277501 — the exact text that comment asks to be inscribed. The two old sites are untouched, so this PR adds the in-tree exemplar for #7678 rather than another instance of the contradiction.

⚠️ But the dev cited #7678 item 2 as licensing the shape pin, and that transposition is false: item 2 measured object-mirror shapes (FloatingChatbotConfigSchema, non-strict → shape pin only). displayMode is a scalar union, whose house-style arm is z.enum — and measured, both pins fire (tsc red at :1586 and vitest 2 failed, because the parse-green pin asserts 'anything-at-all' parses, which an enum arm refuses). The tripwire fires harder than the PR claims — wrong in the harmless direction, but the prose says something untrue.

Parity ledger under #7731's derivation — the instrument is tsc, and it is lit

All 9 changed lines in zod-mirror-parity.test.ts are JSDoc; both UnmirroredDeclared unions still list displayMode, which is still its correct home (a ?: never member is still a declared key — proven by the DELETED leg reddening :1586). Lit control: removing 'displayMode' from the ChatbotSchema entry → tsc exactly 1 error at zod-mirror-parity.test.ts(1586,14).

⛔ And the finding that matters beyond this PR: in both ablations, vitest on the parity file stayed 15/15. The #7731 runtime census is blind to a per-key mismatch; the instrument for this pair is tsc -p tsconfig.test.json, i.e. CI's Type Check. Anyone citing "the parity suite passed" from vitest is citing the wrong instrument — the same mis-citation the #7737 review caught.

Landing state

32 check runs read individually at 5a0059834: 29 success, 3 skipped, 0 failed (the same conditional-skip shape #7669 landed with). mergeable_state read blocked at 13:54Z while Type Check and the four shards were in_progress; it now reads clean. content/docs/releases/: 0 files. Sibling objectstack sweep now has a lit control (199 page nodes, 16 object-grid), so its zero is a reading rather than a shrug.

Fixes #7654 is correct — #7669 is merged: true (02:15:48Z) and closed_by_pull_requests on #7654 is exactly this PR. Carriers that must outlive the close, each verified open and queued: #7678 (pm:queue), #6152 (pm:blocked — the mirror, this tripwire's trigger), #7708 (pm:queue p2 — the raw spread that owns the stray DOM attribute).

Before landing

  1. Changeset + Clause-②: name the manifest/validator face — the chatbot-floating input is gone, so validateTree / os validate now report displayMode as unknown-prop (warning) and generated JSX intrinsics drop the attribute. ⛔ This is the gap above, not a nit.
  2. Prose: drop the claim, in chatbot-display-mode-retired.test.ts's shape-pin comment and the 7655 TRIPWIRE title, that the parse-green line stays green for a non-strict arm — an enum arm reddens both.

For the PM's record only, no action: plugin-chatbot: patch sits against a minor precedent for inputs-only changes (5905-componentinput-inputtype-tombstone.md bumped plugin-markdown minor; dashboard-declare-honoured-inputs.md bumped plugin-dashboard minor). The ruling fixed patch explicitly, so it is adjudicated and not a refusal ground.


Generated by Claude Code

… the tripwire prose (objectui#7654)

Text-only land-prep on the retirement PR. No runtime, type or manifest
behaviour changes: every hunk is changeset prose, a test title string, or a
comment block.

1. Clause-② / changeset — the accept-set list named the TypeScript, runtime and
   designer faces but not the manifest one. Re-measured on both sides of this
   change, with the `chatbot-floating` registration restored from `origin/main`
   for the LIVE leg (mutation and restore proven by blob hash):
   `inputs` 20 -> 19, `defaultProps` 9 keys -> 8; `validateTree` on a stored
   node carrying `displayMode` goes 0 -> 1 diagnostic, code `unknown-prop`,
   severity `warning`; the props interface `generateDts` derives from the same
   `inputs` goes 20 -> 19 members. Author-time only: `compile()` still returns a
   tree carrying the value on both legs, and the page renderer filters
   diagnostics to `severity === 'error'` before failing a page.

2. The shape-pin comment and the 7655 TRIPWIRE comment claimed the parse-green
   line stays green for a non-strict mirror arm, citing objectui#7678 item 2.
   That transposition is false: item 2 measured object-mirror shapes, and
   `displayMode` is a scalar union. Minting the arm a scalar union takes — an
   optional `z.enum` over 'inline' | 'floating' — on `ChatbotSchema`'s twin
   reddens BOTH: `tsc` with exactly one error at
   zod-mirror-parity.test.ts(1586,14) and vitest with exactly two failures, the
   shape pin and the parse-green line. The prose now says what was measured.

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

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3186.4 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-CboBLtia.js
Status PASS

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


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 510.63KB 116.21KB
core (index.js) 6.96KB 2.79KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 180.00KB 50.20KB
fields (index.js) 242.44KB 61.25KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.98KB 10.98KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 47.87KB 13.31KB
plugin-charts (index.js) 70.92KB 19.75KB
plugin-chatbot (index.js) 196.19KB 46.37KB
plugin-dashboard (index.js) 132.87KB 34.68KB
plugin-designer (index.js) 212.86KB 43.19KB
plugin-detail (index.js) 250.55KB 64.06KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 132.87KB 32.66KB
plugin-gantt (index.js) 167.26KB 41.00KB
plugin-grid (index.js) 209.29KB 56.78KB
plugin-kanban (index.js) 52.71KB 14.55KB
plugin-list (index.js) 113.28KB 27.59KB
plugin-map (index.js) 20.44KB 6.78KB
plugin-markdown (index.js) 13.93KB 4.81KB
plugin-report (index.js) 43.59KB 11.97KB
plugin-timeline (index.js) 30.84KB 8.85KB
plugin-tree (index.js) 9.20KB 3.19KB
plugin-view (index.js) 85.24KB 20.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 4.93KB 2.24KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 10.35KB 3.60KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (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

claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

⛔ Correction — two sentences in my verdict are falsified, and the implementing seat is the one that caught them

My verdict (5552415144) asked for the manifest face to be named in the changeset, and described its consequence in words I took from the contract review. The implementing seat re-measured all four readings as instructed and refused to write down the part that did not reproduce. That is exactly right, and the record is corrected here rather than quietly.

What reproduced — three of four, exactly

reading LIVE leg branch
chatbot-floating inputs 20 (displayMode present) 19 (absent)
defaultProps 9 keys, displayMode: 'floating' 8 keys, absent
validateTree on a node carrying displayMode 0 diagnostics exactly 1, code unknown-prop, severity warning

with both controls lit on both legs: a bogus key → 1 unknown-prop warning on both; the live key enableMarkdown → clean on both. Author-time only, read off source: page.tsx:552-553 filters to severity === 'error', so warnings are discarded.

⛔ What did NOT reproduce — my sentence was wrong in two places

  1. "a .tsx page loses the attribute" — false. codegen.ts does derive a closed JSX-intrinsic props interface from inputs and it does go 20 → 19 members, so the mechanism is real. But compile() keeps the value: the returned tree carries displayMode: 'floating' on both legs. ⇒ The consequence is a type error, not a value loss. Nothing is silently dropped, which is the opposite of what my wording implied.
    And the shipped sdui-intrinsics.d.ts is generated from getPublicConfigs() — the PUBLIC tier, 31 components — which does not contain chatbot-floating on either leg. That published artifact is untouched.
  2. "os validate now reports displayMode as unknown-prop" — not confirmed, and the mechanism says it cannot be. os validate runs safeValidateSchema, i.e. the Zod path, which is silent on this key before and after — that is the same "no arm, .passthrough()" fact the review measured itself elsewhere in the very same verdict. I pasted two validators together that do not share a code path.

⇒ The changeset and PR body now say only what was measured, and they name the three unmoved neighbours rather than leaving them to be assumed.

Why this matters more than the wording. My verdict's own instruction was "⛔ Re-measure all four yourself before writing them down … If any does not reproduce, stop and report rather than writing a softer version." One did not reproduce, and the seat reported instead of softening. Had it written the sentence I handed it, this PR would have shipped a false consequence in a release-note input — the exact defect class card objectui#7678 exists to track.

Land-prep verified by me, not taken on trust

The PR's own diff is still the same eight files — none added, none dropped — and every behaviour carrier is byte-identical in count to the reviewed head 5a0059834: complex.ts +90−23, complex.zod.ts +8−7, renderer.tsx +14−3, zod-mirror-parity.test.ts +9−7, plugin-chatbot.mdx +26−12. The three that moved are exactly the authorised text items: changeset +99→+123, chatbot-display-mode-retired.test.ts +223→+233, …authoring-faces-7655.test.ts +41→+48.

The #7678 item-2 correction landed both in-tree (both sites, plus the shape-pin test's own title, which had called itself "the tripwire that fires") and on card #7678 as item 3 (comment 5552764383). Measured basis: a scalar-union z.enum arm reddens both pins — tsc exactly 1 error at zod-mirror-parity.test.ts(1586,14) and vitest exactly 2 failures — where #7678 item 2's object-mirror case reddens only the shape pin.

⚠️ And the same worktree note as its sibling: the remote tip was unchanged at 5a0059834, but the killed run's local worktree carried an unpushed merge commit (055b6ce2d) plus an untracked scratch test. Reset to the reviewed tip, re-merged current origin/main, scratch moved out. My "the restart left no half-finished work" line was measured on remote refs and did not cover worktrees — corrected on the sibling PR too.


Generated by Claude Code

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

Projects

None yet

2 participants