Skip to content

feat(types): widen the overlay family's trigger to the node array every other face already accepts (#7081) - #7768

Merged
os-justin merged 3 commits into
mainfrom
claude/issue-7081-overlay-trigger-union
Sep 5, 2026
Merged

feat(types): widen the overlay family's trigger to the node array every other face already accepts (#7081)#7768
os-justin merged 3 commits into
mainfrom
claude/issue-7081-overlay-trigger-union

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #7081

The overlay family's trigger slot now declares, on the TypeScript face, the node array its Zod mirror, its runtime and its own shipped defaultProps already accept. Seven members widen from SchemaNode to SchemaNode | SchemaNode[]DialogSchema, AlertDialogSchema, SheetSchema, DrawerSchema (optional) and PopoverSchema, HoverCardSchema, DropdownMenuSchema (required) — matching the spelling ContextMenuSchema and TooltipSchema already carried. Optionality is kept per member; SchemaNode itself and every other member are untouched. Each widened docblock names its renderer read site and renderChildren's Array.isArray branch.

Tier: CONTRACT_REVIEW_TIER — the published TS face widens. Left in draft for the domain:spec PM seat's review; label needs:contract-review. Triage on the card (comment 5527740245): the validator's accept set does not move — zod/overlay.zod.ts already spells every one of the nine overlay trigger members z.union([SchemaNodeSchema, z.array(SchemaNodeSchema)]) — so this is the declaration catching up with what ships.

