Skip to content

feat(types,plugin-calendar): converge CalendarViewSchema on the calendar-view renderer's read set - #5739

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-5667-calendar-type-converge
Aug 23, 2026
Merged

feat(types,plugin-calendar): converge CalendarViewSchema on the calendar-view renderer's read set#5739
os-sam merged 1 commit into
mainfrom
claude/issue-5667-calendar-type-converge

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#5667

Maintainer ruling (2026-08-22, recorded on the issue): Option A — the renderer is authoritative; CalendarViewSchema converges on the measured read set, liveness measurement first, docs repaired in the same PR.

Liveness measurement (taken on the authored-node path, not by key-name grep)

The calendar-view registry renderer (packages/plugin-calendar/src/calendar-view-renderer.tsx) reads, per its own source: schema.data + titleField / startDateField / endDateField / allDayField / colorField (event computation, lines ~270-295), view (resolveAuthoredView), currentDate (resolveAuthoredCurrentDate), allowCreate (resolveAuthoredAllowCreate), className (forwarded), plus the function-typed host hatches (HOST_CALLBACKS, incl. onEventClick / onViewChange). An authored events is destructured out as _authoredEvents and dropped (#4433). The registry inputs block (lines 397-469) declares exactly the ten keys the ruling lists.

Authored instances of the nine inert keys on calendar-view nodes: zero — swept apps, examples, e2e, packages, content in this repo (the only real authored nodes, examples/schema-catalog/src/schemas/plugin-calendar/*.json, author exactly the converged set) and the objectstack tree's example apps (no calendar-view node exists there at all). So the ruling's qualifier "retire only what no app authors" permits retiring all nine.

Change

  • packages/types/src/complex.tsCalendarViewSchema retires events (was the only required key besides type), defaultView, defaultDate, date, views, editable, onEventCreate, onEventUpdate, onDateChange; declares data, the five field-name keys, view, currentDate, allowCreate, className, and keeps the two host-only hatches the renderer actually forwards (onEventClick, onViewChange), documented as host-only.
  • packages/types/src/zod/complex.zod.ts — mirror moves in the same stroke. Measured: zod BaseSchema is .passthrough(), so retirement does not create rejections; the material accept change is that events stops being required.
  • content/docs/api/schema-reference.md — the CalendarViewSchema section's example and property table rewritten to the converged surface (the old table published onDateChange et al. as working callbacks; the old example authored defaultView / views / editable / events).
  • packages/plugin-calendar/README.md — Schema API fence, "Basic Calendar" / "Interactive Calendar" / "Customization" / registration / TypeScript-Support examples all repaired (five separate events:-authoring instances); the "type is not the renderer" contradiction note replaced by the converged statement. The readme-calendar-view-schema.test.ts pin (parses both the interface and the fence from source) holds the two together and passes.
  • .changeset/calendar-view-schema-converge.md@object-ui/typesminor (repo policy: breaking ships as minor with the semantics stated in the body; the fixed group's major tracks @objectstack), @object-ui/plugin-calendar patch.

Runtime renderer behaviour is unchanged; the #4433 events-drop pin (calendar-view-renderer.eventsCollision.test.tsx) still passes and is still falsifiable (it pins renderer behaviour, which this PR does not touch).

Measured breaking radius

BaseSchema (TS) carries [key: string]: any — so literals still authoring retired keys keep compiling, and reads of them degrade to any; the compile-level break is limited to annotations that relied on events being required, plus value-level checks on the newly declared keys (e.g. titleField: 42 is now an error — see reverse verification). zod-side, nodes without events now validate; wrong-typed retired keys (e.g. editable: 'yes') are no longer rejected. Out-of-repo annotation use is unmeasurable from here (triage's own confidence gap; stated, not asserted).

Verification (all at 47c00a5, the head of this PR)

  • pnpm exec vitest run packages/types/ packages/plugin-calendar/54 files / 557 tests passed (includes the plugin-calendar: authoring events on a calendar-view node crashes the component — the SDUI action object overwrites the computed CalendarEvent array #4433 pin, the README-schema pin, inertInputs/propsContract/currentDate suites, and the types zod/parity suites). Re-run at the final commit.
  • pnpm --filter @object-ui/types build then dist proof: titleField present in dist/complex.d.ts, zero occurrences of the retired required events: CalendarEvent.
  • Reverse verification against the rebuilt dist (probe file in plugin-calendar scope, resolution via package exports → dist; deleted after): { type: 'calendar-view', titleField: 42 } → red (TS2322: Type 'number' is not assignable to type 'string' — old dist accepted it via the index signature); { type: 'calendar-view' } → compiles (old dist rejected it for missing events). One error, exactly the expected one, in each direction.
  • pnpm --filter @object-ui/types type-check ✓; pnpm --filter '@object-ui/plugin-calendar^...' build + pnpm --filter @object-ui/plugin-calendar type-check ✓.
  • Gates, each green by its own verdict line: check:doc-types ("Every documented component type is registered"), check:doc-snippets ("Every covered documentation snippet compiles against the built types" — 88/88), check:spec-symbols, check:i18n-keys, check:i18n-drift, check:published-dist ("No published package's build output carries tooling material"), check:phantom-deps, check:self-import, check:esm-specifiers, check:node-esm-load, check:action-forward-parity, check:control-bytes, docs:check-links ("Links are valid across 13 scan roots"), pnpm check (CLI schema validation, "All checks passed"), changeset presence / fixed / no-major.
  • Lint: turbo run lint --filter=@object-ui/types --filter=@object-ui/plugin-calendar ✓ (3/3 tasks). Declared narrowing vs the full-farm pnpm lint: objectui lint is per-package eslint and the root eslint.config.js enables no type-aware linting (projectService/parserOptions.project absent), so untouched packages' lint verdicts cannot be moved by this diff; both touched packages were linted in full. Full-farm lint, the 4-shard test farm, the performance budget, and external-link lychee are CI's runs.

Generated by Claude Code


Generated by Claude Code

…dar-view renderer's read set
Fixes#5667 (maintainer ruling: option A, renderer authoritative, scoped by
measurement).
Retires the nine inert keys (events — required-but-dropped per #4433 —
defaultView, defaultDate, date, views, editable, onEventCreate, onEventUpdate,
onDateChange), declares the measured read set (data, titleField,
startDateField, endDateField, allDayField, colorField, view, currentDate,
allowCreate, className) plus the two host-only hatches the renderer forwards
(onEventClick, onViewChange). Zod mirror moves in the same change; the
plugin-calendar README and content/docs/api/schema-reference.md are repaired
so no copy of the old contradiction survives.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7snar5mwF7qoXJazqKhys
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3916.2 KB3990.2 KB
Main entry chunk (gzip)152.5 KB350 KB
Entry fileindex-CMLBWANN.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)10.04KB3.72KB
app-shell (runtime-config.js)12.80KB4.47KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)32.45KB8.06KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)11.67KB4.55KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)510.39KB114.67KB
core (index.js)4.92KB1.97KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)164.55KB45.67KB
fields (index.js)238.40KB59.89KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)23.13KB7.63KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.65KB18.32KB
plugin-chatbot (index.js)181.41KB43.22KB
plugin-dashboard (index.js)128.41KB32.95KB
plugin-designer (index.js)212.30KB42.80KB
plugin-detail (index.js)242.34KB60.98KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)125.63KB30.64KB
plugin-gantt (index.js)164.10KB39.87KB
plugin-grid (index.js)200.79KB54.26KB
plugin-kanban (index.js)52.93KB14.60KB
plugin-list (index.js)111.80KB27.20KB
plugin-map (index.js)20.06KB6.62KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.68KB7.66KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.61KB20.74KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)43.66KB14.77KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.33KB0.69KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (index.js)4.77KB2.16KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)6.92KB2.40KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.59KB1.79KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-samClaude

Copy link
Copy Markdown
CollaboratorAuthor

Build Docs is red here and it is not this PR's#5668, red on base

Stating this once, with the evidence, rather than pushing anything at it.

The failure.@object-ui/site#buildModule not found: Can't resolve 'fs' at pg-connection-string@2.14.0/index.js:88, reached via:

pg-connection-string@2.14.0
← @objectstack/spec@17.1.0/dist/index.mjs
← @objectstack/formula@17.1.0/dist/index.mjs
← packages/core/dist/evaluator/fieldRules.js
← packages/components/dist/index.js
← apps/site/app/components/InteractiveDemo.tsx [Client Component]
← content/docs/plugins/plugin-form.mdx.js / plugin-gantt.mdx.js

Why it is not this diff. This PR changes packages/types/src/complex.ts, its zod mirror, content/docs/api/schema-reference.md, packages/plugin-calendar/README.md and a changeset. None of those appears anywhere in that chain, and none can change module resolution:

  • fieldRules.ts:67 already imports @objectstack/formula on main — pre-existing, untouched here.
  • The two failing MDX routes are plugins/plugin-form and plugins/plugin-gantt; the only doc file this PR edits is api/schema-reference.md, which is not in the trace.
  • The touched packages contain no pg-connection-string reference at all.
  • Trace, failing task, and tally (28 successful, 29 total, Failed: @object-ui/site#build) are byte-identical to the ones recorded on Build Docs is red on main: fs reaches the browser bundle via @objectstack/specpg-connection-string #5668, which documents this as red on main across four consecutive push runs.

A correction to my own earlier reading, recorded because it nearly cost a wrong push. I first judged this as this PR's failure on the grounds that Build Docs passed on the sibling PR #5737 against the identical base. That inference was wrong: #5737's Build Docs completed in 11 seconds (03:11:38→03:11:49) against this one's 3m50s with a real Time: 3m13.651s build. An 11-second green is a cache hit, not a build, so it was never a control. #5668 names this exact trap — "the PR-level check kept passing while the push-level one failed" — and I walked into it anyway. A green whose duration is implausible for the work is not evidence.

Why this does not hold the PR.Build Docs is not gating the merge queue: 34 PRs have merged to main since #5668 was filed (2026-08-22T08:10Z), including #5736 forty minutes ago. The practical block is lifted even though the defect is not fixed.

What I am not doing, and why. Not pushing a fix: the fix is a dependency/bundler-boundary change in @objectstack/spec's browser reachability, entirely outside this card's declared surface, and #5668 is open under domain:devx with a named owner. Widening this PR to chase it would be the wrong shape. Not re-running the job either — a re-run cannot change a base-branch failure, and this is not a flake.

This PR's own gates are read by name and separately; Build Docs is excluded from that reading with the justification above. If Build Docs ever goes green on main again, the honest move is to merge base in and let it re-run — that is tracked on #5668, not here.


Generated by Claude Code

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

Labels

documentationImprovements or additions to documentationpackage: typesplugin

Projects

None yet

2 participants

@os-sam@claude