Triage condition 1 — read sites (measured on 737037f2, re-measured unchanged on c8842a8b)

  • schema.trigger.MEMBER (member access on the slot): 0 hits under packages/ (ts/tsx, excluding dist and node_modules).
  • .trigger.MEMBER / trigger.(type|id|label|props) on ANY receiver: 2 hits, both unrelated types — app-shell/.../FlowRunsPanel.tsx:343 (run.trigger.type, a flow run) and a DOM element in record-picker-label-association.test.tsx:106.
  • Positive controls on the same grep machinery: renderChildren(schema.trigger = 10 hits (the nine overlay renderers plus collapsible.tsx); schema.KEY.MEMBER on any key under packages/components/src = 21 hits.
  • Widening surfaced zero tsc errors at any read site (@object-ui/types and @object-ui/components type-check both exit 0), so nothing was cast away and no single-vs-array bug was hiding behind the narrow declaration.

Triage condition 2 — parity pins

No trigger row existed on any ledger, and none was needed: origin/main (2760075f, PR #7758 for #7069) was merged into this branch before opening, and its fifth ledger WiderThanDeclared excludes slots spelled through SchemaNodeSchema, so the overlay trigger members are outside its population. pnpm --filter @object-ui/types type-check and pnpm exec vitest run packages/types/ (122 files, 2151 tests, the new parity runtime leg included) are green on the merged tree c8842a8b. zod-mirror-parity.test.ts is not touched by this PR.

What moves, file by file

Ablation (recorded from the locked run on 4da4892b; restore proven)

overlay.ts reverted to 3e377c93's blob (9df1af15, byte-identical to the base's): on disk union spellings 9 → 2, singular 7, objectui#7081 mentions 7 → 0. tsc -p packages/types/tsconfig.test.json exit 2, 25 errors: 21 in the new pin (seven _*Trigger, seven _*AdmitsArray, seven shipped* documents) and 4 in the #7082 pin (_HoverCardTrigger plus its three AdmitsArray legs); no error touched a control, the counter-controls or the singular documents. The new pin's runtime legs under the mutation: 9 failed / 62 passed of 71 — the seven "declaration spells the union" source rows and the two declaration census legs red, every mirror, defaultProps, renderer and docs leg green (the mirror and the renderers never moved). Restore: git checkout HEAD -- ABSOLUTE_PATH under an EXIT/INT/TERM trap, git diff HEAD empty, git hash-object = e55ec1c0 = HEAD:packages/types/src/overlay.ts, counts back to 9 / 0 / 7, pin 71/71 green. The pin's type legs compile from src through relative imports (tsconfig.test.json), so no dist is on the ablation path.

Gates (exit captured before any pipe; heavy runs under the shared verify lock, shared-box seconds)

command exit tree verdict
pnpm --filter @object-ui/types build 0 c8842a8b dist completeness: 124 emitted files verified
pnpm --filter @object-ui/types type-check (tsc --noEmit + examples + tests projects) 0 c8842a8b clean
pnpm exec vitest run --maxWorkers=2 packages/types/ 0 c8842a8b 122 files, 2151 tests passed
pnpm --workspace-concurrency=2 --filter '@object-ui/components^...' build 0 4da4892b closure built
pnpm --filter @object-ui/components type-check 0 4da4892b clean
pnpm exec vitest run --maxWorkers=2 packages/components/ 0 4da4892b 233 files, 2166 tests passed
pnpm --filter @object-ui/types lint 0 4da4892b (+ the pin re-linted at 48bfaadf) 0 errors, 270 pre-existing warnings
node scripts/check-changeset-presence.mjs 0 c8842a8b 4 source files of 1 released package, 1 changeset declared
node scripts/check-changeset-fixed.mjs · check-changeset-no-major.mjs 0 · 0 c8842a8b green
node scripts/check-control-bytes.mjs 0 c8842a8b 6327 files OK
pnpm check:spec-symbols · check:doc-types · check:doc-fences · node scripts/check-doc-links.mjs 0 each c8842a8b green
pnpm check:doc-snippets NOT MEASURED its --build-filter closure is 26 packages (the whole workspace); narrowed measurement instead: all 7 changed doc lines sit in plaintext fences and TS_FENCE_LANGUAGES is ts/tsx/typescript, so the gate compiles nothing this PR touches
governed-surface predicate (check-governed-merges.mjs --test, final file list) 0 c8842a8b 0 of 12 paths hit the register — NOT governed

The components legs were run at 4da4892b; the two later commits touch only a test file under packages/types and the merge of origin/main, neither of which the components package imports.

Deviations from the dispatch

  1. alert-dialog-read-dialect-7104.test.ts (one control line) edited outside the named file surface — it reads a doc row this PR changes and would have gone red.
  2. The dispatch mapped :355 to ContextMenuSchema and :608 to TooltipSchema; on the tree it is the reverse (:355 Tooltip, :608 ContextMenu). Both already carried the union; nothing changes.
  3. The pin's describe.each title uses a tuple (%s) rather than $name, which rendered undefined under this vitest.
  4. dropdown-menu.mdx: only the trigger row changed, so its trailing comment no longer aligns with the sibling rows' column (re-aligning would touch rows outside the diff).
  5. REST reads/writes are 403 for this seat; the card and comments were read through the public payload channel plus one MCP comment read, the dedup through two targeted MCP searches (query + control), labels through the MCP read → union → write → read-back fallback.

Out of scope, filed

Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s

🤖 Generated with Claude Code

https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s


Generated by Claude Code

…very other face already accepts (objectui#7081)

`trigger` on DialogSchema, AlertDialogSchema, SheetSchema, DrawerSchema,
PopoverSchema, HoverCardSchema and DropdownMenuSchema goes from `SchemaNode`
to `SchemaNode | SchemaNode[]` on the TypeScript face, optionality kept per
member, each docblock naming its renderer read site and `renderChildren`'s
`Array.isArray` branch. The zod mirror already spelled the union on all nine
overlay `trigger` members, every renderer hands `schema.trigger` to
`renderChildren`, and every registration ships `defaultProps.trigger` as an
array: the declaration catches up with what ships; the accept set does not
move.

Also: the seven overlay doc rows follow the declaration; the #7082 pin's legs
that were built to go red on this change are re-derived to the union; the
#7104 control row likewise; a new pin holds all faces on all nine members
with the two already-union siblings as controls; changeset (minor, a
widening).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
…psible leg at objectui#7767

`describe.each` over objects rendered `$name` as `undefined` in this
vitest, so the suite title is built from a tuple; the out-of-family
Collapsible counter-leg now names the card it was filed as.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
@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) 3187.0 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-fw3Pes87.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) 182.08KB 50.62KB
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

Copy link
Copy Markdown
Collaborator Author

needs:contract-review cleared (2026-09-05T16:30Z) — provenance: in-seat contract review at tier PASSED on head c8842a8b, recorded on the card as objectui#7081 comment 5553183812 (carries the Implemented-by: / Reviewed-by: pair and the three-item judgment). Cleared by the domain:spec execution seat, session session_01BAZFhALsQsGqxui8sNqM8s, via read-current → write-union-minus-target → read-back. If this head moves, the label is re-hung and the delta re-reviewed before any flip.


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