From 62088ac6c0003deba3a96f8b3c9cc95811c76580 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 4 Oct 2026 03:14:50 +0000 Subject: [PATCH] chore: release packages --- .changeset/10002-map-style-remedy-text.md | 29 - .../10005-record-history-row-cap-refusal.md | 26 - .../10006-port-parity-list-pipe-flush.md | 20 - .../10015-gate-reports-refused-view-cap.md | 22 - .../10016-binding-limit-not-authored.md | 40 - .../10018-authoring-state-sheds-approval.md | 14 - .../10019-parts-builder-key-set-texts.md | 4 - .changeset/10020-report-display-locale.md | 39 - .../10021-legend-swatch-custom-property.md | 12 - ...10024-search-results-count-plural-forms.md | 30 - .../10026-refuse-impossible-calendar-day.md | 16 - ...r-alias-refusal-quotes-surviving-clause.md | 16 - ...ar-user-visible-strings-reach-the-packs.md | 38 - .../10033-parity-ledger-retired-upstream.md | 4 - .../10035-objectview-refresh-in-place.md | 13 - .../10035-renderers-read-invalidation.md | 19 - .changeset/10036-gantt-reload-identity-dep.md | 34 - ...0037-gantt-toolbar-filter-reaches-chart.md | 17 - .changeset/10039-publish-drafts-advisories.md | 36 - .changeset/10040-app-shell-favicon-restore.md | 29 - .changeset/10042-one-root-resolver.md | 32 - .../10043-studio-landing-tooltip-i18n.md | 19 - .../10044-record-search-display-name-dep.md | 19 - .../10046-object-page-options-identity.md | 16 - .../10058-quick-actions-capability-gate.md | 57 - .changeset/10059-user-locale-single-source.md | 40 - .../10061-filter-builder-incomplete-range.md | 34 - .../10062-dataset-filter-between-arm.md | 37 - .changeset/10064-object-tree-public-tier.md | 44 - .changeset/10066-slider-step.md | 16 - .changeset/10068-kanban-datasource-sort.md | 20 - .../10069-kanban-lanes-match-by-id-only.md | 42 - .changeset/10071-number-scale-ceiling.md | 18 - .changeset/10073-customfields-merge.md | 27 - .changeset/10074-doc-changeset-text.md | 8 - .../10078-record-id-string-survivors.md | 59 - .../10080-modedefault-fixture-stored-body.md | 10 - .changeset/10083-rowactions-narrow.md | 15 - .changeset/10084-grid-ceiling-describe.md | 5 - .changeset/10088-json-fences-parse.md | 4 - ...096-record-activity-row-cap-non-integer.md | 36 - .../10098-locale-contracts-name-caller.md | 27 - .changeset/10105-pull-to-refresh-late-host.md | 42 - .../10106-settled-schema-equal-payload.md | 25 - ...10107-record-verdict-memo-per-principal.md | 40 - .../10108-form-payload-server-owned-fields.md | 18 - .../10109-app-shell-edit-not-built-moment.md | 5 - .../10109-edit-envelope-not-built-app.md | 12 - .../10112-relatedlist-user-column-names.md | 37 - ...10117-page-header-title-lookup-fallback.md | 53 - .../10120-form-omits-fls-denied-fields.md | 21 - .../10129-action-param-field-backed-picker.md | 44 - ...32-dashboard-i18n-declared-not-resolved.md | 59 - .../10145-row-cap-admits-only-numbers.md | 31 - .../10150-author-shape-header-ruling.md | 6 - .../10155-record-blocks-capability-gate.md | 50 - ...56-edit-form-writes-only-changed-fields.md | 25 - ...10159-action-preview-reference-citation.md | 6 - .../10163-line-items-field-write-gate.md | 17 - .../10163-master-detail-field-write-gate.md | 15 - .../10166-record-form-save-during-upload.md | 48 - .changeset/10167-formpage-file-field-arm.md | 34 - .changeset/10176-formpage-retired-type-pin.md | 4 - ...78-formpage-required-marker-aria-hidden.md | 17 - .../10179-formpage-shared-field-resolver.md | 16 - .changeset/10179-textfield-maxlength.md | 7 - .changeset/10180-wizard-next-keeps-upload.md | 38 - .../10183-date-only-shared-parse-step.md | 22 - ...ord-verdict-memo-forgets-changed-record.md | 46 - .changeset/10186-related-list-fls-select.md | 48 - .../10188-app-shell-doc-menu-audience.md | 21 - .changeset/10188-console-docs-direct-route.md | 19 - .changeset/10188-doc-markdown-editor.md | 29 - .changeset/10188-layout-doc-target-guard.md | 17 - .../10190-drawerform-first-load-window.md | 17 - .../10193-language-reset-on-owner-change.md | 33 - .../10199-related-list-filter-rule-array.md | 34 - .changeset/10207-package-version-from-spec.md | 5 - .../10209-readonly-view-menus-not-empty.md | 19 - .changeset/10210-overlay-marker-only.md | 19 - .changeset/10210-view-config-save-envelope.md | 30 - ...11-connector-refinement-behavioural-pin.md | 4 - .../10220-format-hint-not-date-pattern.md | 23 - .../10221-currency-decimals-iso-minor-unit.md | 56 - .../10222-retire-timeline-metafields-reads.md | 22 - .changeset/10223-lookup-candidates-expand.md | 42 - .../10224-quick-actions-permissions-text.md | 19 - .../10226-image-upload-failure-reported.md | 18 - .changeset/10232-display-locale-faces.md | 20 - ...nslation-bundle-recognised-by-any-group.md | 29 - .changeset/10242-ru-ar-count-labels.md | 39 - .../10247-retire-async-export-job-path.md | 48 - ...10250-self-querying-views-toolbar-state.md | 26 - ...0254-sections-customfields-drawer-modal.md | 29 - .../10257-dataset-filter-read-half-holds.md | 44 - .changeset/10274-action-icon-auto-trigger.md | 23 - .../10275-listview-fls-emptied-select.md | 15 - ...-currency-fraction-digits-not-precision.md | 36 - ...77-harvest-defaultfromrow-target-tokens.md | 34 - .../10280-slider-tooltip-single-or-list.md | 29 - .changeset/10286-mirror-groups-cd-settled.md | 43 - .../10287-navigation-designer-doc-type.md | 21 - .../10288-config-bag-data-object-source.md | 20 - .changeset/10289-action-params-properties.md | 55 - ...10290-container-member-params-evaluated.md | 39 - .changeset/10291-cleared-scalar-saves-null.md | 37 - .changeset/10293-calendar-date-values.md | 9 - .changeset/10295-tooltip-content-is-text.md | 27 - ...296-detail-view-field-options-authoring.md | 37 - .../10301-refuse-impossible-datetime-day.md | 12 - .changeset/10304-calendar-selection-modes.md | 9 - ...10321-named-view-kanban-groupby-refused.md | 70 - ...0326-toolbar-search-withheld-tree-chart.md | 21 - .changeset/10327-dataset-chart-view-filter.md | 32 - ...330-ai-recommendations-carousel-retired.md | 24 - .../10331-console-dates-display-locale.md | 13 - ...0334-dashboard-daterange-spec-authoring.md | 28 - .../10337-widget-input-serializer-key-list.md | 14 - .changeset/10339-daterange-spec-default.md | 15 - .changeset/10343-lookup-option-label-order.md | 39 - .../10345-action-bar-menu-group-placement.md | 31 - .../10354-grid-fixed-currency-cell-footer.md | 32 - .changeset/10355-grid-currency-minor-unit.md | 51 - .changeset/10356-metric-count-not-currency.md | 22 - ...0360-titleformat-dedupe-rendered-fields.md | 32 - .../10367-required-marker-three-forms.md | 40 - .changeset/10368-required-marker-real-span.md | 13 - .../10370-listview-map-location-select.md | 26 - .changeset/10373-fields-display-fls.md | 48 - ...-comment-and-inbox-dates-display-locale.md | 19 - .../10377-calendar-designer-mode-enum.md | 5 - .changeset/10379-favicon-one-writer.md | 26 - .../10380-object-page-stored-options-bag.md | 12 - .../10382-provider-late-bundle-rerender.md | 50 - .../10383-object-view-grid-delete-deletes.md | 15 - .changeset/10383-record-delete-core.md | 11 - .changeset/10384-pager-clamp-after-write.md | 5 - .../10387-header-bar-unread-keys-retired.md | 37 - ...10392-registration-record-source-inputs.md | 45 - .changeset/10393-retire-bare-map-key.md | 80 - .../10396-missing-series-key-refusal.md | 27 - .changeset/10397-header-bar-classname.md | 38 - ...399-record-picker-limit-precedence-text.md | 11 - .../10404-undo-absent-field-not-null.md | 35 - ...22-currency-mode-dynamic-tenant-default.md | 33 - .../10423-mobile-card-field-currency.md | 14 - .changeset/10425-ru-ar-count-labels.md | 40 - .changeset/10432-reseed-purge-error-code.md | 23 - .changeset/10433-peoplepicker-fls-outputs.md | 30 - .changeset/10434-record-title-fls.md | 38 - .changeset/10435-select-label-association.md | 20 - .../10437-retire-default-upgrade-url.md | 21 - .changeset/10439-storage-usage-banner.md | 29 - .changeset/10442-date-faces-display-locale.md | 21 - .changeset/10447-one-title-interpolator.md | 19 - ...48-designer-invalid-not-published-flags.md | 22 - .../10456-objectmap-description-lookup.md | 28 - .../10462-action-entry-object-params.md | 25 - .../10463-dashboard-field-currency-config.md | 30 - .../10466-inline-edit-draft-read-rule.md | 19 - ...10471-tombstone-names-resolved-spelling.md | 25 - .../10472-formpage-widget-degrades-to-type.md | 19 - .../10474-datetime-editor-impossible-day.md | 21 - .../10475-default-arm-section-builder.md | 38 - ...78-filter-condition-value-protocol-rule.md | 44 - .changeset/10482-page-preview-reads-type.md | 13 - ...10485-detail-section-declares-hideempty.md | 42 - .../10486-picker-column-display-name.md | 42 - ...87-lookup-hydrated-label-follows-schema.md | 25 - .changeset/10493-data-uri-no-file-name.md | 25 - .changeset/10496-header-bar-root-dom-props.md | 34 - .changeset/10499-page-header-title-fls.md | 34 - .changeset/10500-search-labels-read-gate.md | 33 - .changeset/10501-lookup-cell-read-gate.md | 30 - .changeset/10506-named-view-context-tokens.md | 53 - .../10512-dataset-chart-applied-filter.md | 22 - .changeset/10516-xaxis-presentation-gate.md | 28 - .../10518-object-chart-y-axis-declared.md | 51 - .changeset/10519-pageview-refresh-in-place.md | 39 - .changeset/10520-orphaned-console-pages.md | 15 - .changeset/10524-check-promise-text.md | 29 - .changeset/10528-grid-object-table-fetch.md | 37 - .changeset/10530-timeline-lookup-display.md | 28 - .changeset/10535-person-name-read-gate.md | 31 - .../10537-simulator-assignment-envelope.md | 31 - .changeset/10538-cel-macro-bound-variable.md | 7 - .../10545-filter-candidates-displayfield.md | 38 - .changeset/10559-picked-lookup-relabels.md | 23 - .changeset/10563-form-arms-write-payload.md | 21 - .../10564-master-detail-child-baseline.md | 20 - .changeset/10565-occ-token-after-save.md | 17 - .changeset/10567-date-only-impossible-day.md | 21 - ...-app-shell-external-refresh-same-commit.md | 5 - ...-plugin-calendar-reads-invalidation-bus.md | 5 - ...plugin-dashboard-reads-invalidation-bus.md | 5 - ...0572-plugin-form-reads-invalidation-bus.md | 5 - ...72-plugin-kanban-reads-invalidation-bus.md | 5 - ...0572-plugin-list-reads-invalidation-bus.md | 5 - .changeset/10578-gantt-error-clears.md | 25 - ...10580-refresh-indicator-translated-name.md | 18 - .../10582-retire-column-width-config.md | 38 - .changeset/10583-masked-cell-copy.md | 71 - .../10584-object-chart-series-describe.md | 30 - .changeset/10585-hook-object-roster-state.md | 34 - .changeset/10586-inspector-strings-i18n-2.md | 23 - .changeset/10586-inspector-strings-i18n.md | 19 - .changeset/10587-xaxis-position.md | 30 - .../10591-tool-preview-api-console-link.md | 11 - .../10594-field-read-rule-core-export.md | 18 - ...94-record-picker-shared-field-read-rule.md | 7 - .../10607-grid-list-filter-context-tokens.md | 40 - ...8-object-chart-legacy-axis-keys-retired.md | 45 - .../10611-filter-ui-operator-retired.md | 38 - .changeset/10612-form-arms-managed-lock.md | 16 - .changeset/10614-file-name-bare-percent.md | 23 - .changeset/10615-simulator-cel-guards.md | 59 - ...ew-handler-event-names-through-renderer.md | 30 - .../10623-readers-follow-invalidation-bus.md | 15 - .changeset/10625-core-native-date-adapters.md | 5 - .changeset/10625-data-table-impossible-day.md | 5 - .../10625-fields-native-date-reexport.md | 5 - .../10625-inline-date-impossible-day.md | 5 - .../10631-master-detail-save-in-flight.md | 21 - .changeset/10633-gantt-silent-overtake.md | 25 - ...34-objectchart-groupby-category-forward.md | 31 - .../10636-objectview-record-count-singular.md | 30 - .changeset/10637-image-alt-translated.md | 17 - .../10638-interface-page-view-field-keys.md | 25 - .changeset/10639-readonly-password-empty.md | 19 - .changeset/10640-agent-preview-chat-link.md | 9 - ...api-console-preset-lazy-route-readiness.md | 4 - .changeset/10654-yaxis-position-honoured.md | 48 - .../10657-components-masked-client-paths.md | 37 - ...0657-fields-masked-cell-renderer-export.md | 19 - ...0657-plugin-dashboard-masked-data-table.md | 25 - .../10657-plugin-dashboard-withheld-draw.md | 29 - ...10657-plugin-detail-masked-related-list.md | 30 - .../10657-plugin-detail-withheld-draw.md | 26 - .../10657-plugin-grid-masked-client-paths.md | 19 - .../10657-plugin-grid-withheld-first-paint.md | 39 - .../10657-plugin-list-grid-object-fields.md | 14 - .changeset/10657-types-masked-doc.md | 13 - .changeset/10657-types-withheld-doc.md | 15 - .../10659-modalform-first-load-window.md | 18 - .../10662-onviewchange-reference-row.md | 21 - .changeset/10663-calendar-error-clears.md | 26 - .changeset/10663-kanban-error-clears.md | 22 - .changeset/10663-timeline-error-clears.md | 24 - .changeset/10664-data-table-filter-bar.md | 8 - .changeset/10664-map-reads-once.md | 7 - .changeset/10664-object-view-table-sort.md | 7 - .changeset/10664-repeater-picker-sort-key.md | 7 - .changeset/10666-filter-token-sweep.md | 33 - .../10666-gallery-filter-context-tokens.md | 7 - ...68-calendar-quick-create-display-locale.md | 11 - .../10668-gantt-timeline-display-locale.md | 13 - ...ome-inbox-relative-times-display-locale.md | 12 - .../10668-i18n-gantt-binding-premise.md | 4 - .changeset/10682-form-error-clears-2.md | 16 - .changeset/10682-form-error-clears.md | 30 - .../10684-reference-rail-superseded-parent.md | 16 - ...0684-report-attachments-superseded-read.md | 18 - .changeset/10684-timeline-superseded-rows.md | 16 - .changeset/10685-drilldown-per-block.md | 79 - .../10689-grid-harvest-inputs-refetch.md | 7 - .../10689-list-harvest-inputs-refetch.md | 7 - .changeset/10690-related-list-reads-once.md | 7 - .changeset/10691-third-yaxis-note.md | 26 - .changeset/10692-debug-run-routing-parity.md | 66 - .../10694-empty-columns-no-projection.md | 36 - ...6-inspector-literals-read-existing-keys.md | 39 - .../10701-agenda-retirement-citations.md | 17 - ...-fields-record-query-cannot-query-reset.md | 25 - ...10712-fields-record-query-latest-answer.md | 18 - ...2-plugin-form-line-items-superseded-run.md | 36 - ...10712-plugin-form-superseded-read-guard.md | 27 - .../10715-form-arms-read-invalidation-bus.md | 28 - .../10719-retire-phase35-validation-types.md | 39 - .changeset/10720-grid-columns-docs.md | 8 - .changeset/10721-scatter-yaxis-note.md | 28 - .changeset/10722-date-fns-display-locale.md | 37 - .changeset/10726-wizard-swap-loading.md | 23 - .changeset/10727-context-menu-sortable.md | 18 - ...-detail-related-list-masked-filter-sort.md | 49 - .../10731-console-map-mock-bare-specifier.md | 10 - .changeset/10735-html-tier-manifest.md | 51 - ...0740-line-items-held-for-another-parent.md | 24 - .../10743-studio-screen-visiblewhen-live.md | 78 - .../10746-joined-report-clears-binding.md | 38 - .changeset/10747-calendar-locale-tag.md | 24 - .changeset/10747-calendar-popover-locale.md | 18 - .../10748-inspector-words-gain-zh-rows.md | 41 - .changeset/10756-html-tier-code-element.md | 51 - .changeset/10757-div-deprecated-html-tier.md | 49 - .../10758-named-view-protocol-members.md | 18 - .changeset/10765-draft-merge-deletion.md | 25 - ...767-value-data-source-rule-array-filter.md | 35 - .../10770-object-chart-react-tier-node.md | 33 - .changeset/10771-dead-citation-sweep.md | 17 - .../10771-write-guard-message-citation.md | 14 - .../10772-inline-screen-visiblewhen-cell.md | 33 - .changeset/10778-dashboard-bus-readers.md | 34 - .changeset/10778-tree-bus-reader.md | 18 - .../10783-grid-currency-scale-not-read.md | 29 - .changeset/10785-avatar-submits-file-id.md | 17 - .changeset/10785-avatar-upload-gates.md | 8 - ...8-empty-operator-map-beside-key-refused.md | 39 - .../10789-render-time-filter-refusals.md | 42 - .../10790-empty-operators-accepted-shape.md | 30 - .changeset/10799-calendar-default-month.md | 34 - .../10803-dead-citation-sweep-eighth-batch.md | 18 - .../10803-dead-citation-sweep-fifth-batch.md | 23 - .../10803-dead-citation-sweep-fourth-batch.md | 21 - .../10803-dead-citation-sweep-second-batch.md | 20 - ...10803-dead-citation-sweep-seventh-batch.md | 23 - .../10803-dead-citation-sweep-sixth-batch.md | 24 - .../10803-dead-citation-sweep-third-batch.md | 20 - .changeset/10803-describe-string-citations.md | 19 - .../10803-fifth-batch-runtime-strings.md | 28 - .../10803-fourth-batch-runtime-strings.md | 23 - .../10803-seventh-batch-runtime-strings.md | 17 - .../10803-sixth-batch-runtime-strings.md | 14 - .../10803-third-batch-runtime-strings.md | 30 - .changeset/10804-designer-notes-locale.md | 25 - .../10813-dataset-filter-empty-operator.md | 13 - .../10813-filter-condition-empty-operator.md | 20 - .changeset/10813-list-view-empty-operator.md | 9 - .../10814-report-line-items-bus-readers.md | 37 - .../10815-dashboard-block-ambient-source.md | 23 - .changeset/10816-tree-keeps-rows-on-reread.md | 18 - .../10817-value-source-empty-operator-map.md | 49 - .../10824-timeline-readme-schema-node.md | 20 - .../10825-filter-builder-value-group-only.md | 17 - .../10827-app-branding-logo-one-spelling.md | 43 - .../10829-value-source-date-comparand.md | 47 - ...0835-dashboard-preview-debug-run-locale.md | 26 - .changeset/10841-timeline-root-dom-props.md | 37 - .changeset/10842-wizard-app-declared-keys.md | 39 - .../10843-dashboard-custom-range-reopen.md | 24 - .changeset/10844-date-only-zone-closure.md | 36 - .../10847-dashboard-strip-i18n-title.md | 22 - .../10848-designer-preview-chrome-locale.md | 23 - .../10853-master-detail-picker-bus-readers.md | 31 - .changeset/10859-ai-node-zod-arms.md | 25 - .changeset/10859-console-phase-2b-stubs.md | 15 - .changeset/10859-console-phase-2c-stubs.md | 13 - .changeset/10859-console-tree-stub.md | 13 - .changeset/10859-dashboard-node-keys.md | 24 - .changeset/10859-designer-zod-arms.md | 23 - .changeset/10859-known-types-phase-2b.md | 19 - .changeset/10859-known-types-phase-2c.md | 16 - .changeset/10859-known-types-phase-2d.md | 13 - .changeset/10859-known-types-retired-keys.md | 17 - .../10859-object-form-properties-bag.md | 30 - .../10859-object-gantt-properties-bag.md | 30 - .changeset/10859-object-map-properties-bag.md | 29 - .changeset/10859-object-timeline-zod-arm.md | 18 - .changeset/10859-page-header-placeholder.md | 13 - .../10859-pivot-object-block-zod-arms.md | 19 - ...0859-plugin-form-readme-object-form-bag.md | 7 - .../10859-plugin-gantt-properties-bag-docs.md | 7 - .../10859-plugin-map-properties-bag-docs.md | 8 - .changeset/10859-record-source-tree-alias.md | 13 - .../10859-retire-bare-field-fallbacks.md | 42 - .../10859-retire-chart-family-aliases.md | 17 - .changeset/10859-retire-designer-node-keys.md | 16 - .changeset/10859-retire-form-analytics.md | 13 - .changeset/10859-retire-import-wizard.md | 13 - .changeset/10859-retire-page-header-layout.md | 23 - .changeset/10859-retire-related-list.md | 13 - .changeset/10859-retire-scatter-chart.md | 20 - .changeset/10859-retire-shared-view-link.md | 13 - .changeset/10859-retire-sidebar-parts.md | 18 - .changeset/10859-retire-tree-alias.md | 15 - .changeset/10859-retire-view-alias.md | 15 - ...10859-sidebar-node-provider-collapsible.md | 9 - .../10862-designer-admin-previews-locale.md | 28 - ...862-designer-automation-previews-locale.md | 29 - ...62-designer-federation-flow-stub-locale.md | 32 - ...62-designer-object-data-previews-locale.md | 28 - .changeset/10864-app-shell-spec-floor.md | 34 - .changeset/10866-calendar-dst-day-moves.md | 16 - .../10866-calendar-gantt-date-only-days.md | 16 - ...10866-gantt-axis-formula-day-arithmetic.md | 9 - .changeset/10866-gantt-move-end-days.md | 12 - .changeset/10866-gantt-zoned-dst-days.md | 11 - .../10866-timeline-charts-i18n-date-only.md | 13 - .changeset/10867-app-wizard-saves-spec-app.md | 25 - .changeset/10868-list-view-leftovers.md | 27 - .../10872-container-children-channel.md | 24 - .../10872-container-children-runtime-pin.md | 13 - .changeset/10872-element-number-arm.md | 18 - .../10872-envelope-responsive-styles.md | 16 - .../10872-flat-arm-responsive-styles.md | 22 - .changeset/10872-flat-props-refusal.md | 23 - .../10872-held-block-content-channels.md | 26 - .changeset/10872-held-public-block-arms.md | 28 - .changeset/10872-public-block-zod-arms.md | 29 - .changeset/10872-record-alert-body-remedy.md | 12 - .changeset/10872-record-line-items-arm.md | 17 - .changeset/10874-ai-node-faces-agree.md | 52 - .../10881-grouping-needs-header-query.md | 57 - .../10885-object-view-route2-named-grid.md | 19 - ...0885-object-view-route2-named-view-rest.md | 23 - ...887-dashboard-filter-options-bus-reader.md | 23 - .../10887-object-view-non-grid-bus-reader.md | 28 - .../10887-react-page-data-invalidation.md | 33 - ...93-signup-carries-verification-callback.md | 32 - .changeset/10894-app-edit-keeps-navigation.md | 18 - ...gin-detail-relatedlist-client-sort-gate.md | 9 - ...10899-assistant-fab-yields-to-open-dock.md | 15 - .../10899-chat-step-turns-no-empty-blocks.md | 19 - ...899-dataset-tile-read-refusal-no-access.md | 23 - ...0899-failed-comment-never-shown-as-sent.md | 20 - .../10899-failed-reaction-write-reverts.md | 21 - ...99-marketplace-update-is-higher-version.md | 19 - ...tudio-bridges-need-authoring-capability.md | 18 - .changeset/10900-zh-cn-leftovers.md | 46 - .changeset/10903-today-reference-day-rule.md | 6 - .changeset/10905-types-stale-docblocks.md | 20 - .changeset/10909-element-number-datasource.md | 20 - ...10916-joined-report-block-pin-two-specs.md | 9 - .changeset/10918-console-action-ctx-org.md | 26 - .changeset/10919-cloud-plan-status.md | 24 - .changeset/10925-plan-card-wait-stream.md | 23 - .../10926-dock-binds-build-thread-to-app.md | 21 - ...0928-content-channel-parser-tier-clause.md | 11 - .changeset/10929-action-aria-retired.md | 42 - .changeset/10932-pivot-drilldown-retired.md | 40 - .changeset/10935-master-detail-i18n-labels.md | 20 - .../10940-joined-report-block-from-spec.md | 15 - ...0946-expression-wire-slots-by-reference.md | 64 - .../10948-flow-inspector-required-keys.md | 22 - .../10951-element-number-no-object-state.md | 22 - .../10959-unknown-prop-parser-tier-clause.md | 9 - .../10963-codewidget-expression-envelope.md | 33 - .changeset/10964-matrix-report-chart.md | 14 - .changeset/10965-changes-card-wait-stream.md | 23 - .changeset/10969-console-zh-leftovers.md | 15 - .../10975-split-popover-create-surface.md | 9 - .changeset/10976-table-slot-relay.md | 55 - ...0981-silence-clause-parser-tier-closure.md | 12 - .changeset/10982-objectview-reread.md | 25 - .../10987-retire-list-view-tabs-fixture.md | 4 - .changeset/10993-batch2-i18nlabel-reads.md | 23 - .changeset/10993-batch3-grid-title.md | 14 - .changeset/10993-batch4-ts-face.md | 19 - .changeset/10993-object-form-i18nlabel.md | 23 - .changeset/10998-register-refusal-codes.md | 19 - .changeset/10999-wizard-form-chrome-i18n.md | 36 - .changeset/11000-closed-affordance-notice.md | 33 - .changeset/11001-record-delete-confirm.md | 18 - .changeset/11004-autorefresh-handler-ref.md | 25 - .changeset/11005-month-grid-calendar-days.md | 12 - .changeset/11007-check-prints-key.md | 27 - .changeset/11008-bind-base-prop.md | 14 - ...1009-protocol-readers-only-bind-warning.md | 4 - .../11011-project-setup-objectview-mount.md | 4 - .../11013-view-row-declared-spellings.md | 27 - .changeset/11015-page-surface-fallback.md | 9 - .changeset/11016-cross-repo-bare-citations.md | 34 - .changeset/11019-reaction-keep-ids.md | 26 - .../11021-grouped-grid-search-both-queries.md | 22 - .changeset/11021-listview-grouped-search.md | 27 - ...22-strict-widget-slot-registered-inputs.md | 19 - ...4-spec-gate-canonical-operator-fixtures.md | 4 - .changeset/11026-number-use-grouping.md | 42 - .changeset/11027-preview-display-keys.md | 13 - .../11028-connector-action-desc-refs.md | 18 - .changeset/11030-register-refusal-map.md | 20 - .../11035-reactions-comment-rows-only.md | 21 - ...11037-time-grid-move-keeps-event-length.md | 13 - .changeset/11039-form-chrome-i18n.md | 29 - .../11040-comment-mask-tracked-files.md | 4 - .changeset/11044-base-props-one-list.md | 21 - .changeset/11051-inline-aria-reader.md | 16 - .changeset/11054-flow-start-api-trigger.md | 24 - .../11056-undo-confirmation-toast-i18n.md | 12 - .changeset/11058-signin-refusal-map.md | 19 - .../11060-overnight-resize-true-edge.md | 23 - .changeset/11061-modal-close-button.md | 20 - .../11062-console-dashboard-auto-refresh.md | 11 - .../11067-drop-platform-event-trigger.md | 16 - .changeset/11068-grid-declared-keys.md | 53 - .changeset/11068-keyboard-navigation.md | 41 - .changeset/11068-object-grid-show-filters.md | 26 - .changeset/11068-row1-booking-17-6.md | 6 - .changeset/11070-dashboard-formula-round6.md | 29 - .changeset/11070-dashboard-keys-round11.md | 19 - .../11070-field-metadata-spec-spellings.md | 18 - ...11070-grid-columns-chart-binding-round7.md | 23 - .changeset/11070-grid-field-keys-round8.md | 33 - .changeset/11070-grid-form-face-round10.md | 20 - .changeset/11070-grid-sort-field-round9.md | 19 - .../11070-react-page-no-adapter-on-node.md | 28 - .changeset/11070-reference-to-round4.md | 39 - .changeset/11070-strict-face-read-keys.md | 15 - .changeset/11070-text-family-round5.md | 28 - .changeset/11071-form-chrome-remainder.md | 33 - .changeset/11073-objectstack-17-5-bump.md | 24 - .changeset/11075-every-node-declared-omit.md | 15 - .changeset/11079-timeline-one-axis.md | 10 - .../11080-undo-fallback-names-object.md | 13 - .changeset/11080-undo-redo-toasts-i18n.md | 12 - .changeset/11081-one-undo-listener.md | 24 - .changeset/11082-detail-undo-capture.md | 14 - .changeset/11083-block-nested-aria.md | 18 - .changeset/11083-nested-aria-family.md | 17 - .../11085-flow-edge-scope-source-outputs.md | 30 - .../11094-value-source-empty-operator.md | 13 - .../11097-dashboard-refresh-button-locale.md | 8 - .changeset/11100-app-preview-label-maps.md | 22 - .changeset/11101-vendor-chunk-initial-only.md | 16 - .../11105-grouped-grid-selects-field-names.md | 19 - .../11106-record-path-derived-stages.md | 11 - .../11112-timeline-gantt-inclusive-end.md | 11 - .changeset/11114-master-detail-fields-text.md | 9 - .changeset/11116-builtin-select-multiple.md | 5 - .../11117-datasource-objectname-waiver.md | 49 - ...117-registration-objectname-description.md | 16 - .changeset/11122-undo-lookup-id.md | 14 - ...24-automations-pillar-honours-read-only.md | 28 - .changeset/11128-app-nav-canvas-label-maps.md | 26 - .changeset/11131-line-items-chrome.md | 22 - .../11132-master-detail-totals-currency.md | 29 - ...136-interfaces-pillar-honours-read-only.md | 25 - .changeset/11140-multiselect-placeholder.md | 9 - .changeset/11141-gantt-inclusive-end.md | 15 - .../11144-inline-columns-sort-amount.md | 29 - .../11145-line-items-chrome-remainder.md | 38 - .changeset/11148-nav-inspector-label-map.md | 11 - .../11153-nav-deep-link-survives-mount.md | 25 - .changeset/11160-line-items-last-english.md | 27 - .../11161-dataset-picker-author-text.md | 29 - .changeset/11163-related-list-actions.md | 14 - ...166-page-header-breadcrumb-slot-retired.md | 23 - .../11167-nav-edit-closes-on-read-only.md | 24 - .../11168-action-family-published-inputs.md | 37 - .changeset/11168-action-group-type-retired.md | 21 - ...-calendar-navigation-opennewtab-wording.md | 7 - .../11168-designer-form-layout-options.md | 5 - .changeset/11168-element-family-inputs.md | 36 - ...68-kanban-navigation-opennewtab-wording.md | 7 - .changeset/11168-map-style-precedence.md | 9 - .changeset/11168-object-form-columns-label.md | 5 - .../11168-object-form-layout-two-values.md | 9 - .changeset/11168-object-gantt-inputs.md | 18 - .changeset/11168-object-map-inputs.md | 11 - .changeset/11168-object-timeline-inputs.md | 14 - .changeset/11168-object-tree-inputs.md | 17 - .../11168-timeline-navigation-wording.md | 18 - .changeset/11168-types-form-layout-mirrors.md | 11 - .changeset/11168-types-object-tree-mirror.md | 15 - .changeset/11168-ui-action-size.md | 7 - .changeset/11168-view-tabs-layout-values.md | 5 - ...73-retire-page-header-breadcrumb-toggle.md | 17 - .changeset/11181-app-label-i18n-resolver.md | 19 - .changeset/11182-action-menu-host-disabled.md | 23 - .../11183-action-node-properties-bag.md | 15 - .../11189-nav-autosave-flush-generation.md | 26 - .../11190-screen-preview-field-projection.md | 22 - .changeset/11195-feed-refused-read-state.md | 39 - .../11196-designer-nav-label-inherit.md | 34 - .../11196-slice2-surface-inspector-birth.md | 31 - .changeset/11197-doc-nav-entry.md | 41 - ...1198-app-composition-nav-label-optional.md | 4 - .../11199-rls-policy-label-description.md | 19 - .changeset/11201-nav-label-verbatim.md | 23 - .../11201-standard-nav-entries-label-less.md | 24 - .../11204-draft-autosave-in-flight-edit.md | 25 - .changeset/11206-computed-strip-wording.md | 26 - .../11211-layout-mobile-tab-resolvehref.md | 22 - .../11212-permission-gates-fail-closed.md | 32 - .changeset/11216-kanban-grouping-typed.md | 24 - .../11220-screen-select-placeholder-i18n.md | 19 - .../11223-nested-page-children-judged.md | 17 - .changeset/11227-object-grid-17-6-keys.md | 46 - .changeset/11227-types-spec-floor-17-6.md | 18 - .../11232-autosave-send-bound-to-target.md | 28 - .../11234-object-kanban-onquickadd-retired.md | 39 - .changeset/11242-disabled-legs-fail-closed.md | 29 - .../11244-related-toolbar-visible-gate.md | 22 - .../11245-book-sidebar-explicit-group.md | 18 - .../11251-schemaform-top-level-union.md | 29 - .changeset/11252-select-placeholders-i18n.md | 15 - .changeset/11253-choice-field-write-guard.md | 26 - .../11253-field-designer-choice-types.md | 16 - .../11254-gantt-number-resolved-width.md | 17 - .../11254-gantt-percent-resolved-width.md | 13 - .../11254-metric-tile-resolved-width.md | 30 - ...1254-mobile-card-percent-resolved-width.md | 12 - .../11254-number-cell-resolved-width.md | 16 - ...a-expressions-field-rule-submit-refusal.md | 11 - .../11261-dimensionless-measures-render.md | 29 - .changeset/11262-blank-gates-diagnosed.md | 46 - .../11270-record-related-row-placement.md | 16 - .../11272-buffer-bound-to-loaded-item.md | 22 - .../11276-core-flex-builder-properties-bag.md | 7 - .changeset/11276-flex-properties-bag.md | 28 - .../11276-object-chart-properties-bag.md | 31 - .../11276-object-grid-properties-bag.md | 38 - .../11276-plugin-grid-properties-bag-docs.md | 12 - .changeset/11281-rail-unbound-reason.md | 28 - .../11293-app-shell-page-record-navigator.md | 9 - .../11293-plugin-calendar-page-navigation.md | 7 - .../11293-plugin-kanban-page-navigation.md | 7 - .../11293-react-page-host-record-navigator.md | 9 - ...11294-components-row-menu-declared-gate.md | 31 - ...1294-plugin-grid-row-menu-declared-gate.md | 24 - .changeset/11295-app-shell-served-labels.md | 28 - .../11295-dashboard-served-localized.md | 29 - .../11299-app-shell-nav-label-locale.md | 13 - .changeset/11299-layout-nav-label-locale.md | 28 - .../11299-plugin-designer-nav-label-call.md | 16 - .../11299-types-nav-label-locale-map.md | 23 - ...2-app-shell-metadata-error-reader-moved.md | 5 - ...-data-objectstack-metadata-error-reader.md | 9 - ...gin-designer-fields-page-refusal-issues.md | 7 - .../11315-core-plugin-charts-no-release.md | 12 - ...-dashboard-chartconfig-structure-unread.md | 30 - ...-types-chartconfig-structure-tombstones.md | 46 - .../11318-page-width-padding-refusal.md | 28 - .changeset/11321-record-feed-host-slots.md | 26 - .../11322-bulk-bar-blank-visible-shown.md | 22 - .changeset/11322-bulk-def-visible-docblock.md | 11 - .../11322-core-docblocks-name-callers.md | 14 - .../11326-i18n-region-locale-fallback.md | 43 - .../11330-runner-retired-version-footer.md | 16 - .../11331-app-shell-cancelled-load-spinner.md | 24 - .changeset/11334-row3-booking-17-6.md | 4 - .changeset/11344-action-outcome-messages.md | 24 - .changeset/11347-components-uncast-reads.md | 37 - .changeset/11348-dashboard-widget-reads.md | 36 - .../11348-object-data-table-page-size.md | 23 - .../11349-schemarenderer-working-copy.md | 13 - .changeset/11354-plugin-form-literals.md | 8 - .changeset/11355-small-p1-sites-r2.md | 19 - .changeset/11355-small-p1-sites.md | 28 - .changeset/11357-page-save-drops-requires.md | 19 - .../11358-declared-gate-fails-closed.md | 34 - .changeset/11362-mobile-tab-bar-nav-guard.md | 24 - .../11363-app-face-refuses-mobile-nav-mode.md | 29 - .changeset/11364-public-block-ts-faces.md | 42 - .changeset/11365-input-otp-separator.md | 12 - .changeset/11366-create-plugin-jsdom-29.md | 19 - .../11368-datasource-editor-external-block.md | 31 - .../11372-core-retire-chart-axis-lowering.md | 13 - ...73-chartconfig-comment-sweep-no-release.md | 12 - .../11379-refused-save-reads-parsed-error.md | 25 - .changeset/11388-widget-layout-complete.md | 39 - .changeset/11395-mobile-tab-bar-order.md | 22 - .changeset/11402-dataset-blank-field.md | 11 - .changeset/11403-console-sdui-manifest.md | 11 - .changeset/11405-list-bind-only.md | 22 - ...-guides-data-table-bind-silence-clauses.md | 4 - .changeset/11415-ai-usage-five-hour-reset.md | 22 - ...dashboard-single-series-dropped-measure.md | 29 - .../11423-layout-guide-page-headings.md | 4 - .changeset/11424-container-padding-set.md | 27 - .changeset/11431-readonly-number-scale.md | 20 - .../11432-plural-categories-every-pack.md | 26 - .../11434-app-shell-relationships-note.md | 5 - .changeset/11434-designer-members-retired.md | 44 - .changeset/11434-designer-readers-types.md | 29 - .../11434-i18n-validation-rule-labels.md | 7 - .../11434-plugin-designer-readers-final.md | 34 - .changeset/11434-plugin-designer-readers.md | 21 - .../11434-plugin-designer-retired-props.md | 14 - .../11434-report-element-field-types.md | 29 - .changeset/11436-page-node-pagetype-sweep.md | 4 - .changeset/11438-objectstack-17-6-bump.md | 11 - .changeset/11440-arm-passing-types.md | 29 - .changeset/11440-console-spec-report-stub.md | 13 - .changeset/11440-drill-drawer-report-node.md | 18 - .changeset/11440-known-types-spec-report.md | 13 - .../11440-object-pivot-drilldown-input.md | 7 - .changeset/11440-report-node-wrapper.md | 15 - .changeset/11440-retire-spec-report.md | 16 - .../11441-known-types-retired-layout-keys.md | 20 - ...11441-retire-nav-responsive-grid-layout.md | 21 - .../11444-readonly-percent-currency-faces.md | 35 - .changeset/11445-app-shell-count-families.md | 5 - .../11445-collaboration-count-families.md | 5 - .changeset/11445-components-count-families.md | 5 - .changeset/11445-fields-count-families.md | 5 - .changeset/11445-i18n-count-families.md | 17 - .changeset/11445-plugin-ai-count-families.md | 5 - .../11445-plugin-detail-count-families.md | 5 - .../11445-plugin-gantt-count-families.md | 5 - .../11445-plugin-grid-count-families.md | 5 - .../11445-plugin-list-count-families.md | 5 - .../11445-plugin-view-count-families.md | 5 - .changeset/11448-json-field-face.md | 46 - .changeset/11450-generate-page-draws-title.md | 9 - .../11450-runner-dead-index-fallback.md | 7 - .../11455-approver-position-spelling.md | 27 - .../11459-dashboard-settled-legend-markup.md | 9 - ...64-sidebar-offcanvas-expanded-on-screen.md | 16 - .changeset/11465-sidebar-declared-surface.md | 35 - .changeset/11466-dashboard-metric-node.md | 9 - .../11466-envelope-object-metric-retired.md | 20 - .changeset/11466-node-slot-union.md | 44 - .changeset/11467-metric-card-arm-inputs.md | 19 - .changeset/11468-bag-carrier-node-types.md | 46 - ...tocol-breakpointcolumnmap-parenthetical.md | 14 - .changeset/11474-layout-spacing-sets.md | 42 - .changeset/11475-dashboard-percent-storage.md | 23 - .changeset/11475-detail-percent-storage.md | 11 - .changeset/11475-gantt-percent-storage.md | 8 - .changeset/11475-grid-percent-storage.md | 21 - .changeset/11475-list-percent-storage.md | 8 - .changeset/11475-percent-declared-storage.md | 64 - .changeset/11476-retire-generate-output.md | 15 - .../11478-anyschema-declared-node-types.md | 33 - .changeset/11479-producers-declared-types.md | 9 - .changeset/11483-metric-card-needs-value.md | 16 - .changeset/11488-retire-generate-from.md | 15 - .changeset/11491-grid-columns-set.md | 44 - ...1494-layout-app-schema-renderer-adapter.md | 13 - .../11494-types-app-schema-renderer-schema.md | 16 - .changeset/11496-retire-cli-add.md | 17 - ...1500-retire-cli-create-lint-test-studio.md | 24 - ...503-project-setup-cli-table-add-analyze.md | 11 - .changeset/11505-grid-flat-columns-retired.md | 34 - .../11506-drill-drawer-runtime-filter.md | 21 - .../11511-project-setup-retired-cli-rows.md | 4 - .changeset/11513-object-chart-families.md | 23 - ...514-app-shell-dashboard-preview-reorder.md | 5 - .../11514-dashboard-slot-entry-types.md | 19 - .../11514-designer-dashboard-entry-type.md | 5 - .changeset/11514-types-widget-arm-type.md | 12 - ...lugin-detail-readme-activity-properties.md | 7 - .../11515-types-ts-twins-zod-only-arms.md | 16 - .../11515-vscode-export-react-annotation.md | 11 - .changeset/11517-drill-report-name-retired.md | 20 - .../11520-object-chart-spectype-routing.md | 18 - .changeset/11521-chart-type-doc-row.md | 9 - .../11522-kanban-rule-dialect-retired.md | 45 - .changeset/11525-inline-metric-retired.md | 42 - ...26-object-metric-rule-filter-spec-shape.md | 51 - .../11530-object-chart-compareto-spectype.md | 14 - ...1533-grid-listview-rule-dialect-retired.md | 33 - .../11536-line-items-published-inputs.md | 29 - .../11539-form-only-from-served-default.md | 24 - .changeset/11541-detail-markdown-editor.md | 25 - .../11544-group-header-field-options.md | 21 - .../11547-drill-url-is-empty-operator.md | 15 - ...11550-fields-tolerated-teaching-dropped.md | 19 - .../11550-object-form-fields-names-only.md | 4 - .changeset/11553-studio-package-less-flows.md | 14 - .changeset/11562-detail-textarea-multiline.md | 21 - .../11572-interface-page-tree-chart-relay.md | 29 - .changeset/11574-grouping-switch-headers.md | 23 - ...11576-create-view-chart-dataset-binding.md | 29 - .changeset/11578-view-save-refusal-said.md | 19 - ...586-tailwind-source-none-console-runner.md | 17 - ...626-formview-section-style-keys-retired.md | 39 - .changeset/14026-list-import-mappings-pin.md | 6 - .changeset/1674-maker-single-composer.md | 31 - .../17147-plugin-disclosure-not-enforced.md | 12 - .../1984-v1-honest-chips-and-ui-fragments.md | 72 - .../3162-types-ledger-batch8-verdicts.md | 45 - .../3719-settings-valuedomain-combobox.md | 36 - .../3743-retire-system-hub-card-wall.md | 23 - .changeset/3880-es-done-listo.md | 30 - .changeset/3906-page-header-canonical-docs.md | 4 - .changeset/3909-query-params-filter-union.md | 38 - .../3917-retire-action-condition-branch.md | 49 - .changeset/3965-mint-box-neutral-container.md | 35 - ...91-builtin-select-empty-state-label-for.md | 41 - .changeset/4044-chartconfig-aria-tombstone.md | 32 - .../4191-autotrigger-honours-visible.md | 36 - ...202-action-renderers-forward-objectname.md | 31 - .changeset/4420-bulk-delete-visiblewhen.md | 34 - .changeset/4421-current-user-can-binding.md | 34 - .../4526-matrix-artifact-by-provenance.md | 21 - .changeset/4535-export-options-spec-parity.md | 41 - .../4631-component-surface-parity-gate.md | 17 - .../4664-related-list-declared-filter.md | 47 - .changeset/4695-no-series-binding-refusal.md | 18 - .../4730-objectview-config-keys-retired.md | 36 - .../4730-retire-dead-locale-key-batch.md | 50 - ...3-drawerform-shared-container-grid-cols.md | 21 - .changeset/4795-bindable-text-keys.md | 50 - .changeset/4795-check-bindable-text-keys.md | 35 - ...4830-app-shell-branding-rightrail-prose.md | 17 - .changeset/4850-misplaced-eslint-disable.md | 21 - .../4894-shared-registration-key-reader.md | 8 - .changeset/4895-retire-block-schema-family.md | 52 - .changeset/4905-inline-default-value-pin.md | 34 - .changeset/4918-stale-strip-mode-prose.md | 16 - .changeset/4919-retire-mobile-overrides.md | 46 - .../4929-plugin-published-stylesheets.md | 52 - .../4934-dropped-fields-reason-boundary.md | 60 - .../4935-element-filter-comment-residue.md | 8 - .changeset/4938-timeline-dead-example-link.md | 12 - .../4947-tombstone-judge-convergence.md | 11 - .changeset/4971-declared-arm-subset-gate.md | 28 - .../4991-lucide-pin-range-consistency.md | 8 - .../5034-navigateonsuccess-url-contract.md | 41 - .changeset/5106-doc-key-table-scan-surface.md | 11 - .../5120-retire-data-table-name-alias.md | 60 - .changeset/5157-object-map-config-strict.md | 36 - ...3-widget-ts-retired-spec-anchor-history.md | 46 - .changeset/5221-onsuccess-navigation.md | 38 - .changeset/5232-view-config-org-wide.md | 42 - .../5234-onnavigate-documented-exception.md | 34 - .changeset/5291-api-console-storage-slot.md | 24 - .changeset/5293-view-sort-order-spelling.md | 58 - .../5325-ineffective-dynamic-import-ledger.md | 19 - ...5397-release-pr-post-version-validation.md | 8 - .changeset/5422-coverage-lane-concurrency.md | 14 - .../5435-list-view-fold-output-authorable.md | 29 - .../5453-retire-grid-column-wrap-forward.md | 49 - .changeset/5458-unprefixed-query-params.md | 39 - .changeset/5483-5439-dts-config-wiring.md | 47 - .changeset/5490-per-chunk-eager-budgets.md | 21 - .changeset/5522-runtime-telemetry-consumer.md | 37 - ...tire-max-tool-roundtrips-plugin-chatbot.md | 23 - .../5605-retire-max-tool-roundtrips-types.md | 31 - .changeset/5631-ui-icon-icon-key-migration.md | 68 - .../5631-ui-icon-visible-placeholder.md | 25 - .../5632-sidebar-trigger-dom-passthrough.md | 39 - .changeset/5632-svg-host-dom-passthrough.md | 37 - .../5674-retire-plugin-component-input.md | 52 - .../5676-layered-envelope-boundary-parse.md | 39 - .changeset/5700-shared-ref-namespaces.md | 26 - .changeset/5729-column-sortability-signal.md | 44 - .../5733-changeset-presence-population.md | 18 - .changeset/5753-providers-drop-spec-dep.md | 28 - .changeset/5754-ci-runs-hook-selftests.md | 14 - .../5775-lane-changeset-reader-mirror.md | 12 - .changeset/5793-spec-range-floors.md | 28 - ...795-related-list-inherit-list-view-sort.md | 40 - .changeset/5817-remove-app-sidebar.md | 29 - .../5853-tablecolumn-type-canonical-union.md | 74 - .../5856-plugin-grid-catalog-entries.md | 26 - .../5859-retire-orphaned-object-exports.md | 45 - .changeset/5861-retire-table-defaultsort.md | 46 - .../5867-layout-plaintext-fences-batch5.md | 9 - .changeset/5867-plaintext-fenced-ts-batch1.md | 15 - .changeset/5867-plaintext-fenced-ts-batch2.md | 20 - .changeset/5867-plaintext-fenced-ts-batch3.md | 23 - .changeset/5867-plaintext-fenced-ts-batch4.md | 22 - .changeset/5867-plaintext-fenced-ts-batch7.md | 14 - .changeset/5867-plaintext-fenced-ts-batch8.md | 12 - .changeset/5869-runtime-features-scim.md | 15 - ...874-expandable-field-family-convergence.md | 44 - .changeset/5876-one-lookup-predicate.md | 34 - .../5896-feeditem-single-constructor.md | 48 - ...5902-marked-refusal-drag-write-surfaces.md | 25 - .changeset/5903-objectgantt-declared-keys.md | 55 - ...5905-componentinput-inputtype-tombstone.md | 64 - ...5-componentinput-retire-constraint-keys.md | 58 - ...record-path-stage-state-accessible-name.md | 22 - .../5920-flow-runner-translation-overlay.md | 40 - .changeset/5924-live-headroom-invariant.md | 31 - .changeset/5926-empty-action-visible-when.md | 45 - .../5927-zod-mirror-group-a-widenings.md | 47 - .../5928-classname-style-props-rename.md | 13 - .../5934-retire-onsuccess-callback-channel.md | 35 - .changeset/5935-one-icon-resolver-seam.md | 55 - ...936-registration-icon-meta-dead-surface.md | 23 - .changeset/5936-retired-icon-spellings.md | 35 - ...5940-detail-collection-decline-to-fetch.md | 20 - .../5942-retire-mobile-component-config.md | 73 - .../5944-preview-page-source-query-params.md | 9 - .changeset/5945-asarray-contract-envelope.md | 49 - .../5954-aggregate-capability-header.md | 10 - .../5956-5957-record-path-a11y-residue.md | 46 - .../5965-vscode-summary-codeql-claim.md | 25 - ...2-loading-group-per-language-uniformity.md | 40 - .changeset/5987-permset-clone-to-customize.md | 35 - .../5993-button-shared-icon-resolver.md | 64 - .../5996-eager-closure-missing-chunk.md | 19 - .../5998-record-path-one-classification.md | 32 - .../6001-drop-redundant-filter-casts.md | 28 - .changeset/6002-dashboard-widget-strict.md | 36 - .changeset/6004-grid-column-emit-boundary.md | 31 - .changeset/6011-tosortitems-order-spelling.md | 40 - .changeset/6014-tree-grid-field-formatting.md | 47 - .changeset/6023-recent-item-type-keys.md | 32 - ...6024-catalog-own-plugin-pin-generalized.md | 36 - ...025-declare-plugin-grid-in-gallery-host.md | 17 - ...6027-sidebar-tailwind-v4-spelling-guard.md | 24 - .changeset/6033-combobox-command-optional.md | 18 - ...6038-production-predicate-fault-warning.md | 70 - .changeset/6041-designer-reference-key.md | 44 - .../6043-retire-designer-formula-control.md | 59 - .changeset/6044-designer-system-key.md | 36 - .changeset/6045-field-payload-sort-order.md | 56 - .changeset/6050-gantt-navigation-basepath.md | 51 - .../6051-gantt-flat-config-declared-keys.md | 101 - .../6052-gantt-export-filename-i18nlabel.md | 23 - .../6058-zod-mirror-unmirrored-ledger.md | 8 - ...9-publish-omit-server-resolved-defaults.md | 36 - .../6063-kanban-resolvedisplay-dead-guard.md | 33 - ...67-component-meta-derive-from-canonical.md | 81 - .../6074-check-ts-stale-migration-comment.md | 21 - .../6075-check-validity-recogniser-recall.md | 32 - ...-release-lane-drop-changeset-prediction.md | 24 - ...9-hook-selftests-step-names-drop-counts.md | 16 - .changeset/6092-entry-guard-sweep.md | 4 - .changeset/6105-tombstone-refusal-message.md | 29 - .changeset/6108-sort-axis-convergence.md | 32 - ...6110-predicate-scope-unbound-evaluators.md | 59 - .changeset/6111-formsection-visiblewhen.md | 49 - .../6120-doc-snippet-dependency-resolution.md | 31 - .changeset/6121-report-authoring-face.md | 51 - .changeset/6121-retire-report-data-source.md | 48 - .changeset/6122-action-prop-renames.md | 29 - .changeset/6124-handler-keys-json-refusal.md | 15 - .../6124-view-handler-keys-are-event-names.md | 38 - .../6126-fields-unresolvable-imports.md | 34 - .changeset/6127-location-map-fence-split.md | 29 - .../6131-sidebar-nav-navgroup-annotation.md | 36 - .changeset/6132-undeclared-action-props.md | 59 - .../6138-fields-schema-block-parity-pr1.md | 50 - .../6138-fields-schema-block-parity-pr2.md | 59 - ...-field-metadata-rows-option-description.md | 57 - .../6143-components-schema-corrections.md | 38 - .../6150-undeclared-but-consumed-keys.md | 106 - .changeset/6151-stack-schema-omit-collapse.md | 66 - .../6152-object-form-unmirrored-members.md | 48 - .changeset/6152-objectgrid-round6-mirrored.md | 20 - .changeset/6152-unmirrored-round3.md | 54 - .changeset/6152-unmirrored-round4.md | 52 - .changeset/6152-unmirrored-round5.md | 42 - .changeset/6158-radio-group-orientation.md | 41 - .../6165-home-item-type-label-parity.md | 17 - .changeset/6166-zh-breadcrumb-reports.md | 34 - .../6167-plugin-form-catalog-entries.md | 31 - .../6169-chatbot-authoring-face-type.md | 60 - .changeset/6170-retire-timeline-dead-keys.md | 56 - .../6170-timeline-schema-declared-keys.md | 48 - .changeset/6172-kanban-trio-rename.md | 45 - .../6172-markdown-kanban-one-authority.md | 55 - .changeset/6175-column-state-persistence.md | 37 - .../6178-detail-section-header-color.md | 41 - .../6188-line-items-child-object-decline.md | 20 - ...90-record-details-heading-slot-converge.md | 41 - .../6194-line-items-row-fetch-decline.md | 28 - .changeset/6208-worktree-recipe-fetch-base.md | 25 - ...core-adapters-readme-owns-its-directory.md | 28 - .changeset/6223-object-payload-spec-keys.md | 54 - .changeset/6230-budget-comment-half-status.md | 29 - .changeset/6235-mergedsort-wrap.md | 47 - .changeset/6236-section-grouping-contract.md | 46 - ...237-section-predicate-layout-diagnostic.md | 39 - .changeset/6237-tabbed-arm-predicate-slot.md | 43 - .changeset/6237-tabbed-section-predicate.md | 36 - .changeset/6237-wizard-step-config-split.md | 35 - .changeset/6238-object-payload-enabled.md | 70 - .changeset/6240-object-payload-fields-map.md | 33 - .../6241-fieldgroups-section-heading-pin.md | 21 - .changeset/6246-action-param-carry-over.md | 28 - .../6247-option-visiblewhen-metadata-admin.md | 77 - .changeset/6250-toast-demo-shapes.md | 18 - .changeset/6252-page-header-action-ids.md | 35 - .../6262-form-features-scope-refused.md | 11 - .changeset/6269-objectview-slot-key-lists.md | 50 - .../6270-schemarenderer-scopeclass-memo.md | 26 - .changeset/6271-kanban-fetch-gate.md | 41 - .changeset/6272-locationfield-spec-shape.md | 45 - .changeset/6278-context-menu-item-icon.md | 9 - .changeset/6280-scan-surface-claims.md | 24 - ...6285-capability-labels-derive-from-spec.md | 26 - .../6286-explain-batch-cap-from-spec.md | 41 - .changeset/6287-flownode-description-key.md | 31 - .../6293-conditionbuilder-reference-value.md | 39 - ...296-conditionbuilder-subject-vocabulary.md | 60 - .../6298-componentconfig-one-authority.md | 32 - .../6301-packaged-automation-setup-page.md | 46 - .changeset/6302-aggregate-filter-lowering.md | 27 - .../6306-action-icon-type-resolution.md | 43 - .changeset/6307-bold-version-literals.md | 35 - .changeset/6308-living-workflow-example.md | 26 - .../6309-delete-object-fields-bridge.md | 28 - .../6310-designer-formula-key-retired.md | 38 - .changeset/6313-quick-reference-node-floor.md | 16 - .../6316-docs-route-eager-closure-gate.md | 15 - .changeset/6318-code-editor-bar-chart-zod.md | 20 - .changeset/6320-check-nested-dist-ignore.md | 24 - .../6321-changeset-guard-self-coverage.md | 7 - .changeset/6326-menubar-item-icon.md | 20 - .changeset/6329-actionparam-one-authority.md | 42 - .../6331-flow-node-label-producer-census.md | 27 - .changeset/6332-explain-request-adoption.md | 25 - .changeset/6335-starred-apps-nav-exclusion.md | 19 - .changeset/6336-changeset-overwrite-guard.md | 21 - .../6342-dead-migration-guide-pointers.md | 23 - .changeset/6347-button-group-schema-block.md | 82 - .changeset/6349-name-authority-batch-3.md | 43 - ...-types-internal-name-collisions-batch-1.md | 43 - ...-types-internal-name-collisions-batch-2.md | 39 - .../6353-timeline-bare-key-ownership.md | 35 - .../6355-retire-timeline-timescale-alias.md | 57 - .changeset/6356-timeline-item-element.md | 80 - .changeset/6357-basechema-bind-declaration.md | 44 - ...ster-detail-declined-detail-config-hint.md | 35 - .changeset/6361-spec-floor-17-2-0.md | 31 - .changeset/6369-dead-lockfile-merge-driver.md | 25 - .../6372-6371-master-detail-entry-identity.md | 57 - .changeset/6373-datatable-emit-boundary.md | 28 - .../6375-concurrent-update-subsumed-guard.md | 23 - .changeset/6378-boot-redirect-splash.md | 47 - .../6379-console-css-source-excludes-tests.md | 34 - .../6391-lockfile-merge-driver-measurement.md | 29 - .changeset/6392-vestigial-pnpm-steps.md | 13 - ...r-detail-underivable-detail-config-hint.md | 31 - .../6395-approvals-characterization-pins.md | 8 - .changeset/6396-previous-values-dom-leak.md | 27 - .../6397-partial-schema-collapse-pin.md | 58 - .changeset/6400-workflow-version-anchor.md | 30 - .../6405-fields-shared-stylesheet-builder.md | 25 - .changeset/6409-keyed-version-recogniser.md | 9 - .../6412-packaged-actions-activation.md | 56 - .changeset/6416-plugin-report-namespace.md | 57 - .changeset/6419-objectview-expand-gate.md | 32 - .../6421-concurrent-update-code-optional.md | 35 - .changeset/6424-dismantle-fitcontent-cast.md | 30 - .changeset/6424-retire-headericon-hold.md | 11 - .../6424-tablecolumn-declares-fitcontent.md | 43 - .../6424-tablecolumn-declares-headericon.md | 37 - .../6425-objectdatatable-column-holds.md | 16 - .changeset/6425-per-key-declare-retire.md | 32 - .../6426-dashboard-test-header-compiled.md | 32 - .changeset/6431-param-dialog-close-parity.md | 28 - .../6436-lockfile-merge-driver-ci-half.md | 25 - .../6442-catalog-blocks-claimant-list.md | 26 - .../6443-nav-visible-fault-diagnostic.md | 41 - .../6444-evaluator-fault-warn-dedupe.md | 24 - .../6445-disabled-gate-fault-diagnostic.md | 14 - .../6447-pnpm-ledger-manifest-anchor.md | 37 - ...48-ci-cd-pipeline-node-version-spelling.md | 25 - .changeset/6453-calendar-expand-gate.md | 29 - .changeset/6455-listview-sort-persist-leak.md | 32 - .changeset/6457-persisted-column-width-key.md | 31 - .../6458-retire-undeclared-column-reads.md | 34 - .../6459-grid-data-table-schema-slot.md | 28 - .../6460-objectview-fetch-view-identity.md | 30 - .changeset/6464-recall-submitter-gate.md | 61 - .changeset/6465-stale-typecheck-headers.md | 33 - .changeset/6467-unused-import-gate.md | 9 - .changeset/6469-gantt-block-precedence.md | 38 - .../6470-gantt-dependency-field-deprecated.md | 49 - .../6471-ganttconfigex-restatement-pin.md | 36 - ...-metadatatypeactions-param-dialog-close.md | 30 - .changeset/6475-gantt-block-face-declared.md | 67 - .../6477-buildconflict-narrowed-type.md | 16 - .changeset/6480-strip-read-decorations.md | 11 - .../6481-objecttree-keyed-schema-latch.md | 32 - .changeset/6487-visibility-advice-per-tier.md | 59 - .changeset/6488-carry-over-field-keys.md | 39 - .changeset/6489-designer-fields-map-keying.md | 32 - .changeset/6490-saveobject-fields-required.md | 42 - .../6493-bind-field-visibility-evaluators.md | 49 - .changeset/6496-toast-button-keys.md | 62 - .changeset/6497-retire-eventable-schema.md | 61 - .changeset/6499-inactive-values-retained.md | 35 - .changeset/6503-concealment-gate-copy.md | 29 - .../6504-disabled-gate-constant-predicate.md | 28 - .../6505-predicate-valued-gate-rules.md | 42 - .changeset/6507-boot-gate-redirect-splash.md | 32 - .../6514-field-visibility-declared-keys.md | 40 - ...515-record-form-current-user-normaliser.md | 28 - .changeset/6519-retired-field-key-strip.md | 46 - ...1-menubar-schema-block-declared-surface.md | 36 - .changeset/6522-objects-page-lookup-keying.md | 30 - .../6523-6346-menuitem-union-onclick.md | 49 - .changeset/6526-formula-422-diagnostic.md | 17 - ...27-retired-field-key-tombstone-registry.md | 26 - .../6528-resolve-reference-to-census.md | 39 - ...6530-plugin-map-marker-title-precedence.md | 53 - .changeset/6541-sonner-button-variant-enum.md | 43 - .changeset/6545-gate-population-census.md | 25 - .changeset/6547-flat-gantt-face-pointers.md | 43 - .changeset/6548-stale-test-name.md | 8 - .changeset/6551-signedin-user-id-required.md | 42 - .../6557-objectview-titlefield-middle-leg.md | 41 - ...8-remove-dead-console-record-title-copy.md | 7 - .../6559-expression-user-input-contract.md | 46 - ...6572-interfacelistpage-titlefield-prose.md | 11 - .changeset/6575-data-table-bind-diagnostic.md | 51 - .changeset/6576-widget-schema-anchors.md | 39 - .changeset/6577-bound-turbo-cache-save.md | 45 - .../6592-rekey-fetch-effects-on-primitives.md | 39 - .../6593-duplicate-package-envelope-unwrap.md | 33 - .changeset/6594-headercolor-mirror-enum.md | 61 - ...-retire-allowrestore-allowpurge-columns.md | 37 - .../6597-retire-fieldmeta-referenceto.md | 63 - .changeset/6598-inert-expression-warning.md | 26 - .../6598-listview-unauthored-columns.md | 41 - .changeset/6600-doc-gate-app-docs-roots.md | 10 - .../6605-permission-bulk-merge-not-replace.md | 14 - .../6609-declared-keys-header-honesty.md | 22 - .changeset/6610-ar-participle-orthography.md | 30 - .../6611-de-auth-device-passive-register.md | 25 - .changeset/6614-brace-literal-subset.md | 51 - .changeset/6617-in-path-right-diagnostic.md | 45 - .changeset/6620-escalation-enabled-default.md | 37 - .changeset/6625-retire-fieldmeta-decimals.md | 41 - .../6629-provision-env-nested-envelope.md | 31 - .../6634-record-title-step-numbering.md | 15 - .changeset/6639-objectgrid-title-mirrored.md | 19 - .changeset/6645-header-bar-crumb-icon.md | 42 - .../6646-breadcrumb-separator-max-items.md | 40 - .../6648-relationship-target-carriers.md | 52 - .../6650-listcolumn-wrap-implemented.md | 45 - .../6654-retire-preview-mode-consumption.md | 33 - .../6655-object-bound-gantt-refuse-loudly.md | 32 - .../6658-schema-persistence-callable-guard.md | 38 - .../6661-app-launcher-nav-menu-renderers.md | 60 - .../6664-location-optional-keys-carry.md | 27 - ...65-data-table-non-array-data-diagnostic.md | 45 - .../6674-registry-deprecation-declaration.md | 25 - .../6677-grid-host-fed-default-columns.md | 60 - ...-datasource-input-declaration-injection.md | 68 - .../6681-declared-lazy-marketplace-routes.md | 35 - .../6683-app-shell-side-effects-array.md | 35 - .changeset/6687-chatbot-surface-authorable.md | 56 - .changeset/6692-app-schema-menuitem-import.md | 25 - .../6694-dashboard-lookup-reference-meta.md | 61 - ...rekey-three-fetch-effects-on-primitives.md | 54 - ...700-objecttree-record-effect-primitives.md | 24 - .changeset/6703-dist-completeness-gate.md | 13 - .changeset/6705-parity-scan-reads-ast.md | 11 - ...props-bag-component-renderer-diagnostic.md | 59 - .changeset/6711-retire-reference-to-field.md | 42 - .changeset/6714-location-range-refusal.md | 43 - .../6715-location-strict-numeric-parse.md | 55 - .../6716-location-refusal-diagnostic.md | 26 - .changeset/6723-inline-data-fls.md | 54 - .../6724-usepermissions-stable-identity.md | 47 - .changeset/6726-find-envelope-records-arms.md | 63 - .../6730-shared-activity-type-bucket.md | 39 - .changeset/6740-flex-is-container.md | 42 - .../6744-location-stored-value-validation.md | 38 - ...45-schema-persistence-ref-during-render.md | 43 - .../6748-preview-mode-provenance-ratchet.md | 17 - .changeset/6750-gantt-empty-items-guard.md | 47 - .changeset/6751-flex-props-envelope-lift.md | 15 - .changeset/6752-degenerate-props-bag-guard.md | 33 - .changeset/6755-field-diagnostics-i18n.md | 28 - ...7-global-search-notifications-renderers.md | 38 - .changeset/6759-gantt-unusable-date-range.md | 22 - .../6760-degenerate-properties-hoist.md | 27 - .changeset/6761-one-config-bag-predicate.md | 22 - .../6764-container-declaration-census.md | 30 - .../6765-number-input-oracle-divergence.md | 47 - .changeset/6768-mock-import-original.md | 12 - .changeset/6770-gantt-null-date-refusal.md | 24 - .changeset/6771-body-dialect-census.md | 6 - .../6771-retire-body-child-list-dialect.md | 138 - .changeset/6773-aspect-ratio-demo-content.md | 28 - .../6776-metadata-admin-lazy-registration.md | 40 - .../6778-per-chunk-baseline-provenance.md | 28 - .../6780-number-input-badinput-announce.md | 40 - .changeset/6781-gantt-date-type-rule.md | 43 - .../6783-readprops-degenerate-config-bag.md | 12 - .changeset/6788-context-menu-demo-content.md | 28 - ...6790-record-alert-degenerate-config-bag.md | 9 - ...umber-widget-browser-deliverable-oracle.md | 7 - .changeset/6794-notify-submitter-default.md | 36 - .../6795-studio-design-consumer-states.md | 39 - .../6797-refs-during-render-three-hooks.md | 46 - .changeset/6799-authored-columns-fls.md | 66 - .changeset/6802-currency-tags-host-onblur.md | 27 - .changeset/6803-numberfield-error-slot.md | 21 - .changeset/6805-6806-catalog-authored-key.md | 13 - .../6809-browser-process-shim-source-only.md | 34 - ...16-activityfeed-unknown-kind-fails-open.md | 25 - .changeset/6817-usetagcache-config-alloc.md | 20 - .../6818-useoffline-auto-sync-stale-queue.md | 44 - .../6823-deprecation-guidance-agreement.md | 23 - .changeset/6824-chatbot-properties-scope.md | 25 - .../6825-aggregate-spec-shape-strict-where.md | 56 - .changeset/6829-badge-children-arm-a.md | 11 - .../6830-flownode-select-declared-default.md | 37 - .../6837-gantt-tree-referenceto-arms.md | 55 - .../6837-recorddrawer-invented-target-arms.md | 38 - .changeset/6837-reference-to-arm-deletion.md | 123 - .../6839-extract-records-records-arm.md | 56 - .../6840-queryresult-count-value-arms.md | 48 - .../6843-record-title-step-numbering-scan.md | 9 - .../6846-studio-design-empty-registry-pins.md | 10 - .../6848-geolocation-clear-emits-null.md | 35 - .../6854-layout-renderer-retired-onclick.md | 42 - .../6859-injected-editor-commit-comment.md | 21 - ...864-aggregate-spec-shape-analytics-keys.md | 50 - .changeset/6868-inline-edit-server-verdict.md | 44 - .changeset/6871-branding-token-docs.md | 37 - .../6872-app-shell-branding-title-jsdoc.md | 13 - .changeset/6874-retire-titleformat.md | 60 - .../6875-grid-relational-meta-derive.md | 35 - .changeset/6877-div-guidance-names-box.md | 25 - .changeset/6879-public-blocks-box.md | 9 - .changeset/6880-worktree-recipe-no-track.md | 22 - .changeset/6881-retire-data-table-toolbar.md | 60 - ...e-render-cell-editor-and-cell-classname.md | 56 - ...87-metadata-viewer-derive-select-option.md | 19 - .../6888-location-residue-refusal-keyed.md | 48 - .changeset/6896-retire-chart-inline-data.md | 83 - .changeset/6898-objectgrid-select-fls.md | 35 - .../6900-required-in-gated-section-refusal.md | 26 - .changeset/6906-hook-selftests-collector.md | 31 - .changeset/6907-gantt-date-spelling-rule.md | 46 - .../6909-fieldeditwidget-dom-pass-through.md | 60 - .../6910-retire-event-handlers-schema.md | 41 - .../6917-queryresult-value-count-arms.md | 55 - ...6921-cellclassname-cell-population-pins.md | 16 - .../6931-tombstone-guidance-remainder.md | 44 - .changeset/6938-checkbox-wrapper-class.md | 21 - ...lter-builder-catalog-operator-spellings.md | 17 - .changeset/6939-filter-builder-mirror.md | 111 - .changeset/6939-kanban-column-cards.md | 46 - .../6939-objectql-record-source-refinement.md | 39 - .changeset/6939-overlay-trigger-mirror.md | 35 - .changeset/6939-tree-view-nodes-mirror.md | 61 - .changeset/6940-rowactions-boolean-mirror.md | 36 - .../6943-fields-tooling-dirs-out-of-emit.md | 31 - .../6950-binding-framework-injected-input.md | 17 - .changeset/6951-text-value-retired.md | 78 - .changeset/6951-tree-view-data-retired.md | 78 - .changeset/6955-headercolor-authoring-enum.md | 40 - ...956-listview-export-options-spec-mirror.md | 62 - .../6956-plugin-list-export-options-casts.md | 17 - ...8-visiblewhen-clears-the-field-it-hides.md | 39 - .changeset/6959-gantt-lazy-read-flake.md | 28 - .changeset/6965-batch-publish-advisories.md | 34 - .../6972-markdown-inert-keys-retired.md | 115 - .changeset/6977-hook-remediation-no-track.md | 42 - .changeset/6980-save-gate-zod-advisory.md | 37 - .../6982-clientvalidation-stale-cures.md | 13 - .changeset/6985-wizard-card-r-alignment.md | 46 - .changeset/7004-cli-root-path-line.md | 27 - .changeset/7004-cli-union-arm-selection.md | 45 - .../7007-relatedlist-schema-chain-gate.md | 31 - .../7008-field-edit-widget-host-plumbing.md | 33 - ...7014-q1-tier1-select-option-convergence.md | 56 - .../7014-q2-option-label-empty-string.md | 26 - ...014-select-option-spec-claim-correction.md | 49 - .../7015-text-expression-content-channel.md | 12 - .changeset/7025-nonoptional-enum-cast.md | 20 - .changeset/7027-gantt-date-brand-gate.md | 32 - .../7028-analytics-rows-single-spelling.md | 16 - .../7029-no-invented-calendar-fields.md | 46 - .../7051-form-section-group-reference.md | 48 - .changeset/7063-widget-empty-state-default.md | 41 - .changeset/7064-empty-section-default.md | 71 - .changeset/7069-parity-wider-ledger.md | 6 - .../7070-no-invented-gantt-date-fields.md | 53 - .../7070-timeline-date-axis-floors-retired.md | 43 - .changeset/7072-catalog-menu-value-keys.md | 28 - ...7073-overlay-menu-docs-declared-surface.md | 49 - ...77-button-group-retire-authored-surface.md | 45 - .../7079-schema-reference-base-props.md | 32 - .changeset/7081-overlay-trigger-union.md | 11 - .../7082-overlay-node-slot-doc-type-names.md | 73 - .changeset/7083-richtext-field-metadata.md | 58 - .../7086-blockquoted-fence-collector.md | 32 - .changeset/7087-disabled-twin-symmetry.md | 35 - .../7088-hidden-jsdoc-single-hide-path.md | 34 - .changeset/7092-launcher-exclusion-reason.md | 17 - .changeset/7097-grid-2xl-breakpoint.md | 35 - ...7104-alert-dialog-read-dialect-declared.md | 41 - .../7105-empty-action-declared-schemanode.md | 42 - ...8-approvals-inbox-dead-record-tombstone.md | 28 - .changeset/7113-chart-data-model.md | 115 - .../7115-root-readme-doc-gate-surface.md | 19 - .../7121-studio-canvas-leaf-affordances.md | 31 - ...7122-capability-manage-org-presentation.md | 24 - .../7122-eager-closure-ceiling-raise.md | 50 - .changeset/7122-objectstack-family-17-3-0.md | 22 - .changeset/7122-postcss-dedupe.md | 19 - .../7122-spec-17-3-0-parity-reconciliation.md | 89 - .changeset/7122-spec-17-3-0-pin-repointing.md | 56 - .changeset/7122-spec-17-3-0-reconciliation.md | 25 - ...7125-dashboard-empty-state-keys-retired.md | 33 - .changeset/7126-inline-widgets-read-error.md | 41 - .../7127-record-details-refuses-not-strips.md | 10 - ...7129-retire-detailviewsection-hideempty.md | 81 - .changeset/7132-empty-state-role-default.md | 50 - .../7137-selection-expires-with-leaf.md | 34 - .changeset/7140-sankey-no-positive-flow.md | 36 - .../7142-activity-timeline-empty-i18n.md | 23 - .changeset/7143-data-error-state-migration.md | 58 - .changeset/7148-sankey-omitted-rows-note.md | 34 - ...49-activity-timeline-remaining-literals.md | 38 - .changeset/7151-legacy-retired-provenance.md | 6 - .../7154-lookup-picker-keys-editor-seam.md | 29 - .../7155-converge-lookup-dialect-camelcase.md | 55 - .changeset/7163-detail-timestamp-i18n.md | 42 - .../7164-gantt-malformed-row-refusal.md | 29 - .changeset/7165-grid-dependent-values.md | 39 - .../7166-retire-inert-fieldmeta-copies.md | 64 - .../7173-ai-pending-actions-inbox-i18n.md | 79 - .changeset/7175-downstream-consumer-census.md | 16 - ...studio-switcher-server-writable-verdict.md | 26 - .changeset/7178-format-measure-date.md | 45 - .changeset/7179-grid-grouping-projection.md | 38 - ...7181-body-dialect-producers-to-children.md | 58 - .../7182-declared-action-ids-one-rule.md | 52 - .changeset/7183-dist-vitest-project.md | 21 - .../7187-relational-copy-set-cell-scoped.md | 33 - .../7188-components-data-table-pending-row.md | 11 - ...lugin-grid-staged-parent-rescopes-child.md | 14 - ...88-types-render-cell-editor-pending-row.md | 24 - .../7189-grouped-grid-partial-disclosure.md | 81 - .changeset/7189-server-side-grid-grouping.md | 80 - .../7190-detail-dependson-lookup-probe.md | 27 - .../7190-detail-inline-dependent-values.md | 46 - ...2-retire-seven-unmounted-detail-exports.md | 62 - .changeset/7194-scatter-one-measure.md | 30 - .changeset/7195-no-numeric-value-refusal.md | 45 - .../7196-plugin-grid-held-key-census.md | 47 - .changeset/7199-listview-description-relay.md | 27 - ...ject-form-section-style-keys-undeclared.md | 36 - .changeset/7201-schema-slot-census-gate.md | 17 - .changeset/7203-gantt-toolbar-period-label.md | 33 - ...gantt-tasklist-width-and-date-predicate.md | 35 - .changeset/7206-dead-context-tail-comments.md | 26 - .changeset/7206-retire-dead-context-tail.md | 29 - ...chema-renderer-context-read-as-declared.md | 36 - .changeset/7210-gantt-paging-chrome.md | 32 - .changeset/7210-non-grid-row-ceiling.md | 49 - ...lished-tsconfig-tooling-exclude-ratchet.md | 41 - .changeset/7215-expand-fls-gate.md | 32 - .changeset/7216-listview-speculative-fls.md | 45 - .changeset/7217-grouping-null-entry-guard.md | 13 - .changeset/7218-rowcolor-host-relay.md | 39 - ...7219-retire-viewdescription-catalog-key.md | 47 - .changeset/7221-filter-dialect-equivalence.md | 4 - .changeset/7225-settled-schema-convergence.md | 51 - .../7228-gantt-column-width-flat-floor.md | 35 - .changeset/7230-expand-fls-gate-five-sites.md | 45 - .changeset/7231-gantt-stale-reload-finally.md | 22 - ...7234-requiredpermissions-author-channel.md | 36 - .../7235-html-tier-discriminator-attr.md | 36 - .changeset/7237-gantt-refresh-in-place.md | 14 - .../7237-stable-list-filter-identity.md | 17 - .changeset/7238-disabled-one-carrier.md | 14 - .changeset/7243-colorfield-shared-ladder.md | 49 - .../7245-default-view-namefield-lead.md | 50 - .../7248-scatter-legend-names-its-series.md | 31 - .../7252-form-outcome-toast-supersede.md | 28 - ...56-chrome-home-follows-declared-landing.md | 29 - .../7257-metadata-hmr-give-up-after-404.md | 30 - .../7258-chart-builtin-aggregate-label.md | 47 - .../7265-components-sort-direction-bound.md | 17 - .changeset/7265-core-context-token-mirrors.md | 16 - ...data-objectstack-filter-operator-rename.md | 27 - ...ugin-detail-record-alert-renderer-props.md | 18 - .../7265-types-user-filter-field-derives.md | 43 - .changeset/7271-localstorage-probe-node26.md | 15 - .../7279-object-view-split-route-pin.md | 7 - .../7281-record-header-title-width-floor.md | 33 - .../7282-console-docs-fragment-markers.md | 24 - .../7287-resolve-title-field-shared-ladder.md | 57 - .changeset/7292-turbo-owns-build-order.md | 26 - .changeset/7293-dataset-metric-subcaption.md | 31 - .changeset/7295-chat-message-avatar-keys.md | 43 - .changeset/7297-record-id-filter-token.md | 14 - .../7298-discussion-explicit-composition.md | 59 - .../7298-page-assignment-priority-read.md | 24 - ...7299-related-list-multivalue-membership.md | 29 - .../7303-kanban-swimlane-column-header-row.md | 32 - ...7308-doc-snippet-nested-package-readmes.md | 34 - .../7313-object-calendar-record-source.md | 42 - .../7316-toast-sonner-button-variant-input.md | 44 - .../7319-dead-schemarenderer-retired.md | 26 - .../7321-record-reach-sections-label.md | 9 - .../7322-object-kanban-component-props.md | 99 - .../7322-object-kanban-group-by-limit.md | 71 - .changeset/7323-adapter-factory-return.md | 79 - ...24-plugin-form-nameable-parameter-types.md | 46 - .changeset/7333-gantt-empty-host-data.md | 23 - .changeset/7334-gantt-navigation-forward.md | 49 - .../7337-i18n-covered-specifier-flip.md | 9 - .changeset/7337-vi-mock-i18n-inherit.md | 8 - .changeset/7340-docs-retired-handler-keys.md | 17 - .changeset/7344-handler-string-any-mirrors.md | 43 - .../7345-master-detail-outcome-toast.md | 25 - .../7347-padded-grouping-refused-pin.md | 14 - .changeset/7352-drill-down-config-mirror.md | 84 - .changeset/7353-retire-widget-dataprovider.md | 55 - .../7354-masterdetail-duplicate-refusal.md | 17 - .../7357-retire-field-metadata-depends-on.md | 64 - .changeset/7363-objectql-union-arms.md | 28 - .changeset/7364-timeline-nonobject-row.md | 13 - .../7368-studio-package-list-error-posture.md | 30 - .../7371-ai-usage-indicator-weekly-reset.md | 24 - ...overy-redirects-follow-declared-landing.md | 44 - .../7382-record-alert-cta-shared-resolver.md | 33 - .../7386-categorical-axis-min-tick-gap.md | 34 - .../7389-retire-use-client-notifications.md | 36 - .changeset/7390-gallery-host-ownership-pin.md | 8 - .../7394-listview-view-switch-refetch.md | 22 - ...tter-extreme-marks-stay-inside-the-plot.md | 36 - .../7397-remove-duplicate-chart-primitives.md | 50 - .changeset/7401-chart-family-from-type.md | 25 - .changeset/7402-scatter-ignores-compareto.md | 37 - .changeset/7415-action-type-input-rename.md | 71 - .../7421-gantt-tasklistwidth-tombstone.md | 22 - .changeset/7429-expand-fls-seven-sites.md | 61 - .../7435-declared-lookup-legs-two-readers.md | 34 - .../7435-remaining-declared-lookup-legs.md | 35 - .changeset/7439-approvals-teardown-race.md | 9 - .changeset/7443-datetime-compact-style.md | 41 - .../7450-element-text-published-variants.md | 14 - .changeset/7450-element-text-refusal-prose.md | 5 - .../7450-inspector-text-variant-options.md | 7 - .../7450-preview-sample-text-variant.md | 5 - .../7450-text-bare-key-resolution-pin.md | 6 - .changeset/7454-calendar-allday-spelling.md | 24 - .../7459-timeline-absent-date-axis-refusal.md | 52 - ...66-timeline-colorfieldladder-settlement.md | 7 - .changeset/7469-app-actions-retired.md | 46 - .../7470-designer-objectname-not-required.md | 26 - .../7472-cli-generated-layout-icon-seam.md | 33 - .../7477-listview-object-provider-fold.md | 44 - .changeset/7479-lazy-locale-catalogues.md | 90 - .changeset/7483-console-objectview-props.md | 34 - ...nput-retire-label-defaultvalue-advanced.md | 85 - .changeset/7495-compareto-one-predicate.md | 37 - .../7499-gantt-non-axis-floors-omitted.md | 57 - .changeset/7501-profile-my-language.md | 44 - .../7507-non-grid-ceiling-correctives.md | 24 - .changeset/7508-non-grid-ceiling-to-core.md | 37 - .../7509-dashboard-root-title-retired.md | 49 - ...9-dashboardview-title-comment-corrected.md | 27 - .changeset/7512-ganttview-unread-residues.md | 21 - .changeset/7515-unreferenced-source-gate.md | 21 - .changeset/7516-fieldorder-relay-rung.md | 18 - .../7519-retire-mobile-residue-types.md | 78 - .../7521-timeline-colorfieldladder-race.md | 24 - .../7530-predicate-envelope-declared.md | 18 - .../7531-listview-column-undeclared-reads.md | 20 - .changeset/7540-option-editor-key-loss.md | 18 - .../7544-listview-chart-capability-gate.md | 34 - .changeset/7546-chart-series-keys-declared.md | 86 - .../7547-forced-path-invented-bindings.md | 30 - .../7551-action-operation-update-executor.md | 50 - ...1-filter-builder-operator-trigger-label.md | 72 - ...7562-filter-field-type-fourteen-members.md | 40 - .changeset/7572-i18n-resources-deep-merge.md | 44 - .changeset/7578-classname-style-describe.md | 27 - .changeset/7579-relatedlist-value-gates.md | 4 - .../7580-responsive-vocabulary-rehome.md | 59 - .../7581-strict-authoring-face-measurement.md | 9 - .../7586-primary-field-consumer-reads.md | 41 - .changeset/7587-quota-reset-promise-pin.md | 10 - .../7588-assignment-value-cel-envelope.md | 27 - .changeset/7593-record-alert-success-icon.md | 33 - .../7597-field-inspector-value-domain.md | 26 - ...603-resource-edit-read-decoration-strip.md | 40 - .../7613-recipient-picker-field-kind.md | 53 - .../7614-flow-runs-parallel-branch-key.md | 11 - .../7615-field-api-name-follows-label.md | 27 - .changeset/7620-data-table-date-convention.md | 26 - ...retire-dashboard-root-title-declaration.md | 35 - .../7625-drop-recharts-from-components.md | 34 - .../7627-shared-record-source-reader.md | 43 - .../7632-shared-record-source-config.md | 53 - .changeset/7635-spec-173-comment-repairs.md | 18 - ...38-navigation-url-follows-record-source.md | 48 - .../7645-schema-registry-kanban-honesty.md | 69 - .../7650-id-field-published-guidance.md | 24 - ...etadata-item-reference-canonicalisation.md | 30 - .../7650-retired-dialect-choke-point.md | 62 - .../7654-chatbot-display-mode-tombstone.md | 123 - ...floating-chatbot-trigger-icon-tombstone.md | 74 - ...55-chatbot-registration-authoring-faces.md | 122 - .../7658-toc-code-span-anchor-parity.md | 29 - .changeset/7659-retire-validation-engine.md | 42 - .changeset/7664-kanban-arm-plugin-dialect.md | 107 - .../7664-plugin-kanban-declared-schema.md | 30 - .../7665-schema-registry-key-set-vs-values.md | 22 - .changeset/7667-toc-emphasis-flanking.md | 39 - .../7678-tombstone-discriminator-agreement.md | 45 - ...7681-chart-series-type-override-dataKey.md | 41 - .changeset/7687-combobox-option-disabled.md | 42 - .changeset/7690-chart-axis-config-declared.md | 32 - ...4-chart-series-chart-type-alias-refusal.md | 106 - .../7696-chart-local-select-cell-measured.md | 15 - .../7697-combobox-option-root-barrel.md | 26 - ...-series-opacity-dasharray-unconditional.md | 41 - .changeset/7699-file-submit-requires-id.md | 23 - .changeset/7702-union-arm-count-prose.md | 21 - .changeset/7703-chatbot-dark-keys-retired.md | 117 - .../7704-schema-registry-chatbot-keys.md | 42 - .../7707-flowrunner-refused-outcome-notice.md | 32 - .../7708-chatbot-floating-spread-fence.md | 34 - .changeset/7709-edit-mode-chip-sample-data.md | 24 - ...11-calendar-filter-is-not-a-config-slot.md | 49 - .../7712-kanban-calendar-filter-input.md | 41 - .../7714-lookup-draft-stays-client-side.md | 52 - .../7715-mirrors-carry-spec-object-checks.md | 19 - ...19-app-menu-item-shortcut-named-refusal.md | 44 - .changeset/7721-actions-reader-census.md | 25 - .changeset/7722-wrapper-class-five-more.md | 48 - ...727-conditional-formatting-record-scope.md | 143 - ...735-zod-mirrors-stop-authoring-defaults.md | 74 - .../7740-identity-import-saved-mappings.md | 33 - .../7741-list-import-mappings-discriminate.md | 45 - .changeset/7742-kanban-arm-batch70.md | 87 - .changeset/7744-chart-type-internal-only.md | 23 - .changeset/7745-formatdate-options-style.md | 33 - .../7747-datetime-format-cast-narrowing.md | 19 - .changeset/7750-retire-datascopemanager.md | 53 - .changeset/7752-analytics-where-lowering.md | 9 - ...59-dashboard-header-global-filters-spec.md | 68 - .changeset/7759-function-slot-keys-refusal.md | 16 - .../7760-lazy-mirror-input-type-args.md | 70 - ...-grid-export-options-bare-array-refusal.md | 75 - .changeset/7767-collapsible-trigger-union.md | 13 - ...7772-page-block-kanban-group-by-control.md | 47 - .../7773-kanban-adapter-groupfield-write.md | 56 - .../7780-object-kanban-record-source.md | 77 - .changeset/7786-storage-spy-counter-probes.md | 28 - .../7787-navigation-overlay-doc-example.md | 18 - .changeset/7791-specparity-cwd-root.md | 13 - .changeset/7798-getdataconfig-doc-example.md | 21 - .changeset/7799-cwd-rooted-package-tests.md | 23 - .../7804-data-table-handler-key-arms.md | 40 - .../7804-detail-handler-slots-declared.md | 45 - .../7804-list-view-handler-slots-declared.md | 71 - .../7804-object-kanban-handler-keys-judged.md | 44 - .changeset/7804-objectql-handler-key-arms.md | 69 - .changeset/7804-tree-view-handler-slot.md | 56 - ...-manage-refresh-failure-is-not-deletion.md | 29 - ...7823-objectview-chart-relay-whole-block.md | 38 - .../7828-calendar-gantt-ladder-harness.md | 19 - .changeset/7833-agents-verified-claim-rule.md | 8 - ...-vscode-export-react-side-effect-import.md | 25 - .changeset/7839-tree-arm-own-reference.md | 29 - .../7842-objectview-datasource-contract.md | 29 - ...unevaluated-diagnostic-lists-properties.md | 25 - .../7862-vscode-export-react-unused-import.md | 36 - .changeset/7867-action-params-templates.md | 39 - ...7874-timeline-relative-defaults-retired.md | 29 - ...876-activity-map-docs-transcription-pin.md | 7 - ...e-lookup-failure-is-not-an-empty-result.md | 27 - .../7895-timeline-settled-schema-gate.md | 47 - .../7903-gallery-settled-schema-gate.md | 56 - .../7907-manage-snapshot-refresh-reports.md | 31 - ...nput-retire-label-defaultvalue-advanced.md | 32 - ...912-schema-renderer-datasource-contract.md | 87 - ...port-breadcrumb-object-tree-zod-schemas.md | 24 - .changeset/7918-zod-lazy-getter-identity.md | 63 - ...3-schema-reference-named-list-view-keys.md | 10 - .changeset/7924-density-mode-through-fold.md | 47 - ...924-named-list-view-disposition-buckets.md | 43 - .../7924-named-list-view-liveness-census.md | 37 - .changeset/7924-named-list-view-retire.md | 82 - .changeset/7926-page-node-refuses-actions.md | 59 - .../7928-listviews-by-reference-fold.md | 69 - .changeset/7947-named-list-view-figures.md | 60 - .../7952-dashboard-widgets-component-arm.md | 15 - .../7963-alert-dialog-footer-keys-retired.md | 57 - .../7967-twin-count-pin-marker-strip.md | 10 - ...74-swipe-direction-honours-declared-set.md | 30 - .../7976-bind-documented-export-preamble.md | 8 - ...979-package-form-dialog-envelope-reader.md | 25 - .changeset/7980-agent-key-envelope-read.md | 32 - .changeset/7989-i18n-readme-locale-count.md | 24 - .../7997-detail-view-related-retired.md | 79 - .changeset/8012-fixture-discipline-heading.md | 8 - .../8018-covered-specifiers-membership-pin.md | 9 - .../8021-schema-rendering-data-context.md | 15 - .../8024-retire-permission-guard-config.md | 48 - ...026-objectcalendar-alldayfield-honoured.md | 43 - .../8031-tree-fixture-retired-target-key.md | 45 - .changeset/8033-homepage-fetch-router.md | 13 - .../8041-create-plugin-licence-prompt.md | 40 - ...055-geolocation-zero-coordinate-display.md | 36 - ...designer-lookup-target-retired-spelling.md | 23 - .../8067-component-input-member-kind.md | 54 - .../8068-mandatory-per-block-member-pin.md | 22 - ...069-field-rule-fault-direction-declared.md | 48 - .../8069-visiblewhen-fault-refuses-submit.md | 56 - .changeset/8070-name-visiblewhen-clear.md | 29 - .../8071-grid-toolbar-member-pins-slice-13.md | 15 - .../8071-master-detail-other-half-slice-18.md | 37 - ...aster-detail-seed-and-sections-slice-15.md | 35 - .../8071-object-form-member-pins-slice-10.md | 24 - .../8071-object-form-member-pins-slice-11.md | 20 - .changeset/8071-object-kanban-member-pins.md | 23 - .../8071-object-metric-query-member-pins.md | 10 - .../8072-input-wrapper-class-mirrored.md | 51 - .../8078-floating-chatbot-classname-merge.md | 39 - .../8083-record-presence-stub-array-shape.md | 12 - .changeset/8086-chart-series-type-arm.md | 20 - .changeset/8099-corepack-pnpm-download.md | 11 - .../8106-listview-callback-param-types.md | 45 - .../8114-detail-tab-activity-timeline.md | 63 - .../8130-tool-display-helpers-test-name.md | 10 - ...137-record-activity-calibration-repoint.md | 10 - .changeset/8140-combobox-schema-members.md | 64 - .../8148-number-badinput-refusal-keyed.md | 42 - .../8149-location-placeholder-localized.md | 31 - .changeset/8155-app-root-residue-swept.md | 36 - .changeset/8157-radar-series-presentation.md | 32 - .changeset/8165-translatefn-one-authority.md | 19 - .changeset/8166-record-scope-data-root.md | 58 - .../8167-conditionbuilder-mount-scope.md | 43 - .../8167-per-surface-condition-scope.md | 44 - .../8167-widget-context-condition-scope.md | 30 - ...bjectchart-absent-category-axis-refusal.md | 43 - .changeset/8169-map-refuses-unbound.md | 46 - ...ndar-refusal-names-an-actionable-remedy.md | 48 - .changeset/8171-calendar-sort-input.md | 80 - .../8174-kanban-calendar-filter-sort.md | 39 - .../8175-record-details-namefield-dedupe.md | 49 - ...178-ai-schemas-retire-zero-read-members.md | 80 - ...81-draft-envelope-read-decoration-strip.md | 43 - ...181-permission-door-read-decoration-pin.md | 8 - .../8187-dataset-preview-dimension-labels.md | 51 - .../8193-objectview-canonical-groupbyfield.md | 49 - .../8194-fields-date-widget-convention.md | 51 - ...198-unused-runtime-declarations-removed.md | 55 - ...1-kanban-calendar-scalar-authoring-keys.md | 16 - .changeset/8201-quickadd-ruled-carve-out.md | 16 - .../8204-refuseskind-invalid-type-decisive.md | 27 - .changeset/8209-datetime-widget-faces.md | 52 - .../8213-objectview-kanban-groupby-retired.md | 37 - .../8214-chatbot-anypart-state-widen.md | 30 - ...8-studio-property-panel-de-developerize.md | 43 - .changeset/8219-ai-chip-label-app-shell.md | 15 - .../8219-chatbot-surface-context-title.md | 11 - .../8219-lone-widget-one-canvas-frame.md | 18 - .../8219-studio-publish-no-draft-outline.md | 13 - .../8220-map-gantt-timeline-query-inputs.md | 56 - .changeset/8221-retire-legacy-string-sort.md | 56 - .../8225-drop-cloud-namespace-reexport.md | 28 - .../8231-machine-name-chip-source-label.md | 24 - .../8236-collapsible-open-intercept-retire.md | 49 - .changeset/8238-live-e2e-report-promise.md | 9 - .changeset/8253-export-tree-view-config.md | 77 - .../8254-objectview-spec-shaped-named-view.md | 53 - .changeset/8255-docs-spec-shaped-list-view.md | 15 - .changeset/8256-readme-kanban-example-pin.md | 8 - .changeset/8261-translatefn-i18n-authority.md | 27 - ...66-dashboard-count-aggregate-series-key.md | 39 - .../8268-testid-emitted-as-data-testid.md | 54 - .../8269-dashboard-category-axis-groupby.md | 45 - .changeset/8278-page-tabs-item-value.md | 49 - .../8279-definition-list-term-description.md | 42 - .changeset/8280-remove-ai-input-panel.md | 20 - .../8284-content-channel-per-component.md | 67 - .changeset/8284-refusal-and-notice-text.md | 23 - .../8285-kanban-quickadd-html-diagnostic.md | 30 - .../8285-object-kanban-quick-add-retired.md | 45 - .../8290-dashboard-reference-widget-keys.md | 4 - .../8291-workspace-admin-reads-the-rung.md | 38 - ...94-fields-readme-cell-renderer-two-step.md | 14 - .../8303-react-dep-peer-contradiction.md | 47 - .changeset/8307-kanban-lane-count-honesty.md | 43 - .../8308-kanban-card-title-one-precedence.md | 21 - .changeset/8310-page-node-body-arity.md | 40 - .../8313-kanban-structured-authoring-keys.md | 15 - ...4-calendar-record-source-authoring-keys.md | 10 - ...i-parser-manifest-binding-field-retired.md | 42 - .changeset/8317-strip-imported-defaults.md | 61 - .../8318-jsdoc-default-tag-corrections.md | 53 - ...8320-metadatacache-example-unimportable.md | 17 - .../8327-cast-read-census-ledger-header.md | 8 - .../8329-ai-build-empty-state-v1-boundary.md | 22 - ...-data-table-empty-action-primitive-node.md | 46 - .changeset/8333-lockfile-dedupe-gate.md | 13 - .changeset/8338-retire-toast-action.md | 88 - ...3-apply-blueprint-awaiting-confirmation.md | 27 - .../8344-node-recursion-point-redirect.md | 140 - ...345-strict-authoring-face-wrapper-kinds.md | 22 - .changeset/8345-strict-authoring-face.md | 30 - ...bject-gantt-judged-against-protocol-row.md | 6 - ...-object-map-judged-against-protocol-row.md | 6 - .../8348-object-tree-data-arm-view-data.md | 20 - ...348-record-source-data-arm-per-spec-row.md | 24 - ...dupe-emptiness-shares-header-definition.md | 48 - .changeset/8351-titleformat-hides-no-row.md | 40 - .../8355-retire-calendar-date-aliases.md | 222 - .../8365-stray-kanban-groupby-refused.md | 77 - .changeset/8366-vitest-timezone-pin.md | 7 - .../8376-detailsection-emptiness-authority.md | 52 - .../8385-bash32-floor-port-rationale.md | 27 - ...88-i18n-designer-table-retirement-sweep.md | 8 - .../8394-record-page-emptiness-authority.md | 58 - .changeset/8395-detail-copy-object-values.md | 34 - .../8397-emit-census-reader-manifest.md | 7 - .changeset/8400-kanban-name-field-skip-set.md | 34 - .../8408-public-form-title-description.md | 32 - .changeset/8411-flat-view-overlay-columns.md | 31 - .../8415-filter-builder-condition-id.md | 154 - .../8416-validate-schema-unknown-param.md | 35 - .../8420-ci-cd-pipeline-command-parity.md | 9 - .changeset/8420-four-section-parity-pins.md | 21 - .../8423-i18n-factory-abstention-pins.md | 12 - .changeset/8426-chat-parts-discriminated.md | 53 - .changeset/8429-page-view-residual-pin.md | 10 - .../8434-unresolved-user-reference-honesty.md | 38 - .changeset/8438-richtext-maxlength-visible.md | 48 - .changeset/8440-masked-field-copy-refusal.md | 26 - .changeset/8441-cell-count-labels-i18n.md | 32 - .../8442-chat-tool-approval-envelope.md | 59 - .changeset/8443-chatbot-runtime-role-fold.md | 36 - ...46-components-css-excludes-test-sources.md | 48 - ...valuedatasource-dollar-operator-refusal.md | 58 - .../8448-kanban-swimlane-scroll-sync.md | 35 - .changeset/8449-swimlane-vertical-scroll.md | 16 - .../8450-inspector-select-placeholder.md | 44 - .../8451-flownode-boolean-declared-default.md | 32 - .../8452-not-contains-non-string-value.md | 20 - .../8454-runner-stylesheet-source-set.md | 38 - .changeset/8458-parity-header-pairs-figure.md | 15 - .../8459-relatedlist-emptiness-agreement.md | 41 - .changeset/8464-summary-chip-object-value.md | 24 - .../8466-calendar-color-allday-fields.md | 68 - .../8474-empty-array-is-not-a-cell-value.md | 44 - .changeset/8478-describe-line-addresses.md | 25 - .changeset/8478-zod-pins-complex.md | 20 - .changeset/8478-zod-pins-form-layout.md | 24 - .../8481-empty-array-is-not-a-cell-value.md | 35 - .../8488-inspector-select-unknown-value.md | 34 - .../8490-fabricated-value-for-empty-array.md | 39 - ...491-8475-shared-empty-value-placeholder.md | 37 - .changeset/8496-emptiness-floor.md | 23 - .../8497-detail-section-group-and-labels.md | 37 - .../8498-any-component-union-discriminated.md | 33 - .changeset/8499-node-slot-registered-arms.md | 115 - .../8504-emptyvalue-remaining-carriers.md | 46 - .../8505-grid-columns-breakpoint-narrowing.md | 56 - ...-detail-placeholders-shared-empty-value.md | 30 - ...8-swimlane-container-aware-column-width.md | 28 - .changeset/8510-react-listview-spelling.md | 9 - .../8513-value-datasource-grouped-filters.md | 46 - ...16-8556-mirror-partial-record-narrowing.md | 66 - .changeset/8522-retire-use-column-widths.md | 33 - .changeset/8524-ai-usage-single-pool.md | 25 - .../8525-empty-container-override-friendly.md | 11 - .../8530-filter-converter-array-comparand.md | 35 - ...8532-kanban-contract-envelope-rows-wait.md | 10 - .changeset/8534-kanban-columns-same-commit.md | 30 - ...37-network-escape-guard-worker-coverage.md | 7 - .../8542-framework-chunk-attribution.md | 28 - .changeset/8554-sensitivity-floor.md | 17 - .../8555-filter-converter-date-comparand.md | 55 - .changeset/8557-view-filter-rule-arity.md | 45 - .../8558-data-objectstack-operator-table.md | 13 - .changeset/8561-e2e-artifact-name.md | 13 - .../8563-nav-target-exclusivity-chained.md | 42 - .../8567-filter-converter-exotic-comparand.md | 58 - ...retire-dollar-dialect-lowercase-aliases.md | 45 - .changeset/8570-inline-empty-markers.md | 31 - .changeset/8572-chatbot-body-retired.md | 127 - .../8580-rich-text-empty-array-and-object.md | 21 - .changeset/8581-date-cell-unparsable-value.md | 28 - .../8582-boolean-cell-non-boolean-scalar.md | 35 - .../8583-record-details-section-members.md | 20 - .../8593-booleanfield-readonly-non-boolean.md | 40 - .../8596-object-literal-cell-renderers.md | 40 - .../8598-zod-subpath-single-bundled-module.md | 56 - ...8603-record-details-hide-empty-restored.md | 18 - .../8604-record-details-columns-enum.md | 46 - .changeset/8613-metric-structured-groupby.md | 42 - .../8620-datapillar-test-empty-adapter.md | 9 - .../8621-retire-declared-divergence-note.md | 31 - .../8626-detail-section-authored-node.md | 48 - .../8628-aspect-ratio-uncurated-reason.md | 4 - ...approvals-unresolvable-record-reference.md | 44 - .../8632-malformed-picklist-option-loud.md | 47 - .changeset/8637-tab-title-one-writer.md | 32 - .changeset/8640-memo-identity-rule.md | 7 - .../8641-console-formpage-section-group.md | 51 - .../8648-ui-action-four-undeclared-keys.md | 66 - .../8649-detail-renderer-undeclared-keys.md | 96 - ...8649-record-block-field-security-triple.md | 43 - .../8650-chart-foreign-dialect-retired.md | 51 - .changeset/8652-kanban-calendar-navigation.md | 13 - ...view-title-retired-rowactiondefs-pinned.md | 54 - .changeset/8654-timeline-navigation.md | 33 - .../8655-object-tree-props-schema-typed.md | 67 - .changeset/8666-tree-expanded-derived.md | 33 - .changeset/8667-inbox-own-receipts-silent.md | 20 - .../8672-lookup-action-param-depends-on.md | 46 - ...okup-dependson-reachability-measurement.md | 35 - .changeset/8674-objectgrid-row-operations.md | 39 - .../8676-object-metadata-write-doors.md | 25 - .changeset/8677-signature-cell-value-class.md | 27 - .changeset/8678-value-independent-cells.md | 23 - .../8686-masked-field-type-authority.md | 34 - .../8688-provider-ctx-wait-alignment.md | 9 - .../8693-expand-fields-rendering-claim.md | 12 - ...-unresolved-lookup-reference-one-answer.md | 62 - .changeset/8696-hooks-per-file-pin.md | 8 - .../8705-listview-absence-settle-window.md | 10 - .changeset/8712-ratchet-vacuous-green.md | 12 - .../8714-test-tsconfig-parity-census.md | 11 - .changeset/8725-formsection-group-resolves.md | 20 - .../8729-summary-chip-accessible-name.md | 31 - .../8730-bulk-action-defs-unusable-member.md | 55 - .../8731-exportoptions-streaming-doc.md | 12 - .changeset/8734-cell-renderer-type-census.md | 31 - ...objectql-mirror-docblocks-not-defaulted.md | 14 - .changeset/8738-fields-warn-route1.md | 25 - .../8738-object-form-fields-description.md | 26 - .../8743-doc-example-internal-symbol.md | 7 - .changeset/8748-icontains-empty-comparand.md | 66 - .changeset/8754-dead-pack-keys-retired.md | 66 - ...dead-keys-one-hop-indirect-template-leg.md | 36 - .changeset/8755-bulk-lookup-depends-on.md | 46 - .changeset/8757-wire-check-doc-examples.md | 10 - .changeset/8760-unfulfilled-chart-stubs.md | 74 - .../8762-shorthand-input-type-refusal.md | 43 - .../8767-object-grid-refuses-string-sort.md | 66 - .changeset/8769-gantt-inline-query-keys.md | 48 - ...8770-true-identity-groups-no-constraint.md | 62 - .changeset/8772-objectstack-17-4-0-line.md | 43 - .../8774-filter-builder-doc-widening-pin.md | 25 - .../8775-sectioning-tags-ruled-reason.md | 4 - .../8778-create-plugin-no-copyright-header.md | 31 - ...8782-agent-key-keyless-success-sentence.md | 41 - .changeset/8784-arm-named-export-pin.md | 43 - .../8786-create-plugin-cancel-and-nontty.md | 35 - .../8793-related-list-identity-fail-closed.md | 36 - .changeset/8797-swimlane-axis-scroll-range.md | 19 - .changeset/8800-retire-ai-insights.md | 74 - ...01-object-kanban-allow-collapse-retired.md | 109 - ...257-8008-kanban-gantt-family-retirement.md | 181 - .changeset/8809-date-carrier-unparsable.md | 41 - .../8813-public-form-section-label-i18n.md | 45 - .../8816-i18n-locales-ceiling-provenance.md | 32 - .changeset/8818-strip-objectfields.md | 23 - .../8820-dashboard-auto-refresh-hook.md | 19 - ...26-kanban-cross-column-landing-position.md | 7 - .changeset/8827-kanban-empty-state-settled.md | 62 - .changeset/8830-calendar-doc-key-set.md | 14 - .../8831-calendar-flat-teaching-face.md | 13 - .changeset/8834-designer-table-parity-gate.md | 23 - .changeset/8841-tree-view-config-derive.md | 58 - ...8847-embeddable-form-fields-description.md | 20 - .../8854-app-shell-readme-flow-draft.md | 55 - .../8862-inspector-select-roster-pending.md | 53 - .../8871-page-node-refuses-breadcrumbs.md | 106 - .../8875-cross-file-line-citation-census.md | 33 - .../8883-reference-rail-parent-scope-arity.md | 35 - .changeset/8885-object-chart-block-props.md | 22 - ...-object-chart-drilldown-title-compareto.md | 19 - .../8889-dataset-subcaption-bundle-limb.md | 40 - .../8892-create-plugin-licence-refusal.md | 18 - .../8894-dashboard-measures-not-rendered.md | 37 - .../8894-designer-type-picker-measure-door.md | 15 - .changeset/8894-metric-family-door-pins.md | 12 - ...4-metric-tile-unrendered-measures-speak.md | 31 - .changeset/8897-installed-spec-pin-claims.md | 38 - .../8900-saved-views-unread-not-absent.md | 28 - .../8903-vi-mock-override-value-shape-gate.md | 13 - .changeset/8908-bridge-falsy-primitives.md | 57 - .changeset/8912-grid-children-items.md | 10 - .../8913-object-kanban-columns-declared.md | 97 - ...8920-grid-format-hint-shared-resolution.md | 9 - ...8923-page-header-single-node-delegation.md | 29 - .changeset/8924-installed-pin-claim-gate.md | 16 - .../8925-designer-refusal-four-state-pin.md | 7 - .../8927-metadata-cache-readme-coalescing.md | 8 - .../8932-kanban-enhanced-types-jsdoc.md | 5 - .changeset/8932-retire-kanban-enhanced.md | 44 - .../8934-chatter-feed-affordance-only.md | 64 - .../8938-retired-dialect-measured-surface.md | 50 - .../8944-chart-drill-filter-composition.md | 44 - .../8945-element-datasource-filter-note.md | 38 - .../8946-flow-edge-evaluated-condition.md | 17 - .changeset/8953-test-path-roots-gate.md | 24 - .changeset/8961-parse-schema-sort-narrow.md | 43 - .../8968-chatter-filtermode-enablementions.md | 32 - .../8970-object-metric-shared-drill-drawer.md | 44 - .../8972-cel-authoring-data-root-advisory.md | 19 - .changeset/8973-grid-orderby-normalize.md | 61 - .../8976-icontains-lowers-in-converter.md | 34 - .../8978-alert-dialog-action-variant.md | 50 - ...3-host-discussion-fallback-one-pipeline.md | 30 - .../8990-object-kanban-groupby-optional.md | 55 - ...8992-user-actions-collapse-and-docblock.md | 78 - .changeset/8993-kanban-lane-id-sweep-key.md | 38 - .../9000-drill-columns-header-labels.md | 28 - .../9001-filter-converter-text-comparand.md | 45 - .changeset/9002-metric-drilldown-refusal.md | 31 - .changeset/9003-changeset-claim-reread.md | 12 - .changeset/9012-core-spec-floor.md | 42 - .../9013-ast-child-vitest-env-membership.md | 22 - .../9022-drill-navigate-placeholder-scope.md | 29 - .../9024-pivot-drill-filter-composition.md | 44 - .../9026-bare-colon-continuation-scope.md | 36 - .../9031-retired-sort-diagnostic-wording.md | 28 - ...-header-bar-right-content-numeric-falsy.md | 39 - .../9034-imported-defaults-keep-describe.md | 9 - .changeset/9035-hinted-column-waitfor.md | 9 - ...40-record-details-top-level-spec-parity.md | 40 - .../9040-retire-record-details-layout.md | 90 - .../9043-kanban-prototype-group-keys.md | 28 - .../9045-kanban-empty-state-lane-count.md | 65 - ...-entry-form-icontains-comparand-refusal.md | 32 - ...-time-filter-refusal-names-the-operator.md | 53 - ...054-record-details-identity-fail-closed.md | 34 - ...6-detail-body-columns-boundary-coercion.md | 18 - .../9061-calendar-map-inline-query-keys.md | 46 - .changeset/9067-zod-barrel-named-arms.md | 55 - .../9071-summary-chip-percent-source.md | 37 - .../9073-doc-union-members-comment-order.md | 39 - ...-fieldstub-picklist-filter-before-slice.md | 24 - .../9081-census-control-names-one-citation.md | 22 - .../9087-arm-named-export-docblock-claims.md | 24 - .changeset/9088-rest-less-tuple-identity.md | 32 - .../9092-inline-locale-declared-face.md | 74 - ...00-record-alert-cel-envelope-config-bag.md | 41 - .../9102-import-boundary-registry-meta.md | 39 - .../9103-census-pairing-optional-default.md | 6 - ...9107-enablement-cel-envelope-config-bag.md | 31 - .changeset/9108-props-bag-loud-refusal.md | 11 - .../9109-flow-node-unbacked-defaults.md | 52 - .changeset/9119-detail-header-cross-axis.md | 42 - .changeset/9126-pack-dynamic-head-report.md | 4 - ...129-filter-token-suggestion-proto-guard.md | 21 - .../9131-action-enablement-verdict-carrier.md | 38 - .../9134-release-pr-head-branch-not-title.md | 9 - .changeset/9136-tree-inline-query-keys.md | 45 - ...137-dataset-drill-conjoin-widget-filter.md | 53 - ...9140-changeset-claims-blind-spot-census.md | 9 - .../9142-root-markdown-shard-trigger.md | 11 - .changeset/9145-prompt-category-inventory.md | 36 - .../9150-report-chart-title-locale-map.md | 55 - ...ed-script-action-toast-characterization.md | 12 - ...55-bundle-analysis-classification-prose.md | 14 - .changeset/9159-drill-url-isnull-operator.md | 57 - .../9161-file-readonly-download-affordance.md | 48 - .../9162-node-slot-guard-class-closure.md | 54 - .changeset/9164-empty-operator-map-refused.md | 55 - .changeset/9165-metric-percent-converged.md | 67 - .../9167-summary-chip-percent-convention.md | 53 - ...170-kanban-empty-state-drops-lane-count.md | 44 - .../9172-dashboard-grid-series-label.md | 11 - .changeset/9174-interpolate-fastpath-trim.md | 30 - ...9175-value-data-source-structured-clone.md | 56 - ...177-coverage-shard-reporter-readability.md | 34 - .changeset/9183-comment-mask-conversion.md | 40 - ...187-record-highlights-layout-two-values.md | 57 - .../9188-playwright-import-meta-root.md | 7 - .../9194-fence-opener-commonmark-run.md | 10 - ...6-objectview-url-filter-operator-suffix.md | 40 - .../9197-record-context-datasource-adapter.md | 58 - .changeset/9201-sweep-skip-objectui-tmp.md | 34 - .../9206-retire-unregistered-rationale.md | 31 - .changeset/9211-spawners-single-source.md | 27 - .../9215-lockfile-dedupe-measurement.md | 6 - .../9217-packaged-flow-unbound-reason.md | 14 - ...18-detailsection-collapsible-showborder.md | 34 - ...9219-objectmanager-system-object-delete.md | 37 - .../9220-readme-exports-list-precondition.md | 12 - .changeset/9223-adr-0055-item-5-amendment.md | 8 - .../9230-picklist-blank-option-label.md | 33 - .changeset/9231-create-app-accessible-name.md | 34 - .changeset/9232-cache-approval-envelope.md | 15 - .../9233-approval-state-survives-merge.md | 29 - .../9239-object-calendar-data-array-arm.md | 27 - ...-stray-kanban-groupby-lane-second-route.md | 86 - .../9248-screen-field-bound-help-reference.md | 30 - .changeset/9251-icons-record-not-eager.md | 33 - .changeset/9256-content-channel-family-d.md | 63 - .../9256-e3-residual-content-channels.md | 44 - .changeset/9256-input-content-channels.md | 36 - .../9256-list-timeline-content-channels.md | 36 - .../9256-public-blocks-content-channels.md | 60 - .changeset/9256-remeasure-content-channels.md | 44 - .../9262-app-probe-measured-verdicts.md | 35 - ...266-commit-history-item-count-agreement.md | 34 - .../9269-grid-summary-percent-converged.md | 72 - ...ockrecord-interrupting-declared-default.md | 32 - .changeset/9278-end-outcome-select.md | 50 - ...80-record-highlights-entry-icon-retired.md | 70 - ...7-objectview-filter-params-key-encoding.md | 26 - .../9295-percent-surfaces-read-scale.md | 58 - .../9299-shared-record-overlay-shell.md | 54 - ...filter-builder-valueless-canonical-fold.md | 67 - .../9306-filter-builder-name-authority.md | 44 - ...06-filter-builder-nested-groups-retired.md | 48 - ...06-filter-builder-protocol-operator-ids.md | 60 - .../9308-data-root-unbound-from-adapter.md | 64 - ...object-gallery-filter-destination-typed.md | 35 - .../9318-field-rule-verdict-from-lint.md | 43 - ...319-ui-library-prompt-section-numbering.md | 34 - .changeset/9323-jsonc-readers-converge.md | 8 - .changeset/9324-comment-mask-param-tags.md | 33 - .changeset/9327-import-history-time-locale.md | 27 - .changeset/9329-published-dist-remedy-text.md | 19 - .changeset/9331-fence-opener-authority.md | 14 - .../9333-record-id-narrows-to-string.md | 93 - .../9335-flow-end-output-variable-refused.md | 22 - .../9336-end-node-refusal-message-control.md | 38 - .changeset/9340-loop-item-variable-hint.md | 22 - .../9341-kanban-card-click-fires-once.md | 56 - .changeset/9342-kanban-oncardmove-prop.md | 62 - ...350-auth-permissions-useauth-guard-both.md | 7 - .../9357-navigation-overlay-consumer-arity.md | 61 - ...357-navigation-overlay-onrowclick-arity.md | 65 - .../9359-list-ast-valueless-canonical-fold.md | 83 - .../9363-dataset-filter-isnull-erases.md | 29 - .../9365-bridgelistview-present-tense.md | 38 - .changeset/9372-unmapped-operator-inert.md | 50 - ...view-detail-overlay-inline-locale-label.md | 31 - .../9375-base-i18n-vocabulary-docblock.md | 37 - ...dataset-filter-date-operator-round-trip.md | 40 - .../9406-types-root-barrel-two-names.md | 34 - .../9409-retire-page-assigned-profiles.md | 35 - .changeset/9412-ungated-docs-paydown.md | 27 - .../9414-lazy-icon-letter-digit-boundary.md | 41 - ...-permission-package-door-reread-refusal.md | 30 - .changeset/9422-required-check-set-patrol.md | 8 - ...9424-comment-mask-returns-interpolation.md | 35 - .../9436-core-declared-name-field-export.md | 27 - .../9436-detail-declared-pointer-order.md | 40 - ...9436-page-header-declared-pointer-order.md | 67 - .../9447-detail-view-handler-key-refusal.md | 51 - .changeset/9449-guard-ruling-c-narration.md | 13 - .../9452-percent-cell-name-keyed-scaling.md | 57 - .../9453-summary-chip-display-locale.md | 26 - ...9462-row-click-modifier-payload-forward.md | 37 - .changeset/9464-admin-scope-write-gate.md | 40 - .../9473-record-source-data-arm-type.md | 22 - ...ed-list-relationship-value-field-uncast.md | 26 - .../9484-env-door-post-save-reread-degrade.md | 37 - .../9485-filecell-view-download-affordance.md | 38 - .changeset/9491-walkabledef-rest-null.md | 31 - .../9492-corebarrel-namespace-narrowed.md | 24 - ...97-validation-rule-condition-draft-lint.md | 39 - .../9502-required-set-readable-pointers.md | 24 - .../9507-url-filter-op-prototype-chain.md | 50 - .../9508-drill-url-dialect-is-not-null.md | 28 - .../9511-datasource-record-id-string.md | 80 - .changeset/9511-record-id-is-a-string.md | 122 - .changeset/9513-at-lib-prose-pointer.md | 21 - .changeset/9522-zod-readme-first-example.md | 33 - ...types-root-barrel-command-element-types.md | 23 - .../9529-detail-section-declares-icon.md | 33 - ...oard-bare-key-converge-plugin-namespace.md | 109 - .changeset/9542-result-dialog-i18nlabel.md | 42 - .changeset/9547-ongrid-onnavigate-prop.md | 17 - .changeset/9549-tree-filter-declared.md | 33 - .changeset/9550-object-tree-root-barrel.md | 35 - ...0-plugin-tree-import-object-tree-schema.md | 26 - .../9556-record-component-aria-honoured.md | 117 - .changeset/9557-feed-diagnostic-block-name.md | 23 - ...559-filter-operator-schema-protocol-set.md | 43 - .changeset/9568-percent-widget-reads-scale.md | 52 - .../9569-components-stylesheet-source-none.md | 75 - .../9571-schema-renderer-data-prop-arm.md | 43 - ...-declared-actions-bar-capability-mirror.md | 37 - .changeset/9574-objectform-step-scale.md | 39 - .changeset/9575-gallery-scale.md | 5 - .../9580-grid-needs-datasource-bare-array.md | 32 - .changeset/9590-item-body-retired.md | 39 - ...-data-objectstack-error-envelope-reader.md | 54 - .../9596-debt-issue-anchor-truthiness.md | 9 - .../9600-import-template-from-server.md | 17 - .../9603-zod-mirror-parity-restated-figure.md | 33 - .changeset/9606-object-kanban-card-title.md | 44 - .changeset/9615-locale-count-ten.md | 24 - .../9618-record-source-ladder-attribution.md | 17 - ...-datatable-row-action-capability-mirror.md | 29 - .../9628-kanban-column-collapsed-honoured.md | 41 - .changeset/9629-9621-prose-residuals.md | 39 - .changeset/9637-post-pass-residuals.md | 13 - .../9641-registry-namespace-by-reference.md | 26 - .../9645-condition-builder-record-roots.md | 31 - .../9651-inspector-select-roster-failure.md | 54 - .../9652-designer-unknown-value-flags.md | 25 - .../9653-kanban-stray-groupby-refusal-text.md | 32 - .../9655-straygroupby-docblock-claim.md | 4 - .../9659-node-recursion-point-inert-clause.md | 78 - .../9664-search-items-available-plural.md | 45 - .../9667-navigation-view-tombstone-twin.md | 32 - .../9673-pageview-drop-context-spread.md | 13 - .changeset/9674-page-assignment-reads-type.md | 39 - .changeset/9675-scatter-spec-axes.md | 35 - .changeset/9676-calendar-pin-blind-regex.md | 14 - .../9681-scatter-zaxis-inert-declaration.md | 20 - .changeset/9684-discriminator-cited-once.md | 113 - .../9691-spec-gesture-fallback-type-order.md | 26 - .changeset/9692-9683-residuals.md | 10 - .../9700-handler-key-reads-wrapper-hop.md | 11 - .../9701-collapsible-bare-string-trigger.md | 11 - .../9710-overlay-trigger-bare-string.md | 16 - ...1-zod-mirror-parity-mirrored-undeclared.md | 12 - .../9722-bulk-executor-datasource-face.md | 43 - .../9726-objectkanban-docblock-tense.md | 4 - ...7-changeset-polarity-instrument-rebuild.md | 42 - ...729-mirror-only-published-keys-measured.md | 14 - .changeset/9736-twins-spec-by-reference.md | 43 - ...737-types-tsconfig-test-invariant-dated.md | 32 - .../9739-object-grid-operators-tombstone.md | 39 - .../9743-gantt-ratchet-rationale-retired.md | 35 - .../9746-render-path-not-a-validation-door.md | 30 - .changeset/9754-polarity-clause-scope.md | 13 - .changeset/9754-slice-2-window-pairing.md | 37 - .changeset/9758-legacy-props-data-strip.md | 44 - .changeset/9760-initial-data-member-merge.md | 35 - .../9764-renderer-docblock-counting-rule.md | 30 - .changeset/9767-census-schema-absent-split.md | 23 - ...9768-comment-projection-forcing-subject.md | 16 - .../9778-object-form-customfields-merge.md | 42 - .../9780-collapsed-implies-collapsible.md | 22 - .../9782-related-toolbar-capability-mirror.md | 35 - .../9784-percent-field-metadata-scale.md | 30 - .../9786-detail-timestamps-display-locale.md | 81 - .changeset/9787-proto-spec-legal-comment.md | 8 - .../9792-scatter-grid-show-grid-lines.md | 14 - .../9799-object-data-table-row-click-arity.md | 40 - .changeset/9802-validations-panel-when-key.md | 48 - .../9806-objectview-modifier-click-comment.md | 36 - .../9806-objectview-modifier-click-new-tab.md | 26 - .changeset/9808-percent-scale-out-of-range.md | 55 - ...0-percent-stored-fraction-decimal-shift.md | 29 - ...13-explain-double-single-record-verdict.md | 22 - .../9816-reference-rail-route-docblock.md | 13 - ...isterlazy-cross-table-collision-warning.md | 13 - .changeset/9830-erased-arm-mark.md | 33 - .../9830-nested-anyof-predicate-string-arm.md | 57 - .../9832-census-never-annotation-polarity.md | 35 - .changeset/9834-drawer-section-description.md | 42 - .changeset/9835-headingless-section-blurb.md | 27 - .changeset/9837-grid-presence-rule.md | 47 - ...39-register-skipfallback-preserves-stub.md | 15 - .../9843-percent-absent-scale-resolver.md | 39 - .changeset/9847-generate-page-children.md | 51 - .../9849-collapse-resolution-converge.md | 34 - .changeset/9849-section-gate-rule-e.md | 33 - .changeset/9849-single-divider-projection.md | 27 - .../9853-grid-display-page-size-from-spec.md | 62 - .../9853-grid-non-positive-page-size.md | 46 - .../9856-client-mount-condition-roots.md | 40 - .../9859-repeater-grid-widget-detectors.md | 29 - .../9867-labeler-hand-hung-label-probe.md | 7 - .changeset/9868-nav-label-inherits-target.md | 42 - .../9870-census-superseded-readings-table.md | 54 - .changeset/9871-body-dialect-producer-scan.md | 24 - .../9874-navigation-view-retired-consumer.md | 46 - .../9875-number-field-step-spec-parity.md | 16 - .../9880-undrawable-view-kinds-both-legs.md | 15 - .../9884-master-detail-fields-intersection.md | 47 - .../9889-control-widget-grid-cell-name.md | 45 - .changeset/9890-census-phantom-final-line.md | 33 - .../9892-fixture-address-rule-spec-rows.md | 16 - .../9897-listview-non-positive-page-size.md | 48 - .../9899-gate-refused-row-cap-not-authored.md | 36 - ...6-lint-coverage-banner-cross-file-claim.md | 17 - .changeset/9909-machine-locale-sweep.md | 115 - .../9910-children-slot-declare-and-pin.md | 62 - .changeset/9912-schemaform-ref-indirection.md | 39 - ...14-filter-condition-between-blank-bound.md | 54 - .../9922-port-parity-snippet-line-count.md | 13 - .../9925-line-items-row-cap-non-positive.md | 38 - .changeset/9925-row-cap-non-positive.md | 39 - .../9928-saved-view-limit-non-positive.md | 44 - .../9931-control-failure-arm-labelable.md | 32 - ...9933-stale-baseschema-premise-docblocks.md | 11 - .../9938-view-navigation-config-docblock.md | 11 - .changeset/9941-tabs-default-items-content.md | 28 - .../9943-viewtype-totals-page-row-retired.md | 10 - .changeset/9945-record-aria-label-retired.md | 49 - .../9950-map-style-reaches-flat-renderer.md | 42 - ...-placeholder-derives-from-offered-roots.md | 33 - ...953-condition-widget-context-derivation.md | 30 - .changeset/9954-read-rate-banner.md | 38 - ...ort-array-string-entry-refused-out-loud.md | 22 - .../9959-refused-data-prop-warn-reset.md | 30 - .changeset/9963-related-list-props-refusal.md | 29 - .../9964-related-list-picker-filter-mirror.md | 38 - .../9965-record-details-hidefields-uncast.md | 23 - .changeset/9973-flow-launch-refused-notice.md | 25 - ...978-page-residual-pin-type-face-derived.md | 8 - ...9979-validation-dialect-source-required.md | 34 - .../9987-gantt-readme-navigation-view.md | 15 - ...9998-activity-landmark-named-by-heading.md | 33 - .changeset/action-callback-retired-7068.md | 77 - .../action-designer-param-vocabulary.md | 24 - .changeset/action-keys-warning-text-5642.md | 35 - .changeset/action-onsuccess-forward-5493.md | 38 - .../action-param-degrade-predicate-5654.md | 25 - .../action-runtime-same-origin-only-5702.md | 25 - .../active-org-clear-removal-failure-5731.md | 44 - ...active-org-storage-memory-fallback-5703.md | 33 - .../activity-map-single-reading-5878.md | 33 - .changeset/adapter-advisory-sink-pin.md | 4 - .changeset/adapter-meta-type-singular-4940.md | 21 - .../adr-0057-d10-citation-attribution-5202.md | 25 - .changeset/ai-chat-public-share-base-4482.md | 28 - .changeset/ai-quota-ledger-vocabulary-3804.md | 18 - .changeset/ai-studio-accessor-5577.md | 27 - .../alert-dialog-fixture-premise-pin-7693.md | 4 - .../alert-dialog-footer-keys-liveness-7963.md | 6 - .../alias-closure-relative-miss-5386.md | 39 - .changeset/all-skipped-filter-tail-9020.md | 43 - .changeset/analytics-coded-400-rejected.md | 26 - .../analytics-error-branch-mapping-5663.md | 51 - .changeset/analytics-failure-code-first.md | 14 - .changeset/anon-seed-scope-pin-5828.md | 11 - .../anonymous-expression-user-id-6534.md | 45 - .changeset/app-hidden-catalogue-flag-7542.md | 7 - .changeset/app-shell-nodenext-pin-5440.md | 7 - .../app-shell-page-header-subtitle-4761.md | 52 - ...app-shell-provision-envelope-shape-6707.md | 31 - .../approvals-inbox-cell-remount-5348.md | 44 - .../approvals-queue-hidden-amount-6020.md | 18 - .changeset/approvals-raw-payload-gate-5553.md | 48 - .../approvals-step-progress-vertical-5554.md | 61 - .changeset/approver-display-name-5414.md | 45 - ...approver-identities-read-positions-5424.md | 30 - .changeset/appsidebar-deprecated-5720.md | 20 - .../audit-field-def-reference-narrow.md | 13 - .changeset/authguard-positions-5424.md | 5 - .changeset/baseline-squash-merge-sha-9355.md | 26 - .changeset/block-config-schema-parity-8216.md | 4 - .changeset/block-schema-docs-truth-4895.md | 46 - .changeset/built-moment-transition-5799.md | 5 - .changeset/built-transition-published-5799.md | 6 - .../button-container-exception-reason-6804.md | 29 - .../calendar-explain-network-escape-5438.md | 35 - ...endar-flat-key-pins-anchor-to-behaviour.md | 11 - .../calendar-gridcell-resolved-locale.md | 16 - .../calendar-readme-schema-keys-5045.md | 26 - .changeset/calendar-unscheduled-area.md | 24 - .changeset/calendar-view-event-rename-5044.md | 22 - .../calendar-view-mode-agenda-retired-5740.md | 31 - .changeset/calendar-view-schema-converge.md | 33 - .../calendarview-a11y-labels-localized.md | 21 - .changeset/canvas-design-run-5800.md | 5 - .../catalog-layout-props-sweep-4891-4890.md | 37 - .../chart-config-locale-heading-9038.md | 51 - .../chart-heading-follows-viewer-8943.md | 37 - .changeset/chart-height-chain-5451.md | 5 - .../chart-refusal-assertion-strength.md | 4 - .changeset/chat-transport-memo-4187.md | 27 - .changeset/chatbot-build-panel-i18n-7388.md | 19 - ...k-schema-positive-marker-and-skip-count.md | 39 - .changeset/chilled-donkeys-shave.md | 4 - .changeset/ci-cd-pipeline-populations-8629.md | 30 - .changeset/ci-decide-markdown-trace-9241.md | 13 - ...ation-census-declared-fixture-addresses.md | 6 - ...cli-app-generator-explicit-branch-cases.md | 7 - ...li-validate-field-widget-namespace-5449.md | 30 - .../closure-claims-bounded-or-derivable.md | 13 - ...cloud-connection-bind-failure-i18n-5054.md | 28 - .changeset/clusterradius-unit-doc-5020.md | 20 - .../component-docs-disabled-inherited-7239.md | 11 - ...-meta-converge-and-deprecate-alias-5893.md | 83 - .changeset/componentinput-reexport-4972.md | 40 - .../componentrendererprops-reexport-4594.md | 36 - ...ents-react-page-published-dts-text-5666.md | 33 - .changeset/confirm-card-terminal-5695.md | 7 - .../confirm-handler-published-type-5835.md | 4 - .../confirm-runtime-close-parity-6034.md | 15 - .../console-action-dispatch-envelope-5611.md | 34 - .changeset/console-boot-request-dedup-5544.md | 43 - .changeset/console-boot-splash.md | 19 - ...rm-container-specs-one-declaration-5596.md | 68 - ...le-form-field-spec-one-declaration-5542.md | 46 - .../console-form-marked-refusal-5210.md | 40 - ...sole-formpage-runtime-default-seed-5727.md | 29 - ...onsole-formpage-visible-predicates-5594.md | 47 - .changeset/console-lazy-docs-portal-5467.md | 45 - .../console-preboot-branding-origin-5660.md | 28 - ...ole-studio-builder-decorative-lazy-5486.md | 35 - .../console-user-preference-request-budget.md | 6 - .../container-declaration-ratchet-6779.md | 8 - ...ascope-field-and-comparison-guards-7751.md | 23 - ...-datascope-unknown-operator-denies-7378.md | 11 - ...reate-plugin-in-repo-scaffold-note-7524.md | 7 - ...rud-guide-declarative-view-binding-5446.md | 8 - .changeset/curly-hoops-attack.md | 15 - .../current-user-default-prefill-5683.md | 6 - .changeset/cyan-donkeys-tickle.md | 4 - .../dashboard-aria-member-retired-5830.md | 21 - .../dashboard-config-aria-retired-5852.md | 42 - .../dashboard-declare-honoured-inputs.md | 5 - ...oard-expandable-family-convergence-5692.md | 26 - .changeset/dashboard-header-collapse-5812.md | 20 - .../dashboard-inline-chartconfig-4044.md | 13 - .../dashboard-readme-card-widget-7035.md | 14 - ...ard-self-contained-unreachable-arm-4620.md | 19 - .../dashboard-stable-empty-rows-4629.md | 22 - ...ashboard-table-header-one-spelling-5425.md | 38 - ...dashboard-table-measure-desc-first-5845.md | 24 - .../dashboard-table-widget-polish-5827.md | 34 - .../dashboard-title-locale-writeback-5428.md | 46 - ...ashboard-widget-dataset-stale-cast-5067.md | 26 - .../dashboard-widget-type-closed-enum.md | 17 - .../data-table-header-declared-key-5351.md | 36 - .../dataset-chartconfig-seam-pin-9203.md | 9 - ...taset-format-8263-impossible-date-prose.md | 17 - .changeset/date-only-calendar-day-10110.md | 30 - .../date-range-default-range-binding-4984.md | 26 - .../datetime-cell-duelike-affordance-8958.md | 49 - .../datetime-cell-format-vocabulary-8853.md | 68 - .changeset/dead-metadata-converters-6224.md | 12 - .../dead-refresh-callback-objectview.md | 12 - .changeset/default-children-retired-5051.md | 36 - .../default-view-agenda-retired-5784.md | 37 - .../defaults-maps-mirror-discovery-7884.md | 9 - .changeset/degenerate-magnitude-charts.md | 20 - .changeset/degrade-set-twin-pin-5880.md | 9 - .../delete-dead-release-workflow-5405.md | 32 - .changeset/designer-field-key-parity-gate.md | 12 - .../designer-publish-package-binding.md | 34 - .../deterministic-child-vitest-env-8616.md | 10 - .changeset/dom-leak-sweep-components-5574.md | 25 - .../dom-leak-sweep-docblock-counts-8659.md | 10 - .../dom-leak-sweep-fixture-depth-5630.md | 9 - ...changes-panel-eager-attribution-comment.md | 4 - .changeset/drawer-bucket-pointer-ruling.md | 25 - .changeset/dts-build-exit-code-5370.md | 7 - .changeset/dts-explicit-extensions-5365.md | 41 - ...like-declared-on-detail-view-field-9738.md | 17 - .changeset/eager-closure-budget-5324.md | 45 - .../eager-closure-header-retired-figures.md | 4 - .changeset/eighty-pandas-listen.md | 4 - .changeset/empty-bucket-drill-is-null-9085.md | 32 - ...description-props-name-the-element-8571.md | 11 - .changeset/esm-load-comment-mask-5382.md | 41 - .../evaluateexpression-jsdoc-links-5580.md | 37 - .changeset/explain-double-wire-shape-7996.md | 10 - .../field-key-spelling-outside-table-9055.md | 11 - .../fields-depends-on-declared-read-6153.md | 14 - .changeset/fields-jest-dom-self-declared.md | 9 - .changeset/filecell-error-slot-5431.md | 19 - .changeset/filter-ast-combinators-6948.md | 30 - .changeset/fix-parity-aria-line-ref.md | 4 - .changeset/flow-entry-condition-builder.md | 20 - .changeset/flow-resume-result-5417.md | 48 - .changeset/flownode-declared-default-pin.md | 4 - .../form-control-renderers-dom-props-5632.md | 51 - ...orm-designer-namespaced-field-type-4838.md | 28 - .../form-field-predicate-current-user-6010.md | 43 - .../form-reset-notification-channels-5235.md | 28 - .../formatpercent-comment-citations-4596.md | 36 - .changeset/formfieldspec-dependson-5040.md | 40 - ...formpage-conditional-rule-surfaces-5627.md | 27 - .../formpage-maxlength-override-5595.md | 38 - .../formpage-record-id-param-comment-4319.md | 11 - .changeset/gantt-bar-object-declaration.md | 44 - .changeset/gantt-envelope-wait-anchor-8665.md | 4 - .changeset/gantt-navconfig-comment-once.md | 21 - .changeset/gantt-owns-data-comment-7222.md | 4 - .changeset/gantt-restated-keep-rationale.md | 13 - .changeset/gantt-row-walk-nontotal-reads.md | 4 - ...tt-viewmode-declared-both-branches-5074.md | 26 - ...gate-listlocalinstalls-marketplace-5620.md | 22 - .../governed-surface-human-merge-5149.md | 7 - .changeset/grid-column-spelling-docs-5352.md | 30 - .../grid-default-filters-lowering-4082.md | 53 - .../grid-dom-attribute-whitelist-4787.md | 27 - .changeset/grid-prefix-read-no-cast-6458.md | 10 - .changeset/grid-select-published-fields.md | 17 - ...d-source-keys-member-pins-8071-slice-14.md | 4 - .../grid-summary-footer-tenant-locale-9294.md | 51 - .../grid-unresolved-column-diagnostic-5349.md | 34 - .../grid-user-actions-collision-5240.md | 33 - .changeset/grid-widget-aria-invalid-3318.md | 17 - ...handler-key-reads-follow-cast-receivers.md | 6 - ...ler-key-reads-keyed-on-the-registration.md | 4 - .changeset/hidden-predicate-widen-7455.md | 13 - .../hollow-view-overlay-hydration-pin-5773.md | 33 - .changeset/home-ai-studio-flag-5521.md | 34 - .changeset/host-dispatch-action-keys-5611.md | 32 - .../host-only-viewtypes-tree-icon-5321.md | 30 - .changeset/humanize-label-single-home-5444.md | 52 - .changeset/hungry-poems-shave.md | 39 - .changeset/i18n-global-reset-4514.md | 14 - .changeset/i18n-guide-label-rule-5081.md | 30 - .changeset/i18n-header-import-rule-8029.md | 4 - .changeset/i18nlabel-comment-4611.md | 33 - .changeset/i18nlabel-inverted-pin-5612.md | 43 - .../icontains-comparand-view-rule-9048.md | 11 - .changeset/identity-fold-skipped-keys-9030.md | 65 - .changeset/inbox-actor-name-retired-5203.md | 28 - .../inbox-arrival-toast-and-desktop-7011.md | 51 - .changeset/inbox-receipt-window-scope.md | 18 - .../inert-lifecycle-path-readout-5768.md | 46 - ...listpage-drop-derived-marker-title-6343.md | 33 - .changeset/interfaces-rail-label-map-11158.md | 17 - .changeset/issue-5373-retire-crud-schema.md | 44 - .../issue-5389-workspace-admin-positions.md | 27 - .../issue-5474-static-table-narrow-types.md | 26 - .../issue-5619-workspace-admin-unresolved.md | 36 - ...e-5709-unconsumed-widget-option-warning.md | 17 - ...issue-5821-table-column-editable-mirror.md | 5 - ...sue-5881-record-highlights-header-prose.md | 9 - .../issue-5887-toplevel-strictness-probes.md | 9 - ...sue-6275-validation-engine-dangling-see.md | 7 - ...sue-6567-hoist-internalformroute-import.md | 10 - .../issue-7992-unmirrored-keys-doc-side.md | 4 - .changeset/issue-8378-usechat-options-cast.md | 11 - ...ssue-8379-reconcile-redundant-assertion.md | 6 - .../issue-8399-dedupe-pin-pins-viewport.md | 6 - .changeset/issue-8690-recorder-wait-audit.md | 9 - ...ue-8703-matcher-dependent-strict-bucket.md | 10 - .changeset/issue-8704-census-matcher-ast.md | 12 - .../issue-8875-cite-by-content-convention.md | 14 - .changeset/issue-9109-widen-default-ledger.md | 4 - .../issue-9124-side-effects-build-state.md | 4 - ...e-9191-new-url-import-meta-url-measured.md | 20 - .../issue-9198-workflow-test-readers-habit.md | 19 - .../issue-9418-write-identity-locks-port.md | 25 - .../issue-9586-enqueue-class-deny-mirror.md | 21 - .changeset/issue-9819-operations-ceiling.md | 11 - .../jsdoc-default-renderer-retest-8318.md | 4 - .changeset/jsonc-fence-extractor-test-only.md | 7 - .changeset/kanban-8826-order-not-claimed.md | 22 - .../kanban-calendar-nav-width-converge.md | 28 - .changeset/kanban-empty-badge-label-8489.md | 17 - .../kbd-group-props-name-the-element-8576.md | 23 - .changeset/khaki-cameras-attack.md | 13 - .changeset/khaki-rocks-shout.md | 22 - .changeset/layout-default-jsdoc-7361.md | 5 - .../layout-direction-default-jsdoc-7734.md | 5 - .changeset/layout-renderers-dom-props-5574.md | 31 - .changeset/lazy-plugin-jsdoc-compiles.md | 13 - .../list-user-actions-collision-5398.md | 38 - .../list-view-nested-aria-label-i18n-5134.md | 41 - .../listview-calendar-crossfield-pin-7122.md | 8 - .changeset/listview-comment-pair-4559.md | 34 - .../listview-map-view-level-config-5042.md | 36 - .../listviews-refused-read-discrimination.md | 50 - .changeset/lockfile-integrity-gate.md | 7 - .changeset/lookup-cell-chip-cap.md | 21 - .../lookup-dropdown-cell-renderer-5492.md | 44 - .changeset/loud-lamps-shake.md | 33 - .changeset/lucide-icon-record-name-gate.md | 14 - .../lucide-react-1-43-0-retired-trash2.md | 61 - .changeset/lucky-buttons-warn.md | 7 - .changeset/lucky-donkeys-repeat.md | 14 - .changeset/lucky-donkeys-shave.md | 96 - .../lucky-forms-omit-server-defaults.md | 19 - .changeset/lucky-moons-shake.md | 32 - .changeset/lucky-pandas-shake.md | 15 - .changeset/lucky-pugs-shake.md | 9 - .changeset/lucky-pugs-shout.md | 30 - .changeset/map-marker-title-binding.md | 20 - ...place-catalog-runtime-before-admin-5557.md | 34 - ...rketplace-detail-admin-guard-order-5583.md | 39 - .../marketplace-detail-disabled-state-5533.md | 33 - .changeset/marketplace-disabled-state-5504.md | 35 - .../master-detail-formtype-vocabulary.md | 20 - .../max-tool-roundtrips-deprecate-5605.md | 39 - ...measure-analytics-starvation-paths-7696.md | 7 - .changeset/measure-datetime-format-8352.md | 54 - .changeset/member-pins-8071-near-miss-four.md | 9 - .../member-pins-object-grid-row-layer-8071.md | 17 - .../member-pins-object-grid-slice-17.md | 11 - .changeset/member-pins-slice-7.md | 9 - .changeset/menu-icon-test-phantom-value.md | 7 - .../metadata-client-actor-retired-4834.md | 30 - .changeset/metadata-lock-state-5024.md | 25 - .changeset/modal-form-section-group-11542.md | 22 - .../named-list-view-protocol-members-8980.md | 58 - .changeset/nav-item-visible-nesting-10119.md | 47 - .../nav-selection-root-keys-edge-5600.md | 25 - .changeset/nervous-donkeys-tap.md | 15 - .changeset/network-escape-batch1.md | 4 - .changeset/network-escape-batch2.md | 4 - .changeset/network-escape-batch3.md | 4 - .changeset/network-escape-batch4.md | 9 - .changeset/network-escapes-batch5.md | 8 - .changeset/network-escapes-batch6.md | 13 - .changeset/nine-holdouts-six-narrow.md | 28 - .../node-gate-data-predicate-report-5687.md | 34 - ...ormalise-client-error-user-message-5901.md | 20 - .changeset/notready-t-interpolates.md | 20 - .../npm-presence-publish-predicate-5442.md | 30 - .../object-calendar-member-pins-8071.md | 4 - ...object-schema-metadata-derive-from-spec.md | 34 - .../object-view-unmirrored-keys-7779.md | 107 - .../objectchart-fieldoptionlabel-ref-5587.md | 29 - .changeset/objectchart-schema-anchor-7946.md | 133 - .../objectmap-marker-title-resolver-5953.md | 27 - .../objectmap-schema-data-shorthand-5305.md | 36 - ...bjectpivottable-i18n-resolver-refs-5625.md | 36 - ...ctui-6844-preview-sample-status-options.md | 12 - .changeset/objectui-7559-relay-rung-census.md | 10 - ...jectview-overlay-pair-completeness-5025.md | 33 - .changeset/objectview-sort-sink-4869.md | 45 - .changeset/olive-buckets-scream.md | 18 - .changeset/olive-cameras-repeat.md | 17 - .changeset/olive-clouds-repeat.md | 10 - .changeset/olive-crabs-shave.md | 20 - .changeset/olive-crabs-visit.md | 21 - .changeset/olive-donkeys-invent.md | 17 - .changeset/olive-donkeys-scream.md | 7 - .changeset/olive-donkeys-shave.md | 17 - .changeset/olive-donkeys-smile.md | 16 - .changeset/olive-donkeys-smoke.md | 9 - .changeset/olive-doors-tickle.md | 24 - .changeset/olive-falcons-invent.md | 33 - .changeset/olive-flowers-yawn.md | 7 - .changeset/olive-mails-repeat.md | 7 - .changeset/olive-moons-reclassify.md | 8 - .changeset/olive-moons-shave.md | 12 - .changeset/olive-pears-invent.md | 27 - .changeset/olive-pugs-repeat.md | 21 - .changeset/olive-pugs-shave.md | 18 - .changeset/olive-pugs-sing.md | 44 - .changeset/one-origin-dev-configs-5745.md | 36 - .changeset/opennativepicker-coverage-7570.md | 7 - .../overlay-shell-mode-measurement-9113.md | 9 - .changeset/overlay-slot-requiredness-7106.md | 8 - .changeset/owd-width-single-home-5477.md | 25 - .../page-kind-node-type-channel-9642.md | 19 - .changeset/page-kind-writing-end-9718.md | 14 - .../page-source-tailwind-framing-5461.md | 47 - ...e-source-tailwind-prose-retraction-5469.md | 51 - .changeset/pageblock-retired-key-gate.md | 6 - .../palette-canonical-discussion-5495.md | 11 - .../palette-exclusion-reason-truthfulness.md | 8 - .../param-dialog-title-fallback-4282.md | 21 - ...d-reference-rule-derives-from-core-5312.md | 35 - .changeset/parity-gate-lazy-registrations.md | 4 - ...wall-moment-exit-and-failure-state-7253.md | 29 - .../pending-drafts-bar-locale-parity-5705.md | 27 - .changeset/pending-drafts-i18n-keys.md | 6 - ...-active-org-and-session-user-purge-5664.md | 55 - .changeset/per-view-config-alias-fold-2890.md | 26 - .../percent-figure-grid-citation-5608.md | 34 - .changeset/percent-summary-chip-one-rule.md | 5 - ...missions-evaluator-prototype-guard-8044.md | 19 - .changeset/pin-advisory-sink-seam-6969.md | 7 - .changeset/pin-ledger-docstring-key-totals.md | 15 - ...-relative-out-of-window-precedence-8262.md | 7 - .../pin-unpinned-wait-preconditions-8709.md | 10 - ...pin-zod-mirror-parity-header-key-totals.md | 10 - ...n-zod-mirror-parity-ledger-entry-counts.md | 7 - .../pivot-table-stable-empty-rows-5562.md | 24 - .changeset/placeholder-spelling-one-rule.md | 10 - .changeset/plain-taxis-attend.md | 22 - .../plugin-component-input-deprecate-5674.md | 39 - ...plugin-detail-8937-parent-scope-residue.md | 28 - .../plugin-detail-viewport-pins-8444.md | 7 - ...n-form-readme-classname-quantifier-5131.md | 28 - .changeset/plugin-map-reach-test-narration.md | 4 - .../preview-sample-lookup-reference-6647.md | 13 - .../previews-shared-empty-description-8526.md | 9 - ...ies-template-visibility-diagnostic-5756.md | 35 - .changeset/proto-instrument-fixture.md | 9 - .../publish-envelope-one-spelling-6962.md | 50 - .changeset/queryparams-closed-keys-7497.md | 52 - .changeset/quick-pots-repeat.md | 32 - .../quick-reference-release-sync-5394.md | 16 - .changeset/quiet-pans-repeat.md | 6 - .../radio-multiple-docblock-correction.md | 10 - ...eact-form-view-bridge-drifted-arms-5652.md | 39 - ...-pages-guide-source-contradictions-5413.md | 33 - .../readonly-richtext-raw-markup-5498.md | 30 - .../reanchor-adr-0124-d1-citations-5701.md | 33 - ...ecord-activity-open-vocabulary-fallback.md | 31 - .../record-activity-scheduled-event-5840.md | 17 - ...activity-types-filter-never-widens-5841.md | 28 - ...ord-activity-unproduced-feed-kinds-5877.md | 34 - .../record-alert-cta-label-i18n-4998.md | 20 - ...ord-alert-loading-frame-diagnostic-5776.md | 22 - .changeset/record-alert-row-binding-4807.md | 43 - .changeset/record-context-binding-casts.md | 18 - .../record-detail-builtin-label-i18n-4645.md | 42 - .../record-detail-param-dialog-title-5610.md | 28 - .changeset/record-handoff-card.md | 27 - .changeset/record-panel-member-pins-8071.md | 21 - .../record-picker-empty-text-i18n-5590.md | 39 - .../record-picker-label-association-5771.md | 33 - ...cord-picker-label-placeholder-i18n-5637.md | 48 - .changeset/record-picker-member-pins-8071.md | 4 - .../record-quick-actions-member-pins-8071.md | 4 - ...ord-quick-actions-resultdialog-pin-5711.md | 11 - ...op-undeclared-objectdef-titlefield-6531.md | 34 - .../reference-rail-entries-stale-prose.md | 11 - .../reference-rail-entry-spec-derived.md | 15 - .changeset/referenceto-carryover-8896.md | 26 - .../registerfunction-casefold-doc-5363.md | 31 - .changeset/registry-assertion-ratchet-8316.md | 13 - .changeset/related-badge-arity-8882.md | 26 - .changeset/related-list-member-pins-8071.md | 4 - ...release-lane-tests-and-concurrency-5404.md | 24 - .changeset/remove-inert-showrefresh-5567.md | 12 - .../rename-command-palette-shortcuts-demo.md | 10 - .../render-publish-advisory-findings-5026.md | 27 - .changeset/replay-dispatch-error-5695.md | 6 - .../report-view-datasource-object-key-5116.md | 51 - .changeset/retire-codecov-upload-5436.md | 24 - ...ire-components-action-param-dialog-5685.md | 39 - .changeset/retire-dead-engine-strings-8547.md | 11 - .../retire-options-shorthand-lift-4356.md | 13 - ...retire-record-details-section-collapsed.md | 32 - .changeset/retire-spec-bridge-6366.md | 52 - .../retire-theme-component-schema-5489.md | 33 - .../retire-theme-switcher-preview-5647.md | 42 - .changeset/retire-usebranding-hook-5368.md | 11 - .changeset/retired-field-type-gate-4914.md | 61 - .changeset/retired-lucide-spellings-5622.md | 41 - .changeset/richtext-cell-renderer-5452.md | 29 - .changeset/rotten-pugs-invent.md | 9 - .../row-predicate-phase2-record-only-5741.md | 60 - .changeset/row-predicate-record-canon-5330.md | 59 - .changeset/rowcolor-prototype-guard-6295.md | 15 - .../runtime-config-server-side-pointer.md | 8 - .../runtime-served-error-reporting-dsn.md | 78 - .changeset/safe-field-label-identity-5564.md | 32 - .changeset/scatter-unplaceable-points.md | 21 - .../schema-input-bridge-permanent-4622.md | 42 - .../sdui-parser-inline-whitespace-5661.md | 26 - .../sdui-preview-page-source-tailwind-5470.md | 26 - .changeset/secret-widget-spellings-5375.md | 40 - .changeset/select-empty-host-id-8803.md | 34 - .changeset/self-import-gate-scan-once-5402.md | 36 - .../sentry-undisableable-telemetry-5522.md | 33 - .changeset/setmessages-honest-surface-8342.md | 41 - .../settled-schema-resolution-hook-6482.md | 18 - .changeset/shaggy-doors-repeat.md | 38 - .changeset/shard-coverage-job-5403.md | 8 - .changeset/shared-zod-wrapper-keys-6923.md | 10 - .changeset/signout-purge-per-key-try-5777.md | 31 - ...e-form-consults-declared-submit-handler.md | 9 - .changeset/six-donkeys-shake.md | 7 - .../skill-provider-envelope-teaching-5372.md | 16 - .changeset/span-full-tier-ladder-9244.md | 23 - .../sparse-predicate-warning-cause-5399.md | 42 - .changeset/spec-17-3-0-lockfile-bump.md | 8 - .changeset/spec-pin-17-1-0-5328.md | 23 - .changeset/spec-refresh-17-2-0-5668.md | 9 - .../spec-symbol-mirrors-app-shell-7265.md | 26 - .../spellgantt-revoked-proxy-exclusion.md | 11 - .changeset/spotty-pages-drop-leaks.md | 23 - .changeset/spotty-pianos-shave.md | 4 - .changeset/spotty-pins-cover-fields.md | 22 - .changeset/stale-4163-pointers-5591.md | 41 - .changeset/stale-disable-directives-4853.md | 6 - .changeset/standard-widgets-phone-coverage.md | 6 - .../standing-pending-drafts-bar-5694.md | 5 - .changeset/stripper-residue-9751.md | 6 - .../studio-jargon-and-tool-card-i18n.md | 27 - .changeset/studio-metadata-form-ux-5416.md | 47 - .changeset/studio-nav-canonical-keys.md | 18 - .../studio-new-object-asks-for-owd-5418.md | 35 - .../studio-route-entry-capability-5519.md | 31 - .changeset/studio-simplify-5813.md | 5 - .changeset/submithandler-variant-forms.md | 13 - .changeset/surface-context-send-1610.md | 7 - .../surface-deeplink-live-channel-5476.md | 40 - .changeset/sweep-store-per-key-try-5763.md | 39 - .../switch-org-declared-reresolve-5750.md | 34 - .../switch-org-identity-reresolve-5719.md | 35 - ...-renderer-declared-column-contract-5350.md | 40 - .changeset/tall-doors-smash.md | 4 - .changeset/tall-tools-shake.md | 4 - .changeset/tame-buses-clean.md | 4 - .changeset/tame-jars-repeat.md | 4 - .../tenant-header-edge-contract-5279.md | 41 - .../test-name-line-citation-gate-8047.md | 6 - ...input-description-aria-describedby-5735.md | 35 - .changeset/text-input-i18n-label-arms-5717.md | 45 - .../text-value-retired-citations-8045.md | 7 - .../theme-clientvalidation-dead-entry-5715.md | 35 - .changeset/theme-schema-doc-rewrite-5648.md | 7 - .changeset/theme-types-localized-5716.md | 19 - .../theme-zod-retired-spec-reexports.md | 7 - .changeset/tidy-buttons-repeat.md | 15 - .changeset/tidy-donkeys-attack.md | 29 - .changeset/tidy-donkeys-repeat.md | 15 - .changeset/tidy-donkeys-shave.md | 13 - .changeset/tidy-flags-obey-the-filter.md | 12 - .changeset/tidy-forms-carry-spec-keys.md | 35 - .../tidy-forms-refuse-target-less-submit.md | 22 - .changeset/tidy-jars-confirm.md | 7 - .changeset/tidy-pans-repeat.md | 8 - .../tidy-permissions-provider-ctx-identity.md | 35 - .changeset/tidy-pugs-invent.md | 4 - .changeset/tidy-pumas-repeat.md | 10 - .../timeline-shared-safe-field-label-5623.md | 8 - .../toc-anchor-parity-cite-by-content.md | 4 - .changeset/tool-title-i18n-channel.md | 29 - .../tree-contract-envelope-waits-6839.md | 6 - .../truthfulness-guard-import-set-7117.md | 4 - .../tsbuildinfo-outside-published-dist.md | 10 - .../types-field-depends-on-declared-6153.md | 20 - .changeset/types-test-script-8590.md | 8 - .changeset/ui-text-variant-align-enforce.md | 17 - .changeset/unbundled-node-boundary-5384.md | 30 - .changeset/unified-pending-drafts-5801.md | 5 - .../uniqueness-deprecation-jsdoc-4765.md | 51 - ...own-component-type-case-suggestion-5247.md | 14 - .../utilities-index-phantom-provider-5360.md | 27 - .changeset/vacuous-dts-justification-5673.md | 40 - .../value-datasource-ast-filter-vocabulary.md | 20 - .../valuedatasource-comparand-shapes-8514.md | 29 - .changeset/vi-mock-inherit-guard-6849.md | 10 - .changeset/vi-mock-inherit-slice1.md | 4 - .../vi-mock-inherit-slice10-plugin-chatbot.md | 7 - ...vi-mock-inherit-slice11-plugin-designer.md | 7 - .../vi-mock-inherit-slice12-plugin-list.md | 9 - .changeset/vi-mock-inherit-slice13-fields.md | 6 - .../vi-mock-inherit-slice14-app-shell.md | 7 - .changeset/vi-mock-inherit-slice2.md | 7 - .changeset/vi-mock-inherit-slice3.md | 8 - .changeset/vi-mock-inherit-slice4.md | 6 - .changeset/vi-mock-inherit-slice5.md | 8 - .../vi-mock-inherit-slice6-components.md | 7 - .../vi-mock-inherit-slice7-plugin-grid.md | 6 - .../vi-mock-inherit-slice8-permissions.md | 7 - .../vi-mock-inherit-slice9-plugin-detail.md | 4 - .changeset/via-override-pin-discriminates.md | 4 - .../view-column-io-canonical-identity-5725.md | 39 - .../view-overlay-write-patch-only-5233.md | 35 - .../view-switcher-chart-gantt-icons-5586.md | 33 - ...viewcolumn-identity-canonical-read-5344.md | 30 - .changeset/violet-donkeys-brake.md | 15 - .changeset/visiblewhen-record-binding-5454.md | 45 - .changeset/vitest-config-unification-3240.md | 13 - ...ocation-guard-package-cwd-coverage-5406.md | 31 - .changeset/wider-ledger-per-arm-8252.md | 4 - .../widget-config-panel-locale-map-5301.md | 42 - .../widget-input-control-vocabulary-5675.md | 44 - .changeset/wild-charts-explain-themselves.md | 19 - .changeset/wild-donkeys-shake.md | 18 - .changeset/wild-tables-shout.md | 4 - .changeset/wire-dropped-fields-shape-6889.md | 21 - .changeset/wise-pandas-pin.md | 6 - .changeset/wise-poems-behave.md | 17 - .changeset/writefields-proto-key-9237.md | 23 - .changeset/zod-array-element-reader-5872.md | 10 - .../zod-base-schema-mirror-parity-4605.md | 46 - .../zod-internals-reader-confinement.md | 8 - .changeset/zod-mirror-parity-arbiter-9546.md | 16 - .../zod-mirror-parity-population-5684.md | 24 - .../zod-mirror-parity-population-derived.md | 8 - QUICK_REFERENCE.md | 2 +- apps/console/CHANGELOG.md | 2953 +++ apps/console/package.json | 2 +- packages/app-shell/CHANGELOG.md | 14908 ++++++++++++ packages/app-shell/package.json | 2 +- packages/auth/CHANGELOG.md | 490 + packages/auth/package.json | 2 +- packages/cli/CHANGELOG.md | 2107 ++ packages/cli/package.json | 2 +- packages/collaboration/CHANGELOG.md | 651 + packages/collaboration/package.json | 2 +- packages/components/CHANGELOG.md | 8750 +++++++ packages/components/package.json | 2 +- packages/core/CHANGELOG.md | 6610 ++++++ packages/core/package.json | 2 +- packages/create-plugin/CHANGELOG.md | 140 + packages/create-plugin/package.json | 2 +- packages/data-objectstack/CHANGELOG.md | 2092 ++ packages/data-objectstack/package.json | 2 +- packages/fields/CHANGELOG.md | 5436 +++++ packages/fields/package.json | 2 +- packages/i18n/CHANGELOG.md | 4320 ++++ packages/i18n/package.json | 2 +- packages/layout/CHANGELOG.md | 1687 ++ packages/layout/package.json | 2 +- packages/mobile/CHANGELOG.md | 824 + packages/mobile/package.json | 2 +- packages/permissions/CHANGELOG.md | 676 + packages/permissions/package.json | 2 +- packages/plugin-ai/CHANGELOG.md | 1194 + packages/plugin-ai/package.json | 2 +- packages/plugin-calendar/CHANGELOG.md | 2791 +++ packages/plugin-calendar/package.json | 2 +- packages/plugin-charts/CHANGELOG.md | 2840 +++ packages/plugin-charts/package.json | 2 +- packages/plugin-chatbot/CHANGELOG.md | 2315 ++ packages/plugin-chatbot/package.json | 2 +- packages/plugin-dashboard/CHANGELOG.md | 4519 ++++ packages/plugin-dashboard/package.json | 2 +- packages/plugin-designer/CHANGELOG.md | 2379 ++ packages/plugin-designer/package.json | 2 +- packages/plugin-detail/CHANGELOG.md | 6741 ++++++ packages/plugin-detail/package.json | 2 +- packages/plugin-editor/CHANGELOG.md | 930 + packages/plugin-editor/package.json | 2 +- packages/plugin-form/CHANGELOG.md | 4187 ++++ packages/plugin-form/package.json | 2 +- packages/plugin-gantt/CHANGELOG.md | 3041 +++ packages/plugin-gantt/package.json | 2 +- packages/plugin-grid/CHANGELOG.md | 5175 +++++ packages/plugin-grid/package.json | 2 +- packages/plugin-kanban/CHANGELOG.md | 3430 +++ packages/plugin-kanban/package.json | 2 +- packages/plugin-list/CHANGELOG.md | 4137 ++++ packages/plugin-list/package.json | 2 +- packages/plugin-map/CHANGELOG.md | 1907 ++ packages/plugin-map/package.json | 2 +- packages/plugin-markdown/CHANGELOG.md | 1209 + packages/plugin-markdown/package.json | 2 +- packages/plugin-report/CHANGELOG.md | 1751 ++ packages/plugin-report/package.json | 2 +- packages/plugin-timeline/CHANGELOG.md | 2221 ++ packages/plugin-timeline/package.json | 2 +- packages/plugin-tree/CHANGELOG.md | 2204 ++ packages/plugin-tree/package.json | 2 +- packages/plugin-view/CHANGELOG.md | 3562 +++ packages/plugin-view/package.json | 2 +- packages/providers/CHANGELOG.md | 559 + packages/providers/package.json | 2 +- packages/react-runtime/CHANGELOG.md | 50 + packages/react-runtime/package.json | 2 +- packages/react/CHANGELOG.md | 3766 +++ packages/react/package.json | 2 +- packages/runner/CHANGELOG.md | 1420 ++ packages/runner/package.json | 2 +- packages/sdui-parser/CHANGELOG.md | 853 + packages/sdui-parser/package.json | 2 +- packages/types/CHANGELOG.md | 19290 ++++++++++++++++ packages/types/package.json | 2 +- packages/vscode-extension/CHANGELOG.md | 896 + packages/vscode-extension/package.json | 2 +- 2819 files changed, 135052 insertions(+), 82888 deletions(-) delete mode 100644 .changeset/10002-map-style-remedy-text.md delete mode 100644 .changeset/10005-record-history-row-cap-refusal.md delete mode 100644 .changeset/10006-port-parity-list-pipe-flush.md delete mode 100644 .changeset/10015-gate-reports-refused-view-cap.md delete mode 100644 .changeset/10016-binding-limit-not-authored.md delete mode 100644 .changeset/10018-authoring-state-sheds-approval.md delete mode 100644 .changeset/10019-parts-builder-key-set-texts.md delete mode 100644 .changeset/10020-report-display-locale.md delete mode 100644 .changeset/10021-legend-swatch-custom-property.md delete mode 100644 .changeset/10024-search-results-count-plural-forms.md delete mode 100644 .changeset/10026-refuse-impossible-calendar-day.md delete mode 100644 .changeset/10030-calendar-alias-refusal-quotes-surviving-clause.md delete mode 100644 .changeset/10031-calendar-user-visible-strings-reach-the-packs.md delete mode 100644 .changeset/10033-parity-ledger-retired-upstream.md delete mode 100644 .changeset/10035-objectview-refresh-in-place.md delete mode 100644 .changeset/10035-renderers-read-invalidation.md delete mode 100644 .changeset/10036-gantt-reload-identity-dep.md delete mode 100644 .changeset/10037-gantt-toolbar-filter-reaches-chart.md delete mode 100644 .changeset/10039-publish-drafts-advisories.md delete mode 100644 .changeset/10040-app-shell-favicon-restore.md delete mode 100644 .changeset/10042-one-root-resolver.md delete mode 100644 .changeset/10043-studio-landing-tooltip-i18n.md delete mode 100644 .changeset/10044-record-search-display-name-dep.md delete mode 100644 .changeset/10046-object-page-options-identity.md delete mode 100644 .changeset/10058-quick-actions-capability-gate.md delete mode 100644 .changeset/10059-user-locale-single-source.md delete mode 100644 .changeset/10061-filter-builder-incomplete-range.md delete mode 100644 .changeset/10062-dataset-filter-between-arm.md delete mode 100644 .changeset/10064-object-tree-public-tier.md delete mode 100644 .changeset/10066-slider-step.md delete mode 100644 .changeset/10068-kanban-datasource-sort.md delete mode 100644 .changeset/10069-kanban-lanes-match-by-id-only.md delete mode 100644 .changeset/10071-number-scale-ceiling.md delete mode 100644 .changeset/10073-customfields-merge.md delete mode 100644 .changeset/10074-doc-changeset-text.md delete mode 100644 .changeset/10078-record-id-string-survivors.md delete mode 100644 .changeset/10080-modedefault-fixture-stored-body.md delete mode 100644 .changeset/10083-rowactions-narrow.md delete mode 100644 .changeset/10084-grid-ceiling-describe.md delete mode 100644 .changeset/10088-json-fences-parse.md delete mode 100644 .changeset/10096-record-activity-row-cap-non-integer.md delete mode 100644 .changeset/10098-locale-contracts-name-caller.md delete mode 100644 .changeset/10105-pull-to-refresh-late-host.md delete mode 100644 .changeset/10106-settled-schema-equal-payload.md delete mode 100644 .changeset/10107-record-verdict-memo-per-principal.md delete mode 100644 .changeset/10108-form-payload-server-owned-fields.md delete mode 100644 .changeset/10109-app-shell-edit-not-built-moment.md delete mode 100644 .changeset/10109-edit-envelope-not-built-app.md delete mode 100644 .changeset/10112-relatedlist-user-column-names.md delete mode 100644 .changeset/10117-page-header-title-lookup-fallback.md delete mode 100644 .changeset/10120-form-omits-fls-denied-fields.md delete mode 100644 .changeset/10129-action-param-field-backed-picker.md delete mode 100644 .changeset/10132-dashboard-i18n-declared-not-resolved.md delete mode 100644 .changeset/10145-row-cap-admits-only-numbers.md delete mode 100644 .changeset/10150-author-shape-header-ruling.md delete mode 100644 .changeset/10155-record-blocks-capability-gate.md delete mode 100644 .changeset/10156-edit-form-writes-only-changed-fields.md delete mode 100644 .changeset/10159-action-preview-reference-citation.md delete mode 100644 .changeset/10163-line-items-field-write-gate.md delete mode 100644 .changeset/10163-master-detail-field-write-gate.md delete mode 100644 .changeset/10166-record-form-save-during-upload.md delete mode 100644 .changeset/10167-formpage-file-field-arm.md delete mode 100644 .changeset/10176-formpage-retired-type-pin.md delete mode 100644 .changeset/10178-formpage-required-marker-aria-hidden.md delete mode 100644 .changeset/10179-formpage-shared-field-resolver.md delete mode 100644 .changeset/10179-textfield-maxlength.md delete mode 100644 .changeset/10180-wizard-next-keeps-upload.md delete mode 100644 .changeset/10183-date-only-shared-parse-step.md delete mode 100644 .changeset/10184-record-verdict-memo-forgets-changed-record.md delete mode 100644 .changeset/10186-related-list-fls-select.md delete mode 100644 .changeset/10188-app-shell-doc-menu-audience.md delete mode 100644 .changeset/10188-console-docs-direct-route.md delete mode 100644 .changeset/10188-doc-markdown-editor.md delete mode 100644 .changeset/10188-layout-doc-target-guard.md delete mode 100644 .changeset/10190-drawerform-first-load-window.md delete mode 100644 .changeset/10193-language-reset-on-owner-change.md delete mode 100644 .changeset/10199-related-list-filter-rule-array.md delete mode 100644 .changeset/10207-package-version-from-spec.md delete mode 100644 .changeset/10209-readonly-view-menus-not-empty.md delete mode 100644 .changeset/10210-overlay-marker-only.md delete mode 100644 .changeset/10210-view-config-save-envelope.md delete mode 100644 .changeset/10211-connector-refinement-behavioural-pin.md delete mode 100644 .changeset/10220-format-hint-not-date-pattern.md delete mode 100644 .changeset/10221-currency-decimals-iso-minor-unit.md delete mode 100644 .changeset/10222-retire-timeline-metafields-reads.md delete mode 100644 .changeset/10223-lookup-candidates-expand.md delete mode 100644 .changeset/10224-quick-actions-permissions-text.md delete mode 100644 .changeset/10226-image-upload-failure-reported.md delete mode 100644 .changeset/10232-display-locale-faces.md delete mode 100644 .changeset/10235-spec-translation-bundle-recognised-by-any-group.md delete mode 100644 .changeset/10242-ru-ar-count-labels.md delete mode 100644 .changeset/10247-retire-async-export-job-path.md delete mode 100644 .changeset/10250-self-querying-views-toolbar-state.md delete mode 100644 .changeset/10254-sections-customfields-drawer-modal.md delete mode 100644 .changeset/10257-dataset-filter-read-half-holds.md delete mode 100644 .changeset/10274-action-icon-auto-trigger.md delete mode 100644 .changeset/10275-listview-fls-emptied-select.md delete mode 100644 .changeset/10276-currency-fraction-digits-not-precision.md delete mode 100644 .changeset/10277-harvest-defaultfromrow-target-tokens.md delete mode 100644 .changeset/10280-slider-tooltip-single-or-list.md delete mode 100644 .changeset/10286-mirror-groups-cd-settled.md delete mode 100644 .changeset/10287-navigation-designer-doc-type.md delete mode 100644 .changeset/10288-config-bag-data-object-source.md delete mode 100644 .changeset/10289-action-params-properties.md delete mode 100644 .changeset/10290-container-member-params-evaluated.md delete mode 100644 .changeset/10291-cleared-scalar-saves-null.md delete mode 100644 .changeset/10293-calendar-date-values.md delete mode 100644 .changeset/10295-tooltip-content-is-text.md delete mode 100644 .changeset/10296-detail-view-field-options-authoring.md delete mode 100644 .changeset/10301-refuse-impossible-datetime-day.md delete mode 100644 .changeset/10304-calendar-selection-modes.md delete mode 100644 .changeset/10321-named-view-kanban-groupby-refused.md delete mode 100644 .changeset/10326-toolbar-search-withheld-tree-chart.md delete mode 100644 .changeset/10327-dataset-chart-view-filter.md delete mode 100644 .changeset/10330-ai-recommendations-carousel-retired.md delete mode 100644 .changeset/10331-console-dates-display-locale.md delete mode 100644 .changeset/10334-dashboard-daterange-spec-authoring.md delete mode 100644 .changeset/10337-widget-input-serializer-key-list.md delete mode 100644 .changeset/10339-daterange-spec-default.md delete mode 100644 .changeset/10343-lookup-option-label-order.md delete mode 100644 .changeset/10345-action-bar-menu-group-placement.md delete mode 100644 .changeset/10354-grid-fixed-currency-cell-footer.md delete mode 100644 .changeset/10355-grid-currency-minor-unit.md delete mode 100644 .changeset/10356-metric-count-not-currency.md delete mode 100644 .changeset/10360-titleformat-dedupe-rendered-fields.md delete mode 100644 .changeset/10367-required-marker-three-forms.md delete mode 100644 .changeset/10368-required-marker-real-span.md delete mode 100644 .changeset/10370-listview-map-location-select.md delete mode 100644 .changeset/10373-fields-display-fls.md delete mode 100644 .changeset/10375-comment-and-inbox-dates-display-locale.md delete mode 100644 .changeset/10377-calendar-designer-mode-enum.md delete mode 100644 .changeset/10379-favicon-one-writer.md delete mode 100644 .changeset/10380-object-page-stored-options-bag.md delete mode 100644 .changeset/10382-provider-late-bundle-rerender.md delete mode 100644 .changeset/10383-object-view-grid-delete-deletes.md delete mode 100644 .changeset/10383-record-delete-core.md delete mode 100644 .changeset/10384-pager-clamp-after-write.md delete mode 100644 .changeset/10387-header-bar-unread-keys-retired.md delete mode 100644 .changeset/10392-registration-record-source-inputs.md delete mode 100644 .changeset/10393-retire-bare-map-key.md delete mode 100644 .changeset/10396-missing-series-key-refusal.md delete mode 100644 .changeset/10397-header-bar-classname.md delete mode 100644 .changeset/10399-record-picker-limit-precedence-text.md delete mode 100644 .changeset/10404-undo-absent-field-not-null.md delete mode 100644 .changeset/10422-currency-mode-dynamic-tenant-default.md delete mode 100644 .changeset/10423-mobile-card-field-currency.md delete mode 100644 .changeset/10425-ru-ar-count-labels.md delete mode 100644 .changeset/10432-reseed-purge-error-code.md delete mode 100644 .changeset/10433-peoplepicker-fls-outputs.md delete mode 100644 .changeset/10434-record-title-fls.md delete mode 100644 .changeset/10435-select-label-association.md delete mode 100644 .changeset/10437-retire-default-upgrade-url.md delete mode 100644 .changeset/10439-storage-usage-banner.md delete mode 100644 .changeset/10442-date-faces-display-locale.md delete mode 100644 .changeset/10447-one-title-interpolator.md delete mode 100644 .changeset/10448-designer-invalid-not-published-flags.md delete mode 100644 .changeset/10456-objectmap-description-lookup.md delete mode 100644 .changeset/10462-action-entry-object-params.md delete mode 100644 .changeset/10463-dashboard-field-currency-config.md delete mode 100644 .changeset/10466-inline-edit-draft-read-rule.md delete mode 100644 .changeset/10471-tombstone-names-resolved-spelling.md delete mode 100644 .changeset/10472-formpage-widget-degrades-to-type.md delete mode 100644 .changeset/10474-datetime-editor-impossible-day.md delete mode 100644 .changeset/10475-default-arm-section-builder.md delete mode 100644 .changeset/10478-filter-condition-value-protocol-rule.md delete mode 100644 .changeset/10482-page-preview-reads-type.md delete mode 100644 .changeset/10485-detail-section-declares-hideempty.md delete mode 100644 .changeset/10486-picker-column-display-name.md delete mode 100644 .changeset/10487-lookup-hydrated-label-follows-schema.md delete mode 100644 .changeset/10493-data-uri-no-file-name.md delete mode 100644 .changeset/10496-header-bar-root-dom-props.md delete mode 100644 .changeset/10499-page-header-title-fls.md delete mode 100644 .changeset/10500-search-labels-read-gate.md delete mode 100644 .changeset/10501-lookup-cell-read-gate.md delete mode 100644 .changeset/10506-named-view-context-tokens.md delete mode 100644 .changeset/10512-dataset-chart-applied-filter.md delete mode 100644 .changeset/10516-xaxis-presentation-gate.md delete mode 100644 .changeset/10518-object-chart-y-axis-declared.md delete mode 100644 .changeset/10519-pageview-refresh-in-place.md delete mode 100644 .changeset/10520-orphaned-console-pages.md delete mode 100644 .changeset/10524-check-promise-text.md delete mode 100644 .changeset/10528-grid-object-table-fetch.md delete mode 100644 .changeset/10530-timeline-lookup-display.md delete mode 100644 .changeset/10535-person-name-read-gate.md delete mode 100644 .changeset/10537-simulator-assignment-envelope.md delete mode 100644 .changeset/10538-cel-macro-bound-variable.md delete mode 100644 .changeset/10545-filter-candidates-displayfield.md delete mode 100644 .changeset/10559-picked-lookup-relabels.md delete mode 100644 .changeset/10563-form-arms-write-payload.md delete mode 100644 .changeset/10564-master-detail-child-baseline.md delete mode 100644 .changeset/10565-occ-token-after-save.md delete mode 100644 .changeset/10567-date-only-impossible-day.md delete mode 100644 .changeset/10572-app-shell-external-refresh-same-commit.md delete mode 100644 .changeset/10572-plugin-calendar-reads-invalidation-bus.md delete mode 100644 .changeset/10572-plugin-dashboard-reads-invalidation-bus.md delete mode 100644 .changeset/10572-plugin-form-reads-invalidation-bus.md delete mode 100644 .changeset/10572-plugin-kanban-reads-invalidation-bus.md delete mode 100644 .changeset/10572-plugin-list-reads-invalidation-bus.md delete mode 100644 .changeset/10578-gantt-error-clears.md delete mode 100644 .changeset/10580-refresh-indicator-translated-name.md delete mode 100644 .changeset/10582-retire-column-width-config.md delete mode 100644 .changeset/10583-masked-cell-copy.md delete mode 100644 .changeset/10584-object-chart-series-describe.md delete mode 100644 .changeset/10585-hook-object-roster-state.md delete mode 100644 .changeset/10586-inspector-strings-i18n-2.md delete mode 100644 .changeset/10586-inspector-strings-i18n.md delete mode 100644 .changeset/10587-xaxis-position.md delete mode 100644 .changeset/10591-tool-preview-api-console-link.md delete mode 100644 .changeset/10594-field-read-rule-core-export.md delete mode 100644 .changeset/10594-record-picker-shared-field-read-rule.md delete mode 100644 .changeset/10607-grid-list-filter-context-tokens.md delete mode 100644 .changeset/10608-object-chart-legacy-axis-keys-retired.md delete mode 100644 .changeset/10611-filter-ui-operator-retired.md delete mode 100644 .changeset/10612-form-arms-managed-lock.md delete mode 100644 .changeset/10614-file-name-bare-percent.md delete mode 100644 .changeset/10615-simulator-cel-guards.md delete mode 100644 .changeset/10616-view-handler-event-names-through-renderer.md delete mode 100644 .changeset/10623-readers-follow-invalidation-bus.md delete mode 100644 .changeset/10625-core-native-date-adapters.md delete mode 100644 .changeset/10625-data-table-impossible-day.md delete mode 100644 .changeset/10625-fields-native-date-reexport.md delete mode 100644 .changeset/10625-inline-date-impossible-day.md delete mode 100644 .changeset/10631-master-detail-save-in-flight.md delete mode 100644 .changeset/10633-gantt-silent-overtake.md delete mode 100644 .changeset/10634-objectchart-groupby-category-forward.md delete mode 100644 .changeset/10636-objectview-record-count-singular.md delete mode 100644 .changeset/10637-image-alt-translated.md delete mode 100644 .changeset/10638-interface-page-view-field-keys.md delete mode 100644 .changeset/10639-readonly-password-empty.md delete mode 100644 .changeset/10640-agent-preview-chat-link.md delete mode 100644 .changeset/10645-api-console-preset-lazy-route-readiness.md delete mode 100644 .changeset/10654-yaxis-position-honoured.md delete mode 100644 .changeset/10657-components-masked-client-paths.md delete mode 100644 .changeset/10657-fields-masked-cell-renderer-export.md delete mode 100644 .changeset/10657-plugin-dashboard-masked-data-table.md delete mode 100644 .changeset/10657-plugin-dashboard-withheld-draw.md delete mode 100644 .changeset/10657-plugin-detail-masked-related-list.md delete mode 100644 .changeset/10657-plugin-detail-withheld-draw.md delete mode 100644 .changeset/10657-plugin-grid-masked-client-paths.md delete mode 100644 .changeset/10657-plugin-grid-withheld-first-paint.md delete mode 100644 .changeset/10657-plugin-list-grid-object-fields.md delete mode 100644 .changeset/10657-types-masked-doc.md delete mode 100644 .changeset/10657-types-withheld-doc.md delete mode 100644 .changeset/10659-modalform-first-load-window.md delete mode 100644 .changeset/10662-onviewchange-reference-row.md delete mode 100644 .changeset/10663-calendar-error-clears.md delete mode 100644 .changeset/10663-kanban-error-clears.md delete mode 100644 .changeset/10663-timeline-error-clears.md delete mode 100644 .changeset/10664-data-table-filter-bar.md delete mode 100644 .changeset/10664-map-reads-once.md delete mode 100644 .changeset/10664-object-view-table-sort.md delete mode 100644 .changeset/10664-repeater-picker-sort-key.md delete mode 100644 .changeset/10666-filter-token-sweep.md delete mode 100644 .changeset/10666-gallery-filter-context-tokens.md delete mode 100644 .changeset/10668-calendar-quick-create-display-locale.md delete mode 100644 .changeset/10668-gantt-timeline-display-locale.md delete mode 100644 .changeset/10668-home-inbox-relative-times-display-locale.md delete mode 100644 .changeset/10668-i18n-gantt-binding-premise.md delete mode 100644 .changeset/10682-form-error-clears-2.md delete mode 100644 .changeset/10682-form-error-clears.md delete mode 100644 .changeset/10684-reference-rail-superseded-parent.md delete mode 100644 .changeset/10684-report-attachments-superseded-read.md delete mode 100644 .changeset/10684-timeline-superseded-rows.md delete mode 100644 .changeset/10685-drilldown-per-block.md delete mode 100644 .changeset/10689-grid-harvest-inputs-refetch.md delete mode 100644 .changeset/10689-list-harvest-inputs-refetch.md delete mode 100644 .changeset/10690-related-list-reads-once.md delete mode 100644 .changeset/10691-third-yaxis-note.md delete mode 100644 .changeset/10692-debug-run-routing-parity.md delete mode 100644 .changeset/10694-empty-columns-no-projection.md delete mode 100644 .changeset/10696-inspector-literals-read-existing-keys.md delete mode 100644 .changeset/10701-agenda-retirement-citations.md delete mode 100644 .changeset/10712-fields-record-query-cannot-query-reset.md delete mode 100644 .changeset/10712-fields-record-query-latest-answer.md delete mode 100644 .changeset/10712-plugin-form-line-items-superseded-run.md delete mode 100644 .changeset/10712-plugin-form-superseded-read-guard.md delete mode 100644 .changeset/10715-form-arms-read-invalidation-bus.md delete mode 100644 .changeset/10719-retire-phase35-validation-types.md delete mode 100644 .changeset/10720-grid-columns-docs.md delete mode 100644 .changeset/10721-scatter-yaxis-note.md delete mode 100644 .changeset/10722-date-fns-display-locale.md delete mode 100644 .changeset/10726-wizard-swap-loading.md delete mode 100644 .changeset/10727-context-menu-sortable.md delete mode 100644 .changeset/10728-plugin-detail-related-list-masked-filter-sort.md delete mode 100644 .changeset/10731-console-map-mock-bare-specifier.md delete mode 100644 .changeset/10735-html-tier-manifest.md delete mode 100644 .changeset/10740-line-items-held-for-another-parent.md delete mode 100644 .changeset/10743-studio-screen-visiblewhen-live.md delete mode 100644 .changeset/10746-joined-report-clears-binding.md delete mode 100644 .changeset/10747-calendar-locale-tag.md delete mode 100644 .changeset/10747-calendar-popover-locale.md delete mode 100644 .changeset/10748-inspector-words-gain-zh-rows.md delete mode 100644 .changeset/10756-html-tier-code-element.md delete mode 100644 .changeset/10757-div-deprecated-html-tier.md delete mode 100644 .changeset/10758-named-view-protocol-members.md delete mode 100644 .changeset/10765-draft-merge-deletion.md delete mode 100644 .changeset/10767-value-data-source-rule-array-filter.md delete mode 100644 .changeset/10770-object-chart-react-tier-node.md delete mode 100644 .changeset/10771-dead-citation-sweep.md delete mode 100644 .changeset/10771-write-guard-message-citation.md delete mode 100644 .changeset/10772-inline-screen-visiblewhen-cell.md delete mode 100644 .changeset/10778-dashboard-bus-readers.md delete mode 100644 .changeset/10778-tree-bus-reader.md delete mode 100644 .changeset/10783-grid-currency-scale-not-read.md delete mode 100644 .changeset/10785-avatar-submits-file-id.md delete mode 100644 .changeset/10785-avatar-upload-gates.md delete mode 100644 .changeset/10788-empty-operator-map-beside-key-refused.md delete mode 100644 .changeset/10789-render-time-filter-refusals.md delete mode 100644 .changeset/10790-empty-operators-accepted-shape.md delete mode 100644 .changeset/10799-calendar-default-month.md delete mode 100644 .changeset/10803-dead-citation-sweep-eighth-batch.md delete mode 100644 .changeset/10803-dead-citation-sweep-fifth-batch.md delete mode 100644 .changeset/10803-dead-citation-sweep-fourth-batch.md delete mode 100644 .changeset/10803-dead-citation-sweep-second-batch.md delete mode 100644 .changeset/10803-dead-citation-sweep-seventh-batch.md delete mode 100644 .changeset/10803-dead-citation-sweep-sixth-batch.md delete mode 100644 .changeset/10803-dead-citation-sweep-third-batch.md delete mode 100644 .changeset/10803-describe-string-citations.md delete mode 100644 .changeset/10803-fifth-batch-runtime-strings.md delete mode 100644 .changeset/10803-fourth-batch-runtime-strings.md delete mode 100644 .changeset/10803-seventh-batch-runtime-strings.md delete mode 100644 .changeset/10803-sixth-batch-runtime-strings.md delete mode 100644 .changeset/10803-third-batch-runtime-strings.md delete mode 100644 .changeset/10804-designer-notes-locale.md delete mode 100644 .changeset/10813-dataset-filter-empty-operator.md delete mode 100644 .changeset/10813-filter-condition-empty-operator.md delete mode 100644 .changeset/10813-list-view-empty-operator.md delete mode 100644 .changeset/10814-report-line-items-bus-readers.md delete mode 100644 .changeset/10815-dashboard-block-ambient-source.md delete mode 100644 .changeset/10816-tree-keeps-rows-on-reread.md delete mode 100644 .changeset/10817-value-source-empty-operator-map.md delete mode 100644 .changeset/10824-timeline-readme-schema-node.md delete mode 100644 .changeset/10825-filter-builder-value-group-only.md delete mode 100644 .changeset/10827-app-branding-logo-one-spelling.md delete mode 100644 .changeset/10829-value-source-date-comparand.md delete mode 100644 .changeset/10835-dashboard-preview-debug-run-locale.md delete mode 100644 .changeset/10841-timeline-root-dom-props.md delete mode 100644 .changeset/10842-wizard-app-declared-keys.md delete mode 100644 .changeset/10843-dashboard-custom-range-reopen.md delete mode 100644 .changeset/10844-date-only-zone-closure.md delete mode 100644 .changeset/10847-dashboard-strip-i18n-title.md delete mode 100644 .changeset/10848-designer-preview-chrome-locale.md delete mode 100644 .changeset/10853-master-detail-picker-bus-readers.md delete mode 100644 .changeset/10859-ai-node-zod-arms.md delete mode 100644 .changeset/10859-console-phase-2b-stubs.md delete mode 100644 .changeset/10859-console-phase-2c-stubs.md delete mode 100644 .changeset/10859-console-tree-stub.md delete mode 100644 .changeset/10859-dashboard-node-keys.md delete mode 100644 .changeset/10859-designer-zod-arms.md delete mode 100644 .changeset/10859-known-types-phase-2b.md delete mode 100644 .changeset/10859-known-types-phase-2c.md delete mode 100644 .changeset/10859-known-types-phase-2d.md delete mode 100644 .changeset/10859-known-types-retired-keys.md delete mode 100644 .changeset/10859-object-form-properties-bag.md delete mode 100644 .changeset/10859-object-gantt-properties-bag.md delete mode 100644 .changeset/10859-object-map-properties-bag.md delete mode 100644 .changeset/10859-object-timeline-zod-arm.md delete mode 100644 .changeset/10859-page-header-placeholder.md delete mode 100644 .changeset/10859-pivot-object-block-zod-arms.md delete mode 100644 .changeset/10859-plugin-form-readme-object-form-bag.md delete mode 100644 .changeset/10859-plugin-gantt-properties-bag-docs.md delete mode 100644 .changeset/10859-plugin-map-properties-bag-docs.md delete mode 100644 .changeset/10859-record-source-tree-alias.md delete mode 100644 .changeset/10859-retire-bare-field-fallbacks.md delete mode 100644 .changeset/10859-retire-chart-family-aliases.md delete mode 100644 .changeset/10859-retire-designer-node-keys.md delete mode 100644 .changeset/10859-retire-form-analytics.md delete mode 100644 .changeset/10859-retire-import-wizard.md delete mode 100644 .changeset/10859-retire-page-header-layout.md delete mode 100644 .changeset/10859-retire-related-list.md delete mode 100644 .changeset/10859-retire-scatter-chart.md delete mode 100644 .changeset/10859-retire-shared-view-link.md delete mode 100644 .changeset/10859-retire-sidebar-parts.md delete mode 100644 .changeset/10859-retire-tree-alias.md delete mode 100644 .changeset/10859-retire-view-alias.md delete mode 100644 .changeset/10859-sidebar-node-provider-collapsible.md delete mode 100644 .changeset/10862-designer-admin-previews-locale.md delete mode 100644 .changeset/10862-designer-automation-previews-locale.md delete mode 100644 .changeset/10862-designer-federation-flow-stub-locale.md delete mode 100644 .changeset/10862-designer-object-data-previews-locale.md delete mode 100644 .changeset/10864-app-shell-spec-floor.md delete mode 100644 .changeset/10866-calendar-dst-day-moves.md delete mode 100644 .changeset/10866-calendar-gantt-date-only-days.md delete mode 100644 .changeset/10866-gantt-axis-formula-day-arithmetic.md delete mode 100644 .changeset/10866-gantt-move-end-days.md delete mode 100644 .changeset/10866-gantt-zoned-dst-days.md delete mode 100644 .changeset/10866-timeline-charts-i18n-date-only.md delete mode 100644 .changeset/10867-app-wizard-saves-spec-app.md delete mode 100644 .changeset/10868-list-view-leftovers.md delete mode 100644 .changeset/10872-container-children-channel.md delete mode 100644 .changeset/10872-container-children-runtime-pin.md delete mode 100644 .changeset/10872-element-number-arm.md delete mode 100644 .changeset/10872-envelope-responsive-styles.md delete mode 100644 .changeset/10872-flat-arm-responsive-styles.md delete mode 100644 .changeset/10872-flat-props-refusal.md delete mode 100644 .changeset/10872-held-block-content-channels.md delete mode 100644 .changeset/10872-held-public-block-arms.md delete mode 100644 .changeset/10872-public-block-zod-arms.md delete mode 100644 .changeset/10872-record-alert-body-remedy.md delete mode 100644 .changeset/10872-record-line-items-arm.md delete mode 100644 .changeset/10874-ai-node-faces-agree.md delete mode 100644 .changeset/10881-grouping-needs-header-query.md delete mode 100644 .changeset/10885-object-view-route2-named-grid.md delete mode 100644 .changeset/10885-object-view-route2-named-view-rest.md delete mode 100644 .changeset/10887-dashboard-filter-options-bus-reader.md delete mode 100644 .changeset/10887-object-view-non-grid-bus-reader.md delete mode 100644 .changeset/10887-react-page-data-invalidation.md delete mode 100644 .changeset/10893-signup-carries-verification-callback.md delete mode 100644 .changeset/10894-app-edit-keeps-navigation.md delete mode 100644 .changeset/10895-plugin-detail-relatedlist-client-sort-gate.md delete mode 100644 .changeset/10899-assistant-fab-yields-to-open-dock.md delete mode 100644 .changeset/10899-chat-step-turns-no-empty-blocks.md delete mode 100644 .changeset/10899-dataset-tile-read-refusal-no-access.md delete mode 100644 .changeset/10899-failed-comment-never-shown-as-sent.md delete mode 100644 .changeset/10899-failed-reaction-write-reverts.md delete mode 100644 .changeset/10899-marketplace-update-is-higher-version.md delete mode 100644 .changeset/10899-studio-bridges-need-authoring-capability.md delete mode 100644 .changeset/10900-zh-cn-leftovers.md delete mode 100644 .changeset/10903-today-reference-day-rule.md delete mode 100644 .changeset/10905-types-stale-docblocks.md delete mode 100644 .changeset/10909-element-number-datasource.md delete mode 100644 .changeset/10916-joined-report-block-pin-two-specs.md delete mode 100644 .changeset/10918-console-action-ctx-org.md delete mode 100644 .changeset/10919-cloud-plan-status.md delete mode 100644 .changeset/10925-plan-card-wait-stream.md delete mode 100644 .changeset/10926-dock-binds-build-thread-to-app.md delete mode 100644 .changeset/10928-content-channel-parser-tier-clause.md delete mode 100644 .changeset/10929-action-aria-retired.md delete mode 100644 .changeset/10932-pivot-drilldown-retired.md delete mode 100644 .changeset/10935-master-detail-i18n-labels.md delete mode 100644 .changeset/10940-joined-report-block-from-spec.md delete mode 100644 .changeset/10946-expression-wire-slots-by-reference.md delete mode 100644 .changeset/10948-flow-inspector-required-keys.md delete mode 100644 .changeset/10951-element-number-no-object-state.md delete mode 100644 .changeset/10959-unknown-prop-parser-tier-clause.md delete mode 100644 .changeset/10963-codewidget-expression-envelope.md delete mode 100644 .changeset/10964-matrix-report-chart.md delete mode 100644 .changeset/10965-changes-card-wait-stream.md delete mode 100644 .changeset/10969-console-zh-leftovers.md delete mode 100644 .changeset/10975-split-popover-create-surface.md delete mode 100644 .changeset/10976-table-slot-relay.md delete mode 100644 .changeset/10981-silence-clause-parser-tier-closure.md delete mode 100644 .changeset/10982-objectview-reread.md delete mode 100644 .changeset/10987-retire-list-view-tabs-fixture.md delete mode 100644 .changeset/10993-batch2-i18nlabel-reads.md delete mode 100644 .changeset/10993-batch3-grid-title.md delete mode 100644 .changeset/10993-batch4-ts-face.md delete mode 100644 .changeset/10993-object-form-i18nlabel.md delete mode 100644 .changeset/10998-register-refusal-codes.md delete mode 100644 .changeset/10999-wizard-form-chrome-i18n.md delete mode 100644 .changeset/11000-closed-affordance-notice.md delete mode 100644 .changeset/11001-record-delete-confirm.md delete mode 100644 .changeset/11004-autorefresh-handler-ref.md delete mode 100644 .changeset/11005-month-grid-calendar-days.md delete mode 100644 .changeset/11007-check-prints-key.md delete mode 100644 .changeset/11008-bind-base-prop.md delete mode 100644 .changeset/11009-protocol-readers-only-bind-warning.md delete mode 100644 .changeset/11011-project-setup-objectview-mount.md delete mode 100644 .changeset/11013-view-row-declared-spellings.md delete mode 100644 .changeset/11015-page-surface-fallback.md delete mode 100644 .changeset/11016-cross-repo-bare-citations.md delete mode 100644 .changeset/11019-reaction-keep-ids.md delete mode 100644 .changeset/11021-grouped-grid-search-both-queries.md delete mode 100644 .changeset/11021-listview-grouped-search.md delete mode 100644 .changeset/11022-strict-widget-slot-registered-inputs.md delete mode 100644 .changeset/11024-spec-gate-canonical-operator-fixtures.md delete mode 100644 .changeset/11026-number-use-grouping.md delete mode 100644 .changeset/11027-preview-display-keys.md delete mode 100644 .changeset/11028-connector-action-desc-refs.md delete mode 100644 .changeset/11030-register-refusal-map.md delete mode 100644 .changeset/11035-reactions-comment-rows-only.md delete mode 100644 .changeset/11037-time-grid-move-keeps-event-length.md delete mode 100644 .changeset/11039-form-chrome-i18n.md delete mode 100644 .changeset/11040-comment-mask-tracked-files.md delete mode 100644 .changeset/11044-base-props-one-list.md delete mode 100644 .changeset/11051-inline-aria-reader.md delete mode 100644 .changeset/11054-flow-start-api-trigger.md delete mode 100644 .changeset/11056-undo-confirmation-toast-i18n.md delete mode 100644 .changeset/11058-signin-refusal-map.md delete mode 100644 .changeset/11060-overnight-resize-true-edge.md delete mode 100644 .changeset/11061-modal-close-button.md delete mode 100644 .changeset/11062-console-dashboard-auto-refresh.md delete mode 100644 .changeset/11067-drop-platform-event-trigger.md delete mode 100644 .changeset/11068-grid-declared-keys.md delete mode 100644 .changeset/11068-keyboard-navigation.md delete mode 100644 .changeset/11068-object-grid-show-filters.md delete mode 100644 .changeset/11068-row1-booking-17-6.md delete mode 100644 .changeset/11070-dashboard-formula-round6.md delete mode 100644 .changeset/11070-dashboard-keys-round11.md delete mode 100644 .changeset/11070-field-metadata-spec-spellings.md delete mode 100644 .changeset/11070-grid-columns-chart-binding-round7.md delete mode 100644 .changeset/11070-grid-field-keys-round8.md delete mode 100644 .changeset/11070-grid-form-face-round10.md delete mode 100644 .changeset/11070-grid-sort-field-round9.md delete mode 100644 .changeset/11070-react-page-no-adapter-on-node.md delete mode 100644 .changeset/11070-reference-to-round4.md delete mode 100644 .changeset/11070-strict-face-read-keys.md delete mode 100644 .changeset/11070-text-family-round5.md delete mode 100644 .changeset/11071-form-chrome-remainder.md delete mode 100644 .changeset/11073-objectstack-17-5-bump.md delete mode 100644 .changeset/11075-every-node-declared-omit.md delete mode 100644 .changeset/11079-timeline-one-axis.md delete mode 100644 .changeset/11080-undo-fallback-names-object.md delete mode 100644 .changeset/11080-undo-redo-toasts-i18n.md delete mode 100644 .changeset/11081-one-undo-listener.md delete mode 100644 .changeset/11082-detail-undo-capture.md delete mode 100644 .changeset/11083-block-nested-aria.md delete mode 100644 .changeset/11083-nested-aria-family.md delete mode 100644 .changeset/11085-flow-edge-scope-source-outputs.md delete mode 100644 .changeset/11094-value-source-empty-operator.md delete mode 100644 .changeset/11097-dashboard-refresh-button-locale.md delete mode 100644 .changeset/11100-app-preview-label-maps.md delete mode 100644 .changeset/11101-vendor-chunk-initial-only.md delete mode 100644 .changeset/11105-grouped-grid-selects-field-names.md delete mode 100644 .changeset/11106-record-path-derived-stages.md delete mode 100644 .changeset/11112-timeline-gantt-inclusive-end.md delete mode 100644 .changeset/11114-master-detail-fields-text.md delete mode 100644 .changeset/11116-builtin-select-multiple.md delete mode 100644 .changeset/11117-datasource-objectname-waiver.md delete mode 100644 .changeset/11117-registration-objectname-description.md delete mode 100644 .changeset/11122-undo-lookup-id.md delete mode 100644 .changeset/11124-automations-pillar-honours-read-only.md delete mode 100644 .changeset/11128-app-nav-canvas-label-maps.md delete mode 100644 .changeset/11131-line-items-chrome.md delete mode 100644 .changeset/11132-master-detail-totals-currency.md delete mode 100644 .changeset/11136-interfaces-pillar-honours-read-only.md delete mode 100644 .changeset/11140-multiselect-placeholder.md delete mode 100644 .changeset/11141-gantt-inclusive-end.md delete mode 100644 .changeset/11144-inline-columns-sort-amount.md delete mode 100644 .changeset/11145-line-items-chrome-remainder.md delete mode 100644 .changeset/11148-nav-inspector-label-map.md delete mode 100644 .changeset/11153-nav-deep-link-survives-mount.md delete mode 100644 .changeset/11160-line-items-last-english.md delete mode 100644 .changeset/11161-dataset-picker-author-text.md delete mode 100644 .changeset/11163-related-list-actions.md delete mode 100644 .changeset/11166-page-header-breadcrumb-slot-retired.md delete mode 100644 .changeset/11167-nav-edit-closes-on-read-only.md delete mode 100644 .changeset/11168-action-family-published-inputs.md delete mode 100644 .changeset/11168-action-group-type-retired.md delete mode 100644 .changeset/11168-calendar-navigation-opennewtab-wording.md delete mode 100644 .changeset/11168-designer-form-layout-options.md delete mode 100644 .changeset/11168-element-family-inputs.md delete mode 100644 .changeset/11168-kanban-navigation-opennewtab-wording.md delete mode 100644 .changeset/11168-map-style-precedence.md delete mode 100644 .changeset/11168-object-form-columns-label.md delete mode 100644 .changeset/11168-object-form-layout-two-values.md delete mode 100644 .changeset/11168-object-gantt-inputs.md delete mode 100644 .changeset/11168-object-map-inputs.md delete mode 100644 .changeset/11168-object-timeline-inputs.md delete mode 100644 .changeset/11168-object-tree-inputs.md delete mode 100644 .changeset/11168-timeline-navigation-wording.md delete mode 100644 .changeset/11168-types-form-layout-mirrors.md delete mode 100644 .changeset/11168-types-object-tree-mirror.md delete mode 100644 .changeset/11168-ui-action-size.md delete mode 100644 .changeset/11168-view-tabs-layout-values.md delete mode 100644 .changeset/11173-retire-page-header-breadcrumb-toggle.md delete mode 100644 .changeset/11181-app-label-i18n-resolver.md delete mode 100644 .changeset/11182-action-menu-host-disabled.md delete mode 100644 .changeset/11183-action-node-properties-bag.md delete mode 100644 .changeset/11189-nav-autosave-flush-generation.md delete mode 100644 .changeset/11190-screen-preview-field-projection.md delete mode 100644 .changeset/11195-feed-refused-read-state.md delete mode 100644 .changeset/11196-designer-nav-label-inherit.md delete mode 100644 .changeset/11196-slice2-surface-inspector-birth.md delete mode 100644 .changeset/11197-doc-nav-entry.md delete mode 100644 .changeset/11198-app-composition-nav-label-optional.md delete mode 100644 .changeset/11199-rls-policy-label-description.md delete mode 100644 .changeset/11201-nav-label-verbatim.md delete mode 100644 .changeset/11201-standard-nav-entries-label-less.md delete mode 100644 .changeset/11204-draft-autosave-in-flight-edit.md delete mode 100644 .changeset/11206-computed-strip-wording.md delete mode 100644 .changeset/11211-layout-mobile-tab-resolvehref.md delete mode 100644 .changeset/11212-permission-gates-fail-closed.md delete mode 100644 .changeset/11216-kanban-grouping-typed.md delete mode 100644 .changeset/11220-screen-select-placeholder-i18n.md delete mode 100644 .changeset/11223-nested-page-children-judged.md delete mode 100644 .changeset/11227-object-grid-17-6-keys.md delete mode 100644 .changeset/11227-types-spec-floor-17-6.md delete mode 100644 .changeset/11232-autosave-send-bound-to-target.md delete mode 100644 .changeset/11234-object-kanban-onquickadd-retired.md delete mode 100644 .changeset/11242-disabled-legs-fail-closed.md delete mode 100644 .changeset/11244-related-toolbar-visible-gate.md delete mode 100644 .changeset/11245-book-sidebar-explicit-group.md delete mode 100644 .changeset/11251-schemaform-top-level-union.md delete mode 100644 .changeset/11252-select-placeholders-i18n.md delete mode 100644 .changeset/11253-choice-field-write-guard.md delete mode 100644 .changeset/11253-field-designer-choice-types.md delete mode 100644 .changeset/11254-gantt-number-resolved-width.md delete mode 100644 .changeset/11254-gantt-percent-resolved-width.md delete mode 100644 .changeset/11254-metric-tile-resolved-width.md delete mode 100644 .changeset/11254-mobile-card-percent-resolved-width.md delete mode 100644 .changeset/11254-number-cell-resolved-width.md delete mode 100644 .changeset/11256-schema-expressions-field-rule-submit-refusal.md delete mode 100644 .changeset/11261-dimensionless-measures-render.md delete mode 100644 .changeset/11262-blank-gates-diagnosed.md delete mode 100644 .changeset/11270-record-related-row-placement.md delete mode 100644 .changeset/11272-buffer-bound-to-loaded-item.md delete mode 100644 .changeset/11276-core-flex-builder-properties-bag.md delete mode 100644 .changeset/11276-flex-properties-bag.md delete mode 100644 .changeset/11276-object-chart-properties-bag.md delete mode 100644 .changeset/11276-object-grid-properties-bag.md delete mode 100644 .changeset/11276-plugin-grid-properties-bag-docs.md delete mode 100644 .changeset/11281-rail-unbound-reason.md delete mode 100644 .changeset/11293-app-shell-page-record-navigator.md delete mode 100644 .changeset/11293-plugin-calendar-page-navigation.md delete mode 100644 .changeset/11293-plugin-kanban-page-navigation.md delete mode 100644 .changeset/11293-react-page-host-record-navigator.md delete mode 100644 .changeset/11294-components-row-menu-declared-gate.md delete mode 100644 .changeset/11294-plugin-grid-row-menu-declared-gate.md delete mode 100644 .changeset/11295-app-shell-served-labels.md delete mode 100644 .changeset/11295-dashboard-served-localized.md delete mode 100644 .changeset/11299-app-shell-nav-label-locale.md delete mode 100644 .changeset/11299-layout-nav-label-locale.md delete mode 100644 .changeset/11299-plugin-designer-nav-label-call.md delete mode 100644 .changeset/11299-types-nav-label-locale-map.md delete mode 100644 .changeset/11302-app-shell-metadata-error-reader-moved.md delete mode 100644 .changeset/11302-data-objectstack-metadata-error-reader.md delete mode 100644 .changeset/11302-plugin-designer-fields-page-refusal-issues.md delete mode 100644 .changeset/11315-core-plugin-charts-no-release.md delete mode 100644 .changeset/11315-plugin-dashboard-chartconfig-structure-unread.md delete mode 100644 .changeset/11315-types-chartconfig-structure-tombstones.md delete mode 100644 .changeset/11318-page-width-padding-refusal.md delete mode 100644 .changeset/11321-record-feed-host-slots.md delete mode 100644 .changeset/11322-bulk-bar-blank-visible-shown.md delete mode 100644 .changeset/11322-bulk-def-visible-docblock.md delete mode 100644 .changeset/11322-core-docblocks-name-callers.md delete mode 100644 .changeset/11326-i18n-region-locale-fallback.md delete mode 100644 .changeset/11330-runner-retired-version-footer.md delete mode 100644 .changeset/11331-app-shell-cancelled-load-spinner.md delete mode 100644 .changeset/11334-row3-booking-17-6.md delete mode 100644 .changeset/11344-action-outcome-messages.md delete mode 100644 .changeset/11347-components-uncast-reads.md delete mode 100644 .changeset/11348-dashboard-widget-reads.md delete mode 100644 .changeset/11348-object-data-table-page-size.md delete mode 100644 .changeset/11349-schemarenderer-working-copy.md delete mode 100644 .changeset/11354-plugin-form-literals.md delete mode 100644 .changeset/11355-small-p1-sites-r2.md delete mode 100644 .changeset/11355-small-p1-sites.md delete mode 100644 .changeset/11357-page-save-drops-requires.md delete mode 100644 .changeset/11358-declared-gate-fails-closed.md delete mode 100644 .changeset/11362-mobile-tab-bar-nav-guard.md delete mode 100644 .changeset/11363-app-face-refuses-mobile-nav-mode.md delete mode 100644 .changeset/11364-public-block-ts-faces.md delete mode 100644 .changeset/11365-input-otp-separator.md delete mode 100644 .changeset/11366-create-plugin-jsdom-29.md delete mode 100644 .changeset/11368-datasource-editor-external-block.md delete mode 100644 .changeset/11372-core-retire-chart-axis-lowering.md delete mode 100644 .changeset/11373-chartconfig-comment-sweep-no-release.md delete mode 100644 .changeset/11379-refused-save-reads-parsed-error.md delete mode 100644 .changeset/11388-widget-layout-complete.md delete mode 100644 .changeset/11395-mobile-tab-bar-order.md delete mode 100644 .changeset/11402-dataset-blank-field.md delete mode 100644 .changeset/11403-console-sdui-manifest.md delete mode 100644 .changeset/11405-list-bind-only.md delete mode 100644 .changeset/11414-guides-data-table-bind-silence-clauses.md delete mode 100644 .changeset/11415-ai-usage-five-hour-reset.md delete mode 100644 .changeset/11417-dashboard-single-series-dropped-measure.md delete mode 100644 .changeset/11423-layout-guide-page-headings.md delete mode 100644 .changeset/11424-container-padding-set.md delete mode 100644 .changeset/11431-readonly-number-scale.md delete mode 100644 .changeset/11432-plural-categories-every-pack.md delete mode 100644 .changeset/11434-app-shell-relationships-note.md delete mode 100644 .changeset/11434-designer-members-retired.md delete mode 100644 .changeset/11434-designer-readers-types.md delete mode 100644 .changeset/11434-i18n-validation-rule-labels.md delete mode 100644 .changeset/11434-plugin-designer-readers-final.md delete mode 100644 .changeset/11434-plugin-designer-readers.md delete mode 100644 .changeset/11434-plugin-designer-retired-props.md delete mode 100644 .changeset/11434-report-element-field-types.md delete mode 100644 .changeset/11436-page-node-pagetype-sweep.md delete mode 100644 .changeset/11438-objectstack-17-6-bump.md delete mode 100644 .changeset/11440-arm-passing-types.md delete mode 100644 .changeset/11440-console-spec-report-stub.md delete mode 100644 .changeset/11440-drill-drawer-report-node.md delete mode 100644 .changeset/11440-known-types-spec-report.md delete mode 100644 .changeset/11440-object-pivot-drilldown-input.md delete mode 100644 .changeset/11440-report-node-wrapper.md delete mode 100644 .changeset/11440-retire-spec-report.md delete mode 100644 .changeset/11441-known-types-retired-layout-keys.md delete mode 100644 .changeset/11441-retire-nav-responsive-grid-layout.md delete mode 100644 .changeset/11444-readonly-percent-currency-faces.md delete mode 100644 .changeset/11445-app-shell-count-families.md delete mode 100644 .changeset/11445-collaboration-count-families.md delete mode 100644 .changeset/11445-components-count-families.md delete mode 100644 .changeset/11445-fields-count-families.md delete mode 100644 .changeset/11445-i18n-count-families.md delete mode 100644 .changeset/11445-plugin-ai-count-families.md delete mode 100644 .changeset/11445-plugin-detail-count-families.md delete mode 100644 .changeset/11445-plugin-gantt-count-families.md delete mode 100644 .changeset/11445-plugin-grid-count-families.md delete mode 100644 .changeset/11445-plugin-list-count-families.md delete mode 100644 .changeset/11445-plugin-view-count-families.md delete mode 100644 .changeset/11448-json-field-face.md delete mode 100644 .changeset/11450-generate-page-draws-title.md delete mode 100644 .changeset/11450-runner-dead-index-fallback.md delete mode 100644 .changeset/11455-approver-position-spelling.md delete mode 100644 .changeset/11459-dashboard-settled-legend-markup.md delete mode 100644 .changeset/11464-sidebar-offcanvas-expanded-on-screen.md delete mode 100644 .changeset/11465-sidebar-declared-surface.md delete mode 100644 .changeset/11466-dashboard-metric-node.md delete mode 100644 .changeset/11466-envelope-object-metric-retired.md delete mode 100644 .changeset/11466-node-slot-union.md delete mode 100644 .changeset/11467-metric-card-arm-inputs.md delete mode 100644 .changeset/11468-bag-carrier-node-types.md delete mode 100644 .changeset/11471-protocol-breakpointcolumnmap-parenthetical.md delete mode 100644 .changeset/11474-layout-spacing-sets.md delete mode 100644 .changeset/11475-dashboard-percent-storage.md delete mode 100644 .changeset/11475-detail-percent-storage.md delete mode 100644 .changeset/11475-gantt-percent-storage.md delete mode 100644 .changeset/11475-grid-percent-storage.md delete mode 100644 .changeset/11475-list-percent-storage.md delete mode 100644 .changeset/11475-percent-declared-storage.md delete mode 100644 .changeset/11476-retire-generate-output.md delete mode 100644 .changeset/11478-anyschema-declared-node-types.md delete mode 100644 .changeset/11479-producers-declared-types.md delete mode 100644 .changeset/11483-metric-card-needs-value.md delete mode 100644 .changeset/11488-retire-generate-from.md delete mode 100644 .changeset/11491-grid-columns-set.md delete mode 100644 .changeset/11494-layout-app-schema-renderer-adapter.md delete mode 100644 .changeset/11494-types-app-schema-renderer-schema.md delete mode 100644 .changeset/11496-retire-cli-add.md delete mode 100644 .changeset/11500-retire-cli-create-lint-test-studio.md delete mode 100644 .changeset/11503-project-setup-cli-table-add-analyze.md delete mode 100644 .changeset/11505-grid-flat-columns-retired.md delete mode 100644 .changeset/11506-drill-drawer-runtime-filter.md delete mode 100644 .changeset/11511-project-setup-retired-cli-rows.md delete mode 100644 .changeset/11513-object-chart-families.md delete mode 100644 .changeset/11514-app-shell-dashboard-preview-reorder.md delete mode 100644 .changeset/11514-dashboard-slot-entry-types.md delete mode 100644 .changeset/11514-designer-dashboard-entry-type.md delete mode 100644 .changeset/11514-types-widget-arm-type.md delete mode 100644 .changeset/11515-plugin-detail-readme-activity-properties.md delete mode 100644 .changeset/11515-types-ts-twins-zod-only-arms.md delete mode 100644 .changeset/11515-vscode-export-react-annotation.md delete mode 100644 .changeset/11517-drill-report-name-retired.md delete mode 100644 .changeset/11520-object-chart-spectype-routing.md delete mode 100644 .changeset/11521-chart-type-doc-row.md delete mode 100644 .changeset/11522-kanban-rule-dialect-retired.md delete mode 100644 .changeset/11525-inline-metric-retired.md delete mode 100644 .changeset/11526-object-metric-rule-filter-spec-shape.md delete mode 100644 .changeset/11530-object-chart-compareto-spectype.md delete mode 100644 .changeset/11533-grid-listview-rule-dialect-retired.md delete mode 100644 .changeset/11536-line-items-published-inputs.md delete mode 100644 .changeset/11539-form-only-from-served-default.md delete mode 100644 .changeset/11541-detail-markdown-editor.md delete mode 100644 .changeset/11544-group-header-field-options.md delete mode 100644 .changeset/11547-drill-url-is-empty-operator.md delete mode 100644 .changeset/11550-fields-tolerated-teaching-dropped.md delete mode 100644 .changeset/11550-object-form-fields-names-only.md delete mode 100644 .changeset/11553-studio-package-less-flows.md delete mode 100644 .changeset/11562-detail-textarea-multiline.md delete mode 100644 .changeset/11572-interface-page-tree-chart-relay.md delete mode 100644 .changeset/11574-grouping-switch-headers.md delete mode 100644 .changeset/11576-create-view-chart-dataset-binding.md delete mode 100644 .changeset/11578-view-save-refusal-said.md delete mode 100644 .changeset/11586-tailwind-source-none-console-runner.md delete mode 100644 .changeset/13626-formview-section-style-keys-retired.md delete mode 100644 .changeset/14026-list-import-mappings-pin.md delete mode 100644 .changeset/1674-maker-single-composer.md delete mode 100644 .changeset/17147-plugin-disclosure-not-enforced.md delete mode 100644 .changeset/1984-v1-honest-chips-and-ui-fragments.md delete mode 100644 .changeset/3162-types-ledger-batch8-verdicts.md delete mode 100644 .changeset/3719-settings-valuedomain-combobox.md delete mode 100644 .changeset/3743-retire-system-hub-card-wall.md delete mode 100644 .changeset/3880-es-done-listo.md delete mode 100644 .changeset/3906-page-header-canonical-docs.md delete mode 100644 .changeset/3909-query-params-filter-union.md delete mode 100644 .changeset/3917-retire-action-condition-branch.md delete mode 100644 .changeset/3965-mint-box-neutral-container.md delete mode 100644 .changeset/3991-builtin-select-empty-state-label-for.md delete mode 100644 .changeset/4044-chartconfig-aria-tombstone.md delete mode 100644 .changeset/4191-autotrigger-honours-visible.md delete mode 100644 .changeset/4202-action-renderers-forward-objectname.md delete mode 100644 .changeset/4420-bulk-delete-visiblewhen.md delete mode 100644 .changeset/4421-current-user-can-binding.md delete mode 100644 .changeset/4526-matrix-artifact-by-provenance.md delete mode 100644 .changeset/4535-export-options-spec-parity.md delete mode 100644 .changeset/4631-component-surface-parity-gate.md delete mode 100644 .changeset/4664-related-list-declared-filter.md delete mode 100644 .changeset/4695-no-series-binding-refusal.md delete mode 100644 .changeset/4730-objectview-config-keys-retired.md delete mode 100644 .changeset/4730-retire-dead-locale-key-batch.md delete mode 100644 .changeset/4783-drawerform-shared-container-grid-cols.md delete mode 100644 .changeset/4795-bindable-text-keys.md delete mode 100644 .changeset/4795-check-bindable-text-keys.md delete mode 100644 .changeset/4830-app-shell-branding-rightrail-prose.md delete mode 100644 .changeset/4850-misplaced-eslint-disable.md delete mode 100644 .changeset/4894-shared-registration-key-reader.md delete mode 100644 .changeset/4895-retire-block-schema-family.md delete mode 100644 .changeset/4905-inline-default-value-pin.md delete mode 100644 .changeset/4918-stale-strip-mode-prose.md delete mode 100644 .changeset/4919-retire-mobile-overrides.md delete mode 100644 .changeset/4929-plugin-published-stylesheets.md delete mode 100644 .changeset/4934-dropped-fields-reason-boundary.md delete mode 100644 .changeset/4935-element-filter-comment-residue.md delete mode 100644 .changeset/4938-timeline-dead-example-link.md delete mode 100644 .changeset/4947-tombstone-judge-convergence.md delete mode 100644 .changeset/4971-declared-arm-subset-gate.md delete mode 100644 .changeset/4991-lucide-pin-range-consistency.md delete mode 100644 .changeset/5034-navigateonsuccess-url-contract.md delete mode 100644 .changeset/5106-doc-key-table-scan-surface.md delete mode 100644 .changeset/5120-retire-data-table-name-alias.md delete mode 100644 .changeset/5157-object-map-config-strict.md delete mode 100644 .changeset/5213-widget-ts-retired-spec-anchor-history.md delete mode 100644 .changeset/5221-onsuccess-navigation.md delete mode 100644 .changeset/5232-view-config-org-wide.md delete mode 100644 .changeset/5234-onnavigate-documented-exception.md delete mode 100644 .changeset/5291-api-console-storage-slot.md delete mode 100644 .changeset/5293-view-sort-order-spelling.md delete mode 100644 .changeset/5325-ineffective-dynamic-import-ledger.md delete mode 100644 .changeset/5397-release-pr-post-version-validation.md delete mode 100644 .changeset/5422-coverage-lane-concurrency.md delete mode 100644 .changeset/5435-list-view-fold-output-authorable.md delete mode 100644 .changeset/5453-retire-grid-column-wrap-forward.md delete mode 100644 .changeset/5458-unprefixed-query-params.md delete mode 100644 .changeset/5483-5439-dts-config-wiring.md delete mode 100644 .changeset/5490-per-chunk-eager-budgets.md delete mode 100644 .changeset/5522-runtime-telemetry-consumer.md delete mode 100644 .changeset/5605-retire-max-tool-roundtrips-plugin-chatbot.md delete mode 100644 .changeset/5605-retire-max-tool-roundtrips-types.md delete mode 100644 .changeset/5631-ui-icon-icon-key-migration.md delete mode 100644 .changeset/5631-ui-icon-visible-placeholder.md delete mode 100644 .changeset/5632-sidebar-trigger-dom-passthrough.md delete mode 100644 .changeset/5632-svg-host-dom-passthrough.md delete mode 100644 .changeset/5674-retire-plugin-component-input.md delete mode 100644 .changeset/5676-layered-envelope-boundary-parse.md delete mode 100644 .changeset/5700-shared-ref-namespaces.md delete mode 100644 .changeset/5729-column-sortability-signal.md delete mode 100644 .changeset/5733-changeset-presence-population.md delete mode 100644 .changeset/5753-providers-drop-spec-dep.md delete mode 100644 .changeset/5754-ci-runs-hook-selftests.md delete mode 100644 .changeset/5775-lane-changeset-reader-mirror.md delete mode 100644 .changeset/5793-spec-range-floors.md delete mode 100644 .changeset/5795-related-list-inherit-list-view-sort.md delete mode 100644 .changeset/5817-remove-app-sidebar.md delete mode 100644 .changeset/5853-tablecolumn-type-canonical-union.md delete mode 100644 .changeset/5856-plugin-grid-catalog-entries.md delete mode 100644 .changeset/5859-retire-orphaned-object-exports.md delete mode 100644 .changeset/5861-retire-table-defaultsort.md delete mode 100644 .changeset/5867-layout-plaintext-fences-batch5.md delete mode 100644 .changeset/5867-plaintext-fenced-ts-batch1.md delete mode 100644 .changeset/5867-plaintext-fenced-ts-batch2.md delete mode 100644 .changeset/5867-plaintext-fenced-ts-batch3.md delete mode 100644 .changeset/5867-plaintext-fenced-ts-batch4.md delete mode 100644 .changeset/5867-plaintext-fenced-ts-batch7.md delete mode 100644 .changeset/5867-plaintext-fenced-ts-batch8.md delete mode 100644 .changeset/5869-runtime-features-scim.md delete mode 100644 .changeset/5874-expandable-field-family-convergence.md delete mode 100644 .changeset/5876-one-lookup-predicate.md delete mode 100644 .changeset/5896-feeditem-single-constructor.md delete mode 100644 .changeset/5902-marked-refusal-drag-write-surfaces.md delete mode 100644 .changeset/5903-objectgantt-declared-keys.md delete mode 100644 .changeset/5905-componentinput-inputtype-tombstone.md delete mode 100644 .changeset/5905-componentinput-retire-constraint-keys.md delete mode 100644 .changeset/5916-record-path-stage-state-accessible-name.md delete mode 100644 .changeset/5920-flow-runner-translation-overlay.md delete mode 100644 .changeset/5924-live-headroom-invariant.md delete mode 100644 .changeset/5926-empty-action-visible-when.md delete mode 100644 .changeset/5927-zod-mirror-group-a-widenings.md delete mode 100644 .changeset/5928-classname-style-props-rename.md delete mode 100644 .changeset/5934-retire-onsuccess-callback-channel.md delete mode 100644 .changeset/5935-one-icon-resolver-seam.md delete mode 100644 .changeset/5936-registration-icon-meta-dead-surface.md delete mode 100644 .changeset/5936-retired-icon-spellings.md delete mode 100644 .changeset/5940-detail-collection-decline-to-fetch.md delete mode 100644 .changeset/5942-retire-mobile-component-config.md delete mode 100644 .changeset/5944-preview-page-source-query-params.md delete mode 100644 .changeset/5945-asarray-contract-envelope.md delete mode 100644 .changeset/5954-aggregate-capability-header.md delete mode 100644 .changeset/5956-5957-record-path-a11y-residue.md delete mode 100644 .changeset/5965-vscode-summary-codeql-claim.md delete mode 100644 .changeset/5972-loading-group-per-language-uniformity.md delete mode 100644 .changeset/5987-permset-clone-to-customize.md delete mode 100644 .changeset/5993-button-shared-icon-resolver.md delete mode 100644 .changeset/5996-eager-closure-missing-chunk.md delete mode 100644 .changeset/5998-record-path-one-classification.md delete mode 100644 .changeset/6001-drop-redundant-filter-casts.md delete mode 100644 .changeset/6002-dashboard-widget-strict.md delete mode 100644 .changeset/6004-grid-column-emit-boundary.md delete mode 100644 .changeset/6011-tosortitems-order-spelling.md delete mode 100644 .changeset/6014-tree-grid-field-formatting.md delete mode 100644 .changeset/6023-recent-item-type-keys.md delete mode 100644 .changeset/6024-catalog-own-plugin-pin-generalized.md delete mode 100644 .changeset/6025-declare-plugin-grid-in-gallery-host.md delete mode 100644 .changeset/6027-sidebar-tailwind-v4-spelling-guard.md delete mode 100644 .changeset/6033-combobox-command-optional.md delete mode 100644 .changeset/6038-production-predicate-fault-warning.md delete mode 100644 .changeset/6041-designer-reference-key.md delete mode 100644 .changeset/6043-retire-designer-formula-control.md delete mode 100644 .changeset/6044-designer-system-key.md delete mode 100644 .changeset/6045-field-payload-sort-order.md delete mode 100644 .changeset/6050-gantt-navigation-basepath.md delete mode 100644 .changeset/6051-gantt-flat-config-declared-keys.md delete mode 100644 .changeset/6052-gantt-export-filename-i18nlabel.md delete mode 100644 .changeset/6058-zod-mirror-unmirrored-ledger.md delete mode 100644 .changeset/6059-publish-omit-server-resolved-defaults.md delete mode 100644 .changeset/6063-kanban-resolvedisplay-dead-guard.md delete mode 100644 .changeset/6067-component-meta-derive-from-canonical.md delete mode 100644 .changeset/6074-check-ts-stale-migration-comment.md delete mode 100644 .changeset/6075-check-validity-recogniser-recall.md delete mode 100644 .changeset/6081-release-lane-drop-changeset-prediction.md delete mode 100644 .changeset/6089-hook-selftests-step-names-drop-counts.md delete mode 100644 .changeset/6092-entry-guard-sweep.md delete mode 100644 .changeset/6105-tombstone-refusal-message.md delete mode 100644 .changeset/6108-sort-axis-convergence.md delete mode 100644 .changeset/6110-predicate-scope-unbound-evaluators.md delete mode 100644 .changeset/6111-formsection-visiblewhen.md delete mode 100644 .changeset/6120-doc-snippet-dependency-resolution.md delete mode 100644 .changeset/6121-report-authoring-face.md delete mode 100644 .changeset/6121-retire-report-data-source.md delete mode 100644 .changeset/6122-action-prop-renames.md delete mode 100644 .changeset/6124-handler-keys-json-refusal.md delete mode 100644 .changeset/6124-view-handler-keys-are-event-names.md delete mode 100644 .changeset/6126-fields-unresolvable-imports.md delete mode 100644 .changeset/6127-location-map-fence-split.md delete mode 100644 .changeset/6131-sidebar-nav-navgroup-annotation.md delete mode 100644 .changeset/6132-undeclared-action-props.md delete mode 100644 .changeset/6138-fields-schema-block-parity-pr1.md delete mode 100644 .changeset/6138-fields-schema-block-parity-pr2.md delete mode 100644 .changeset/6140-field-metadata-rows-option-description.md delete mode 100644 .changeset/6143-components-schema-corrections.md delete mode 100644 .changeset/6150-undeclared-but-consumed-keys.md delete mode 100644 .changeset/6151-stack-schema-omit-collapse.md delete mode 100644 .changeset/6152-object-form-unmirrored-members.md delete mode 100644 .changeset/6152-objectgrid-round6-mirrored.md delete mode 100644 .changeset/6152-unmirrored-round3.md delete mode 100644 .changeset/6152-unmirrored-round4.md delete mode 100644 .changeset/6152-unmirrored-round5.md delete mode 100644 .changeset/6158-radio-group-orientation.md delete mode 100644 .changeset/6165-home-item-type-label-parity.md delete mode 100644 .changeset/6166-zh-breadcrumb-reports.md delete mode 100644 .changeset/6167-plugin-form-catalog-entries.md delete mode 100644 .changeset/6169-chatbot-authoring-face-type.md delete mode 100644 .changeset/6170-retire-timeline-dead-keys.md delete mode 100644 .changeset/6170-timeline-schema-declared-keys.md delete mode 100644 .changeset/6172-kanban-trio-rename.md delete mode 100644 .changeset/6172-markdown-kanban-one-authority.md delete mode 100644 .changeset/6175-column-state-persistence.md delete mode 100644 .changeset/6178-detail-section-header-color.md delete mode 100644 .changeset/6188-line-items-child-object-decline.md delete mode 100644 .changeset/6190-record-details-heading-slot-converge.md delete mode 100644 .changeset/6194-line-items-row-fetch-decline.md delete mode 100644 .changeset/6208-worktree-recipe-fetch-base.md delete mode 100644 .changeset/6213-core-adapters-readme-owns-its-directory.md delete mode 100644 .changeset/6223-object-payload-spec-keys.md delete mode 100644 .changeset/6230-budget-comment-half-status.md delete mode 100644 .changeset/6235-mergedsort-wrap.md delete mode 100644 .changeset/6236-section-grouping-contract.md delete mode 100644 .changeset/6237-section-predicate-layout-diagnostic.md delete mode 100644 .changeset/6237-tabbed-arm-predicate-slot.md delete mode 100644 .changeset/6237-tabbed-section-predicate.md delete mode 100644 .changeset/6237-wizard-step-config-split.md delete mode 100644 .changeset/6238-object-payload-enabled.md delete mode 100644 .changeset/6240-object-payload-fields-map.md delete mode 100644 .changeset/6241-fieldgroups-section-heading-pin.md delete mode 100644 .changeset/6246-action-param-carry-over.md delete mode 100644 .changeset/6247-option-visiblewhen-metadata-admin.md delete mode 100644 .changeset/6250-toast-demo-shapes.md delete mode 100644 .changeset/6252-page-header-action-ids.md delete mode 100644 .changeset/6262-form-features-scope-refused.md delete mode 100644 .changeset/6269-objectview-slot-key-lists.md delete mode 100644 .changeset/6270-schemarenderer-scopeclass-memo.md delete mode 100644 .changeset/6271-kanban-fetch-gate.md delete mode 100644 .changeset/6272-locationfield-spec-shape.md delete mode 100644 .changeset/6278-context-menu-item-icon.md delete mode 100644 .changeset/6280-scan-surface-claims.md delete mode 100644 .changeset/6285-capability-labels-derive-from-spec.md delete mode 100644 .changeset/6286-explain-batch-cap-from-spec.md delete mode 100644 .changeset/6287-flownode-description-key.md delete mode 100644 .changeset/6293-conditionbuilder-reference-value.md delete mode 100644 .changeset/6296-conditionbuilder-subject-vocabulary.md delete mode 100644 .changeset/6298-componentconfig-one-authority.md delete mode 100644 .changeset/6301-packaged-automation-setup-page.md delete mode 100644 .changeset/6302-aggregate-filter-lowering.md delete mode 100644 .changeset/6306-action-icon-type-resolution.md delete mode 100644 .changeset/6307-bold-version-literals.md delete mode 100644 .changeset/6308-living-workflow-example.md delete mode 100644 .changeset/6309-delete-object-fields-bridge.md delete mode 100644 .changeset/6310-designer-formula-key-retired.md delete mode 100644 .changeset/6313-quick-reference-node-floor.md delete mode 100644 .changeset/6316-docs-route-eager-closure-gate.md delete mode 100644 .changeset/6318-code-editor-bar-chart-zod.md delete mode 100644 .changeset/6320-check-nested-dist-ignore.md delete mode 100644 .changeset/6321-changeset-guard-self-coverage.md delete mode 100644 .changeset/6326-menubar-item-icon.md delete mode 100644 .changeset/6329-actionparam-one-authority.md delete mode 100644 .changeset/6331-flow-node-label-producer-census.md delete mode 100644 .changeset/6332-explain-request-adoption.md delete mode 100644 .changeset/6335-starred-apps-nav-exclusion.md delete mode 100644 .changeset/6336-changeset-overwrite-guard.md delete mode 100644 .changeset/6342-dead-migration-guide-pointers.md delete mode 100644 .changeset/6347-button-group-schema-block.md delete mode 100644 .changeset/6349-name-authority-batch-3.md delete mode 100644 .changeset/6349-types-internal-name-collisions-batch-1.md delete mode 100644 .changeset/6349-types-internal-name-collisions-batch-2.md delete mode 100644 .changeset/6353-timeline-bare-key-ownership.md delete mode 100644 .changeset/6355-retire-timeline-timescale-alias.md delete mode 100644 .changeset/6356-timeline-item-element.md delete mode 100644 .changeset/6357-basechema-bind-declaration.md delete mode 100644 .changeset/6360-master-detail-declined-detail-config-hint.md delete mode 100644 .changeset/6361-spec-floor-17-2-0.md delete mode 100644 .changeset/6369-dead-lockfile-merge-driver.md delete mode 100644 .changeset/6372-6371-master-detail-entry-identity.md delete mode 100644 .changeset/6373-datatable-emit-boundary.md delete mode 100644 .changeset/6375-concurrent-update-subsumed-guard.md delete mode 100644 .changeset/6378-boot-redirect-splash.md delete mode 100644 .changeset/6379-console-css-source-excludes-tests.md delete mode 100644 .changeset/6391-lockfile-merge-driver-measurement.md delete mode 100644 .changeset/6392-vestigial-pnpm-steps.md delete mode 100644 .changeset/6394-master-detail-underivable-detail-config-hint.md delete mode 100644 .changeset/6395-approvals-characterization-pins.md delete mode 100644 .changeset/6396-previous-values-dom-leak.md delete mode 100644 .changeset/6397-partial-schema-collapse-pin.md delete mode 100644 .changeset/6400-workflow-version-anchor.md delete mode 100644 .changeset/6405-fields-shared-stylesheet-builder.md delete mode 100644 .changeset/6409-keyed-version-recogniser.md delete mode 100644 .changeset/6412-packaged-actions-activation.md delete mode 100644 .changeset/6416-plugin-report-namespace.md delete mode 100644 .changeset/6419-objectview-expand-gate.md delete mode 100644 .changeset/6421-concurrent-update-code-optional.md delete mode 100644 .changeset/6424-dismantle-fitcontent-cast.md delete mode 100644 .changeset/6424-retire-headericon-hold.md delete mode 100644 .changeset/6424-tablecolumn-declares-fitcontent.md delete mode 100644 .changeset/6424-tablecolumn-declares-headericon.md delete mode 100644 .changeset/6425-objectdatatable-column-holds.md delete mode 100644 .changeset/6425-per-key-declare-retire.md delete mode 100644 .changeset/6426-dashboard-test-header-compiled.md delete mode 100644 .changeset/6431-param-dialog-close-parity.md delete mode 100644 .changeset/6436-lockfile-merge-driver-ci-half.md delete mode 100644 .changeset/6442-catalog-blocks-claimant-list.md delete mode 100644 .changeset/6443-nav-visible-fault-diagnostic.md delete mode 100644 .changeset/6444-evaluator-fault-warn-dedupe.md delete mode 100644 .changeset/6445-disabled-gate-fault-diagnostic.md delete mode 100644 .changeset/6447-pnpm-ledger-manifest-anchor.md delete mode 100644 .changeset/6448-ci-cd-pipeline-node-version-spelling.md delete mode 100644 .changeset/6453-calendar-expand-gate.md delete mode 100644 .changeset/6455-listview-sort-persist-leak.md delete mode 100644 .changeset/6457-persisted-column-width-key.md delete mode 100644 .changeset/6458-retire-undeclared-column-reads.md delete mode 100644 .changeset/6459-grid-data-table-schema-slot.md delete mode 100644 .changeset/6460-objectview-fetch-view-identity.md delete mode 100644 .changeset/6464-recall-submitter-gate.md delete mode 100644 .changeset/6465-stale-typecheck-headers.md delete mode 100644 .changeset/6467-unused-import-gate.md delete mode 100644 .changeset/6469-gantt-block-precedence.md delete mode 100644 .changeset/6470-gantt-dependency-field-deprecated.md delete mode 100644 .changeset/6471-ganttconfigex-restatement-pin.md delete mode 100644 .changeset/6473-metadatatypeactions-param-dialog-close.md delete mode 100644 .changeset/6475-gantt-block-face-declared.md delete mode 100644 .changeset/6477-buildconflict-narrowed-type.md delete mode 100644 .changeset/6480-strip-read-decorations.md delete mode 100644 .changeset/6481-objecttree-keyed-schema-latch.md delete mode 100644 .changeset/6487-visibility-advice-per-tier.md delete mode 100644 .changeset/6488-carry-over-field-keys.md delete mode 100644 .changeset/6489-designer-fields-map-keying.md delete mode 100644 .changeset/6490-saveobject-fields-required.md delete mode 100644 .changeset/6493-bind-field-visibility-evaluators.md delete mode 100644 .changeset/6496-toast-button-keys.md delete mode 100644 .changeset/6497-retire-eventable-schema.md delete mode 100644 .changeset/6499-inactive-values-retained.md delete mode 100644 .changeset/6503-concealment-gate-copy.md delete mode 100644 .changeset/6504-disabled-gate-constant-predicate.md delete mode 100644 .changeset/6505-predicate-valued-gate-rules.md delete mode 100644 .changeset/6507-boot-gate-redirect-splash.md delete mode 100644 .changeset/6514-field-visibility-declared-keys.md delete mode 100644 .changeset/6515-record-form-current-user-normaliser.md delete mode 100644 .changeset/6519-retired-field-key-strip.md delete mode 100644 .changeset/6521-menubar-schema-block-declared-surface.md delete mode 100644 .changeset/6522-objects-page-lookup-keying.md delete mode 100644 .changeset/6523-6346-menuitem-union-onclick.md delete mode 100644 .changeset/6526-formula-422-diagnostic.md delete mode 100644 .changeset/6527-retired-field-key-tombstone-registry.md delete mode 100644 .changeset/6528-resolve-reference-to-census.md delete mode 100644 .changeset/6530-plugin-map-marker-title-precedence.md delete mode 100644 .changeset/6541-sonner-button-variant-enum.md delete mode 100644 .changeset/6545-gate-population-census.md delete mode 100644 .changeset/6547-flat-gantt-face-pointers.md delete mode 100644 .changeset/6548-stale-test-name.md delete mode 100644 .changeset/6551-signedin-user-id-required.md delete mode 100644 .changeset/6557-objectview-titlefield-middle-leg.md delete mode 100644 .changeset/6558-remove-dead-console-record-title-copy.md delete mode 100644 .changeset/6559-expression-user-input-contract.md delete mode 100644 .changeset/6572-interfacelistpage-titlefield-prose.md delete mode 100644 .changeset/6575-data-table-bind-diagnostic.md delete mode 100644 .changeset/6576-widget-schema-anchors.md delete mode 100644 .changeset/6577-bound-turbo-cache-save.md delete mode 100644 .changeset/6592-rekey-fetch-effects-on-primitives.md delete mode 100644 .changeset/6593-duplicate-package-envelope-unwrap.md delete mode 100644 .changeset/6594-headercolor-mirror-enum.md delete mode 100644 .changeset/6595-retire-allowrestore-allowpurge-columns.md delete mode 100644 .changeset/6597-retire-fieldmeta-referenceto.md delete mode 100644 .changeset/6598-inert-expression-warning.md delete mode 100644 .changeset/6598-listview-unauthored-columns.md delete mode 100644 .changeset/6600-doc-gate-app-docs-roots.md delete mode 100644 .changeset/6605-permission-bulk-merge-not-replace.md delete mode 100644 .changeset/6609-declared-keys-header-honesty.md delete mode 100644 .changeset/6610-ar-participle-orthography.md delete mode 100644 .changeset/6611-de-auth-device-passive-register.md delete mode 100644 .changeset/6614-brace-literal-subset.md delete mode 100644 .changeset/6617-in-path-right-diagnostic.md delete mode 100644 .changeset/6620-escalation-enabled-default.md delete mode 100644 .changeset/6625-retire-fieldmeta-decimals.md delete mode 100644 .changeset/6629-provision-env-nested-envelope.md delete mode 100644 .changeset/6634-record-title-step-numbering.md delete mode 100644 .changeset/6639-objectgrid-title-mirrored.md delete mode 100644 .changeset/6645-header-bar-crumb-icon.md delete mode 100644 .changeset/6646-breadcrumb-separator-max-items.md delete mode 100644 .changeset/6648-relationship-target-carriers.md delete mode 100644 .changeset/6650-listcolumn-wrap-implemented.md delete mode 100644 .changeset/6654-retire-preview-mode-consumption.md delete mode 100644 .changeset/6655-object-bound-gantt-refuse-loudly.md delete mode 100644 .changeset/6658-schema-persistence-callable-guard.md delete mode 100644 .changeset/6661-app-launcher-nav-menu-renderers.md delete mode 100644 .changeset/6664-location-optional-keys-carry.md delete mode 100644 .changeset/6665-data-table-non-array-data-diagnostic.md delete mode 100644 .changeset/6674-registry-deprecation-declaration.md delete mode 100644 .changeset/6677-grid-host-fed-default-columns.md delete mode 100644 .changeset/6678-datasource-input-declaration-injection.md delete mode 100644 .changeset/6681-declared-lazy-marketplace-routes.md delete mode 100644 .changeset/6683-app-shell-side-effects-array.md delete mode 100644 .changeset/6687-chatbot-surface-authorable.md delete mode 100644 .changeset/6692-app-schema-menuitem-import.md delete mode 100644 .changeset/6694-dashboard-lookup-reference-meta.md delete mode 100644 .changeset/6697-rekey-three-fetch-effects-on-primitives.md delete mode 100644 .changeset/6700-objecttree-record-effect-primitives.md delete mode 100644 .changeset/6703-dist-completeness-gate.md delete mode 100644 .changeset/6705-parity-scan-reads-ast.md delete mode 100644 .changeset/6708-props-bag-component-renderer-diagnostic.md delete mode 100644 .changeset/6711-retire-reference-to-field.md delete mode 100644 .changeset/6714-location-range-refusal.md delete mode 100644 .changeset/6715-location-strict-numeric-parse.md delete mode 100644 .changeset/6716-location-refusal-diagnostic.md delete mode 100644 .changeset/6723-inline-data-fls.md delete mode 100644 .changeset/6724-usepermissions-stable-identity.md delete mode 100644 .changeset/6726-find-envelope-records-arms.md delete mode 100644 .changeset/6730-shared-activity-type-bucket.md delete mode 100644 .changeset/6740-flex-is-container.md delete mode 100644 .changeset/6744-location-stored-value-validation.md delete mode 100644 .changeset/6745-schema-persistence-ref-during-render.md delete mode 100644 .changeset/6748-preview-mode-provenance-ratchet.md delete mode 100644 .changeset/6750-gantt-empty-items-guard.md delete mode 100644 .changeset/6751-flex-props-envelope-lift.md delete mode 100644 .changeset/6752-degenerate-props-bag-guard.md delete mode 100644 .changeset/6755-field-diagnostics-i18n.md delete mode 100644 .changeset/6757-global-search-notifications-renderers.md delete mode 100644 .changeset/6759-gantt-unusable-date-range.md delete mode 100644 .changeset/6760-degenerate-properties-hoist.md delete mode 100644 .changeset/6761-one-config-bag-predicate.md delete mode 100644 .changeset/6764-container-declaration-census.md delete mode 100644 .changeset/6765-number-input-oracle-divergence.md delete mode 100644 .changeset/6768-mock-import-original.md delete mode 100644 .changeset/6770-gantt-null-date-refusal.md delete mode 100644 .changeset/6771-body-dialect-census.md delete mode 100644 .changeset/6771-retire-body-child-list-dialect.md delete mode 100644 .changeset/6773-aspect-ratio-demo-content.md delete mode 100644 .changeset/6776-metadata-admin-lazy-registration.md delete mode 100644 .changeset/6778-per-chunk-baseline-provenance.md delete mode 100644 .changeset/6780-number-input-badinput-announce.md delete mode 100644 .changeset/6781-gantt-date-type-rule.md delete mode 100644 .changeset/6783-readprops-degenerate-config-bag.md delete mode 100644 .changeset/6788-context-menu-demo-content.md delete mode 100644 .changeset/6790-record-alert-degenerate-config-bag.md delete mode 100644 .changeset/6793-number-widget-browser-deliverable-oracle.md delete mode 100644 .changeset/6794-notify-submitter-default.md delete mode 100644 .changeset/6795-studio-design-consumer-states.md delete mode 100644 .changeset/6797-refs-during-render-three-hooks.md delete mode 100644 .changeset/6799-authored-columns-fls.md delete mode 100644 .changeset/6802-currency-tags-host-onblur.md delete mode 100644 .changeset/6803-numberfield-error-slot.md delete mode 100644 .changeset/6805-6806-catalog-authored-key.md delete mode 100644 .changeset/6809-browser-process-shim-source-only.md delete mode 100644 .changeset/6816-activityfeed-unknown-kind-fails-open.md delete mode 100644 .changeset/6817-usetagcache-config-alloc.md delete mode 100644 .changeset/6818-useoffline-auto-sync-stale-queue.md delete mode 100644 .changeset/6823-deprecation-guidance-agreement.md delete mode 100644 .changeset/6824-chatbot-properties-scope.md delete mode 100644 .changeset/6825-aggregate-spec-shape-strict-where.md delete mode 100644 .changeset/6829-badge-children-arm-a.md delete mode 100644 .changeset/6830-flownode-select-declared-default.md delete mode 100644 .changeset/6837-gantt-tree-referenceto-arms.md delete mode 100644 .changeset/6837-recorddrawer-invented-target-arms.md delete mode 100644 .changeset/6837-reference-to-arm-deletion.md delete mode 100644 .changeset/6839-extract-records-records-arm.md delete mode 100644 .changeset/6840-queryresult-count-value-arms.md delete mode 100644 .changeset/6843-record-title-step-numbering-scan.md delete mode 100644 .changeset/6846-studio-design-empty-registry-pins.md delete mode 100644 .changeset/6848-geolocation-clear-emits-null.md delete mode 100644 .changeset/6854-layout-renderer-retired-onclick.md delete mode 100644 .changeset/6859-injected-editor-commit-comment.md delete mode 100644 .changeset/6864-aggregate-spec-shape-analytics-keys.md delete mode 100644 .changeset/6868-inline-edit-server-verdict.md delete mode 100644 .changeset/6871-branding-token-docs.md delete mode 100644 .changeset/6872-app-shell-branding-title-jsdoc.md delete mode 100644 .changeset/6874-retire-titleformat.md delete mode 100644 .changeset/6875-grid-relational-meta-derive.md delete mode 100644 .changeset/6877-div-guidance-names-box.md delete mode 100644 .changeset/6879-public-blocks-box.md delete mode 100644 .changeset/6880-worktree-recipe-no-track.md delete mode 100644 .changeset/6881-retire-data-table-toolbar.md delete mode 100644 .changeset/6882-datatable-declare-render-cell-editor-and-cell-classname.md delete mode 100644 .changeset/6887-metadata-viewer-derive-select-option.md delete mode 100644 .changeset/6888-location-residue-refusal-keyed.md delete mode 100644 .changeset/6896-retire-chart-inline-data.md delete mode 100644 .changeset/6898-objectgrid-select-fls.md delete mode 100644 .changeset/6900-required-in-gated-section-refusal.md delete mode 100644 .changeset/6906-hook-selftests-collector.md delete mode 100644 .changeset/6907-gantt-date-spelling-rule.md delete mode 100644 .changeset/6909-fieldeditwidget-dom-pass-through.md delete mode 100644 .changeset/6910-retire-event-handlers-schema.md delete mode 100644 .changeset/6917-queryresult-value-count-arms.md delete mode 100644 .changeset/6921-cellclassname-cell-population-pins.md delete mode 100644 .changeset/6931-tombstone-guidance-remainder.md delete mode 100644 .changeset/6938-checkbox-wrapper-class.md delete mode 100644 .changeset/6939-filter-builder-catalog-operator-spellings.md delete mode 100644 .changeset/6939-filter-builder-mirror.md delete mode 100644 .changeset/6939-kanban-column-cards.md delete mode 100644 .changeset/6939-objectql-record-source-refinement.md delete mode 100644 .changeset/6939-overlay-trigger-mirror.md delete mode 100644 .changeset/6939-tree-view-nodes-mirror.md delete mode 100644 .changeset/6940-rowactions-boolean-mirror.md delete mode 100644 .changeset/6943-fields-tooling-dirs-out-of-emit.md delete mode 100644 .changeset/6950-binding-framework-injected-input.md delete mode 100644 .changeset/6951-text-value-retired.md delete mode 100644 .changeset/6951-tree-view-data-retired.md delete mode 100644 .changeset/6955-headercolor-authoring-enum.md delete mode 100644 .changeset/6956-listview-export-options-spec-mirror.md delete mode 100644 .changeset/6956-plugin-list-export-options-casts.md delete mode 100644 .changeset/6958-visiblewhen-clears-the-field-it-hides.md delete mode 100644 .changeset/6959-gantt-lazy-read-flake.md delete mode 100644 .changeset/6965-batch-publish-advisories.md delete mode 100644 .changeset/6972-markdown-inert-keys-retired.md delete mode 100644 .changeset/6977-hook-remediation-no-track.md delete mode 100644 .changeset/6980-save-gate-zod-advisory.md delete mode 100644 .changeset/6982-clientvalidation-stale-cures.md delete mode 100644 .changeset/6985-wizard-card-r-alignment.md delete mode 100644 .changeset/7004-cli-root-path-line.md delete mode 100644 .changeset/7004-cli-union-arm-selection.md delete mode 100644 .changeset/7007-relatedlist-schema-chain-gate.md delete mode 100644 .changeset/7008-field-edit-widget-host-plumbing.md delete mode 100644 .changeset/7014-q1-tier1-select-option-convergence.md delete mode 100644 .changeset/7014-q2-option-label-empty-string.md delete mode 100644 .changeset/7014-select-option-spec-claim-correction.md delete mode 100644 .changeset/7015-text-expression-content-channel.md delete mode 100644 .changeset/7025-nonoptional-enum-cast.md delete mode 100644 .changeset/7027-gantt-date-brand-gate.md delete mode 100644 .changeset/7028-analytics-rows-single-spelling.md delete mode 100644 .changeset/7029-no-invented-calendar-fields.md delete mode 100644 .changeset/7051-form-section-group-reference.md delete mode 100644 .changeset/7063-widget-empty-state-default.md delete mode 100644 .changeset/7064-empty-section-default.md delete mode 100644 .changeset/7069-parity-wider-ledger.md delete mode 100644 .changeset/7070-no-invented-gantt-date-fields.md delete mode 100644 .changeset/7070-timeline-date-axis-floors-retired.md delete mode 100644 .changeset/7072-catalog-menu-value-keys.md delete mode 100644 .changeset/7073-overlay-menu-docs-declared-surface.md delete mode 100644 .changeset/7077-button-group-retire-authored-surface.md delete mode 100644 .changeset/7079-schema-reference-base-props.md delete mode 100644 .changeset/7081-overlay-trigger-union.md delete mode 100644 .changeset/7082-overlay-node-slot-doc-type-names.md delete mode 100644 .changeset/7083-richtext-field-metadata.md delete mode 100644 .changeset/7086-blockquoted-fence-collector.md delete mode 100644 .changeset/7087-disabled-twin-symmetry.md delete mode 100644 .changeset/7088-hidden-jsdoc-single-hide-path.md delete mode 100644 .changeset/7092-launcher-exclusion-reason.md delete mode 100644 .changeset/7097-grid-2xl-breakpoint.md delete mode 100644 .changeset/7104-alert-dialog-read-dialect-declared.md delete mode 100644 .changeset/7105-empty-action-declared-schemanode.md delete mode 100644 .changeset/7108-approvals-inbox-dead-record-tombstone.md delete mode 100644 .changeset/7113-chart-data-model.md delete mode 100644 .changeset/7115-root-readme-doc-gate-surface.md delete mode 100644 .changeset/7121-studio-canvas-leaf-affordances.md delete mode 100644 .changeset/7122-capability-manage-org-presentation.md delete mode 100644 .changeset/7122-eager-closure-ceiling-raise.md delete mode 100644 .changeset/7122-objectstack-family-17-3-0.md delete mode 100644 .changeset/7122-postcss-dedupe.md delete mode 100644 .changeset/7122-spec-17-3-0-parity-reconciliation.md delete mode 100644 .changeset/7122-spec-17-3-0-pin-repointing.md delete mode 100644 .changeset/7122-spec-17-3-0-reconciliation.md delete mode 100644 .changeset/7125-dashboard-empty-state-keys-retired.md delete mode 100644 .changeset/7126-inline-widgets-read-error.md delete mode 100644 .changeset/7127-record-details-refuses-not-strips.md delete mode 100644 .changeset/7129-retire-detailviewsection-hideempty.md delete mode 100644 .changeset/7132-empty-state-role-default.md delete mode 100644 .changeset/7137-selection-expires-with-leaf.md delete mode 100644 .changeset/7140-sankey-no-positive-flow.md delete mode 100644 .changeset/7142-activity-timeline-empty-i18n.md delete mode 100644 .changeset/7143-data-error-state-migration.md delete mode 100644 .changeset/7148-sankey-omitted-rows-note.md delete mode 100644 .changeset/7149-activity-timeline-remaining-literals.md delete mode 100644 .changeset/7151-legacy-retired-provenance.md delete mode 100644 .changeset/7154-lookup-picker-keys-editor-seam.md delete mode 100644 .changeset/7155-converge-lookup-dialect-camelcase.md delete mode 100644 .changeset/7163-detail-timestamp-i18n.md delete mode 100644 .changeset/7164-gantt-malformed-row-refusal.md delete mode 100644 .changeset/7165-grid-dependent-values.md delete mode 100644 .changeset/7166-retire-inert-fieldmeta-copies.md delete mode 100644 .changeset/7173-ai-pending-actions-inbox-i18n.md delete mode 100644 .changeset/7175-downstream-consumer-census.md delete mode 100644 .changeset/7177-studio-switcher-server-writable-verdict.md delete mode 100644 .changeset/7178-format-measure-date.md delete mode 100644 .changeset/7179-grid-grouping-projection.md delete mode 100644 .changeset/7181-body-dialect-producers-to-children.md delete mode 100644 .changeset/7182-declared-action-ids-one-rule.md delete mode 100644 .changeset/7183-dist-vitest-project.md delete mode 100644 .changeset/7187-relational-copy-set-cell-scoped.md delete mode 100644 .changeset/7188-components-data-table-pending-row.md delete mode 100644 .changeset/7188-plugin-grid-staged-parent-rescopes-child.md delete mode 100644 .changeset/7188-types-render-cell-editor-pending-row.md delete mode 100644 .changeset/7189-grouped-grid-partial-disclosure.md delete mode 100644 .changeset/7189-server-side-grid-grouping.md delete mode 100644 .changeset/7190-detail-dependson-lookup-probe.md delete mode 100644 .changeset/7190-detail-inline-dependent-values.md delete mode 100644 .changeset/7192-retire-seven-unmounted-detail-exports.md delete mode 100644 .changeset/7194-scatter-one-measure.md delete mode 100644 .changeset/7195-no-numeric-value-refusal.md delete mode 100644 .changeset/7196-plugin-grid-held-key-census.md delete mode 100644 .changeset/7199-listview-description-relay.md delete mode 100644 .changeset/7200-object-form-section-style-keys-undeclared.md delete mode 100644 .changeset/7201-schema-slot-census-gate.md delete mode 100644 .changeset/7203-gantt-toolbar-period-label.md delete mode 100644 .changeset/7204-gantt-tasklist-width-and-date-predicate.md delete mode 100644 .changeset/7206-dead-context-tail-comments.md delete mode 100644 .changeset/7206-retire-dead-context-tail.md delete mode 100644 .changeset/7209-schema-renderer-context-read-as-declared.md delete mode 100644 .changeset/7210-gantt-paging-chrome.md delete mode 100644 .changeset/7210-non-grid-row-ceiling.md delete mode 100644 .changeset/7212-published-tsconfig-tooling-exclude-ratchet.md delete mode 100644 .changeset/7215-expand-fls-gate.md delete mode 100644 .changeset/7216-listview-speculative-fls.md delete mode 100644 .changeset/7217-grouping-null-entry-guard.md delete mode 100644 .changeset/7218-rowcolor-host-relay.md delete mode 100644 .changeset/7219-retire-viewdescription-catalog-key.md delete mode 100644 .changeset/7221-filter-dialect-equivalence.md delete mode 100644 .changeset/7225-settled-schema-convergence.md delete mode 100644 .changeset/7228-gantt-column-width-flat-floor.md delete mode 100644 .changeset/7230-expand-fls-gate-five-sites.md delete mode 100644 .changeset/7231-gantt-stale-reload-finally.md delete mode 100644 .changeset/7234-requiredpermissions-author-channel.md delete mode 100644 .changeset/7235-html-tier-discriminator-attr.md delete mode 100644 .changeset/7237-gantt-refresh-in-place.md delete mode 100644 .changeset/7237-stable-list-filter-identity.md delete mode 100644 .changeset/7238-disabled-one-carrier.md delete mode 100644 .changeset/7243-colorfield-shared-ladder.md delete mode 100644 .changeset/7245-default-view-namefield-lead.md delete mode 100644 .changeset/7248-scatter-legend-names-its-series.md delete mode 100644 .changeset/7252-form-outcome-toast-supersede.md delete mode 100644 .changeset/7256-chrome-home-follows-declared-landing.md delete mode 100644 .changeset/7257-metadata-hmr-give-up-after-404.md delete mode 100644 .changeset/7258-chart-builtin-aggregate-label.md delete mode 100644 .changeset/7265-components-sort-direction-bound.md delete mode 100644 .changeset/7265-core-context-token-mirrors.md delete mode 100644 .changeset/7265-data-objectstack-filter-operator-rename.md delete mode 100644 .changeset/7265-plugin-detail-record-alert-renderer-props.md delete mode 100644 .changeset/7265-types-user-filter-field-derives.md delete mode 100644 .changeset/7271-localstorage-probe-node26.md delete mode 100644 .changeset/7279-object-view-split-route-pin.md delete mode 100644 .changeset/7281-record-header-title-width-floor.md delete mode 100644 .changeset/7282-console-docs-fragment-markers.md delete mode 100644 .changeset/7287-resolve-title-field-shared-ladder.md delete mode 100644 .changeset/7292-turbo-owns-build-order.md delete mode 100644 .changeset/7293-dataset-metric-subcaption.md delete mode 100644 .changeset/7295-chat-message-avatar-keys.md delete mode 100644 .changeset/7297-record-id-filter-token.md delete mode 100644 .changeset/7298-discussion-explicit-composition.md delete mode 100644 .changeset/7298-page-assignment-priority-read.md delete mode 100644 .changeset/7299-related-list-multivalue-membership.md delete mode 100644 .changeset/7303-kanban-swimlane-column-header-row.md delete mode 100644 .changeset/7308-doc-snippet-nested-package-readmes.md delete mode 100644 .changeset/7313-object-calendar-record-source.md delete mode 100644 .changeset/7316-toast-sonner-button-variant-input.md delete mode 100644 .changeset/7319-dead-schemarenderer-retired.md delete mode 100644 .changeset/7321-record-reach-sections-label.md delete mode 100644 .changeset/7322-object-kanban-component-props.md delete mode 100644 .changeset/7322-object-kanban-group-by-limit.md delete mode 100644 .changeset/7323-adapter-factory-return.md delete mode 100644 .changeset/7324-plugin-form-nameable-parameter-types.md delete mode 100644 .changeset/7333-gantt-empty-host-data.md delete mode 100644 .changeset/7334-gantt-navigation-forward.md delete mode 100644 .changeset/7337-i18n-covered-specifier-flip.md delete mode 100644 .changeset/7337-vi-mock-i18n-inherit.md delete mode 100644 .changeset/7340-docs-retired-handler-keys.md delete mode 100644 .changeset/7344-handler-string-any-mirrors.md delete mode 100644 .changeset/7345-master-detail-outcome-toast.md delete mode 100644 .changeset/7347-padded-grouping-refused-pin.md delete mode 100644 .changeset/7352-drill-down-config-mirror.md delete mode 100644 .changeset/7353-retire-widget-dataprovider.md delete mode 100644 .changeset/7354-masterdetail-duplicate-refusal.md delete mode 100644 .changeset/7357-retire-field-metadata-depends-on.md delete mode 100644 .changeset/7363-objectql-union-arms.md delete mode 100644 .changeset/7364-timeline-nonobject-row.md delete mode 100644 .changeset/7368-studio-package-list-error-posture.md delete mode 100644 .changeset/7371-ai-usage-indicator-weekly-reset.md delete mode 100644 .changeset/7373-recovery-redirects-follow-declared-landing.md delete mode 100644 .changeset/7382-record-alert-cta-shared-resolver.md delete mode 100644 .changeset/7386-categorical-axis-min-tick-gap.md delete mode 100644 .changeset/7389-retire-use-client-notifications.md delete mode 100644 .changeset/7390-gallery-host-ownership-pin.md delete mode 100644 .changeset/7394-listview-view-switch-refetch.md delete mode 100644 .changeset/7396-scatter-extreme-marks-stay-inside-the-plot.md delete mode 100644 .changeset/7397-remove-duplicate-chart-primitives.md delete mode 100644 .changeset/7401-chart-family-from-type.md delete mode 100644 .changeset/7402-scatter-ignores-compareto.md delete mode 100644 .changeset/7415-action-type-input-rename.md delete mode 100644 .changeset/7421-gantt-tasklistwidth-tombstone.md delete mode 100644 .changeset/7429-expand-fls-seven-sites.md delete mode 100644 .changeset/7435-declared-lookup-legs-two-readers.md delete mode 100644 .changeset/7435-remaining-declared-lookup-legs.md delete mode 100644 .changeset/7439-approvals-teardown-race.md delete mode 100644 .changeset/7443-datetime-compact-style.md delete mode 100644 .changeset/7450-element-text-published-variants.md delete mode 100644 .changeset/7450-element-text-refusal-prose.md delete mode 100644 .changeset/7450-inspector-text-variant-options.md delete mode 100644 .changeset/7450-preview-sample-text-variant.md delete mode 100644 .changeset/7450-text-bare-key-resolution-pin.md delete mode 100644 .changeset/7454-calendar-allday-spelling.md delete mode 100644 .changeset/7459-timeline-absent-date-axis-refusal.md delete mode 100644 .changeset/7466-timeline-colorfieldladder-settlement.md delete mode 100644 .changeset/7469-app-actions-retired.md delete mode 100644 .changeset/7470-designer-objectname-not-required.md delete mode 100644 .changeset/7472-cli-generated-layout-icon-seam.md delete mode 100644 .changeset/7477-listview-object-provider-fold.md delete mode 100644 .changeset/7479-lazy-locale-catalogues.md delete mode 100644 .changeset/7483-console-objectview-props.md delete mode 100644 .changeset/7493-componentinput-retire-label-defaultvalue-advanced.md delete mode 100644 .changeset/7495-compareto-one-predicate.md delete mode 100644 .changeset/7499-gantt-non-axis-floors-omitted.md delete mode 100644 .changeset/7501-profile-my-language.md delete mode 100644 .changeset/7507-non-grid-ceiling-correctives.md delete mode 100644 .changeset/7508-non-grid-ceiling-to-core.md delete mode 100644 .changeset/7509-dashboard-root-title-retired.md delete mode 100644 .changeset/7509-dashboardview-title-comment-corrected.md delete mode 100644 .changeset/7512-ganttview-unread-residues.md delete mode 100644 .changeset/7515-unreferenced-source-gate.md delete mode 100644 .changeset/7516-fieldorder-relay-rung.md delete mode 100644 .changeset/7519-retire-mobile-residue-types.md delete mode 100644 .changeset/7521-timeline-colorfieldladder-race.md delete mode 100644 .changeset/7530-predicate-envelope-declared.md delete mode 100644 .changeset/7531-listview-column-undeclared-reads.md delete mode 100644 .changeset/7540-option-editor-key-loss.md delete mode 100644 .changeset/7544-listview-chart-capability-gate.md delete mode 100644 .changeset/7546-chart-series-keys-declared.md delete mode 100644 .changeset/7547-forced-path-invented-bindings.md delete mode 100644 .changeset/7551-action-operation-update-executor.md delete mode 100644 .changeset/7561-filter-builder-operator-trigger-label.md delete mode 100644 .changeset/7562-filter-field-type-fourteen-members.md delete mode 100644 .changeset/7572-i18n-resources-deep-merge.md delete mode 100644 .changeset/7578-classname-style-describe.md delete mode 100644 .changeset/7579-relatedlist-value-gates.md delete mode 100644 .changeset/7580-responsive-vocabulary-rehome.md delete mode 100644 .changeset/7581-strict-authoring-face-measurement.md delete mode 100644 .changeset/7586-primary-field-consumer-reads.md delete mode 100644 .changeset/7587-quota-reset-promise-pin.md delete mode 100644 .changeset/7588-assignment-value-cel-envelope.md delete mode 100644 .changeset/7593-record-alert-success-icon.md delete mode 100644 .changeset/7597-field-inspector-value-domain.md delete mode 100644 .changeset/7603-resource-edit-read-decoration-strip.md delete mode 100644 .changeset/7613-recipient-picker-field-kind.md delete mode 100644 .changeset/7614-flow-runs-parallel-branch-key.md delete mode 100644 .changeset/7615-field-api-name-follows-label.md delete mode 100644 .changeset/7620-data-table-date-convention.md delete mode 100644 .changeset/7623-retire-dashboard-root-title-declaration.md delete mode 100644 .changeset/7625-drop-recharts-from-components.md delete mode 100644 .changeset/7627-shared-record-source-reader.md delete mode 100644 .changeset/7632-shared-record-source-config.md delete mode 100644 .changeset/7635-spec-173-comment-repairs.md delete mode 100644 .changeset/7638-navigation-url-follows-record-source.md delete mode 100644 .changeset/7645-schema-registry-kanban-honesty.md delete mode 100644 .changeset/7650-id-field-published-guidance.md delete mode 100644 .changeset/7650-metadata-item-reference-canonicalisation.md delete mode 100644 .changeset/7650-retired-dialect-choke-point.md delete mode 100644 .changeset/7654-chatbot-display-mode-tombstone.md delete mode 100644 .changeset/7654-floating-chatbot-trigger-icon-tombstone.md delete mode 100644 .changeset/7655-chatbot-registration-authoring-faces.md delete mode 100644 .changeset/7658-toc-code-span-anchor-parity.md delete mode 100644 .changeset/7659-retire-validation-engine.md delete mode 100644 .changeset/7664-kanban-arm-plugin-dialect.md delete mode 100644 .changeset/7664-plugin-kanban-declared-schema.md delete mode 100644 .changeset/7665-schema-registry-key-set-vs-values.md delete mode 100644 .changeset/7667-toc-emphasis-flanking.md delete mode 100644 .changeset/7678-tombstone-discriminator-agreement.md delete mode 100644 .changeset/7681-chart-series-type-override-dataKey.md delete mode 100644 .changeset/7687-combobox-option-disabled.md delete mode 100644 .changeset/7690-chart-axis-config-declared.md delete mode 100644 .changeset/7694-chart-series-chart-type-alias-refusal.md delete mode 100644 .changeset/7696-chart-local-select-cell-measured.md delete mode 100644 .changeset/7697-combobox-option-root-barrel.md delete mode 100644 .changeset/7698-series-opacity-dasharray-unconditional.md delete mode 100644 .changeset/7699-file-submit-requires-id.md delete mode 100644 .changeset/7702-union-arm-count-prose.md delete mode 100644 .changeset/7703-chatbot-dark-keys-retired.md delete mode 100644 .changeset/7704-schema-registry-chatbot-keys.md delete mode 100644 .changeset/7707-flowrunner-refused-outcome-notice.md delete mode 100644 .changeset/7708-chatbot-floating-spread-fence.md delete mode 100644 .changeset/7709-edit-mode-chip-sample-data.md delete mode 100644 .changeset/7711-calendar-filter-is-not-a-config-slot.md delete mode 100644 .changeset/7712-kanban-calendar-filter-input.md delete mode 100644 .changeset/7714-lookup-draft-stays-client-side.md delete mode 100644 .changeset/7715-mirrors-carry-spec-object-checks.md delete mode 100644 .changeset/7719-app-menu-item-shortcut-named-refusal.md delete mode 100644 .changeset/7721-actions-reader-census.md delete mode 100644 .changeset/7722-wrapper-class-five-more.md delete mode 100644 .changeset/7727-conditional-formatting-record-scope.md delete mode 100644 .changeset/7735-zod-mirrors-stop-authoring-defaults.md delete mode 100644 .changeset/7740-identity-import-saved-mappings.md delete mode 100644 .changeset/7741-list-import-mappings-discriminate.md delete mode 100644 .changeset/7742-kanban-arm-batch70.md delete mode 100644 .changeset/7744-chart-type-internal-only.md delete mode 100644 .changeset/7745-formatdate-options-style.md delete mode 100644 .changeset/7747-datetime-format-cast-narrowing.md delete mode 100644 .changeset/7750-retire-datascopemanager.md delete mode 100644 .changeset/7752-analytics-where-lowering.md delete mode 100644 .changeset/7759-dashboard-header-global-filters-spec.md delete mode 100644 .changeset/7759-function-slot-keys-refusal.md delete mode 100644 .changeset/7760-lazy-mirror-input-type-args.md delete mode 100644 .changeset/7762-object-grid-export-options-bare-array-refusal.md delete mode 100644 .changeset/7767-collapsible-trigger-union.md delete mode 100644 .changeset/7772-page-block-kanban-group-by-control.md delete mode 100644 .changeset/7773-kanban-adapter-groupfield-write.md delete mode 100644 .changeset/7780-object-kanban-record-source.md delete mode 100644 .changeset/7786-storage-spy-counter-probes.md delete mode 100644 .changeset/7787-navigation-overlay-doc-example.md delete mode 100644 .changeset/7791-specparity-cwd-root.md delete mode 100644 .changeset/7798-getdataconfig-doc-example.md delete mode 100644 .changeset/7799-cwd-rooted-package-tests.md delete mode 100644 .changeset/7804-data-table-handler-key-arms.md delete mode 100644 .changeset/7804-detail-handler-slots-declared.md delete mode 100644 .changeset/7804-list-view-handler-slots-declared.md delete mode 100644 .changeset/7804-object-kanban-handler-keys-judged.md delete mode 100644 .changeset/7804-objectql-handler-key-arms.md delete mode 100644 .changeset/7804-tree-view-handler-slot.md delete mode 100644 .changeset/7821-manage-refresh-failure-is-not-deletion.md delete mode 100644 .changeset/7823-objectview-chart-relay-whole-block.md delete mode 100644 .changeset/7828-calendar-gantt-ladder-harness.md delete mode 100644 .changeset/7833-agents-verified-claim-rule.md delete mode 100644 .changeset/7837-vscode-export-react-side-effect-import.md delete mode 100644 .changeset/7839-tree-arm-own-reference.md delete mode 100644 .changeset/7842-objectview-datasource-contract.md delete mode 100644 .changeset/7849-unevaluated-diagnostic-lists-properties.md delete mode 100644 .changeset/7862-vscode-export-react-unused-import.md delete mode 100644 .changeset/7867-action-params-templates.md delete mode 100644 .changeset/7874-timeline-relative-defaults-retired.md delete mode 100644 .changeset/7876-activity-map-docs-transcription-pin.md delete mode 100644 .changeset/7881-package-lookup-failure-is-not-an-empty-result.md delete mode 100644 .changeset/7895-timeline-settled-schema-gate.md delete mode 100644 .changeset/7903-gallery-settled-schema-gate.md delete mode 100644 .changeset/7907-manage-snapshot-refresh-reports.md delete mode 100644 .changeset/7911-widget-input-retire-label-defaultvalue-advanced.md delete mode 100644 .changeset/7912-schema-renderer-datasource-contract.md delete mode 100644 .changeset/7917-export-breadcrumb-object-tree-zod-schemas.md delete mode 100644 .changeset/7918-zod-lazy-getter-identity.md delete mode 100644 .changeset/7923-schema-reference-named-list-view-keys.md delete mode 100644 .changeset/7924-density-mode-through-fold.md delete mode 100644 .changeset/7924-named-list-view-disposition-buckets.md delete mode 100644 .changeset/7924-named-list-view-liveness-census.md delete mode 100644 .changeset/7924-named-list-view-retire.md delete mode 100644 .changeset/7926-page-node-refuses-actions.md delete mode 100644 .changeset/7928-listviews-by-reference-fold.md delete mode 100644 .changeset/7947-named-list-view-figures.md delete mode 100644 .changeset/7952-dashboard-widgets-component-arm.md delete mode 100644 .changeset/7963-alert-dialog-footer-keys-retired.md delete mode 100644 .changeset/7967-twin-count-pin-marker-strip.md delete mode 100644 .changeset/7974-swipe-direction-honours-declared-set.md delete mode 100644 .changeset/7976-bind-documented-export-preamble.md delete mode 100644 .changeset/7979-package-form-dialog-envelope-reader.md delete mode 100644 .changeset/7980-agent-key-envelope-read.md delete mode 100644 .changeset/7989-i18n-readme-locale-count.md delete mode 100644 .changeset/7997-detail-view-related-retired.md delete mode 100644 .changeset/8012-fixture-discipline-heading.md delete mode 100644 .changeset/8018-covered-specifiers-membership-pin.md delete mode 100644 .changeset/8021-schema-rendering-data-context.md delete mode 100644 .changeset/8024-retire-permission-guard-config.md delete mode 100644 .changeset/8026-objectcalendar-alldayfield-honoured.md delete mode 100644 .changeset/8031-tree-fixture-retired-target-key.md delete mode 100644 .changeset/8033-homepage-fetch-router.md delete mode 100644 .changeset/8041-create-plugin-licence-prompt.md delete mode 100644 .changeset/8055-geolocation-zero-coordinate-display.md delete mode 100644 .changeset/8058-designer-lookup-target-retired-spelling.md delete mode 100644 .changeset/8067-component-input-member-kind.md delete mode 100644 .changeset/8068-mandatory-per-block-member-pin.md delete mode 100644 .changeset/8069-field-rule-fault-direction-declared.md delete mode 100644 .changeset/8069-visiblewhen-fault-refuses-submit.md delete mode 100644 .changeset/8070-name-visiblewhen-clear.md delete mode 100644 .changeset/8071-grid-toolbar-member-pins-slice-13.md delete mode 100644 .changeset/8071-master-detail-other-half-slice-18.md delete mode 100644 .changeset/8071-master-detail-seed-and-sections-slice-15.md delete mode 100644 .changeset/8071-object-form-member-pins-slice-10.md delete mode 100644 .changeset/8071-object-form-member-pins-slice-11.md delete mode 100644 .changeset/8071-object-kanban-member-pins.md delete mode 100644 .changeset/8071-object-metric-query-member-pins.md delete mode 100644 .changeset/8072-input-wrapper-class-mirrored.md delete mode 100644 .changeset/8078-floating-chatbot-classname-merge.md delete mode 100644 .changeset/8083-record-presence-stub-array-shape.md delete mode 100644 .changeset/8086-chart-series-type-arm.md delete mode 100644 .changeset/8099-corepack-pnpm-download.md delete mode 100644 .changeset/8106-listview-callback-param-types.md delete mode 100644 .changeset/8114-detail-tab-activity-timeline.md delete mode 100644 .changeset/8130-tool-display-helpers-test-name.md delete mode 100644 .changeset/8137-record-activity-calibration-repoint.md delete mode 100644 .changeset/8140-combobox-schema-members.md delete mode 100644 .changeset/8148-number-badinput-refusal-keyed.md delete mode 100644 .changeset/8149-location-placeholder-localized.md delete mode 100644 .changeset/8155-app-root-residue-swept.md delete mode 100644 .changeset/8157-radar-series-presentation.md delete mode 100644 .changeset/8165-translatefn-one-authority.md delete mode 100644 .changeset/8166-record-scope-data-root.md delete mode 100644 .changeset/8167-conditionbuilder-mount-scope.md delete mode 100644 .changeset/8167-per-surface-condition-scope.md delete mode 100644 .changeset/8167-widget-context-condition-scope.md delete mode 100644 .changeset/8168-objectchart-absent-category-axis-refusal.md delete mode 100644 .changeset/8169-map-refuses-unbound.md delete mode 100644 .changeset/8170-calendar-refusal-names-an-actionable-remedy.md delete mode 100644 .changeset/8171-calendar-sort-input.md delete mode 100644 .changeset/8174-kanban-calendar-filter-sort.md delete mode 100644 .changeset/8175-record-details-namefield-dedupe.md delete mode 100644 .changeset/8178-ai-schemas-retire-zero-read-members.md delete mode 100644 .changeset/8181-draft-envelope-read-decoration-strip.md delete mode 100644 .changeset/8181-permission-door-read-decoration-pin.md delete mode 100644 .changeset/8187-dataset-preview-dimension-labels.md delete mode 100644 .changeset/8193-objectview-canonical-groupbyfield.md delete mode 100644 .changeset/8194-fields-date-widget-convention.md delete mode 100644 .changeset/8198-unused-runtime-declarations-removed.md delete mode 100644 .changeset/8201-kanban-calendar-scalar-authoring-keys.md delete mode 100644 .changeset/8201-quickadd-ruled-carve-out.md delete mode 100644 .changeset/8204-refuseskind-invalid-type-decisive.md delete mode 100644 .changeset/8209-datetime-widget-faces.md delete mode 100644 .changeset/8213-objectview-kanban-groupby-retired.md delete mode 100644 .changeset/8214-chatbot-anypart-state-widen.md delete mode 100644 .changeset/8218-studio-property-panel-de-developerize.md delete mode 100644 .changeset/8219-ai-chip-label-app-shell.md delete mode 100644 .changeset/8219-chatbot-surface-context-title.md delete mode 100644 .changeset/8219-lone-widget-one-canvas-frame.md delete mode 100644 .changeset/8219-studio-publish-no-draft-outline.md delete mode 100644 .changeset/8220-map-gantt-timeline-query-inputs.md delete mode 100644 .changeset/8221-retire-legacy-string-sort.md delete mode 100644 .changeset/8225-drop-cloud-namespace-reexport.md delete mode 100644 .changeset/8231-machine-name-chip-source-label.md delete mode 100644 .changeset/8236-collapsible-open-intercept-retire.md delete mode 100644 .changeset/8238-live-e2e-report-promise.md delete mode 100644 .changeset/8253-export-tree-view-config.md delete mode 100644 .changeset/8254-objectview-spec-shaped-named-view.md delete mode 100644 .changeset/8255-docs-spec-shaped-list-view.md delete mode 100644 .changeset/8256-readme-kanban-example-pin.md delete mode 100644 .changeset/8261-translatefn-i18n-authority.md delete mode 100644 .changeset/8266-dashboard-count-aggregate-series-key.md delete mode 100644 .changeset/8268-testid-emitted-as-data-testid.md delete mode 100644 .changeset/8269-dashboard-category-axis-groupby.md delete mode 100644 .changeset/8278-page-tabs-item-value.md delete mode 100644 .changeset/8279-definition-list-term-description.md delete mode 100644 .changeset/8280-remove-ai-input-panel.md delete mode 100644 .changeset/8284-content-channel-per-component.md delete mode 100644 .changeset/8284-refusal-and-notice-text.md delete mode 100644 .changeset/8285-kanban-quickadd-html-diagnostic.md delete mode 100644 .changeset/8285-object-kanban-quick-add-retired.md delete mode 100644 .changeset/8290-dashboard-reference-widget-keys.md delete mode 100644 .changeset/8291-workspace-admin-reads-the-rung.md delete mode 100644 .changeset/8294-fields-readme-cell-renderer-two-step.md delete mode 100644 .changeset/8303-react-dep-peer-contradiction.md delete mode 100644 .changeset/8307-kanban-lane-count-honesty.md delete mode 100644 .changeset/8308-kanban-card-title-one-precedence.md delete mode 100644 .changeset/8310-page-node-body-arity.md delete mode 100644 .changeset/8313-kanban-structured-authoring-keys.md delete mode 100644 .changeset/8314-calendar-record-source-authoring-keys.md delete mode 100644 .changeset/8315-sdui-parser-manifest-binding-field-retired.md delete mode 100644 .changeset/8317-strip-imported-defaults.md delete mode 100644 .changeset/8318-jsdoc-default-tag-corrections.md delete mode 100644 .changeset/8320-metadatacache-example-unimportable.md delete mode 100644 .changeset/8327-cast-read-census-ledger-header.md delete mode 100644 .changeset/8329-ai-build-empty-state-v1-boundary.md delete mode 100644 .changeset/8331-data-table-empty-action-primitive-node.md delete mode 100644 .changeset/8333-lockfile-dedupe-gate.md delete mode 100644 .changeset/8338-retire-toast-action.md delete mode 100644 .changeset/8343-apply-blueprint-awaiting-confirmation.md delete mode 100644 .changeset/8344-node-recursion-point-redirect.md delete mode 100644 .changeset/8345-strict-authoring-face-wrapper-kinds.md delete mode 100644 .changeset/8345-strict-authoring-face.md delete mode 100644 .changeset/8348-object-gantt-judged-against-protocol-row.md delete mode 100644 .changeset/8348-object-map-judged-against-protocol-row.md delete mode 100644 .changeset/8348-object-tree-data-arm-view-data.md delete mode 100644 .changeset/8348-record-source-data-arm-per-spec-row.md delete mode 100644 .changeset/8350-dedupe-emptiness-shares-header-definition.md delete mode 100644 .changeset/8351-titleformat-hides-no-row.md delete mode 100644 .changeset/8355-retire-calendar-date-aliases.md delete mode 100644 .changeset/8365-stray-kanban-groupby-refused.md delete mode 100644 .changeset/8366-vitest-timezone-pin.md delete mode 100644 .changeset/8376-detailsection-emptiness-authority.md delete mode 100644 .changeset/8385-bash32-floor-port-rationale.md delete mode 100644 .changeset/8388-i18n-designer-table-retirement-sweep.md delete mode 100644 .changeset/8394-record-page-emptiness-authority.md delete mode 100644 .changeset/8395-detail-copy-object-values.md delete mode 100644 .changeset/8397-emit-census-reader-manifest.md delete mode 100644 .changeset/8400-kanban-name-field-skip-set.md delete mode 100644 .changeset/8408-public-form-title-description.md delete mode 100644 .changeset/8411-flat-view-overlay-columns.md delete mode 100644 .changeset/8415-filter-builder-condition-id.md delete mode 100644 .changeset/8416-validate-schema-unknown-param.md delete mode 100644 .changeset/8420-ci-cd-pipeline-command-parity.md delete mode 100644 .changeset/8420-four-section-parity-pins.md delete mode 100644 .changeset/8423-i18n-factory-abstention-pins.md delete mode 100644 .changeset/8426-chat-parts-discriminated.md delete mode 100644 .changeset/8429-page-view-residual-pin.md delete mode 100644 .changeset/8434-unresolved-user-reference-honesty.md delete mode 100644 .changeset/8438-richtext-maxlength-visible.md delete mode 100644 .changeset/8440-masked-field-copy-refusal.md delete mode 100644 .changeset/8441-cell-count-labels-i18n.md delete mode 100644 .changeset/8442-chat-tool-approval-envelope.md delete mode 100644 .changeset/8443-chatbot-runtime-role-fold.md delete mode 100644 .changeset/8446-components-css-excludes-test-sources.md delete mode 100644 .changeset/8447-valuedatasource-dollar-operator-refusal.md delete mode 100644 .changeset/8448-kanban-swimlane-scroll-sync.md delete mode 100644 .changeset/8449-swimlane-vertical-scroll.md delete mode 100644 .changeset/8450-inspector-select-placeholder.md delete mode 100644 .changeset/8451-flownode-boolean-declared-default.md delete mode 100644 .changeset/8452-not-contains-non-string-value.md delete mode 100644 .changeset/8454-runner-stylesheet-source-set.md delete mode 100644 .changeset/8458-parity-header-pairs-figure.md delete mode 100644 .changeset/8459-relatedlist-emptiness-agreement.md delete mode 100644 .changeset/8464-summary-chip-object-value.md delete mode 100644 .changeset/8466-calendar-color-allday-fields.md delete mode 100644 .changeset/8474-empty-array-is-not-a-cell-value.md delete mode 100644 .changeset/8478-describe-line-addresses.md delete mode 100644 .changeset/8478-zod-pins-complex.md delete mode 100644 .changeset/8478-zod-pins-form-layout.md delete mode 100644 .changeset/8481-empty-array-is-not-a-cell-value.md delete mode 100644 .changeset/8488-inspector-select-unknown-value.md delete mode 100644 .changeset/8490-fabricated-value-for-empty-array.md delete mode 100644 .changeset/8491-8475-shared-empty-value-placeholder.md delete mode 100644 .changeset/8496-emptiness-floor.md delete mode 100644 .changeset/8497-detail-section-group-and-labels.md delete mode 100644 .changeset/8498-any-component-union-discriminated.md delete mode 100644 .changeset/8499-node-slot-registered-arms.md delete mode 100644 .changeset/8504-emptyvalue-remaining-carriers.md delete mode 100644 .changeset/8505-grid-columns-breakpoint-narrowing.md delete mode 100644 .changeset/8506-detail-placeholders-shared-empty-value.md delete mode 100644 .changeset/8508-swimlane-container-aware-column-width.md delete mode 100644 .changeset/8510-react-listview-spelling.md delete mode 100644 .changeset/8513-value-datasource-grouped-filters.md delete mode 100644 .changeset/8516-8556-mirror-partial-record-narrowing.md delete mode 100644 .changeset/8522-retire-use-column-widths.md delete mode 100644 .changeset/8524-ai-usage-single-pool.md delete mode 100644 .changeset/8525-empty-container-override-friendly.md delete mode 100644 .changeset/8530-filter-converter-array-comparand.md delete mode 100644 .changeset/8532-kanban-contract-envelope-rows-wait.md delete mode 100644 .changeset/8534-kanban-columns-same-commit.md delete mode 100644 .changeset/8537-network-escape-guard-worker-coverage.md delete mode 100644 .changeset/8542-framework-chunk-attribution.md delete mode 100644 .changeset/8554-sensitivity-floor.md delete mode 100644 .changeset/8555-filter-converter-date-comparand.md delete mode 100644 .changeset/8557-view-filter-rule-arity.md delete mode 100644 .changeset/8558-data-objectstack-operator-table.md delete mode 100644 .changeset/8561-e2e-artifact-name.md delete mode 100644 .changeset/8563-nav-target-exclusivity-chained.md delete mode 100644 .changeset/8567-filter-converter-exotic-comparand.md delete mode 100644 .changeset/8568-retire-dollar-dialect-lowercase-aliases.md delete mode 100644 .changeset/8570-inline-empty-markers.md delete mode 100644 .changeset/8572-chatbot-body-retired.md delete mode 100644 .changeset/8580-rich-text-empty-array-and-object.md delete mode 100644 .changeset/8581-date-cell-unparsable-value.md delete mode 100644 .changeset/8582-boolean-cell-non-boolean-scalar.md delete mode 100644 .changeset/8583-record-details-section-members.md delete mode 100644 .changeset/8593-booleanfield-readonly-non-boolean.md delete mode 100644 .changeset/8596-object-literal-cell-renderers.md delete mode 100644 .changeset/8598-zod-subpath-single-bundled-module.md delete mode 100644 .changeset/8603-record-details-hide-empty-restored.md delete mode 100644 .changeset/8604-record-details-columns-enum.md delete mode 100644 .changeset/8613-metric-structured-groupby.md delete mode 100644 .changeset/8620-datapillar-test-empty-adapter.md delete mode 100644 .changeset/8621-retire-declared-divergence-note.md delete mode 100644 .changeset/8626-detail-section-authored-node.md delete mode 100644 .changeset/8628-aspect-ratio-uncurated-reason.md delete mode 100644 .changeset/8631-approvals-unresolvable-record-reference.md delete mode 100644 .changeset/8632-malformed-picklist-option-loud.md delete mode 100644 .changeset/8637-tab-title-one-writer.md delete mode 100644 .changeset/8640-memo-identity-rule.md delete mode 100644 .changeset/8641-console-formpage-section-group.md delete mode 100644 .changeset/8648-ui-action-four-undeclared-keys.md delete mode 100644 .changeset/8649-detail-renderer-undeclared-keys.md delete mode 100644 .changeset/8649-record-block-field-security-triple.md delete mode 100644 .changeset/8650-chart-foreign-dialect-retired.md delete mode 100644 .changeset/8652-kanban-calendar-navigation.md delete mode 100644 .changeset/8653-listview-title-retired-rowactiondefs-pinned.md delete mode 100644 .changeset/8654-timeline-navigation.md delete mode 100644 .changeset/8655-object-tree-props-schema-typed.md delete mode 100644 .changeset/8666-tree-expanded-derived.md delete mode 100644 .changeset/8667-inbox-own-receipts-silent.md delete mode 100644 .changeset/8672-lookup-action-param-depends-on.md delete mode 100644 .changeset/8672-lookup-dependson-reachability-measurement.md delete mode 100644 .changeset/8674-objectgrid-row-operations.md delete mode 100644 .changeset/8676-object-metadata-write-doors.md delete mode 100644 .changeset/8677-signature-cell-value-class.md delete mode 100644 .changeset/8678-value-independent-cells.md delete mode 100644 .changeset/8686-masked-field-type-authority.md delete mode 100644 .changeset/8688-provider-ctx-wait-alignment.md delete mode 100644 .changeset/8693-expand-fields-rendering-claim.md delete mode 100644 .changeset/8695-unresolved-lookup-reference-one-answer.md delete mode 100644 .changeset/8696-hooks-per-file-pin.md delete mode 100644 .changeset/8705-listview-absence-settle-window.md delete mode 100644 .changeset/8712-ratchet-vacuous-green.md delete mode 100644 .changeset/8714-test-tsconfig-parity-census.md delete mode 100644 .changeset/8725-formsection-group-resolves.md delete mode 100644 .changeset/8729-summary-chip-accessible-name.md delete mode 100644 .changeset/8730-bulk-action-defs-unusable-member.md delete mode 100644 .changeset/8731-exportoptions-streaming-doc.md delete mode 100644 .changeset/8734-cell-renderer-type-census.md delete mode 100644 .changeset/8735-objectql-mirror-docblocks-not-defaulted.md delete mode 100644 .changeset/8738-fields-warn-route1.md delete mode 100644 .changeset/8738-object-form-fields-description.md delete mode 100644 .changeset/8743-doc-example-internal-symbol.md delete mode 100644 .changeset/8748-icontains-empty-comparand.md delete mode 100644 .changeset/8754-dead-pack-keys-retired.md delete mode 100644 .changeset/8754-i18n-dead-keys-one-hop-indirect-template-leg.md delete mode 100644 .changeset/8755-bulk-lookup-depends-on.md delete mode 100644 .changeset/8757-wire-check-doc-examples.md delete mode 100644 .changeset/8760-unfulfilled-chart-stubs.md delete mode 100644 .changeset/8762-shorthand-input-type-refusal.md delete mode 100644 .changeset/8767-object-grid-refuses-string-sort.md delete mode 100644 .changeset/8769-gantt-inline-query-keys.md delete mode 100644 .changeset/8770-true-identity-groups-no-constraint.md delete mode 100644 .changeset/8772-objectstack-17-4-0-line.md delete mode 100644 .changeset/8774-filter-builder-doc-widening-pin.md delete mode 100644 .changeset/8775-sectioning-tags-ruled-reason.md delete mode 100644 .changeset/8778-create-plugin-no-copyright-header.md delete mode 100644 .changeset/8782-agent-key-keyless-success-sentence.md delete mode 100644 .changeset/8784-arm-named-export-pin.md delete mode 100644 .changeset/8786-create-plugin-cancel-and-nontty.md delete mode 100644 .changeset/8793-related-list-identity-fail-closed.md delete mode 100644 .changeset/8797-swimlane-axis-scroll-range.md delete mode 100644 .changeset/8800-retire-ai-insights.md delete mode 100644 .changeset/8801-object-kanban-allow-collapse-retired.md delete mode 100644 .changeset/8802-8257-8008-kanban-gantt-family-retirement.md delete mode 100644 .changeset/8809-date-carrier-unparsable.md delete mode 100644 .changeset/8813-public-form-section-label-i18n.md delete mode 100644 .changeset/8816-i18n-locales-ceiling-provenance.md delete mode 100644 .changeset/8818-strip-objectfields.md delete mode 100644 .changeset/8820-dashboard-auto-refresh-hook.md delete mode 100644 .changeset/8826-kanban-cross-column-landing-position.md delete mode 100644 .changeset/8827-kanban-empty-state-settled.md delete mode 100644 .changeset/8830-calendar-doc-key-set.md delete mode 100644 .changeset/8831-calendar-flat-teaching-face.md delete mode 100644 .changeset/8834-designer-table-parity-gate.md delete mode 100644 .changeset/8841-tree-view-config-derive.md delete mode 100644 .changeset/8847-embeddable-form-fields-description.md delete mode 100644 .changeset/8854-app-shell-readme-flow-draft.md delete mode 100644 .changeset/8862-inspector-select-roster-pending.md delete mode 100644 .changeset/8871-page-node-refuses-breadcrumbs.md delete mode 100644 .changeset/8875-cross-file-line-citation-census.md delete mode 100644 .changeset/8883-reference-rail-parent-scope-arity.md delete mode 100644 .changeset/8885-object-chart-block-props.md delete mode 100644 .changeset/8885-object-chart-drilldown-title-compareto.md delete mode 100644 .changeset/8889-dataset-subcaption-bundle-limb.md delete mode 100644 .changeset/8892-create-plugin-licence-refusal.md delete mode 100644 .changeset/8894-dashboard-measures-not-rendered.md delete mode 100644 .changeset/8894-designer-type-picker-measure-door.md delete mode 100644 .changeset/8894-metric-family-door-pins.md delete mode 100644 .changeset/8894-metric-tile-unrendered-measures-speak.md delete mode 100644 .changeset/8897-installed-spec-pin-claims.md delete mode 100644 .changeset/8900-saved-views-unread-not-absent.md delete mode 100644 .changeset/8903-vi-mock-override-value-shape-gate.md delete mode 100644 .changeset/8908-bridge-falsy-primitives.md delete mode 100644 .changeset/8912-grid-children-items.md delete mode 100644 .changeset/8913-object-kanban-columns-declared.md delete mode 100644 .changeset/8920-grid-format-hint-shared-resolution.md delete mode 100644 .changeset/8923-page-header-single-node-delegation.md delete mode 100644 .changeset/8924-installed-pin-claim-gate.md delete mode 100644 .changeset/8925-designer-refusal-four-state-pin.md delete mode 100644 .changeset/8927-metadata-cache-readme-coalescing.md delete mode 100644 .changeset/8932-kanban-enhanced-types-jsdoc.md delete mode 100644 .changeset/8932-retire-kanban-enhanced.md delete mode 100644 .changeset/8934-chatter-feed-affordance-only.md delete mode 100644 .changeset/8938-retired-dialect-measured-surface.md delete mode 100644 .changeset/8944-chart-drill-filter-composition.md delete mode 100644 .changeset/8945-element-datasource-filter-note.md delete mode 100644 .changeset/8946-flow-edge-evaluated-condition.md delete mode 100644 .changeset/8953-test-path-roots-gate.md delete mode 100644 .changeset/8961-parse-schema-sort-narrow.md delete mode 100644 .changeset/8968-chatter-filtermode-enablementions.md delete mode 100644 .changeset/8970-object-metric-shared-drill-drawer.md delete mode 100644 .changeset/8972-cel-authoring-data-root-advisory.md delete mode 100644 .changeset/8973-grid-orderby-normalize.md delete mode 100644 .changeset/8976-icontains-lowers-in-converter.md delete mode 100644 .changeset/8978-alert-dialog-action-variant.md delete mode 100644 .changeset/8983-host-discussion-fallback-one-pipeline.md delete mode 100644 .changeset/8990-object-kanban-groupby-optional.md delete mode 100644 .changeset/8992-user-actions-collapse-and-docblock.md delete mode 100644 .changeset/8993-kanban-lane-id-sweep-key.md delete mode 100644 .changeset/9000-drill-columns-header-labels.md delete mode 100644 .changeset/9001-filter-converter-text-comparand.md delete mode 100644 .changeset/9002-metric-drilldown-refusal.md delete mode 100644 .changeset/9003-changeset-claim-reread.md delete mode 100644 .changeset/9012-core-spec-floor.md delete mode 100644 .changeset/9013-ast-child-vitest-env-membership.md delete mode 100644 .changeset/9022-drill-navigate-placeholder-scope.md delete mode 100644 .changeset/9024-pivot-drill-filter-composition.md delete mode 100644 .changeset/9026-bare-colon-continuation-scope.md delete mode 100644 .changeset/9031-retired-sort-diagnostic-wording.md delete mode 100644 .changeset/9033-header-bar-right-content-numeric-falsy.md delete mode 100644 .changeset/9034-imported-defaults-keep-describe.md delete mode 100644 .changeset/9035-hinted-column-waitfor.md delete mode 100644 .changeset/9040-record-details-top-level-spec-parity.md delete mode 100644 .changeset/9040-retire-record-details-layout.md delete mode 100644 .changeset/9043-kanban-prototype-group-keys.md delete mode 100644 .changeset/9045-kanban-empty-state-lane-count.md delete mode 100644 .changeset/9048-entry-form-icontains-comparand-refusal.md delete mode 100644 .changeset/9050-render-time-filter-refusal-names-the-operator.md delete mode 100644 .changeset/9054-record-details-identity-fail-closed.md delete mode 100644 .changeset/9056-detail-body-columns-boundary-coercion.md delete mode 100644 .changeset/9061-calendar-map-inline-query-keys.md delete mode 100644 .changeset/9067-zod-barrel-named-arms.md delete mode 100644 .changeset/9071-summary-chip-percent-source.md delete mode 100644 .changeset/9073-doc-union-members-comment-order.md delete mode 100644 .changeset/9074-fieldstub-picklist-filter-before-slice.md delete mode 100644 .changeset/9081-census-control-names-one-citation.md delete mode 100644 .changeset/9087-arm-named-export-docblock-claims.md delete mode 100644 .changeset/9088-rest-less-tuple-identity.md delete mode 100644 .changeset/9092-inline-locale-declared-face.md delete mode 100644 .changeset/9100-record-alert-cel-envelope-config-bag.md delete mode 100644 .changeset/9102-import-boundary-registry-meta.md delete mode 100644 .changeset/9103-census-pairing-optional-default.md delete mode 100644 .changeset/9107-enablement-cel-envelope-config-bag.md delete mode 100644 .changeset/9108-props-bag-loud-refusal.md delete mode 100644 .changeset/9109-flow-node-unbacked-defaults.md delete mode 100644 .changeset/9119-detail-header-cross-axis.md delete mode 100644 .changeset/9126-pack-dynamic-head-report.md delete mode 100644 .changeset/9129-filter-token-suggestion-proto-guard.md delete mode 100644 .changeset/9131-action-enablement-verdict-carrier.md delete mode 100644 .changeset/9134-release-pr-head-branch-not-title.md delete mode 100644 .changeset/9136-tree-inline-query-keys.md delete mode 100644 .changeset/9137-dataset-drill-conjoin-widget-filter.md delete mode 100644 .changeset/9140-changeset-claims-blind-spot-census.md delete mode 100644 .changeset/9142-root-markdown-shard-trigger.md delete mode 100644 .changeset/9145-prompt-category-inventory.md delete mode 100644 .changeset/9150-report-chart-title-locale-map.md delete mode 100644 .changeset/9151-failed-script-action-toast-characterization.md delete mode 100644 .changeset/9155-bundle-analysis-classification-prose.md delete mode 100644 .changeset/9159-drill-url-isnull-operator.md delete mode 100644 .changeset/9161-file-readonly-download-affordance.md delete mode 100644 .changeset/9162-node-slot-guard-class-closure.md delete mode 100644 .changeset/9164-empty-operator-map-refused.md delete mode 100644 .changeset/9165-metric-percent-converged.md delete mode 100644 .changeset/9167-summary-chip-percent-convention.md delete mode 100644 .changeset/9170-kanban-empty-state-drops-lane-count.md delete mode 100644 .changeset/9172-dashboard-grid-series-label.md delete mode 100644 .changeset/9174-interpolate-fastpath-trim.md delete mode 100644 .changeset/9175-value-data-source-structured-clone.md delete mode 100644 .changeset/9177-coverage-shard-reporter-readability.md delete mode 100644 .changeset/9183-comment-mask-conversion.md delete mode 100644 .changeset/9187-record-highlights-layout-two-values.md delete mode 100644 .changeset/9188-playwright-import-meta-root.md delete mode 100644 .changeset/9194-fence-opener-commonmark-run.md delete mode 100644 .changeset/9196-objectview-url-filter-operator-suffix.md delete mode 100644 .changeset/9197-record-context-datasource-adapter.md delete mode 100644 .changeset/9201-sweep-skip-objectui-tmp.md delete mode 100644 .changeset/9206-retire-unregistered-rationale.md delete mode 100644 .changeset/9211-spawners-single-source.md delete mode 100644 .changeset/9215-lockfile-dedupe-measurement.md delete mode 100644 .changeset/9217-packaged-flow-unbound-reason.md delete mode 100644 .changeset/9218-detailsection-collapsible-showborder.md delete mode 100644 .changeset/9219-objectmanager-system-object-delete.md delete mode 100644 .changeset/9220-readme-exports-list-precondition.md delete mode 100644 .changeset/9223-adr-0055-item-5-amendment.md delete mode 100644 .changeset/9230-picklist-blank-option-label.md delete mode 100644 .changeset/9231-create-app-accessible-name.md delete mode 100644 .changeset/9232-cache-approval-envelope.md delete mode 100644 .changeset/9233-approval-state-survives-merge.md delete mode 100644 .changeset/9239-object-calendar-data-array-arm.md delete mode 100644 .changeset/9242-stray-kanban-groupby-lane-second-route.md delete mode 100644 .changeset/9248-screen-field-bound-help-reference.md delete mode 100644 .changeset/9251-icons-record-not-eager.md delete mode 100644 .changeset/9256-content-channel-family-d.md delete mode 100644 .changeset/9256-e3-residual-content-channels.md delete mode 100644 .changeset/9256-input-content-channels.md delete mode 100644 .changeset/9256-list-timeline-content-channels.md delete mode 100644 .changeset/9256-public-blocks-content-channels.md delete mode 100644 .changeset/9256-remeasure-content-channels.md delete mode 100644 .changeset/9262-app-probe-measured-verdicts.md delete mode 100644 .changeset/9266-commit-history-item-count-agreement.md delete mode 100644 .changeset/9269-grid-summary-percent-converged.md delete mode 100644 .changeset/9277-flownode-lockrecord-interrupting-declared-default.md delete mode 100644 .changeset/9278-end-outcome-select.md delete mode 100644 .changeset/9280-record-highlights-entry-icon-retired.md delete mode 100644 .changeset/9287-objectview-filter-params-key-encoding.md delete mode 100644 .changeset/9295-percent-surfaces-read-scale.md delete mode 100644 .changeset/9299-shared-record-overlay-shell.md delete mode 100644 .changeset/9302-filter-builder-valueless-canonical-fold.md delete mode 100644 .changeset/9306-filter-builder-name-authority.md delete mode 100644 .changeset/9306-filter-builder-nested-groups-retired.md delete mode 100644 .changeset/9306-filter-builder-protocol-operator-ids.md delete mode 100644 .changeset/9308-data-root-unbound-from-adapter.md delete mode 100644 .changeset/9309-object-gallery-filter-destination-typed.md delete mode 100644 .changeset/9318-field-rule-verdict-from-lint.md delete mode 100644 .changeset/9319-ui-library-prompt-section-numbering.md delete mode 100644 .changeset/9323-jsonc-readers-converge.md delete mode 100644 .changeset/9324-comment-mask-param-tags.md delete mode 100644 .changeset/9327-import-history-time-locale.md delete mode 100644 .changeset/9329-published-dist-remedy-text.md delete mode 100644 .changeset/9331-fence-opener-authority.md delete mode 100644 .changeset/9333-record-id-narrows-to-string.md delete mode 100644 .changeset/9335-flow-end-output-variable-refused.md delete mode 100644 .changeset/9336-end-node-refusal-message-control.md delete mode 100644 .changeset/9340-loop-item-variable-hint.md delete mode 100644 .changeset/9341-kanban-card-click-fires-once.md delete mode 100644 .changeset/9342-kanban-oncardmove-prop.md delete mode 100644 .changeset/9350-auth-permissions-useauth-guard-both.md delete mode 100644 .changeset/9357-navigation-overlay-consumer-arity.md delete mode 100644 .changeset/9357-navigation-overlay-onrowclick-arity.md delete mode 100644 .changeset/9359-list-ast-valueless-canonical-fold.md delete mode 100644 .changeset/9363-dataset-filter-isnull-erases.md delete mode 100644 .changeset/9365-bridgelistview-present-tense.md delete mode 100644 .changeset/9372-unmapped-operator-inert.md delete mode 100644 .changeset/9373-listview-detail-overlay-inline-locale-label.md delete mode 100644 .changeset/9375-base-i18n-vocabulary-docblock.md delete mode 100644 .changeset/9382-dataset-filter-date-operator-round-trip.md delete mode 100644 .changeset/9406-types-root-barrel-two-names.md delete mode 100644 .changeset/9409-retire-page-assigned-profiles.md delete mode 100644 .changeset/9412-ungated-docs-paydown.md delete mode 100644 .changeset/9414-lazy-icon-letter-digit-boundary.md delete mode 100644 .changeset/9420-permission-package-door-reread-refusal.md delete mode 100644 .changeset/9422-required-check-set-patrol.md delete mode 100644 .changeset/9424-comment-mask-returns-interpolation.md delete mode 100644 .changeset/9436-core-declared-name-field-export.md delete mode 100644 .changeset/9436-detail-declared-pointer-order.md delete mode 100644 .changeset/9436-page-header-declared-pointer-order.md delete mode 100644 .changeset/9447-detail-view-handler-key-refusal.md delete mode 100644 .changeset/9449-guard-ruling-c-narration.md delete mode 100644 .changeset/9452-percent-cell-name-keyed-scaling.md delete mode 100644 .changeset/9453-summary-chip-display-locale.md delete mode 100644 .changeset/9462-row-click-modifier-payload-forward.md delete mode 100644 .changeset/9464-admin-scope-write-gate.md delete mode 100644 .changeset/9473-record-source-data-arm-type.md delete mode 100644 .changeset/9475-related-list-relationship-value-field-uncast.md delete mode 100644 .changeset/9484-env-door-post-save-reread-degrade.md delete mode 100644 .changeset/9485-filecell-view-download-affordance.md delete mode 100644 .changeset/9491-walkabledef-rest-null.md delete mode 100644 .changeset/9492-corebarrel-namespace-narrowed.md delete mode 100644 .changeset/9497-validation-rule-condition-draft-lint.md delete mode 100644 .changeset/9502-required-set-readable-pointers.md delete mode 100644 .changeset/9507-url-filter-op-prototype-chain.md delete mode 100644 .changeset/9508-drill-url-dialect-is-not-null.md delete mode 100644 .changeset/9511-datasource-record-id-string.md delete mode 100644 .changeset/9511-record-id-is-a-string.md delete mode 100644 .changeset/9513-at-lib-prose-pointer.md delete mode 100644 .changeset/9522-zod-readme-first-example.md delete mode 100644 .changeset/9526-types-root-barrel-command-element-types.md delete mode 100644 .changeset/9529-detail-section-declares-icon.md delete mode 100644 .changeset/9533-dashboard-bare-key-converge-plugin-namespace.md delete mode 100644 .changeset/9542-result-dialog-i18nlabel.md delete mode 100644 .changeset/9547-ongrid-onnavigate-prop.md delete mode 100644 .changeset/9549-tree-filter-declared.md delete mode 100644 .changeset/9550-object-tree-root-barrel.md delete mode 100644 .changeset/9550-plugin-tree-import-object-tree-schema.md delete mode 100644 .changeset/9556-record-component-aria-honoured.md delete mode 100644 .changeset/9557-feed-diagnostic-block-name.md delete mode 100644 .changeset/9559-filter-operator-schema-protocol-set.md delete mode 100644 .changeset/9568-percent-widget-reads-scale.md delete mode 100644 .changeset/9569-components-stylesheet-source-none.md delete mode 100644 .changeset/9571-schema-renderer-data-prop-arm.md delete mode 100644 .changeset/9572-declared-actions-bar-capability-mirror.md delete mode 100644 .changeset/9574-objectform-step-scale.md delete mode 100644 .changeset/9575-gallery-scale.md delete mode 100644 .changeset/9580-grid-needs-datasource-bare-array.md delete mode 100644 .changeset/9590-item-body-retired.md delete mode 100644 .changeset/9594-data-objectstack-error-envelope-reader.md delete mode 100644 .changeset/9596-debt-issue-anchor-truthiness.md delete mode 100644 .changeset/9600-import-template-from-server.md delete mode 100644 .changeset/9603-zod-mirror-parity-restated-figure.md delete mode 100644 .changeset/9606-object-kanban-card-title.md delete mode 100644 .changeset/9615-locale-count-ten.md delete mode 100644 .changeset/9618-record-source-ladder-attribution.md delete mode 100644 .changeset/9623-datatable-row-action-capability-mirror.md delete mode 100644 .changeset/9628-kanban-column-collapsed-honoured.md delete mode 100644 .changeset/9629-9621-prose-residuals.md delete mode 100644 .changeset/9637-post-pass-residuals.md delete mode 100644 .changeset/9641-registry-namespace-by-reference.md delete mode 100644 .changeset/9645-condition-builder-record-roots.md delete mode 100644 .changeset/9651-inspector-select-roster-failure.md delete mode 100644 .changeset/9652-designer-unknown-value-flags.md delete mode 100644 .changeset/9653-kanban-stray-groupby-refusal-text.md delete mode 100644 .changeset/9655-straygroupby-docblock-claim.md delete mode 100644 .changeset/9659-node-recursion-point-inert-clause.md delete mode 100644 .changeset/9664-search-items-available-plural.md delete mode 100644 .changeset/9667-navigation-view-tombstone-twin.md delete mode 100644 .changeset/9673-pageview-drop-context-spread.md delete mode 100644 .changeset/9674-page-assignment-reads-type.md delete mode 100644 .changeset/9675-scatter-spec-axes.md delete mode 100644 .changeset/9676-calendar-pin-blind-regex.md delete mode 100644 .changeset/9681-scatter-zaxis-inert-declaration.md delete mode 100644 .changeset/9684-discriminator-cited-once.md delete mode 100644 .changeset/9691-spec-gesture-fallback-type-order.md delete mode 100644 .changeset/9692-9683-residuals.md delete mode 100644 .changeset/9700-handler-key-reads-wrapper-hop.md delete mode 100644 .changeset/9701-collapsible-bare-string-trigger.md delete mode 100644 .changeset/9710-overlay-trigger-bare-string.md delete mode 100644 .changeset/9711-zod-mirror-parity-mirrored-undeclared.md delete mode 100644 .changeset/9722-bulk-executor-datasource-face.md delete mode 100644 .changeset/9726-objectkanban-docblock-tense.md delete mode 100644 .changeset/9727-changeset-polarity-instrument-rebuild.md delete mode 100644 .changeset/9729-mirror-only-published-keys-measured.md delete mode 100644 .changeset/9736-twins-spec-by-reference.md delete mode 100644 .changeset/9737-types-tsconfig-test-invariant-dated.md delete mode 100644 .changeset/9739-object-grid-operators-tombstone.md delete mode 100644 .changeset/9743-gantt-ratchet-rationale-retired.md delete mode 100644 .changeset/9746-render-path-not-a-validation-door.md delete mode 100644 .changeset/9754-polarity-clause-scope.md delete mode 100644 .changeset/9754-slice-2-window-pairing.md delete mode 100644 .changeset/9758-legacy-props-data-strip.md delete mode 100644 .changeset/9760-initial-data-member-merge.md delete mode 100644 .changeset/9764-renderer-docblock-counting-rule.md delete mode 100644 .changeset/9767-census-schema-absent-split.md delete mode 100644 .changeset/9768-comment-projection-forcing-subject.md delete mode 100644 .changeset/9778-object-form-customfields-merge.md delete mode 100644 .changeset/9780-collapsed-implies-collapsible.md delete mode 100644 .changeset/9782-related-toolbar-capability-mirror.md delete mode 100644 .changeset/9784-percent-field-metadata-scale.md delete mode 100644 .changeset/9786-detail-timestamps-display-locale.md delete mode 100644 .changeset/9787-proto-spec-legal-comment.md delete mode 100644 .changeset/9792-scatter-grid-show-grid-lines.md delete mode 100644 .changeset/9799-object-data-table-row-click-arity.md delete mode 100644 .changeset/9802-validations-panel-when-key.md delete mode 100644 .changeset/9806-objectview-modifier-click-comment.md delete mode 100644 .changeset/9806-objectview-modifier-click-new-tab.md delete mode 100644 .changeset/9808-percent-scale-out-of-range.md delete mode 100644 .changeset/9810-percent-stored-fraction-decimal-shift.md delete mode 100644 .changeset/9813-explain-double-single-record-verdict.md delete mode 100644 .changeset/9816-reference-rail-route-docblock.md delete mode 100644 .changeset/9821-registerlazy-cross-table-collision-warning.md delete mode 100644 .changeset/9830-erased-arm-mark.md delete mode 100644 .changeset/9830-nested-anyof-predicate-string-arm.md delete mode 100644 .changeset/9832-census-never-annotation-polarity.md delete mode 100644 .changeset/9834-drawer-section-description.md delete mode 100644 .changeset/9835-headingless-section-blurb.md delete mode 100644 .changeset/9837-grid-presence-rule.md delete mode 100644 .changeset/9839-register-skipfallback-preserves-stub.md delete mode 100644 .changeset/9843-percent-absent-scale-resolver.md delete mode 100644 .changeset/9847-generate-page-children.md delete mode 100644 .changeset/9849-collapse-resolution-converge.md delete mode 100644 .changeset/9849-section-gate-rule-e.md delete mode 100644 .changeset/9849-single-divider-projection.md delete mode 100644 .changeset/9853-grid-display-page-size-from-spec.md delete mode 100644 .changeset/9853-grid-non-positive-page-size.md delete mode 100644 .changeset/9856-client-mount-condition-roots.md delete mode 100644 .changeset/9859-repeater-grid-widget-detectors.md delete mode 100644 .changeset/9867-labeler-hand-hung-label-probe.md delete mode 100644 .changeset/9868-nav-label-inherits-target.md delete mode 100644 .changeset/9870-census-superseded-readings-table.md delete mode 100644 .changeset/9871-body-dialect-producer-scan.md delete mode 100644 .changeset/9874-navigation-view-retired-consumer.md delete mode 100644 .changeset/9875-number-field-step-spec-parity.md delete mode 100644 .changeset/9880-undrawable-view-kinds-both-legs.md delete mode 100644 .changeset/9884-master-detail-fields-intersection.md delete mode 100644 .changeset/9889-control-widget-grid-cell-name.md delete mode 100644 .changeset/9890-census-phantom-final-line.md delete mode 100644 .changeset/9892-fixture-address-rule-spec-rows.md delete mode 100644 .changeset/9897-listview-non-positive-page-size.md delete mode 100644 .changeset/9899-gate-refused-row-cap-not-authored.md delete mode 100644 .changeset/9906-lint-coverage-banner-cross-file-claim.md delete mode 100644 .changeset/9909-machine-locale-sweep.md delete mode 100644 .changeset/9910-children-slot-declare-and-pin.md delete mode 100644 .changeset/9912-schemaform-ref-indirection.md delete mode 100644 .changeset/9914-filter-condition-between-blank-bound.md delete mode 100644 .changeset/9922-port-parity-snippet-line-count.md delete mode 100644 .changeset/9925-line-items-row-cap-non-positive.md delete mode 100644 .changeset/9925-row-cap-non-positive.md delete mode 100644 .changeset/9928-saved-view-limit-non-positive.md delete mode 100644 .changeset/9931-control-failure-arm-labelable.md delete mode 100644 .changeset/9933-stale-baseschema-premise-docblocks.md delete mode 100644 .changeset/9938-view-navigation-config-docblock.md delete mode 100644 .changeset/9941-tabs-default-items-content.md delete mode 100644 .changeset/9943-viewtype-totals-page-row-retired.md delete mode 100644 .changeset/9945-record-aria-label-retired.md delete mode 100644 .changeset/9950-map-style-reaches-flat-renderer.md delete mode 100644 .changeset/9952-condition-placeholder-derives-from-offered-roots.md delete mode 100644 .changeset/9953-condition-widget-context-derivation.md delete mode 100644 .changeset/9954-read-rate-banner.md delete mode 100644 .changeset/9955-sort-array-string-entry-refused-out-loud.md delete mode 100644 .changeset/9959-refused-data-prop-warn-reset.md delete mode 100644 .changeset/9963-related-list-props-refusal.md delete mode 100644 .changeset/9964-related-list-picker-filter-mirror.md delete mode 100644 .changeset/9965-record-details-hidefields-uncast.md delete mode 100644 .changeset/9973-flow-launch-refused-notice.md delete mode 100644 .changeset/9978-page-residual-pin-type-face-derived.md delete mode 100644 .changeset/9979-validation-dialect-source-required.md delete mode 100644 .changeset/9987-gantt-readme-navigation-view.md delete mode 100644 .changeset/9998-activity-landmark-named-by-heading.md delete mode 100644 .changeset/action-callback-retired-7068.md delete mode 100644 .changeset/action-designer-param-vocabulary.md delete mode 100644 .changeset/action-keys-warning-text-5642.md delete mode 100644 .changeset/action-onsuccess-forward-5493.md delete mode 100644 .changeset/action-param-degrade-predicate-5654.md delete mode 100644 .changeset/action-runtime-same-origin-only-5702.md delete mode 100644 .changeset/active-org-clear-removal-failure-5731.md delete mode 100644 .changeset/active-org-storage-memory-fallback-5703.md delete mode 100644 .changeset/activity-map-single-reading-5878.md delete mode 100644 .changeset/adapter-advisory-sink-pin.md delete mode 100644 .changeset/adapter-meta-type-singular-4940.md delete mode 100644 .changeset/adr-0057-d10-citation-attribution-5202.md delete mode 100644 .changeset/ai-chat-public-share-base-4482.md delete mode 100644 .changeset/ai-quota-ledger-vocabulary-3804.md delete mode 100644 .changeset/ai-studio-accessor-5577.md delete mode 100644 .changeset/alert-dialog-fixture-premise-pin-7693.md delete mode 100644 .changeset/alert-dialog-footer-keys-liveness-7963.md delete mode 100644 .changeset/alias-closure-relative-miss-5386.md delete mode 100644 .changeset/all-skipped-filter-tail-9020.md delete mode 100644 .changeset/analytics-coded-400-rejected.md delete mode 100644 .changeset/analytics-error-branch-mapping-5663.md delete mode 100644 .changeset/analytics-failure-code-first.md delete mode 100644 .changeset/anon-seed-scope-pin-5828.md delete mode 100644 .changeset/anonymous-expression-user-id-6534.md delete mode 100644 .changeset/app-hidden-catalogue-flag-7542.md delete mode 100644 .changeset/app-shell-nodenext-pin-5440.md delete mode 100644 .changeset/app-shell-page-header-subtitle-4761.md delete mode 100644 .changeset/app-shell-provision-envelope-shape-6707.md delete mode 100644 .changeset/approvals-inbox-cell-remount-5348.md delete mode 100644 .changeset/approvals-queue-hidden-amount-6020.md delete mode 100644 .changeset/approvals-raw-payload-gate-5553.md delete mode 100644 .changeset/approvals-step-progress-vertical-5554.md delete mode 100644 .changeset/approver-display-name-5414.md delete mode 100644 .changeset/approver-identities-read-positions-5424.md delete mode 100644 .changeset/appsidebar-deprecated-5720.md delete mode 100644 .changeset/audit-field-def-reference-narrow.md delete mode 100644 .changeset/authguard-positions-5424.md delete mode 100644 .changeset/baseline-squash-merge-sha-9355.md delete mode 100644 .changeset/block-config-schema-parity-8216.md delete mode 100644 .changeset/block-schema-docs-truth-4895.md delete mode 100644 .changeset/built-moment-transition-5799.md delete mode 100644 .changeset/built-transition-published-5799.md delete mode 100644 .changeset/button-container-exception-reason-6804.md delete mode 100644 .changeset/calendar-explain-network-escape-5438.md delete mode 100644 .changeset/calendar-flat-key-pins-anchor-to-behaviour.md delete mode 100644 .changeset/calendar-gridcell-resolved-locale.md delete mode 100644 .changeset/calendar-readme-schema-keys-5045.md delete mode 100644 .changeset/calendar-unscheduled-area.md delete mode 100644 .changeset/calendar-view-event-rename-5044.md delete mode 100644 .changeset/calendar-view-mode-agenda-retired-5740.md delete mode 100644 .changeset/calendar-view-schema-converge.md delete mode 100644 .changeset/calendarview-a11y-labels-localized.md delete mode 100644 .changeset/canvas-design-run-5800.md delete mode 100644 .changeset/catalog-layout-props-sweep-4891-4890.md delete mode 100644 .changeset/chart-config-locale-heading-9038.md delete mode 100644 .changeset/chart-heading-follows-viewer-8943.md delete mode 100644 .changeset/chart-height-chain-5451.md delete mode 100644 .changeset/chart-refusal-assertion-strength.md delete mode 100644 .changeset/chat-transport-memo-4187.md delete mode 100644 .changeset/chatbot-build-panel-i18n-7388.md delete mode 100644 .changeset/check-schema-positive-marker-and-skip-count.md delete mode 100644 .changeset/chilled-donkeys-shave.md delete mode 100644 .changeset/ci-cd-pipeline-populations-8629.md delete mode 100644 .changeset/ci-decide-markdown-trace-9241.md delete mode 100644 .changeset/citation-census-declared-fixture-addresses.md delete mode 100644 .changeset/cli-app-generator-explicit-branch-cases.md delete mode 100644 .changeset/cli-validate-field-widget-namespace-5449.md delete mode 100644 .changeset/closure-claims-bounded-or-derivable.md delete mode 100644 .changeset/cloud-connection-bind-failure-i18n-5054.md delete mode 100644 .changeset/clusterradius-unit-doc-5020.md delete mode 100644 .changeset/component-docs-disabled-inherited-7239.md delete mode 100644 .changeset/component-meta-converge-and-deprecate-alias-5893.md delete mode 100644 .changeset/componentinput-reexport-4972.md delete mode 100644 .changeset/componentrendererprops-reexport-4594.md delete mode 100644 .changeset/components-react-page-published-dts-text-5666.md delete mode 100644 .changeset/confirm-card-terminal-5695.md delete mode 100644 .changeset/confirm-handler-published-type-5835.md delete mode 100644 .changeset/confirm-runtime-close-parity-6034.md delete mode 100644 .changeset/console-action-dispatch-envelope-5611.md delete mode 100644 .changeset/console-boot-request-dedup-5544.md delete mode 100644 .changeset/console-boot-splash.md delete mode 100644 .changeset/console-form-container-specs-one-declaration-5596.md delete mode 100644 .changeset/console-form-field-spec-one-declaration-5542.md delete mode 100644 .changeset/console-form-marked-refusal-5210.md delete mode 100644 .changeset/console-formpage-runtime-default-seed-5727.md delete mode 100644 .changeset/console-formpage-visible-predicates-5594.md delete mode 100644 .changeset/console-lazy-docs-portal-5467.md delete mode 100644 .changeset/console-preboot-branding-origin-5660.md delete mode 100644 .changeset/console-studio-builder-decorative-lazy-5486.md delete mode 100644 .changeset/console-user-preference-request-budget.md delete mode 100644 .changeset/container-declaration-ratchet-6779.md delete mode 100644 .changeset/core-datascope-field-and-comparison-guards-7751.md delete mode 100644 .changeset/core-datascope-unknown-operator-denies-7378.md delete mode 100644 .changeset/create-plugin-in-repo-scaffold-note-7524.md delete mode 100644 .changeset/crud-guide-declarative-view-binding-5446.md delete mode 100644 .changeset/curly-hoops-attack.md delete mode 100644 .changeset/current-user-default-prefill-5683.md delete mode 100644 .changeset/cyan-donkeys-tickle.md delete mode 100644 .changeset/dashboard-aria-member-retired-5830.md delete mode 100644 .changeset/dashboard-config-aria-retired-5852.md delete mode 100644 .changeset/dashboard-declare-honoured-inputs.md delete mode 100644 .changeset/dashboard-expandable-family-convergence-5692.md delete mode 100644 .changeset/dashboard-header-collapse-5812.md delete mode 100644 .changeset/dashboard-inline-chartconfig-4044.md delete mode 100644 .changeset/dashboard-readme-card-widget-7035.md delete mode 100644 .changeset/dashboard-self-contained-unreachable-arm-4620.md delete mode 100644 .changeset/dashboard-stable-empty-rows-4629.md delete mode 100644 .changeset/dashboard-table-header-one-spelling-5425.md delete mode 100644 .changeset/dashboard-table-measure-desc-first-5845.md delete mode 100644 .changeset/dashboard-table-widget-polish-5827.md delete mode 100644 .changeset/dashboard-title-locale-writeback-5428.md delete mode 100644 .changeset/dashboard-widget-dataset-stale-cast-5067.md delete mode 100644 .changeset/dashboard-widget-type-closed-enum.md delete mode 100644 .changeset/data-table-header-declared-key-5351.md delete mode 100644 .changeset/dataset-chartconfig-seam-pin-9203.md delete mode 100644 .changeset/dataset-format-8263-impossible-date-prose.md delete mode 100644 .changeset/date-only-calendar-day-10110.md delete mode 100644 .changeset/date-range-default-range-binding-4984.md delete mode 100644 .changeset/datetime-cell-duelike-affordance-8958.md delete mode 100644 .changeset/datetime-cell-format-vocabulary-8853.md delete mode 100644 .changeset/dead-metadata-converters-6224.md delete mode 100644 .changeset/dead-refresh-callback-objectview.md delete mode 100644 .changeset/default-children-retired-5051.md delete mode 100644 .changeset/default-view-agenda-retired-5784.md delete mode 100644 .changeset/defaults-maps-mirror-discovery-7884.md delete mode 100644 .changeset/degenerate-magnitude-charts.md delete mode 100644 .changeset/degrade-set-twin-pin-5880.md delete mode 100644 .changeset/delete-dead-release-workflow-5405.md delete mode 100644 .changeset/designer-field-key-parity-gate.md delete mode 100644 .changeset/designer-publish-package-binding.md delete mode 100644 .changeset/deterministic-child-vitest-env-8616.md delete mode 100644 .changeset/dom-leak-sweep-components-5574.md delete mode 100644 .changeset/dom-leak-sweep-docblock-counts-8659.md delete mode 100644 .changeset/dom-leak-sweep-fixture-depth-5630.md delete mode 100644 .changeset/draft-changes-panel-eager-attribution-comment.md delete mode 100644 .changeset/drawer-bucket-pointer-ruling.md delete mode 100644 .changeset/dts-build-exit-code-5370.md delete mode 100644 .changeset/dts-explicit-extensions-5365.md delete mode 100644 .changeset/duelike-declared-on-detail-view-field-9738.md delete mode 100644 .changeset/eager-closure-budget-5324.md delete mode 100644 .changeset/eager-closure-header-retired-figures.md delete mode 100644 .changeset/eighty-pandas-listen.md delete mode 100644 .changeset/empty-bucket-drill-is-null-9085.md delete mode 100644 .changeset/empty-description-props-name-the-element-8571.md delete mode 100644 .changeset/esm-load-comment-mask-5382.md delete mode 100644 .changeset/evaluateexpression-jsdoc-links-5580.md delete mode 100644 .changeset/explain-double-wire-shape-7996.md delete mode 100644 .changeset/field-key-spelling-outside-table-9055.md delete mode 100644 .changeset/fields-depends-on-declared-read-6153.md delete mode 100644 .changeset/fields-jest-dom-self-declared.md delete mode 100644 .changeset/filecell-error-slot-5431.md delete mode 100644 .changeset/filter-ast-combinators-6948.md delete mode 100644 .changeset/fix-parity-aria-line-ref.md delete mode 100644 .changeset/flow-entry-condition-builder.md delete mode 100644 .changeset/flow-resume-result-5417.md delete mode 100644 .changeset/flownode-declared-default-pin.md delete mode 100644 .changeset/form-control-renderers-dom-props-5632.md delete mode 100644 .changeset/form-designer-namespaced-field-type-4838.md delete mode 100644 .changeset/form-field-predicate-current-user-6010.md delete mode 100644 .changeset/form-reset-notification-channels-5235.md delete mode 100644 .changeset/formatpercent-comment-citations-4596.md delete mode 100644 .changeset/formfieldspec-dependson-5040.md delete mode 100644 .changeset/formpage-conditional-rule-surfaces-5627.md delete mode 100644 .changeset/formpage-maxlength-override-5595.md delete mode 100644 .changeset/formpage-record-id-param-comment-4319.md delete mode 100644 .changeset/gantt-bar-object-declaration.md delete mode 100644 .changeset/gantt-envelope-wait-anchor-8665.md delete mode 100644 .changeset/gantt-navconfig-comment-once.md delete mode 100644 .changeset/gantt-owns-data-comment-7222.md delete mode 100644 .changeset/gantt-restated-keep-rationale.md delete mode 100644 .changeset/gantt-row-walk-nontotal-reads.md delete mode 100644 .changeset/gantt-viewmode-declared-both-branches-5074.md delete mode 100644 .changeset/gate-listlocalinstalls-marketplace-5620.md delete mode 100644 .changeset/governed-surface-human-merge-5149.md delete mode 100644 .changeset/grid-column-spelling-docs-5352.md delete mode 100644 .changeset/grid-default-filters-lowering-4082.md delete mode 100644 .changeset/grid-dom-attribute-whitelist-4787.md delete mode 100644 .changeset/grid-prefix-read-no-cast-6458.md delete mode 100644 .changeset/grid-select-published-fields.md delete mode 100644 .changeset/grid-source-keys-member-pins-8071-slice-14.md delete mode 100644 .changeset/grid-summary-footer-tenant-locale-9294.md delete mode 100644 .changeset/grid-unresolved-column-diagnostic-5349.md delete mode 100644 .changeset/grid-user-actions-collision-5240.md delete mode 100644 .changeset/grid-widget-aria-invalid-3318.md delete mode 100644 .changeset/handler-key-reads-follow-cast-receivers.md delete mode 100644 .changeset/handler-key-reads-keyed-on-the-registration.md delete mode 100644 .changeset/hidden-predicate-widen-7455.md delete mode 100644 .changeset/hollow-view-overlay-hydration-pin-5773.md delete mode 100644 .changeset/home-ai-studio-flag-5521.md delete mode 100644 .changeset/host-dispatch-action-keys-5611.md delete mode 100644 .changeset/host-only-viewtypes-tree-icon-5321.md delete mode 100644 .changeset/humanize-label-single-home-5444.md delete mode 100644 .changeset/hungry-poems-shave.md delete mode 100644 .changeset/i18n-global-reset-4514.md delete mode 100644 .changeset/i18n-guide-label-rule-5081.md delete mode 100644 .changeset/i18n-header-import-rule-8029.md delete mode 100644 .changeset/i18nlabel-comment-4611.md delete mode 100644 .changeset/i18nlabel-inverted-pin-5612.md delete mode 100644 .changeset/icontains-comparand-view-rule-9048.md delete mode 100644 .changeset/identity-fold-skipped-keys-9030.md delete mode 100644 .changeset/inbox-actor-name-retired-5203.md delete mode 100644 .changeset/inbox-arrival-toast-and-desktop-7011.md delete mode 100644 .changeset/inbox-receipt-window-scope.md delete mode 100644 .changeset/inert-lifecycle-path-readout-5768.md delete mode 100644 .changeset/interfacelistpage-drop-derived-marker-title-6343.md delete mode 100644 .changeset/interfaces-rail-label-map-11158.md delete mode 100644 .changeset/issue-5373-retire-crud-schema.md delete mode 100644 .changeset/issue-5389-workspace-admin-positions.md delete mode 100644 .changeset/issue-5474-static-table-narrow-types.md delete mode 100644 .changeset/issue-5619-workspace-admin-unresolved.md delete mode 100644 .changeset/issue-5709-unconsumed-widget-option-warning.md delete mode 100644 .changeset/issue-5821-table-column-editable-mirror.md delete mode 100644 .changeset/issue-5881-record-highlights-header-prose.md delete mode 100644 .changeset/issue-5887-toplevel-strictness-probes.md delete mode 100644 .changeset/issue-6275-validation-engine-dangling-see.md delete mode 100644 .changeset/issue-6567-hoist-internalformroute-import.md delete mode 100644 .changeset/issue-7992-unmirrored-keys-doc-side.md delete mode 100644 .changeset/issue-8378-usechat-options-cast.md delete mode 100644 .changeset/issue-8379-reconcile-redundant-assertion.md delete mode 100644 .changeset/issue-8399-dedupe-pin-pins-viewport.md delete mode 100644 .changeset/issue-8690-recorder-wait-audit.md delete mode 100644 .changeset/issue-8703-matcher-dependent-strict-bucket.md delete mode 100644 .changeset/issue-8704-census-matcher-ast.md delete mode 100644 .changeset/issue-8875-cite-by-content-convention.md delete mode 100644 .changeset/issue-9109-widen-default-ledger.md delete mode 100644 .changeset/issue-9124-side-effects-build-state.md delete mode 100644 .changeset/issue-9191-new-url-import-meta-url-measured.md delete mode 100644 .changeset/issue-9198-workflow-test-readers-habit.md delete mode 100644 .changeset/issue-9418-write-identity-locks-port.md delete mode 100644 .changeset/issue-9586-enqueue-class-deny-mirror.md delete mode 100644 .changeset/issue-9819-operations-ceiling.md delete mode 100644 .changeset/jsdoc-default-renderer-retest-8318.md delete mode 100644 .changeset/jsonc-fence-extractor-test-only.md delete mode 100644 .changeset/kanban-8826-order-not-claimed.md delete mode 100644 .changeset/kanban-calendar-nav-width-converge.md delete mode 100644 .changeset/kanban-empty-badge-label-8489.md delete mode 100644 .changeset/kbd-group-props-name-the-element-8576.md delete mode 100644 .changeset/khaki-cameras-attack.md delete mode 100644 .changeset/khaki-rocks-shout.md delete mode 100644 .changeset/layout-default-jsdoc-7361.md delete mode 100644 .changeset/layout-direction-default-jsdoc-7734.md delete mode 100644 .changeset/layout-renderers-dom-props-5574.md delete mode 100644 .changeset/lazy-plugin-jsdoc-compiles.md delete mode 100644 .changeset/list-user-actions-collision-5398.md delete mode 100644 .changeset/list-view-nested-aria-label-i18n-5134.md delete mode 100644 .changeset/listview-calendar-crossfield-pin-7122.md delete mode 100644 .changeset/listview-comment-pair-4559.md delete mode 100644 .changeset/listview-map-view-level-config-5042.md delete mode 100644 .changeset/listviews-refused-read-discrimination.md delete mode 100644 .changeset/lockfile-integrity-gate.md delete mode 100644 .changeset/lookup-cell-chip-cap.md delete mode 100644 .changeset/lookup-dropdown-cell-renderer-5492.md delete mode 100644 .changeset/loud-lamps-shake.md delete mode 100644 .changeset/lucide-icon-record-name-gate.md delete mode 100644 .changeset/lucide-react-1-43-0-retired-trash2.md delete mode 100644 .changeset/lucky-buttons-warn.md delete mode 100644 .changeset/lucky-donkeys-repeat.md delete mode 100644 .changeset/lucky-donkeys-shave.md delete mode 100644 .changeset/lucky-forms-omit-server-defaults.md delete mode 100644 .changeset/lucky-moons-shake.md delete mode 100644 .changeset/lucky-pandas-shake.md delete mode 100644 .changeset/lucky-pugs-shake.md delete mode 100644 .changeset/lucky-pugs-shout.md delete mode 100644 .changeset/map-marker-title-binding.md delete mode 100644 .changeset/marketplace-catalog-runtime-before-admin-5557.md delete mode 100644 .changeset/marketplace-detail-admin-guard-order-5583.md delete mode 100644 .changeset/marketplace-detail-disabled-state-5533.md delete mode 100644 .changeset/marketplace-disabled-state-5504.md delete mode 100644 .changeset/master-detail-formtype-vocabulary.md delete mode 100644 .changeset/max-tool-roundtrips-deprecate-5605.md delete mode 100644 .changeset/measure-analytics-starvation-paths-7696.md delete mode 100644 .changeset/measure-datetime-format-8352.md delete mode 100644 .changeset/member-pins-8071-near-miss-four.md delete mode 100644 .changeset/member-pins-object-grid-row-layer-8071.md delete mode 100644 .changeset/member-pins-object-grid-slice-17.md delete mode 100644 .changeset/member-pins-slice-7.md delete mode 100644 .changeset/menu-icon-test-phantom-value.md delete mode 100644 .changeset/metadata-client-actor-retired-4834.md delete mode 100644 .changeset/metadata-lock-state-5024.md delete mode 100644 .changeset/modal-form-section-group-11542.md delete mode 100644 .changeset/named-list-view-protocol-members-8980.md delete mode 100644 .changeset/nav-item-visible-nesting-10119.md delete mode 100644 .changeset/nav-selection-root-keys-edge-5600.md delete mode 100644 .changeset/nervous-donkeys-tap.md delete mode 100644 .changeset/network-escape-batch1.md delete mode 100644 .changeset/network-escape-batch2.md delete mode 100644 .changeset/network-escape-batch3.md delete mode 100644 .changeset/network-escape-batch4.md delete mode 100644 .changeset/network-escapes-batch5.md delete mode 100644 .changeset/network-escapes-batch6.md delete mode 100644 .changeset/nine-holdouts-six-narrow.md delete mode 100644 .changeset/node-gate-data-predicate-report-5687.md delete mode 100644 .changeset/normalise-client-error-user-message-5901.md delete mode 100644 .changeset/notready-t-interpolates.md delete mode 100644 .changeset/npm-presence-publish-predicate-5442.md delete mode 100644 .changeset/object-calendar-member-pins-8071.md delete mode 100644 .changeset/object-schema-metadata-derive-from-spec.md delete mode 100644 .changeset/object-view-unmirrored-keys-7779.md delete mode 100644 .changeset/objectchart-fieldoptionlabel-ref-5587.md delete mode 100644 .changeset/objectchart-schema-anchor-7946.md delete mode 100644 .changeset/objectmap-marker-title-resolver-5953.md delete mode 100644 .changeset/objectmap-schema-data-shorthand-5305.md delete mode 100644 .changeset/objectpivottable-i18n-resolver-refs-5625.md delete mode 100644 .changeset/objectui-6844-preview-sample-status-options.md delete mode 100644 .changeset/objectui-7559-relay-rung-census.md delete mode 100644 .changeset/objectview-overlay-pair-completeness-5025.md delete mode 100644 .changeset/objectview-sort-sink-4869.md delete mode 100644 .changeset/olive-buckets-scream.md delete mode 100644 .changeset/olive-cameras-repeat.md delete mode 100644 .changeset/olive-clouds-repeat.md delete mode 100644 .changeset/olive-crabs-shave.md delete mode 100644 .changeset/olive-crabs-visit.md delete mode 100644 .changeset/olive-donkeys-invent.md delete mode 100644 .changeset/olive-donkeys-scream.md delete mode 100644 .changeset/olive-donkeys-shave.md delete mode 100644 .changeset/olive-donkeys-smile.md delete mode 100644 .changeset/olive-donkeys-smoke.md delete mode 100644 .changeset/olive-doors-tickle.md delete mode 100644 .changeset/olive-falcons-invent.md delete mode 100644 .changeset/olive-flowers-yawn.md delete mode 100644 .changeset/olive-mails-repeat.md delete mode 100644 .changeset/olive-moons-reclassify.md delete mode 100644 .changeset/olive-moons-shave.md delete mode 100644 .changeset/olive-pears-invent.md delete mode 100644 .changeset/olive-pugs-repeat.md delete mode 100644 .changeset/olive-pugs-shave.md delete mode 100644 .changeset/olive-pugs-sing.md delete mode 100644 .changeset/one-origin-dev-configs-5745.md delete mode 100644 .changeset/opennativepicker-coverage-7570.md delete mode 100644 .changeset/overlay-shell-mode-measurement-9113.md delete mode 100644 .changeset/overlay-slot-requiredness-7106.md delete mode 100644 .changeset/owd-width-single-home-5477.md delete mode 100644 .changeset/page-kind-node-type-channel-9642.md delete mode 100644 .changeset/page-kind-writing-end-9718.md delete mode 100644 .changeset/page-source-tailwind-framing-5461.md delete mode 100644 .changeset/page-source-tailwind-prose-retraction-5469.md delete mode 100644 .changeset/pageblock-retired-key-gate.md delete mode 100644 .changeset/palette-canonical-discussion-5495.md delete mode 100644 .changeset/palette-exclusion-reason-truthfulness.md delete mode 100644 .changeset/param-dialog-title-fallback-4282.md delete mode 100644 .changeset/paramtofield-reference-rule-derives-from-core-5312.md delete mode 100644 .changeset/parity-gate-lazy-registrations.md delete mode 100644 .changeset/paywall-moment-exit-and-failure-state-7253.md delete mode 100644 .changeset/pending-drafts-bar-locale-parity-5705.md delete mode 100644 .changeset/pending-drafts-i18n-keys.md delete mode 100644 .changeset/per-user-active-org-and-session-user-purge-5664.md delete mode 100644 .changeset/per-view-config-alias-fold-2890.md delete mode 100644 .changeset/percent-figure-grid-citation-5608.md delete mode 100644 .changeset/percent-summary-chip-one-rule.md delete mode 100644 .changeset/permissions-evaluator-prototype-guard-8044.md delete mode 100644 .changeset/pin-advisory-sink-seam-6969.md delete mode 100644 .changeset/pin-ledger-docstring-key-totals.md delete mode 100644 .changeset/pin-relative-out-of-window-precedence-8262.md delete mode 100644 .changeset/pin-unpinned-wait-preconditions-8709.md delete mode 100644 .changeset/pin-zod-mirror-parity-header-key-totals.md delete mode 100644 .changeset/pin-zod-mirror-parity-ledger-entry-counts.md delete mode 100644 .changeset/pivot-table-stable-empty-rows-5562.md delete mode 100644 .changeset/placeholder-spelling-one-rule.md delete mode 100644 .changeset/plain-taxis-attend.md delete mode 100644 .changeset/plugin-component-input-deprecate-5674.md delete mode 100644 .changeset/plugin-detail-8937-parent-scope-residue.md delete mode 100644 .changeset/plugin-detail-viewport-pins-8444.md delete mode 100644 .changeset/plugin-form-readme-classname-quantifier-5131.md delete mode 100644 .changeset/plugin-map-reach-test-narration.md delete mode 100644 .changeset/preview-sample-lookup-reference-6647.md delete mode 100644 .changeset/previews-shared-empty-description-8526.md delete mode 100644 .changeset/properties-template-visibility-diagnostic-5756.md delete mode 100644 .changeset/proto-instrument-fixture.md delete mode 100644 .changeset/publish-envelope-one-spelling-6962.md delete mode 100644 .changeset/queryparams-closed-keys-7497.md delete mode 100644 .changeset/quick-pots-repeat.md delete mode 100644 .changeset/quick-reference-release-sync-5394.md delete mode 100644 .changeset/quiet-pans-repeat.md delete mode 100644 .changeset/radio-multiple-docblock-correction.md delete mode 100644 .changeset/react-form-view-bridge-drifted-arms-5652.md delete mode 100644 .changeset/react-pages-guide-source-contradictions-5413.md delete mode 100644 .changeset/readonly-richtext-raw-markup-5498.md delete mode 100644 .changeset/reanchor-adr-0124-d1-citations-5701.md delete mode 100644 .changeset/record-activity-open-vocabulary-fallback.md delete mode 100644 .changeset/record-activity-scheduled-event-5840.md delete mode 100644 .changeset/record-activity-types-filter-never-widens-5841.md delete mode 100644 .changeset/record-activity-unproduced-feed-kinds-5877.md delete mode 100644 .changeset/record-alert-cta-label-i18n-4998.md delete mode 100644 .changeset/record-alert-loading-frame-diagnostic-5776.md delete mode 100644 .changeset/record-alert-row-binding-4807.md delete mode 100644 .changeset/record-context-binding-casts.md delete mode 100644 .changeset/record-detail-builtin-label-i18n-4645.md delete mode 100644 .changeset/record-detail-param-dialog-title-5610.md delete mode 100644 .changeset/record-handoff-card.md delete mode 100644 .changeset/record-panel-member-pins-8071.md delete mode 100644 .changeset/record-picker-empty-text-i18n-5590.md delete mode 100644 .changeset/record-picker-label-association-5771.md delete mode 100644 .changeset/record-picker-label-placeholder-i18n-5637.md delete mode 100644 .changeset/record-picker-member-pins-8071.md delete mode 100644 .changeset/record-quick-actions-member-pins-8071.md delete mode 100644 .changeset/record-quick-actions-resultdialog-pin-5711.md delete mode 100644 .changeset/record-title-drop-undeclared-objectdef-titlefield-6531.md delete mode 100644 .changeset/reference-rail-entries-stale-prose.md delete mode 100644 .changeset/reference-rail-entry-spec-derived.md delete mode 100644 .changeset/referenceto-carryover-8896.md delete mode 100644 .changeset/registerfunction-casefold-doc-5363.md delete mode 100644 .changeset/registry-assertion-ratchet-8316.md delete mode 100644 .changeset/related-badge-arity-8882.md delete mode 100644 .changeset/related-list-member-pins-8071.md delete mode 100644 .changeset/release-lane-tests-and-concurrency-5404.md delete mode 100644 .changeset/remove-inert-showrefresh-5567.md delete mode 100644 .changeset/rename-command-palette-shortcuts-demo.md delete mode 100644 .changeset/render-publish-advisory-findings-5026.md delete mode 100644 .changeset/replay-dispatch-error-5695.md delete mode 100644 .changeset/report-view-datasource-object-key-5116.md delete mode 100644 .changeset/retire-codecov-upload-5436.md delete mode 100644 .changeset/retire-components-action-param-dialog-5685.md delete mode 100644 .changeset/retire-dead-engine-strings-8547.md delete mode 100644 .changeset/retire-options-shorthand-lift-4356.md delete mode 100644 .changeset/retire-record-details-section-collapsed.md delete mode 100644 .changeset/retire-spec-bridge-6366.md delete mode 100644 .changeset/retire-theme-component-schema-5489.md delete mode 100644 .changeset/retire-theme-switcher-preview-5647.md delete mode 100644 .changeset/retire-usebranding-hook-5368.md delete mode 100644 .changeset/retired-field-type-gate-4914.md delete mode 100644 .changeset/retired-lucide-spellings-5622.md delete mode 100644 .changeset/richtext-cell-renderer-5452.md delete mode 100644 .changeset/rotten-pugs-invent.md delete mode 100644 .changeset/row-predicate-phase2-record-only-5741.md delete mode 100644 .changeset/row-predicate-record-canon-5330.md delete mode 100644 .changeset/rowcolor-prototype-guard-6295.md delete mode 100644 .changeset/runtime-config-server-side-pointer.md delete mode 100644 .changeset/runtime-served-error-reporting-dsn.md delete mode 100644 .changeset/safe-field-label-identity-5564.md delete mode 100644 .changeset/scatter-unplaceable-points.md delete mode 100644 .changeset/schema-input-bridge-permanent-4622.md delete mode 100644 .changeset/sdui-parser-inline-whitespace-5661.md delete mode 100644 .changeset/sdui-preview-page-source-tailwind-5470.md delete mode 100644 .changeset/secret-widget-spellings-5375.md delete mode 100644 .changeset/select-empty-host-id-8803.md delete mode 100644 .changeset/self-import-gate-scan-once-5402.md delete mode 100644 .changeset/sentry-undisableable-telemetry-5522.md delete mode 100644 .changeset/setmessages-honest-surface-8342.md delete mode 100644 .changeset/settled-schema-resolution-hook-6482.md delete mode 100644 .changeset/shaggy-doors-repeat.md delete mode 100644 .changeset/shard-coverage-job-5403.md delete mode 100644 .changeset/shared-zod-wrapper-keys-6923.md delete mode 100644 .changeset/signout-purge-per-key-try-5777.md delete mode 100644 .changeset/simple-form-consults-declared-submit-handler.md delete mode 100644 .changeset/six-donkeys-shake.md delete mode 100644 .changeset/skill-provider-envelope-teaching-5372.md delete mode 100644 .changeset/span-full-tier-ladder-9244.md delete mode 100644 .changeset/sparse-predicate-warning-cause-5399.md delete mode 100644 .changeset/spec-17-3-0-lockfile-bump.md delete mode 100644 .changeset/spec-pin-17-1-0-5328.md delete mode 100644 .changeset/spec-refresh-17-2-0-5668.md delete mode 100644 .changeset/spec-symbol-mirrors-app-shell-7265.md delete mode 100644 .changeset/spellgantt-revoked-proxy-exclusion.md delete mode 100644 .changeset/spotty-pages-drop-leaks.md delete mode 100644 .changeset/spotty-pianos-shave.md delete mode 100644 .changeset/spotty-pins-cover-fields.md delete mode 100644 .changeset/stale-4163-pointers-5591.md delete mode 100644 .changeset/stale-disable-directives-4853.md delete mode 100644 .changeset/standard-widgets-phone-coverage.md delete mode 100644 .changeset/standing-pending-drafts-bar-5694.md delete mode 100644 .changeset/stripper-residue-9751.md delete mode 100644 .changeset/studio-jargon-and-tool-card-i18n.md delete mode 100644 .changeset/studio-metadata-form-ux-5416.md delete mode 100644 .changeset/studio-nav-canonical-keys.md delete mode 100644 .changeset/studio-new-object-asks-for-owd-5418.md delete mode 100644 .changeset/studio-route-entry-capability-5519.md delete mode 100644 .changeset/studio-simplify-5813.md delete mode 100644 .changeset/submithandler-variant-forms.md delete mode 100644 .changeset/surface-context-send-1610.md delete mode 100644 .changeset/surface-deeplink-live-channel-5476.md delete mode 100644 .changeset/sweep-store-per-key-try-5763.md delete mode 100644 .changeset/switch-org-declared-reresolve-5750.md delete mode 100644 .changeset/switch-org-identity-reresolve-5719.md delete mode 100644 .changeset/table-renderer-declared-column-contract-5350.md delete mode 100644 .changeset/tall-doors-smash.md delete mode 100644 .changeset/tall-tools-shake.md delete mode 100644 .changeset/tame-buses-clean.md delete mode 100644 .changeset/tame-jars-repeat.md delete mode 100644 .changeset/tenant-header-edge-contract-5279.md delete mode 100644 .changeset/test-name-line-citation-gate-8047.md delete mode 100644 .changeset/text-input-description-aria-describedby-5735.md delete mode 100644 .changeset/text-input-i18n-label-arms-5717.md delete mode 100644 .changeset/text-value-retired-citations-8045.md delete mode 100644 .changeset/theme-clientvalidation-dead-entry-5715.md delete mode 100644 .changeset/theme-schema-doc-rewrite-5648.md delete mode 100644 .changeset/theme-types-localized-5716.md delete mode 100644 .changeset/theme-zod-retired-spec-reexports.md delete mode 100644 .changeset/tidy-buttons-repeat.md delete mode 100644 .changeset/tidy-donkeys-attack.md delete mode 100644 .changeset/tidy-donkeys-repeat.md delete mode 100644 .changeset/tidy-donkeys-shave.md delete mode 100644 .changeset/tidy-flags-obey-the-filter.md delete mode 100644 .changeset/tidy-forms-carry-spec-keys.md delete mode 100644 .changeset/tidy-forms-refuse-target-less-submit.md delete mode 100644 .changeset/tidy-jars-confirm.md delete mode 100644 .changeset/tidy-pans-repeat.md delete mode 100644 .changeset/tidy-permissions-provider-ctx-identity.md delete mode 100644 .changeset/tidy-pugs-invent.md delete mode 100644 .changeset/tidy-pumas-repeat.md delete mode 100644 .changeset/timeline-shared-safe-field-label-5623.md delete mode 100644 .changeset/toc-anchor-parity-cite-by-content.md delete mode 100644 .changeset/tool-title-i18n-channel.md delete mode 100644 .changeset/tree-contract-envelope-waits-6839.md delete mode 100644 .changeset/truthfulness-guard-import-set-7117.md delete mode 100644 .changeset/tsbuildinfo-outside-published-dist.md delete mode 100644 .changeset/types-field-depends-on-declared-6153.md delete mode 100644 .changeset/types-test-script-8590.md delete mode 100644 .changeset/ui-text-variant-align-enforce.md delete mode 100644 .changeset/unbundled-node-boundary-5384.md delete mode 100644 .changeset/unified-pending-drafts-5801.md delete mode 100644 .changeset/uniqueness-deprecation-jsdoc-4765.md delete mode 100644 .changeset/unknown-component-type-case-suggestion-5247.md delete mode 100644 .changeset/utilities-index-phantom-provider-5360.md delete mode 100644 .changeset/vacuous-dts-justification-5673.md delete mode 100644 .changeset/value-datasource-ast-filter-vocabulary.md delete mode 100644 .changeset/valuedatasource-comparand-shapes-8514.md delete mode 100644 .changeset/vi-mock-inherit-guard-6849.md delete mode 100644 .changeset/vi-mock-inherit-slice1.md delete mode 100644 .changeset/vi-mock-inherit-slice10-plugin-chatbot.md delete mode 100644 .changeset/vi-mock-inherit-slice11-plugin-designer.md delete mode 100644 .changeset/vi-mock-inherit-slice12-plugin-list.md delete mode 100644 .changeset/vi-mock-inherit-slice13-fields.md delete mode 100644 .changeset/vi-mock-inherit-slice14-app-shell.md delete mode 100644 .changeset/vi-mock-inherit-slice2.md delete mode 100644 .changeset/vi-mock-inherit-slice3.md delete mode 100644 .changeset/vi-mock-inherit-slice4.md delete mode 100644 .changeset/vi-mock-inherit-slice5.md delete mode 100644 .changeset/vi-mock-inherit-slice6-components.md delete mode 100644 .changeset/vi-mock-inherit-slice7-plugin-grid.md delete mode 100644 .changeset/vi-mock-inherit-slice8-permissions.md delete mode 100644 .changeset/vi-mock-inherit-slice9-plugin-detail.md delete mode 100644 .changeset/via-override-pin-discriminates.md delete mode 100644 .changeset/view-column-io-canonical-identity-5725.md delete mode 100644 .changeset/view-overlay-write-patch-only-5233.md delete mode 100644 .changeset/view-switcher-chart-gantt-icons-5586.md delete mode 100644 .changeset/viewcolumn-identity-canonical-read-5344.md delete mode 100644 .changeset/violet-donkeys-brake.md delete mode 100644 .changeset/visiblewhen-record-binding-5454.md delete mode 100644 .changeset/vitest-config-unification-3240.md delete mode 100644 .changeset/vitest-invocation-guard-package-cwd-coverage-5406.md delete mode 100644 .changeset/wider-ledger-per-arm-8252.md delete mode 100644 .changeset/widget-config-panel-locale-map-5301.md delete mode 100644 .changeset/widget-input-control-vocabulary-5675.md delete mode 100644 .changeset/wild-charts-explain-themselves.md delete mode 100644 .changeset/wild-donkeys-shake.md delete mode 100644 .changeset/wild-tables-shout.md delete mode 100644 .changeset/wire-dropped-fields-shape-6889.md delete mode 100644 .changeset/wise-pandas-pin.md delete mode 100644 .changeset/wise-poems-behave.md delete mode 100644 .changeset/writefields-proto-key-9237.md delete mode 100644 .changeset/zod-array-element-reader-5872.md delete mode 100644 .changeset/zod-base-schema-mirror-parity-4605.md delete mode 100644 .changeset/zod-internals-reader-confinement.md delete mode 100644 .changeset/zod-mirror-parity-arbiter-9546.md delete mode 100644 .changeset/zod-mirror-parity-population-5684.md delete mode 100644 .changeset/zod-mirror-parity-population-derived.md diff --git a/.changeset/10002-map-style-remedy-text.md b/.changeset/10002-map-style-remedy-text.md deleted file mode 100644 index b487becc65..0000000000 --- a/.changeset/10002-map-style-remedy-text.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/plugin-map': patch ---- - -fix(plugin-map): the top-level-`style` warning now prescribes a spelling the runtime reads - -`warnOnTopLevelStyleUrl` fires when a map node carries a string `style` — the base -schema's inline-CSS key, which is never read as a map style — and tells the author -where to write it instead. Its last sentence ended "spell it `map: { mapStyle }` -there". `ObjectMapConfigSchema` does not declare `mapStyle`, so neither view -flattener's whitelist carries it and `getMapConfig` never reads it: an author who -obeyed the correction wrote metadata that was discarded a second time, with no -second diagnostic. That text is read at the moment the author is ALREADY being -corrected, which is why prescribing refused metadata there was ruled out for a -sibling sink (objectui#9031). - -The remedy now names the declared block — `map: { style: 'URL' }` — on the node -path and on the view path alike. That is also what moved underneath it: since -objectui#9950 both flatteners carry a declared `style` out of `options.map` under -its flat spelling `mapStyle`, so a view's declared block arrives and is read, and -neither producer of an `object-map` node emits a top-level `style` any more. The -sentence had gone on describing the pre-#9950 transport. - -⛔ The remedy is no longer defended by a string assertion — that is how it rotted -in the first place, green the whole time because nothing executed it. Every key it -prescribes inside a `map` block is now parsed out of the warning the component -really emits and written into a real `map` block, measured end to end through the -declared block and through the real `ListView` flatten, so the sentence and the -runtime cannot drift apart without a test going red. diff --git a/.changeset/10005-record-history-row-cap-refusal.md b/.changeset/10005-record-history-row-cap-refusal.md deleted file mode 100644 index 660983a5ee..0000000000 --- a/.changeset/10005-record-history-row-cap-refusal.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -`record:history` refuses a row cap the contract rejects instead of repairing it -(objectui#10005). - -`@objectstack/spec` declares this block's member a positive integer — -`RecordHistoryProps.limit` is `z.number().int().positive().optional()`, described there -as the `$top` of the self-fetch query with a renderer default of 50. Two values the -contract refuses were nevertheless reaching the adapter: - -- an authored `limit: -5` came back as a **one-row** window. The old derivation ended in - `|| 50`, which catches `0`, `NaN` and `''`, but a negative is truthy and survived it; - the `Math.max(1, …)` at the wire then repaired it to `1` rather than refusing it. -- an authored `limit: 2.5` was forwarded **untouched** as a fractional `$top`. - -Both now fall back to this block's own default of 50, silently, which is the answer its -sibling `record:activity` already gives through `normalizeLimit`. Absent, `0`, `NaN` and -a non-numeric string keep answering 50 exactly as before, a usable cap still passes -through unchanged, and a numeric string still resolves. `record:history`'s default of 50 -and `record:activity`'s of 20 are unchanged and still differ deliberately. - -What an author sees change: a record page whose history block declared a negative or -fractional cap showed one row (or an unpredictable window) and named no cause; it now -shows the default 50. diff --git a/.changeset/10006-port-parity-list-pipe-flush.md b/.changeset/10006-port-parity-list-pipe-flush.md deleted file mode 100644 index e447677245..0000000000 --- a/.changeset/10006-port-parity-list-pipe-flush.md +++ /dev/null @@ -1,20 +0,0 @@ ---- ---- - -Tooling and tests only, no package released: `scripts/check-upstream-port-parity.mjs` no longer ends -on `process.exit(...)`. On POSIX, `process.stdout` is asynchronous when it is a pipe, and -`process.exit` discards whatever is still queued — so `--list`, which is nothing but a `console.log` -loop, reached a piped caller cut at a point that depended on runner load. The gate's own wiring test -captures it with `execFileSync`, so a lost line failed as `no listing line for ID under FILE`: a -specific and false claim about a file the branch under test had never touched. Four unrelated pull -requests were reddened that way, one of them ejected from the merge queue and one a comment-only -diff; the control is the same commit `0a4bf6deb`, no new commits and no rebase, going red then green -(objectui#10006). - -The entrypoint now sets `process.exitCode` and lets Node exit once the streams drain. Every exit -code is unchanged, proven path by path — clean, drift, unreadable pin, structurally unusable pin, -uncaught throw, and all four `--resync` refusals plus its success path — and the stdout/stderr bytes -are identical too. The wiring test grows two pins: the listing reconciles against the count the gate -itself announces, so a short capture fails as "less arrived than was sent" rather than as a claim -about one divergence; and a synthetic pin drives a listing past what a pipe holds and requires the -piped capture to equal the same run's capture to a file. diff --git a/.changeset/10015-gate-reports-refused-view-cap.md b/.changeset/10015-gate-reports-refused-view-cap.md deleted file mode 100644 index 5cfffc6130..0000000000 --- a/.changeset/10015-gate-reports-refused-view-cap.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/react': patch ---- - -`ElementDataSourceGate` now reports a saved view's refused row cap on the renderer path -(objectui#10015). - -objectui#9928 made `@object-ui/core` drop a saved view's `pagination.pageSize` (or legacy flat -`limit`) when the contract refuses it: `0`, a negative, or a fraction. The drop is correct, but on -the renderer path it removed the author's only diagnostic. The node's cap went from `0` to absent, -and the consuming renderer treats an absent key as "not a mistake". The gate had never reported a -VIEW cap, so nothing reported it at all. - -The gate now emits `elementDataSourceRefusedLimitMessage`, the same sentence `ViewDataProvider` -already uses on the path with no renderer. It is emitted once per declaration, from an effect and -never from render, on the same `console.warn` channel. It fires only when the refusal changed what -the block receives: the block reads a row cap, the binding declares no `limit` of its own, and the -component's own cap is not a usable one. A view with no cap, a usable view cap, a usable component -cap, a binding `limit`, or a block with no row cap stays silent. It never fires together with the -gate's existing displaced-cap message (objectui#9899), because that message needs a usable cap to -have been written and, with the view's cap refused, the only one left is a binding `limit`. No -wire value changes. diff --git a/.changeset/10016-binding-limit-not-authored.md b/.changeset/10016-binding-limit-not-authored.md deleted file mode 100644 index 5e93804838..0000000000 --- a/.changeset/10016-binding-limit-not-authored.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/react': minor ---- - -A `dataSource` binding's own `limit` that the contract refuses is now treated as **not -authored**: the row cap falls through to the named saved view's usable cap, and only when -that is absent too to the consumer's own default (objectui#10016). - -**Behaviour change.** `composeElementDataSource` resolved the cap as -`config.limit ?? savedViewLimit(view)`. objectui#9928 put a positivity check on the view's -operand only, so a binding `limit` of `0`, `-10`, `25.5` or a non-number went through -unchecked: - -- through `ViewDataProvider.resolveElementDataSource` it reached `DataFetcher.fetchRecords` - verbatim, and nothing said so; -- through `ElementDataSourceGate` it was written over everything, a usable component cap - included, and the consuming block then dropped it and drew its own default, so the read - went wider than either the view or the component asked for. - -Both operands now pass the same check, and a refused cap from either is not authored. The -chain is: a usable binding cap, else a usable view cap, else none. This is the rule -objectui#10009 set one layer up (a value the contract refuses is not authored, so the other -source wins), applied to the two operands of one resolver. On the renderer path the view's -cap that takes the binding's place is a baseline like any other view-sourced value, so a -usable component cap still wins over it. A usable binding `limit` still beats both, exactly -as before. - -**Diagnostics.** `elementDataSourceRefusedLimitMessage` takes two optional trailing -parameters, the binding and the operand (`'view'`, the default, or `'binding'`). The binding -operand has its own sentence, naming the binding, so a binding refusal and a view refusal -are told apart when both fire. `ViewDataProvider` and `ElementDataSourceGate` report it once -per declaration on the existing `console.warn` channel; the gate reports it only for a block -that reads a row cap. Called with three arguments the builder answers exactly as before. - -**Fixed with it.** `ViewDataProvider` reported a saved view's refused cap even when the -binding's own usable `limit` was the cap actually used, and that warning's claim that the -fetch falls back to a default was false. The view's refusal is now reported only when the -binding's `limit` is absent or refused. The builder applies that condition itself, so both -callers share one copy of it. diff --git a/.changeset/10018-authoring-state-sheds-approval.md b/.changeset/10018-authoring-state-sheds-approval.md deleted file mode 100644 index d13f7d4da1..0000000000 --- a/.changeset/10018-authoring-state-sheds-approval.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-chatbot': minor ---- - -BREAKING (`@object-ui/types`, `@object-ui/plugin-chatbot`): the authoring `ChatToolInvocation.state` union sheds the AI SDK's three runtime-only approval states — `approval-requested`, `approval-responded` and `output-denied` — so a schema-authored tool invocation can no longer claim an approval the runtime has nothing to back (objectui#10018, the residual clause of the objectui#8426 ruling, decision batch #86). - -(The bump is `minor` by this repo's release model — objectui's major is pinned to the `@objectstack` family major, and its own breaking changes ship as `minor` with the breaking semantics stated here.) - -**Break 1 — authored approval states are refused.** `ChatToolInvocation.state` (and so `ChatMessage.toolInvocations[].state` and `ChatbotSchema.messages`) no longer admits the three approval states, and the Zod mirror `ChatToolInvocationSchema` refuses them as an `invalid_value` at `state`. The refusal holds with or without an `approval` envelope: the envelope does not make a runtime-only state authorable. A chat runtime still produces these states — from the SDK's approval envelope, or promoted from an ObjectStack pending-action result — and still renders them; only the authoring face stops declaring them. Migration: author the state the tool call is actually in (`input-streaming`, `input-available`, `output-available`, `output-error`, or a legacy `partial-call` / `call` / `result`), and leave approval states to the runtime. - -**Break 2 — `onSend` handlers typed against the authoring `ChatMessage[]`.** The messages a chat runtime hands back can carry those three states, so they are no longer a subtype of the authoring `ChatMessage`. `ChatbotSchema.onSend`'s `messages` is now typed as the authoring message widened by exactly those states, and `useObjectChat`'s `ObjectChatMessage` is no longer assignable to the authoring `ChatMessage`. A handler that declares its parameter as the authoring `ChatMessage[]` stops type-checking. Migration: let the parameter be inferred from the slot, or declare it as `ObjectChatMessage[]` from `@object-ui/plugin-chatbot` when passing `onSend` to `useObjectChat`. - -Not breaking: `UseObjectChatOptions.initialMessages`, `SeamToolInvocation` and `toRuntimeToolState` now take the seam's state vocabulary (authoring plus runtime), which is the same set of values they accepted before, so every existing caller still compiles. `UseObjectChatOptions.initialMessages` also moves from the authoring `ChatMessage` to the exported `SeamChatMessage`, so nine optional runtime-only keys are now declared on that option: `buildProgress`, `blueprintProgress` and `charts` on a message, and `pendingActionId`, `draftReview`, `proposedPlan`, `proposedChanges`, `builderHandoff` and `replayOutcome` on each tool invocation. Nothing changes at runtime, because the hook's two builders behave exactly as before: local mode's `normalizeMessages` forwards `toolInvocations` whole (so the six tool-invocation keys survive) but copies only the base message fields (so `buildProgress`, `blueprintProgress` and `charts` are dropped), and API mode's `aiInitialMessages` rebuilds each message as SDK parts that carry none of the nine. Each key was already declared on `SeamChatMessage`; what changes is that a host passing one in an object literal is no longer told it is an excess property. No new name is exported: the three runtime-only states are named only by a non-exported alias in `@object-ui/types`, pinned equal to `ChatbotEnhanced`'s runtime union by `chat-message-contract.test.ts`. The effect on out-of-repo authors and hosts was not measured. diff --git a/.changeset/10019-parts-builder-key-set-texts.md b/.changeset/10019-parts-builder-key-set-texts.md deleted file mode 100644 index d1a5590a09..0000000000 --- a/.changeset/10019-parts-builder-key-set-texts.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`: the cache-write comment inside `sanitizeChatMessagesForCache` described the AI-chat parts builder by a literal key list, which objectui#10017 retired when it made that builder construct a discriminated tool part per state. The comment now cites `toSdkToolPart` — the builder that owns the key set — rather than restating it, and the argument it exists to make is unchanged. No published behaviour changes (objectui#10019). diff --git a/.changeset/10020-report-display-locale.md b/.changeset/10020-report-display-locale.md deleted file mode 100644 index 88e36d9406..0000000000 --- a/.changeset/10020-report-display-locale.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/plugin-report': minor ---- - -Report display sites follow the display locale instead of the literal tag `en-US` -(objectui#10020). - -Five display paths in this package handed `Intl` the literal BCP-47 tag `en-US` — -four branches of `formatValue` (`currency` / `currency_cny`, `currency_usd`, -`percent`, and the default thousand-separated branch) and the Excel cell formatter -behind `exportExcelWithFormulas`. That is the exact tag `useDisplayLocale`'s contract -in `@object-ui/i18n` names as the wrong answer, in as many words: *"Note this is -`'en'`, not `'en-US'`: the point of objectui#4033 is that `en-US` is not the world's -default."* A tenant that had configured `de-DE`, or a user reading the console in -Chinese, saw US grouping and decimal marks regardless — while the same package already -resolved that channel three times in `DatasetReportRenderer`. - -**Additive, not breaking.** `formatValue` is a published export, so its new display -locale is an OPTIONAL third parameter and `exportExcelWithFormulas` takes an optional -`locale` on the options bag it already had. Every call that compiled before compiles -after, and omitting the argument formats in `'en'` — the display channel's own last -resort, which is neither `en-US` nor an absent tag. - -**What that means for callers.** An optional parameter nobody passes would be the same -defect with a longer signature, so `ReportViewer` now resolves `useDisplayLocale()` -itself and threads it at all three of its call sites. If you call `formatValue` or -`exportExcelWithFormulas` from your own code, pass the locale you render in — -`useDisplayLocale()` in React, and for a non-React caller the tag your session -resolved. `exportExcelWithFormulas` cannot read the channel itself: it is not a -component, and a display locale is a property of the session rather than of the -authored report schema, so its caller is the only place the tag can come from. - -Threading a tag also introduces a hazard a literal never had — a tenant-configured tag -can be malformed (`en_US`, underscore instead of hyphen, makes `Intl` throw -`RangeError`), and these calls sit inside a cell render. A malformed tag now degrades -to the same last resort rather than taking the report down. It deliberately does NOT -degrade to a dropped tag, which would mean the machine's locale — the separate defect -shape tracked on objectui#9909, still present in this package's HTML export header and -deliberately not merged into this change. diff --git a/.changeset/10021-legend-swatch-custom-property.md b/.changeset/10021-legend-swatch-custom-property.md deleted file mode 100644 index 37e1c97a1c..0000000000 --- a/.changeset/10021-legend-swatch-custom-property.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/plugin-charts': patch ---- - -fix(plugin-charts): the legend swatch carries its series colour as a custom property - -`ChartLegendContent` painted each swatch with an inline `backgroundColor`, the -colour-bearing property AGENTS.md's styling carve-out names as forbidden. The -swatch now publishes the author-declared colour as `--color-bg` and a static -`bg-(--color-bg)` utility consumes it, the same shape the tooltip indicator in -the same file already uses, so the theme keeps control of the rule. The -rendered colour is unchanged. diff --git a/.changeset/10024-search-results-count-plural-forms.md b/.changeset/10024-search-results-count-plural-forms.md deleted file mode 100644 index ee99dd90da..0000000000 --- a/.changeset/10024-search-results-count-plural-forms.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/i18n': patch -'@object-ui/app-shell': patch ---- - -Full-page search results now read correctly in Russian and Arabic at every -count (objectui#10024). - -The results line picks `search.resultsCount` at exactly one result and -`search.resultsCountPlural` at every other count. Two slots cover English; they do -not cover Russian, which needs three noun forms for whole numbers, or Arabic, which -needs more. Russian's second slot held the form for 5 to 20, so two results read -`2 результатов` (the language needs `2 результата`) and twenty-one read -`21 результатов` (it needs `21 результат`). Arabic's two slots were the same string -byte for byte, so the switch gave Arabic nothing at 2 or at 3 to 10. - -In both packs the count-not-one half is now a count label that reads correctly at -any number: `Результатов по запросу "…": N` and `عدد نتائج البحث عن "…": N`. That is -the device both packs already use where two slots are all there are — Russian's -`collaboration.commentCount` (`Комментариев: N`) is the same shape on the same -two-key convention. The singular half, the call site, the key set and the other -eight packs are unchanged; `zh`, `ja` and `ko` keep one string in both halves -because their languages have a single plural category. - -⚠️ **Dated note, 2026-10-02 — superseded in this release — objectui#11445.** -Later in this same release the `search.resultsCount` / `search.resultsCountPlural` -switch gave way to a `search.resultsCount` count family in all ten packs: -`ru` and `ar` now write a noun form for each CLDR category instead of the count -label above (`2 результата`, `21 результат`), and `search.resultsCountPlural` left -every pack. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10026-refuse-impossible-calendar-day.md b/.changeset/10026-refuse-impossible-calendar-day.md deleted file mode 100644 index 4ed840ae5c..0000000000 --- a/.changeset/10026-refuse-impossible-calendar-day.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/components': patch -'@object-ui/fields': patch ---- - -fix(core): the shared date path refuses a calendar day that does not exist, with the marker it already renders for an unparsable value - -A date-only value naming a day its month does not have — `2026-02-30`, `2024-02-31`, `2025-02-29` — used to render as a real, different day on every date face: the engine's parse accepts a day of `01`-`31` for any month and rolls the surplus forward, so `2026-02-30` showed as `Mar 2`, with nothing to say the stored value was wrong. The filter builder already refused the same value at the authoring boundary, so the repo gave one concept two answers. - -- **New export `isRealCalendarDate(dateOnly)` from `@object-ui/core`.** It moved from `@object-ui/components`' filter builder, which now imports it — one implementation, shared by the authoring boundary and the display path. It answers `true` only for a `YYYY-MM-DD` string whose year, month and day exist. It now also reads a year below 100 as that year (it used to answer `false` for `0026-08-01`), so the filter builder keeps such a date instead of clearing it. -- **`toDisplayDate` returns an Invalid Date for such a value**, so `formatDate` (every face: default, `short`, `relative`), `formatRelativeDate` and `formatDateTime` render `—`, and `formatDateTimeCompactParts` returns `null` — each function's existing answer for an unparsable value. A caller that reads `toDisplayDate` directly gets the same refusal and shows its own unparsable face: the History tab and the record summary chip now show the stored string instead of a rolled date. -- **A dataset measure agrees with the list cell on the refusal.** A date-only measure value of `2024-02-30` renders `—`, the same as the `date` cell beside it. The measure takes that answer from the shared path and makes no judgement of its own. -- **`@object-ui/fields`:** the `date` and `datetime` cells, the readonly `DateField` and a date-returning `FormulaField` show the shared "No value" placeholder for such a day, exactly as for an unparsable value, instead of a bare dash. - -This change covers date-only values only. (A value that carries a time, such as `2026-02-30T10:00:00Z`, is refused by the same path too — objectui#10301, a separate entry in this release.) diff --git a/.changeset/10030-calendar-alias-refusal-quotes-surviving-clause.md b/.changeset/10030-calendar-alias-refusal-quotes-surviving-clause.md deleted file mode 100644 index 7099dd1334..0000000000 --- a/.changeset/10030-calendar-alias-refusal-quotes-surviving-clause.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/types': patch ---- - -The `dateField` alias refusal that objectui#8355 adds to a calendar binding -quotes only the first clause of the calendar refusal screen, "Calendar -configuration required": the clause objectui#8170 left unchanged -(objectui#10030). - -That refusal message tells an author what happens when the alias is kept rather -than refused: the calendar falls through to its refusal screen. Quoting only -the first clause keeps the message true of that screen both as published and as -objectui#8170 rewrites it. The rewrite keeps the first clause and replaces the -second sentence, which named `titleField` as required; `titleField` is optional. -The message's closing claim, that the screen names the canonical keys and never -the key the author wrote, holds for both versions of the screen. diff --git a/.changeset/10031-calendar-user-visible-strings-reach-the-packs.md b/.changeset/10031-calendar-user-visible-strings-reach-the-packs.md deleted file mode 100644 index f2f2300e69..0000000000 --- a/.changeset/10031-calendar-user-visible-strings-reach-the-packs.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch -'@object-ui/i18n': patch ---- - -`ObjectCalendar`'s user-visible copy now reaches the locale packs. The component -was already i18n-aware — it imports and calls both translation hooks — and a set -of English sentences sat beside those calls as literals, so a non-English session -read a half-translated calendar: the unscheduled label and the two write-failure -toasts in its own language, and the loading screen, the error screen, the refusal -screen, the pull-to-refresh affordance, the whole quick-create dialog and the -record overlay's fallback title in English (objectui#10031). - -Every one of those now reads a key. Two of them reuse keys the packs already -carried (`common.cancel`, `common.create`), one reuses `calendar.newEvent`, and -twelve are new under `calendar.`. - -**The hook is chosen per site by one criterion, which the file already stated for -its existing call:** `useSafeTranslate`'s `tt(key, fallback)` passes no options to -i18next and therefore cannot fill a hole, so the two sentences that carry one — -the error prefix and the quick-create date line — read their key through -`useObjectTranslation`'s `t()` with an inline default, and every hole-free string -uses `tt()`. - -**⚠️ A key added to `en` is not an `en`-only change in this repo**, and that is -worth stating because the cheap route looks available: the English fallback does -carry the English text at the call site, but the key-set invariant is a -pack-vs-pack one — every pack defines every `en` key — so it is answered by the -locale packs, not by the call site. All ten packs therefore carry the twelve new -keys, with real translations rather than the English value. The instrument that -says so is `all-locales-key-parity.test.ts`; `pnpm check:i18n-drift` prints which -of the two owns an addition. - -**One rendered English string moved**: the loading placeholder's three ASCII full -stops became the typographic ellipsis, because its sentence is now a pack value -and `ellipsis-glyph-3878.test.ts` holds every pack value to U+2026. The refusal -screen's copy is byte-identical to what it rendered before, which is what keeps -the five suites that pin it green. diff --git a/.changeset/10033-parity-ledger-retired-upstream.md b/.changeset/10033-parity-ledger-retired-upstream.md deleted file mode 100644 index c916c6cd01..0000000000 --- a/.changeset/10033-parity-ledger-retired-upstream.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Test-only change to the console's registry-inputs spec-parity gate; no published behaviour changes. The unjudged-block ledger gains a third reason class, RETIRED UPSTREAM, checked against the spec's own retirement signals, and the two older reasons now fail on a type the spec retired. `user:profile`, `element:form` and `element:filter` move to it. diff --git a/.changeset/10035-objectview-refresh-in-place.md b/.changeset/10035-objectview-refresh-in-place.md deleted file mode 100644 index 7e68fa6c98..0000000000 --- a/.changeset/10035-objectview-refresh-in-place.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/plugin-view': patch -'@object-ui/app-shell': patch ---- - -A save, delete or other write no longer rebuilds the object view it happened in — the view refetches its rows in place and keeps its component state (objectui#10035). - -Both `ObjectView` layers carried their refresh counter in a React `key`, so every write remounted the whole view and reset everything held in it: a calendar jumped back to the current month and its default mode, the object page's list lost its scroll position and the visualization picked in its own switcher. The counter now reaches the rendered view as a data signal instead: - -- `@object-ui/app-shell`: the object page hands its refresh counter to `ListView` as `refreshTrigger`, the input `ListView`'s fetch already follows, and keys the list on the object and view alone. -- `@object-ui/plugin-view`: kanban, calendar, gallery, timeline, map and tree views keep their instance across a write and receive the refetched rows. - -Views whose renderer fetches for itself — gantt and chart views in both layers, any object-page list whose visualization whitelist offers gantt or chart, and the standalone grid `plugin-view` renders when no host list view is supplied — refresh in place too, through the data-invalidation bus; see the `plugin-grid` / `plugin-gantt` / `plugin-charts` note for objectui#10035 in this release. diff --git a/.changeset/10035-renderers-read-invalidation.md b/.changeset/10035-renderers-read-invalidation.md deleted file mode 100644 index 6267af6fd2..0000000000 --- a/.changeset/10035-renderers-read-invalidation.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/plugin-grid': patch -'@object-ui/plugin-gantt': patch -'@object-ui/plugin-charts': patch -'@object-ui/plugin-view': patch -'@object-ui/app-shell': patch ---- - -Gantt, chart and grid views refresh in place after a write instead of being rebuilt (objectui#10035). - -`ObjectGrid`, `ObjectGantt` and `ObjectChart` query for themselves and read no refresh input, so both object-view layers could show them a write only by remounting them — which lost a gantt's scroll, collapsed groups and zoom, a chart's open drill-down, and a grid's selection, column state and in-progress edit. Each now refetches when the data-invalidation bus (`notifyDataChanged` / `useDataInvalidation` from `@object-ui/react`) reports a change to the object it reads: - -- `@object-ui/plugin-grid`: `ObjectGrid` re-reads its rows into the same table. -- `@object-ui/plugin-gantt`: `ObjectGantt` re-reads silently and keeps the chart mounted, as its toolbar refresh does. -- `@object-ui/plugin-charts`: `ObjectChart` re-runs its query on both binding shapes — an object-bound aggregate follows its `objectName`, a dataset-bound chart follows the dataset's base object as the `queryDataset` answer names it. -- `@object-ui/plugin-view`: the object view keys every view on its identity alone, and declares on the bus its own saves and deletes and each `onMutation` write it hears. -- `@object-ui/app-shell`: the object page keys its list and its chart view on identity alone, and declares on the bus the changes it learns of without a data-source write — server actions, flows, imports, realtime events and an explicit refresh. - -Rows a host hands these components (`data`, `bind`, inline values) are still the host's to refresh; only the components' own queries follow the bus. diff --git a/.changeset/10036-gantt-reload-identity-dep.md b/.changeset/10036-gantt-reload-identity-dep.md deleted file mode 100644 index 596245c70d..0000000000 --- a/.changeset/10036-gantt-reload-identity-dep.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/plugin-gantt': patch ---- - -`ObjectGantt` no longer re-issues its record query because React threw a memo cache -away (objectui#10036). - -The fetch seam carried two dependencies that AGENTS.md §5 commandment #10 bans — the -ninth and tenth instances of the class ruled on objectui#8640. `reload`'s dependency -list named `effectiveDataSource`, a `useMemo` result, and the mount effect named -`reload`, a `useCallback` result. Both hooks are documented performance hints: React -may discard the cache and recompute even when the dependency list compares equal, and -the object that comes back is then a new one. - -That is not harmless here. `resolveDataSource` returns the context adapter UNCHANGED -for `provider: 'object'`, but CONSTRUCTS a fresh `ApiDataSource` / `ValueDataSource` -for `provider: 'api'` and `provider: 'value'` — so on those two providers a discard -alone handed `reload` a brand-new adapter for a byte-identical authored config, rebuilt -`reload`, and re-fired the mount effect: one redundant round trip per discard, on a -view nobody had touched. A discarded `useCallback` moves `reload`'s identity whatever -its own dependency list says, so the second half had to move with the first. - -The record fetch now READS the adapter through a ref and KEYS on the values that -determine it: the authored config slice `resolveDataSource` actually reads, per -provider arm, plus the host's `dataSource` and `apiFetch`. Every authored or host -change that used to refetch still refetches — a changed `api` endpoint, changed -`read`/`write` config, changed inline `items`, a swapped adapter, a swapped -authenticated fetch, a changed object, filter or sort. What no longer refetches is a -discard, and an inert key inside `data` that the resolved adapter never reads. - -The file already recorded half of this in the first person: `dataItems` came off that -same dependency list because a discard «was enough to give `reload` a fresh identity -and re-fire the mount effect below (objectui#6592)». One banned identity came off the -line then; the other stayed on it until now. diff --git a/.changeset/10037-gantt-toolbar-filter-reaches-chart.md b/.changeset/10037-gantt-toolbar-filter-reaches-chart.md deleted file mode 100644 index 273a217eb3..0000000000 --- a/.changeset/10037-gantt-toolbar-filter-reaches-chart.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -On a `gantt` list view, the toolbar's Filter control and the `UserFilters` chips now -narrow the chart (objectui#10037). - -Both controls were offered on a gantt view and changed nothing the user could see. -`ListView`'s own fetch applies the authored filter, the toolbar's filter group and the -chips together, but the gantt chart does not draw those rows: it queries for itself — -its registered renderer takes only the node's `schema` — and the node it was handed -carried the authored `filter` alone. - -The gantt node now carries the same effective filter `ListView`'s own fetch sends, so the -chart's query honours both controls. The value keeps its identity while its content is -unchanged, so re-rendering the list does not re-query the chart. The row ceiling from -objectui#7210 is untouched. diff --git a/.changeset/10039-publish-drafts-advisories.md b/.changeset/10039-publish-drafts-advisories.md deleted file mode 100644 index 5b41fdbcf2..0000000000 --- a/.changeset/10039-publish-drafts-advisories.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -The AI build bar, the Studio workbench and the chat transcript's draft cards report the runtime authoring gate's per-draft advisories (objectui#10039) - -`POST /packages/:id/publish-drafts` has answered `advisories` on each -`published[]` element since objectstack#9343 landed, and `ce986aafc` built the -seam that reports them — `MetadataClient.publishPackageDrafts`, which emits one -advisory event per advised element into the sink, renderer and wording the save -and single-item publish doors use. Three app-shell call sites were still firing -that route with a bare `fetch`, so on those surfaces the findings were parsed by -nobody: `console/ai/PendingDraftsBar`, `views/studio-design/StudioDesignSurface` -and the chat draft card's publish handler in `console/ai/AiChatPage`. Each of the -three now takes its client from `useMetadataClient` and calls that method, which -is the whole change — the advisory toast is the client's, so all three surfaces -report identically to the two `ce986aafc` routed, with no new UI shape. - -What moves with the route, at all three: - -- A non-2xx raises `MetadataError` inside the client instead of being read off - `res.ok`. The message is still the server's own, and the ADR-0112 - producer-marked `error.userMessage` now outranks the diagnostic `error.message` - where the refusal carries one — the rule `36fc74629` landed on `PackagesPage`, - reaching these surfaces by the same seam rather than by a fourth copy. - `StudioDesignSurface` keeps its field-anchored issue rendering: the client - already carries `error.details.issues` on `MetadataError.issues`, which is what - its `formatMetadataError` reads. -- `failed[]` / `failedCount` / `seedApplied` are read through ONE spelling. The - client unwraps the dispatcher's `{ success, data }` for this route — the one - route whose spec declaration says the body arrives inside one — so the two - server compositions are reconciled before a caller sees them, where the bare - `fetch` sites each carried their own `payload?.data?.x ?? payload?.x` ladder. -- The 2xx batch verdict stays each surface's own, unchanged: `success: false` is - not a refusal on this route, and the three surfaces disagree on purpose about - what a partial or rolled-back batch should say. diff --git a/.changeset/10040-app-shell-favicon-restore.md b/.changeset/10040-app-shell-favicon-restore.md deleted file mode 100644 index 81b3a9dca9..0000000000 --- a/.changeset/10040-app-shell-favicon-restore.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/layout': patch ---- - -`useAppShellBranding` now puts the previous favicon back when the shell unmounts -(objectui#10040), the same way it already puts the previous tab title back -(objectui#8637). - -The hook's effect makes two branded writes to the document: `document.title` and the -`href` of the page's icon link. The title write was scoped to the mount; the favicon -write was not, so a branded `favicon` stayed on the icon link after the shell went -away unless something else happened to re-apply an icon. In the console that something was -`FaviconSync`, which wrote the icon only when an operator favicon was configured (until -objectui#10379 removed that write) — so on a deployment without one, the icon link kept -a branded app's URL after the user left the app. - -When `branding.favicon` is set and the page has an icon link (`#favicon`, otherwise -`link[rel="icon"]`), the hook now records that link and its `href` attribute before -writing the branded URL, and restores the recorded attribute in the same cleanup that -restores the title — so switching from one branded app to another and then leaving -puts back the icon from before the first one. The attribute is captured rather than -the `href` property, because the property resolves an empty `href=""` (the console's -icon link before an operator favicon exists) to the page's own URL; an icon link that -had no `href` attribute is left without one. A shell with no `favicon`, or a page with -no icon link, is untouched in both directions, and the hook still never creates an -icon link. - -As with the title, the restore replays the captured value unconditionally: an icon -written by something else while the shell is mounted is overwritten when it unmounts. diff --git a/.changeset/10042-one-root-resolver.md b/.changeset/10042-one-root-resolver.md deleted file mode 100644 index de8cc264e9..0000000000 --- a/.changeset/10042-one-root-resolver.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -**Breaking — the published `RootRedirect` is removed; `/` now has exactly one resolver.** - -`/` had two answers in this repo, and the published one was the poorer. This -package exported `RootRedirect`, which sent `/` to `/home` as soon as metadata -finished loading — ignoring the app a product declares with `isDefault`, the -same declaration every Home affordance in the console chrome follows -(objectui#7256). The console that actually ships never mounted it: it mounts an -element that resolves the landing from the app metadata, where the `isDefault` -app wins, a single visible app that is not the platform Setup console is -entered directly (objectui#4048), and an app list that never loaded refuses to -conclude anything at all (objectui#4233). A consumer assembling a console from -these building blocks got the unguarded answer, and nothing said so. - -The two become one by removing the published twin rather than by moving the -guarded one. The console's own `/` behaviour is unchanged by this release. - -**What this means for a consumer.** If your route table mounts `RootRedirect` -at `path="/"`, the import no longer resolves and the build fails — this is a -compile error, never a silent change of where your users land. Route `/` in -your own route table instead; `examples/console-starter` shows the smallest -form of it, landing on `/home` inside the same `AuthenticatedRoute` guard it -used before. Every other console building block — `ConsoleShell`, -`ConnectedShell`, `AuthenticatedRoute`, `RequireOrganization`, `SystemRedirect`, -`SetupRedirect` — is untouched. - -Marked `minor`, not `major`: this repo's fixed release group is pinned to the -`@objectstack` major (AGENTS.md, 版本号策略), so a breaking change is declared in -the narrative rather than in the bump. diff --git a/.changeset/10043-studio-landing-tooltip-i18n.md b/.changeset/10043-studio-landing-tooltip-i18n.md deleted file mode 100644 index 2751cb4d13..0000000000 --- a/.changeset/10043-studio-landing-tooltip-i18n.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/console': patch -'@object-ui/i18n': patch ---- - -Localize the Studio front door's wordmark tooltip (objectui#10043). - -The `/studio` landing's wordmark carried its `title` tooltip as a hard-coded literal -in one language, outside i18n entirely — the only user-visible string on that surface -that never reached a translation bundle, so every other locale read it in that one -language. AGENTS.md commandment #-1 names titles in the categories it covers. - -It now resolves through `useObjectTranslation` and a new `console.studio.backToHome` -key, which is the mechanism the rest of this app's chrome already uses (the same route -objectui#4024 took for the settings screen, whose chrome was hard-coded beside a keyed -sibling). The key ships in all ten locale packs, and each pack's value is that pack's -own existing wording for this affordance rather than a new translation — the sibling -Home button one route away inside the same frame says the same thing, and the two must -not name the same home two different ways. diff --git a/.changeset/10044-record-search-display-name-dep.md b/.changeset/10044-record-search-display-name-dep.md deleted file mode 100644 index 777c19f616..0000000000 --- a/.changeset/10044-record-search-display-name-dep.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/react': patch ---- - -`useRecordSearch` no longer keys its search effect on the identity of the -caller-supplied `getDisplayName` option (objectui#10044). - -The resolver is read only inside a run, to label hits; it never decides whether a -run happens. It was nevertheless the last entry of the search effect's dependency -list, and that effect's cleanup clears the pending debounce timer. A caller passing -the obvious spelling for an optional callback, an inline arrow, handed the hook a new -function on every render, with two opposite results: a parent re-rendering faster -than `debounceMs` (250 ms by default) never searched at all, and a parent re-rendering -sparsely issued a second, identical request after the first had gone out. This is -the dependency AGENTS.md §5 commandment #10 bans. - -Each run now reads the resolver of the latest render through a ref, so an inline -resolver is safe. A swapped resolver labels the hits of the next run; results already -shown keep their labels. The option's name, type and default are unchanged. diff --git a/.changeset/10046-object-page-options-identity.md b/.changeset/10046-object-page-options-identity.md deleted file mode 100644 index 3ca800f8b6..0000000000 --- a/.changeset/10046-object-page-options-identity.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@object-ui/app-shell": patch ---- - -fix(app-shell): the object page no longer re-issues the identical list query on re-renders that change nothing - -The object page rebuilt the `options` bag it hands `ListView` as a fresh object -on every render, and `ListView` names `schema.options` by identity in its fetch -effect's dependencies. So every re-render of the page re-ran that effect into a -byte-identical `dataSource.find`: one extra round trip when the page mounted -(the record count landing re-renders it), two when a record was opened and two -more when it was closed. - -The page now keeps the previous `options` object while its content is -unchanged, compared by value. Any real change to the bag still hands over a new -object and still refetches, and a view switch still issues exactly one query. diff --git a/.changeset/10058-quick-actions-capability-gate.md b/.changeset/10058-quick-actions-capability-gate.md deleted file mode 100644 index 7835d50aa3..0000000000 --- a/.changeset/10058-quick-actions-capability-gate.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -fix(plugin-detail): `record:quick_actions.requiredPermissions` is an ADR-0066 capability set, read fail-closed — it used to pass for every reader of the object - -The block-level gate is published as "Hide the whole bar unless the current -user holds every named permission on this object". It evaluated each name -through the permission context's OBJECT-ACTION path, whose second argument is -the closed object-action enum — not the ADR-0066 system capability set the same -word names on `action`, `app`, `field` and `bulkAction`. - -Under the stock `/me/permissions` provider that path maps eight verbs (`read`, -`view`, `create`, `update`, `edit`, `delete`, `import`, `export`) and sends -everything else to the object's `allowRead` bit. Measured on that provider with -a REPORTED-empty capability set and `allowRead: true`: `crm.manage` and -`manage_users` both answered `true` — **a declared permission gate that passed -for every reader of the object, with no refusal, no warning and no log**. The -same fallback swallowed five members of the enum itself (`manage`, `admin`, -`share`, `configure`, `execute`), none of which is in that map either. Under -the role-based `PermissionProvider` the identical declaration was instead -refused for everyone when the object carried a permission config and allowed -for everyone when it did not — one declaration, two providers, neither -consulting the caller's capabilities. - -The bar now reads the capability path (`hasCapabilities` over the reported -`systemPermissions`) and gates **fail-closed**: an unheld or unrecognised -capability hides the whole bar. The object name is no longer part of the -verdict — a system capability is not object-scoped, and the old -`objectName`-present guard was a second silent fail-open that skipped the -declared gate entirely on a bar rendered outside a record context. - -**Behaviour change, in both directions.** A deployment whose backend reports -`systemPermissions` now hides a bar whose declared capabilities the user does -not hold — which is what the key always said it did — and shows one whose -capabilities the user holds even where the object's read bit is off. A provider -that never REPORTS capabilities (`systemPermissions` absent: the role-based -provider, a backend predating ADR-0066, or no provider mounted) still opens the -gate; that is `hasCapabilities`'s own unreported-vs-empty doctrine, shared with -every other capability gate in the tree, and this change does not move it. A -REPORTED empty array is a real answer and gates strictly. - -`perms.can()` itself is untouched: no other caller moves, and the full -before/after truth table of both stock providers is pinned as unchanged. - -**Correction, 2026-10-01 (objectui#10224).** The phrase "hides the whole bar" -above is wrong about what the reader sees. When a declared capability is unheld or -unrecognised, no action is drawn and an insufficient-permissions notice -(`role="status"`) renders where the bar would be. That is what the contract's -shared record-block `requiredPermissions` describe says: "this block does not -render its content; wherever it would otherwise render, an -insufficient-permissions notice takes its place". The `record:quick_actions` -registration now publishes that describe verbatim, in place of "Hide the whole -bar unless the user holds these permissions", and the contract wording quoted -in the first paragraph is retired upstream (objectstack#18159). Everything -else above stands: the capabilities the gate asks for, its fail-closed -verdict, and the fail-open when capabilities are unreported. diff --git a/.changeset/10059-user-locale-single-source.md b/.changeset/10059-user-locale-single-source.md deleted file mode 100644 index 7328a8507f..0000000000 --- a/.changeset/10059-user-locale-single-source.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -'@object-ui/app-shell': minor -'@object-ui/i18n': patch ---- - -A signed-in user's language has one source of truth: `sys_user.locale`. - -One word 「语言」 named two settings. The profile page's language card wrote the -server column `sys_user.locale`; the console's globe menu switched a -device-local UI language in `localStorage`. Neither writer could see the other, -so a user who chose 日本語 on their profile went on reading an English console, -with no refusal and no notice — and the profile card's own description said the -two were separate, which was true and is what this change ends. - -For a signed-in user the column now decides, and the wiring is what makes that -hold rather than anyone's discipline: - -- the globe writes `sys_user.locale` through the same adapter the profile card - already used, so there is one writer path rather than two settings; -- `@object-ui/app-shell` reads the column back once per shell, on mount and on - every `sys_user` mutation the invalidation bus reports — which includes the - profile card's save, so changing the language in either place changes it in - both, in the same session and with no reload; -- the device-local value is kept and demoted to a CACHE: it still decides before - sign-in and for the first paint of a boot (the column cannot be read - synchronously), and it is overwritten by the column as soon as the row is - read. A stale device value can no longer outlive one round trip. - -A failed write is reported to the user and the local switch stands until the -next successful read, which then takes the UI back to what the column says — -never a silent no-op. A signed-out visitor is unaffected: with no `sys_user` -row nothing is read and nothing is written, and the globe is the device-local -switch it has always been. - -`@object-ui/i18n` is prose only here. Its precedence chain still adjudicates -what it can see (device choice → tenant seed → browser → `en`), and its -docblocks now say that a signed-in user's language is not one of those tiers: -reading a `sys_user` row needs an authenticated data adapter, which a renderer -package does not take as a dependency, so the host applies the column through -the ordinary `changeLanguage`. diff --git a/.changeset/10061-filter-builder-incomplete-range.md b/.changeset/10061-filter-builder-incomplete-range.md deleted file mode 100644 index bdbf9fa38b..0000000000 --- a/.changeset/10061-filter-builder-incomplete-range.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/components': patch ---- - -fix(components): a half-typed `between` range in the filter builder shows itself as -incomplete instead of being dropped with no signal (objectui#10061) - -Ruling batch #146 item 5 letter A (objectstack `176b03582`) declares that while one bound of a -`between` pair is blank the condition is incomplete — **not emitted, and shown as -incomplete in the UI**. The first half has been true since objectui#5025: every write -path folds the row through the builder's own arity-aware `isFilterValueComplete`, so a -range with one blank bound never reaches a live query or a stored view. The second half -was unbuilt. An author who typed one bound saw their value sitting on screen while the -row silently counted for nothing — the range was gone from the query and nothing said so. - -The blank bound of a half-filled pair now carries `aria-invalid` and an -`aria-describedby` description naming the side that is missing ("To is required"), plus a -destructive border so the state is visible and not only announced. The description reuses -the shared `validation.required` key rather than declaring a new one, so it is already -translated in every pack. - -⛔ This is a diagnostic, never a refusal. The completeness rule is unchanged, nothing -gates on the marker, and the other rows of the group keep applying — an incomplete row is -a UI state, not an error that blocks the filter. - -What does NOT carry the marker: a complete pair; a row whose bounds are both blank, which -is the untouched shape `Add filter` draws and is no more half-written than an `equals` row -with no value yet; and any non-pair operator. - -⚠️ A blank bound is not a zero bound. `0` is a legitimate lower bound on a number column -and `''` is an unfilled one, so `[0, '']` is marked on its upper bound and `[0, 10]` is -complete and marked nowhere. Reading the bounds for truthiness instead would mark the `0` -the author had just typed and leave the blank side clean — the pins for that distinction -sit beside the ones for the marker itself. diff --git a/.changeset/10062-dataset-filter-between-arm.md b/.changeset/10062-dataset-filter-between-arm.md deleted file mode 100644 index 1f831d4a11..0000000000 --- a/.changeset/10062-dataset-filter-between-arm.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the Studio dataset-filter inspector stores a `between` range as the -spec's `$between`, with both bounds required (objectui#10062) - -Executes ruling batch #146 item 5 letter A (objectstack `176b03582`): the `between` arm of the -dataset-filter bridge maps once a both-bounds completeness rule exists, and one does. Until -now a `Between` row in a dataset's or a measure's filter was dropped on every commit — -inertly since objectui#9372, but dropped — so a date range could be drawn in the inspector -and never saved. - -- **Both bounds typed** ⇒ stored as `{ field: { $between: [lo, hi] } }`, the spec's own - token and shape. It reopens as `Between` with both bounds on screen and writes back - unchanged. -- **A bound missing** ⇒ not emitted. Whether the row is finished is the builder's own - `isFilterValueComplete` (objectui#5025), not a local check: `0` is a real bound, `''` is - not. As the only row it commits nothing and the stored filter stays; beside other rows, - only those rows are stored. -- **A stored `$between` this bridge would not have written is not opened as an editable - row.** It still goes to the Source tab, as it did while `$between` was unmapped. That is - exactly two cases: - - it is not a complete pair: a blank or missing bound, a scalar, or a list of the wrong - length. As a row, it would be dropped by the next edit to any other row; - - its column's filter menu does not offer `Between`. Only `date`, `datetime` and `time` - columns offer it. Every other type is refused, and so is a column listed without a type - or not listed at all, because the menu draws the text operators for both. As a row, the - operator would show blank, and touching the row's field picker would store `$eq` - instead of the range. - -The completeness check for every other operator now calls the same function; for scalar -and list operators its answer is the one the removed inline check gave. - -Forward note for anyone pinning stored filters: a dataset filter written by this version -may carry `$between`, which an older app-shell reads as non-representable and sends to the -Source tab. diff --git a/.changeset/10064-object-tree-public-tier.md b/.changeset/10064-object-tree-public-tier.md deleted file mode 100644 index 02b4b005c4..0000000000 --- a/.changeset/10064-object-tree-public-tier.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -'@object-ui/core': minor ---- - -feat(core): `object-tree` joins the curated public tier — the spec declared the block, the roster withheld it - -`@objectstack/spec` declares `object-tree` on `ComponentPropsMap`, and -`@object-ui/plugin-tree` has registered the renderer all along. The curated -`PUBLIC_BLOCKS` roster — the one face that decides the ADR-0080 public tier — -carried no tree name, so `getPublicConfigs()` reported the block as outside the -contract. The tier was NARROWER than the declaration. - -That absence reached everything downstream, and nothing downstream could repair -it. `getPublicConfigs()` is the read both manifest producers serialize through -`manifestFromConfigs` (`apps/console/dev/manifest-dump.tsx`, and the framework's -node generator for its tracked `sdui.manifest.json`), so the published manifest -and the generated JSX intrinsics could not carry a block the contract says -exists — regenerating them was a no-op, and moving the objectui pin could not -help while the pinned source had nothing to carry. - -**What moves for a user.** `object-tree` is now part of the AI-authoring -vocabulary and of the generated manifest and intrinsics, and it joins the -`kind:'react'` page scope as `ObjectTree` (that scope is built from the same -public configs, minus declared containers; this block declares no containment). -The renderer, its props and every existing schema are untouched: nothing that -rendered before renders differently, and no key changes meaning. - -**What deliberately does not move.** The same module registers this renderer a -second time under the bare `tree` alias, and that spelling stays out: the spec -declares no such key, so curating it would widen the vocabulary past the -declaration rather than pull the tier back to it, and two names for one block is -ambiguity an authoring model cannot resolve — the ground `record:chatter` is -held out on. - -The admission is a roster entry, not a `tier: 'public'` flag on the -registration. Both routes reach `getPublicConfigs()`; the siblings -(`object-grid`, `object-map`, `object-gantt`, …) all take the roster, no -published registration in this repo declares the flag, and the roster's own -header asks callers to prefer the list over scattered flags. - -⚠️ **Dated note, 2026-10-02 — the `tree` alias is no longer registered at all — objectui#10859.** -Later in this same release objectui#10859 batch 8 unregistered the bare `tree` alias outright -(`objectui validate` refused it at `type`, and nothing authored it), so the "second time" the -paragraph above describes is gone too. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10066-slider-step.md b/.changeset/10066-slider-step.md deleted file mode 100644 index f07759b67c..0000000000 --- a/.changeset/10066-slider-step.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/types': patch -'@object-ui/fields': patch ---- - -feat(types): `SliderFieldMetadata` declares `step` - -`@objectstack/spec`'s `FieldSchema` declares `step` ("Step increment for slider -(default: 1)") and `SliderField` has always read it, defaulting to `1`, but the -published `SliderFieldMetadata` did not declare it, so an author annotating a -slider field with the type could not write the key the widget honours. The -member is now declared, matching the spec's prose. - -`SliderField` now reads `min`, `max` and `step` through the keys -`SliderFieldMetadata` declares instead of an untyped `field as any` carrier. No -runtime behaviour changes. diff --git a/.changeset/10068-kanban-datasource-sort.md b/.changeset/10068-kanban-datasource-sort.md deleted file mode 100644 index 63fddbd303..0000000000 --- a/.changeset/10068-kanban-datasource-sort.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/plugin-kanban': patch -'@object-ui/types': patch ---- - -fix(plugin-kanban): `object-kanban` honours the binding's `dataSource.sort` - -The per-element binding declares `{ object, view, filter, sort, limit }` for every -block, and `object-kanban` accepted `dataSource.sort` (or a named view's `sort`) -and then dropped it: the board's fetch carried no `$orderby`, with no error and no -warning. `OBJECT_KANBAN_DATA_SOURCE` now maps `sort`, and the fetch lowers it onto -`$orderby` through `convertSortToQueryParams`, the same way the calendar, map, -gantt and timeline blocks do. Lanes bucket records in fetch order, so the declared -order is also the order of the cards inside each lane. With no declared `sort` the -query is unchanged. - -`@object-ui/types`: doc comments only. The `ObjectKanbanSchema` notes that said the -board has no `schema.sort` read site now say that the board reads it only as the -gate's carrier for `dataSource.sort`. No top-level `sort` key is declared on -`object-kanban`, because the spec declares none. diff --git a/.changeset/10069-kanban-lanes-match-by-id-only.md b/.changeset/10069-kanban-lanes-match-by-id-only.md deleted file mode 100644 index fc2786bac4..0000000000 --- a/.changeset/10069-kanban-lanes-match-by-id-only.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/plugin-kanban': minor ---- - -fix(plugin-kanban): a kanban lane matches records by its `id` only, never by its `title` - -⚠️ Behaviour change (narrowing), declared `minor` under this repo's fixed-group -versioning. Executes maintainer ruling A on objectui#10069. - -A kanban board decides which lane a record belongs to by comparing the record's -stored `groupBy` value with each lane's `id` — the picklist option value. Until -now `bucketCardsIntoColumns` also lowercased every lane `title` into that lookup, -so the title was a second, undeclared bucketing key. That had three -user-visible effects, and all three are gone: - -- renaming a lane in authored `columns` moved records between lanes; -- relabelling a picklist option moved records too, because lanes derived from - the `groupBy` field's options take `title: opt.label`; -- membership depended on the viewer's locale, because lane titles are - translated: a record storing the English label bucketed into its lane in one - locale and into "Uncategorized" in another. - -The lane `title` is now presentation only. The id comparison keeps its existing -case folding (`IN_PROGRESS` still matches a lane `in_progress`). - -A record whose value matches no lane id still surfaces in the trailing -"Uncategorized" lane (#2792), and the board now also names it on the console: -one `console.warn` per distinct raw value per bucketing pass, giving the -`groupBy` field, the raw value, the number of records carrying it and the -available lane ids. An empty group value is not warned about. - -**Migration.** Records whose group field stores an option's LABEL (for example -`'In Progress'`) instead of its VALUE (`'in_progress'`) used to reach their lane -through the retired title match; they now appear under "Uncategorized", and the -console warning names each such value. Fix the data, not the board: update each -record to store the option value. A drag from "Uncategorized" into the right lane -writes the lane id and so repairs one record at a time; for a bulk repair, find -the affected records with a filter that selects values outside the field's -option values, e.g. `['and', ['status', 'nin', ['in_progress', 'done']], -['status', '!=', null], ['status', '!=', '']]`, and update each to the value -whose option label it stores. ⛔ Do not add the label as a lane `id` to make the -records reappear: that re-teaches the label as a second value for the same state. diff --git a/.changeset/10071-number-scale-ceiling.md b/.changeset/10071-number-scale-ceiling.md deleted file mode 100644 index 15ce082308..0000000000 --- a/.changeset/10071-number-scale-ceiling.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): a declared `scale` above 100 no longer crashes the number cell or a grid's computed column (#10071) - -`@objectstack/spec` 17.4.0 accepts a field `scale` above 100, but both -`Intl.NumberFormat` and `Number.prototype.toFixed` refuse more than 100 fraction -digits. `NumberCellRenderer` passed the declared `scale` straight into `Intl`, -so the cell threw `RangeError` at render; `computeRow` rounded a computed grid -column with `toFixed(scale)`, so editing a master-detail line threw out of the -edit. Both now take the ruling the percent faces already took (objectui#9808): -the width is clamped to 100 and a one-time `console.warn` names the declared -width, the rendered width and the card. In-range, negative and non-integer -widths are unchanged. - -⚠️ **Dated note, 2026-09-29 — the clamp above was retired in this same release — objectui#11073.** -Later in this release this repository began resolving `@objectstack/spec` 17.5.0, which refuses a field `scale` above 100 at the declaration (`too_big` at `scale`, a computed number field included). The objectui#9808 ruling this change followed retires at exactly that point, so the clamp and its one-time warning are gone from `NumberCellRenderer` and from a grid's computed column: the declared width is passed through again, and a width above 100 is no longer something an author can declare. diff --git a/.changeset/10073-customfields-merge.md b/.changeset/10073-customfields-merge.md deleted file mode 100644 index 3c4899fd2e..0000000000 --- a/.changeset/10073-customfields-merge.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): `customFields` merges on the drawer and modal arms too - -The registered description of `object-form.customFields` is one sentence for -every `formType`: "Field definitions merged over the set generated from object -metadata." The default arm has merged since objectui#9778, but an `object-form` -with `formType: 'drawer'` or `'modal'` (and a `DrawerForm` / `ModalForm` mounted -directly) still REPLACED the generated fields with the members, so the same key -meant two different things depending on the arm. - -All three arms now resolve the members through one rule: a member naming a -declared field is that field's whole definition, in its position; a declared -field no member names still renders; a member naming nothing declared is -appended after the generated set, in authored order. With no data source the -members remain the only field source. - -`customFields` also no longer switches off the object's `fieldGroups` fallback -or the modal's auto-layout (and so its auto-sized width), matching the default -arm: the groups are derived over the merged field set. - -⚠️ Behaviour change for authors who relied on the drawer or modal replacing the -generated set: the object's other fields now appear alongside the members. To -narrow the generated set, list the fields to draw in the `fields` whitelist, as -on the default arm; the members are drawn either way. diff --git a/.changeset/10074-doc-changeset-text.md b/.changeset/10074-doc-changeset-text.md deleted file mode 100644 index 1342fe4e3e..0000000000 --- a/.changeset/10074-doc-changeset-text.md +++ /dev/null @@ -1,8 +0,0 @@ ---- ---- - -Correct two stale text sites: the `ObjectDataTable.onRowClick` docblock paraphrase in -`packages/types/src/data-display.ts` (it dropped the `recordDrillEnabled` gate), and the -"not in this change" sentence in `.changeset/9462-row-click-modifier-payload-forward.md` -(`ObjectDataTableSchema.onRowClick` was widened separately, by objectui#9799, not left at -one parameter). No published behaviour changes. diff --git a/.changeset/10078-record-id-string-survivors.md b/.changeset/10078-record-id-string-survivors.md deleted file mode 100644 index 316d0812af..0000000000 --- a/.changeset/10078-record-id-string-survivors.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/core': minor -'@object-ui/data-objectstack': minor ---- - -**BREAKING** — three more record ids that the objectui#9511 ruling's enumeration left out are -strings now (objectui#10078). `CommentSearchResult.recordId`, `RecordSubscription.recordId` -and `DataSourceMutationEvent.id` narrow **FROM** `string | number` **TO** `string`. ⚠️ Other -record ids in `@object-ui/types` still admit a number and are not touched here, among them -`DetailViewSchema.recordNavigation` (`recordIds`, `onNavigate`), `FeedItem.sourceId`, and the -`onNavigate` slots on `ObjectGridSchema`, `ObjectViewSchema` and `ListViewRuntimeProps`. - -```ts -// before — compiled -const bell: RecordSubscription = { recordId: 42, subscribed: true }; -// after — refused by the compiler; write the id the protocol carries -const bell: RecordSubscription = { recordId: '42', subscribed: true }; -``` - -**Why.** objectui#9511 (director batch #195 item 1, letter A) ruled that a record id is a -string wherever **metadata** names one, and extended that, as 「the same principle」, to -`CommentEntry.recordId` and `MentionNotification.recordId`. It did not name these three, which -are runtime and API shapes rather than metadata. Carrying the rule to them is the `domain:spec` -seat's inheritance decision, recorded in the claim on objectui#10078: they hold the same id and -were left with the old spelling. `CommentSearchResult.recordId` is copied straight from -`CommentEntry.recordId`, `RecordSubscription.recordId` names the record a notification bell is -for, and `DataSourceMutationEvent.id` is the id the `update` / `delete` doors already take as a -string. - -**What changes at runtime.** `ValueDataSource` and `ObjectStackAdapter` now emit -`onMutation` events whose `id` is always a string. Both methods still accept a numeric id -through their own wider parameter, and each converts it at its own boundary before emitting — -the one place the rule says the conversion lives. An in-memory `value` source whose items -carry numeric keys therefore announces `'42'`, not `42`. A subscriber that compared -`event.id` against a number must compare against the string. The two in-repo subscribers -that read `event.id` already pass it through `String(...)`, so they see no difference. - -**Packages that narrow without a source change.** `@object-ui/collaboration` (`useCommentSearch` -returns `CommentSearchResult[]`) and `@object-ui/plugin-detail` (`SubscriptionToggleProps` -carries a `RecordSubscription`) publish the narrower type through their own `.d.ts`. - -**What a host has to do.** Code that builds a `RecordSubscription`, reads -`CommentSearchResult.recordId`, or implements `DataSource.onMutation` with numeric keys -converts once, where the number enters (its own adapter or data boundary), and passes the -string from there on. ⛔ Nothing converts silently on the reading side. - -**Disposition: ADR-0087 D7 — a published runtime TypeScript interface with no metadata -surface is carried by the compiler and needs no ledger entry; ⛔ no conversion entry, ⛔ not -a tombstone, ⛔ not an npm `major`.** None of the three has a zod mirror, none is authored into JSON, and no schema -references them, so there is no parse-time door and nothing for a conversion table to -rewrite: the compiler error at the numeric site is the delivery channel. The level is `minor` -because objectui marks its own breaking changes `minor` with this banner (AGENTS.md, version -alignment); `major` is refused outright because every publishable package sits in one `fixed` -group pinned to the `@objectstack` major (`scripts/check-changeset-no-major.mjs`). - -**Pin.** `record-id-string-survivors-10078.test.ts` in `@object-ui/types` asserts all three -members read `string` (not `any`), refuses a numeric literal at each, and keeps a -source-text census of the three declarations with controls that prove the census can fire. diff --git a/.changeset/10080-modedefault-fixture-stored-body.md b/.changeset/10080-modedefault-fixture-stored-body.md deleted file mode 100644 index 4115845c14..0000000000 --- a/.changeset/10080-modedefault-fixture-stored-body.md +++ /dev/null @@ -1,10 +0,0 @@ ---- ---- - -Split the `useNavigationOverlay.modeDefault` fixture that was carrying two pins in -one declaration (objectui#10080): the objectui#4550 TYPE pin keeps the -`SpecAuthoredInput` annotation and now authors a key -the spec still declares, while the objectui#9874 BEHAVIOUR pin's legacy body — the -`view` member `@objectstack/spec` 17.5.0 retired under ADR-0049 — is fed as the -stored `Record` it is. Test only; no package is released by this -change, and no assertion changed. diff --git a/.changeset/10083-rowactions-narrow.md b/.changeset/10083-rowactions-narrow.md deleted file mode 100644 index f1412a5493..0000000000 --- a/.changeset/10083-rowactions-narrow.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/plugin-grid': minor ---- - -`object-grid`'s `rowActions` now NARROWS the row kebab's generic Edit / Delete inside the `operations` ceiling — the second half of the ruling whose first half ("`operations` is the ceiling") shipped with objectui#9819. - -The gate in `resolveRowCrudAffordances` is now `operations. AND (rowActions names it OR rowActions is absent) AND the callback is wired AND the object allows it`. `ObjectGrid` passes a new `rowActionsDeclared` signal (whether the view declared a `rowActions` array at all), because "`rowActions` absent" and "`rowActions` declared without this name" used to arrive at the gate as the same `false`. - -BEHAVIOUR CHANGE, and the direction is NARROWING: - -- A view that declares a `rowActions` list without `'edit'` (or `'delete'`) rendered the generic Edit (or Delete) entry before and hides it now — whether or not the view declares an `operations` block. This includes a list that names only custom actions (`rowActions: ['approve']` keeps its Approve entry and loses the generic pair) and an empty list (`rowActions: []`). To keep a generic entry, name it: `rowActions: ['approve', 'edit', 'delete']`. -- As with objectui#9819, a page that wrote `operations.: false` together with a `rowActions` entry for it hides that button. -- Views that declare no `rowActions` at all are unaffected: the generic entries keep their default, still bounded by `operations` and the wired `onEdit` / `onDelete`. - -Maintainer ruling of 2026-09-18, ruling batch #162 item 1, letter A, on objectui#9819; landed by objectui#10083. diff --git a/.changeset/10084-grid-ceiling-describe.md b/.changeset/10084-grid-ceiling-describe.md deleted file mode 100644 index b71588b2af..0000000000 --- a/.changeset/10084-grid-ceiling-describe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/types': patch ---- - -`object-grid`'s `rowActions` now carries a describe, and the `ObjectGridSchema.operations` / `rowActions` docblocks state how the two keys combine: `operations` is the CEILING over `rowActions` (`operations.update: false` / `delete: false`, or a member a declared block does not name, withholds that generic row entry whatever `rowActions` says), a declared `rowActions` list offers the generic Edit / Delete only for the canonical `edit` / `delete` names it carries, and an absent `rowActions` keeps the default. Text only: no member is added and no behaviour changes — it describes what objectui#9819 and objectui#10083 landed. diff --git a/.changeset/10088-json-fences-parse.md b/.changeset/10088-json-fences-parse.md deleted file mode 100644 index a9380625b6..0000000000 --- a/.changeset/10088-json-fences-parse.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Docs and test-only change; no published behaviour changes. Every `json` fence under `content/docs` now survives `JSON.parse`, and a fence that annotates JSON with comments is tagged `jsonc`. The one source file touched is a test in `@object-ui/types`: `page-actions-refusal-7926.test.ts` pinned four unparseable `json` fences in `guide/layout.md` as its blind spot, and that count is zero now. diff --git a/.changeset/10096-record-activity-row-cap-non-integer.md b/.changeset/10096-record-activity-row-cap-non-integer.md deleted file mode 100644 index 1c87eda4d6..0000000000 --- a/.changeset/10096-record-activity-row-cap-non-integer.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -`record:activity` refuses a NON-INTEGER row cap instead of flooring it -(objectui#10096). - -`@objectstack/spec` declares this block's member a positive integer — -`RecordActivityProps.limit` is `z.number().int().positive().default(20)`, described -there as "Number of items to load per page" — so a fractional cap is a value the -contract refuses. `normalizeLimit` nevertheless read `Math.floor(Number(value))` and -then admitted anything finite and positive, so an authored `limit: 2.5` came back as -**2**: a two-row feed the author never asked for, with no cause named anywhere. - -It now falls back to this block's default of 20, silently, which is the answer its -sibling `record:history` gives through `normalizeHistoryLimit` (objectui#10093). -`Number.isInteger` replaces `Number.isFinite` and nothing else, so `0`, a negative, -`NaN`, both infinities, an absent value and a non-numeric string keep answering 20 -exactly as before; a usable cap still passes through unchanged and a numeric string -still resolves (`'5'` is still `5`). What narrows is the admitted value set, not how a -node's value is read. `record:activity`'s default of 20 and `record:history`'s of 50 -are unchanged and still differ deliberately. - -`record:chatter` and `record:discussion` resolve `feed.limit` through the same -function — `RecordChatterProps.feed` is `RecordActivityProps`, the same declared -member — so they get the same refusal. - -What an author sees change: a record page whose activity, chatter or discussion block -declared a fractional cap showed a floored window (`2.5` → two rows) and named no -cause; it now shows the block's default of 20. - -The `Math.max(1, Math.floor(pageSize) || …)` clamp inside `applyFeedConfig` is -unchanged and settled as an internal clamp rather than the same defect: `pageSize` is -not an authored member but the paging window, computed at both call sites as -`limit * (extraPages + 1)` over an already-normalized limit, so every value reaching it -is a positive integer on which all three of its arms are the identity. diff --git a/.changeset/10098-locale-contracts-name-caller.md b/.changeset/10098-locale-contracts-name-caller.md deleted file mode 100644 index 95d82b416a..0000000000 --- a/.changeset/10098-locale-contracts-name-caller.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/core': patch -'@object-ui/i18n': patch -'@object-ui/plugin-report': patch ---- - -The two declared display-locale contracts now each name the caller they govern, -and each points at the other (objectui#10098). This is documentation only: no -module's behaviour moves. - -- `DisplayNumberFormatOptions.locale` (`@object-ui/core`): leaving the tag - `undefined` means the runtime default, and that rule is written for a non-React - display caller with no tag in hand. For that caller the viewer's own environment - is the honest locale for a user-facing display. A malformed tag lands in the - same place through `formatDisplayNumber`'s retry. -- `useDisplayLocale` (`@object-ui/i18n`): its concrete `'en'` last resort, kept for - determinism, is the rule for a React renderer whose provider chain yields no tag - at all, not a rule for every caller without a tag. -- `formatNumberInDisplayLocale` (`@object-ui/plugin-report`): the note on its - malformed-tag retry no longer calls the dropped-tag retry behind - `formatDisplayNumber` a wrong answer. Each retry follows its own package's - declared contract. - -Read alone, either docblock used to look like a rule for every caller, and each -contradicted the other. The new wording reaches each package's published type -declarations, which is why this is declared as a patch rather than left -undeclared. diff --git a/.changeset/10105-pull-to-refresh-late-host.md b/.changeset/10105-pull-to-refresh-late-host.md deleted file mode 100644 index 6f50a706cd..0000000000 --- a/.changeset/10105-pull-to-refresh-late-host.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/mobile': patch ---- - -fix(mobile): `usePullToRefresh` arms on a host that mounts after the first render, and one pull has one owner (objectui#10105) - -The hook returns an object ref, so it cannot see when a consumer attaches it. -It used to bind its touch listeners in an effect keyed only on its handlers and -`enabled`, which read `ref.current` once. A view whose first render is a -loading screen has no host at that moment. When the host appeared, none of the -effect's keys had changed, so it never ran again and the pull gesture did -nothing, with no error. The listeners now follow the element the ref points at -after each commit: they bind when it appears, move when it is replaced, and are -released when it goes away or the consumer unmounts. - -Measured on this branch, on the internal-fetch path (the view fetches its own -rows): the gesture was dead on `ObjectCalendar`, `ObjectGrid` and -`ObjectTimeline` and now arms and refetches. `ListView` renders its host on the -first render and was not affected. - -Nested pull hosts now have one owner. `ListView` has its own pull host, and -so does the view it renders inside itself. A touch on the inner view bubbles -to `ListView`, so both used to respond to one pull. Before this change, the -calendar and timeline views inside `ListView` drew two "Pull to refresh" -strips for one pull, and arming the grid would have made its view do the -same. The gesture now belongs to the OUTERMOST armed pull host: an inner host -lets a pull go when an armed pull host is its ancestor in the DOM. So one pull -inside `ListView` draws one indicator, `ListView`'s, and runs one refetch, -which reloads the rows `ListView` hands the inner view. A view with no pull -host above it keeps its own pull. While it is armed, the hook marks its -element with a `data-pull-to-refresh-host` attribute; that attribute is how one -hook instance sees another, including across two copies of this package. - -Product-visible: - -- Nothing changes in what renders while loading. -- A pull inside `ListView` (calendar, grid or timeline view) shows one - indicator (calendar and timeline used to show two; the grid view keeps its - one), and still triggers one refetch. -- The pull gesture now works on those views when they fetch their own rows. - -The exported signature and return type of `usePullToRefresh` are unchanged. diff --git a/.changeset/10106-settled-schema-equal-payload.md b/.changeset/10106-settled-schema-equal-payload.md deleted file mode 100644 index 7fa7b7ca15..0000000000 --- a/.changeset/10106-settled-schema-equal-payload.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/react': patch ---- - -`useSettledSchema` no longer republishes an EQUAL definition as a new object, -so swapping the adapter on a record-bound view costs ONE record query instead -of two. - -The hook refetches `getObjectSchema` whenever the adapter identity changes, and -every consumer its doc comment instructs — `ObjectGantt`, `ObjectCalendar`, -`ObjectView`, `ObjectTimeline`, `ObjectGallery` — keys its record fetch on the -returned `def`, which is what `AGENTS.md` §5 commandment #10 tells a consumer to -do (key on the payload, never on a memo identity). The producer half of that -same sentence is what this fixes: a byte-identical answer arriving as a fresh -object re-fired every one of those fetches, and the duplicate query carried the -same `$expand` set as the one before it. Measured first-hand on `ObjectGantt` -with an instrumented adapter, with a control swap in the same command; the -counts, and the control that makes them a discrimination rather than a counting -artefact, are asserted by -`packages/react/src/hooks/__tests__/useSettledSchema.equalPayload-10106.test.tsx` -(objectui#10106). - -A definition that genuinely CHANGED across the swap still publishes a new -object and still re-queries — that case is pinned in the same file, because -"fetch less" would have been the wrong repair. diff --git a/.changeset/10107-record-verdict-memo-per-principal.md b/.changeset/10107-record-verdict-memo-per-principal.md deleted file mode 100644 index be9d1fc1d4..0000000000 --- a/.changeset/10107-record-verdict-memo-per-principal.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -fix(plugin-detail): the record-grained write verdict is memoised PER PRINCIPAL -(objectui#10107). - -`useRecordEditable` — the record-level gate behind the detail header's Edit / Delete -CTAs, the drawer's, and (imported from here) the console record page's — asks the -explain engine `POST /api/v1/security/explain` for the row verdict and memoises the -answer so revisiting a record is free. The memo was keyed -`object:recordId:operation`, with nothing about WHO the verdict was computed for, and -it lives at module scope, so it outlives every unmount for the life of the tab. - -Signing out does not end that life. This repo already records that no sign-out call -site reloads the page — that is exactly why `AuthProvider.signOut` purges the per-tab -storage caches by hand (objectui#5198) — and this map was not among what it purged. So -the next principal to sign in in the same tab was answered from the previous -principal's verdicts, and answered SYNCHRONOUSLY as the hook's initial state, so no -probe was sent and no later answer could correct it. - -Both fail directions were reachable, and both are now pinned: - -- a `false` computed for someone else hid Edit from a user who holds a record-level - `edit` share, for the rest of the tab's life, while `PATCH` on that record - succeeded — the report this card carries; -- a `true` computed for a privileged principal offered Edit to one holding no grant, - the UI inviting a write the server refuses. That direction is the worse one. - -The key now carries the acting principal (`usePermissions().userId`, the identity -`/me/permissions` already publishes — the verdict itself still comes from the explain -engine alone, so this adds no second source of permission truth), and the map is -dropped whenever that principal changes, so no entry can span a sign-out. A key change -with no cached answer also resets to the hook's fail-open default instead of leaving -the previous key's verdict on screen across the round trip — the same posture the hook -states for every other uncertainty (ADR-0124 D1: the server enforces, the client is -courtesy). - -Unchanged: the fail-open contract on an unknown answer, the request shape, the probe's -authenticated channel, and the memo itself within one principal. diff --git a/.changeset/10108-form-payload-server-owned-fields.md b/.changeset/10108-form-payload-server-owned-fields.md deleted file mode 100644 index 97fd9367c3..0000000000 --- a/.changeset/10108-form-payload-server-owned-fields.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -A form no longer emits the columns the server owns, and a master-detail batch sends only the cells the user changed (objectui#10108). - -**Clause-②: no** — nothing an author writes changes, and no export moves. `SERVER_OWNED_FIELD_NAMES` is module-scoped inside the package (the package publishes `.` only, from `index.tsx`, which does not re-export `sanitize`), so this is a change to what the client PUTS on the wire, not to the package's face. - -**What it was.** The write-side roster in `sanitize.ts` and the render-side roster in `autoLayout.ts` were two hand-written copies of the same list, and they drifted. The render copy had learned to drop `owner_id`; the write copy never did. A form therefore showed the user business inputs only, and sent back every ownership and audit column it had read — `owner_id`, `owning_business_unit_id`, `created_by`, `updated_by` — while dropping `created_at` and `organization_id` from the same payload, because those two happened to be in the write copy. - -That is not a cosmetic difference. The platform refuses a write to a system-managed ownership column unless the caller holds the transfer grant, and it cannot tell a round-trip of the value it just served from an attempted ownership transfer. Echoing an UNCHANGED `owner_id` back was therefore a 403 for every role without that grant — and a master-detail save commits as one atomic batch, so one echoed column on one row refused the parent and every sibling row with it. The roles this blocked are the line-entry roles the feature exists for, which by definition do not hold the transfer grant. - -**What changed, in observable terms.** - -- One roster now serves both readings, so a form never writes a field it refuses to render. The unified list adds `owning_business_unit_id`, `company_id`, `space`, `_id`, `__v`, `created`, `modified`, `modified_by` and the camelCase spellings of the ownership FKs to BOTH sides. ⚠️ If an auto-laid-out form in your app was rendering one of those as an editable input, it no longer does, and no form writes one. -- `sanitizeFormData` also refuses any field the object schema marks `system: true`, whatever it is called — so the next column the platform injects does not need an edit here to be refused. -- A master-detail edit batch sends only the cells that differ from the loaded snapshot, and a row where nothing moved produces no operation at all (it used to be rewritten in full on every save). The comparison resolves everything it cannot settle towards SENDING, so a real edit is never dropped: `1000` and `'1000'` read as different, and a snapshot that does not show a row already linked still gets its FK re-asserted. -- The lifecycle bookkeeping columns (`locked`, `instance_state`, `deleted`, `is_deleted`) are deliberately NOT in the roster — they are plausibly author-writable, and adding them on the strength of the pattern alone would silently drop a value a form was asked to persist. diff --git a/.changeset/10109-app-shell-edit-not-built-moment.md b/.changeset/10109-app-shell-edit-not-built-moment.md deleted file mode 100644 index 6a6f0967eb..0000000000 --- a/.changeset/10109-app-shell-edit-not-built-moment.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -When the AI chat receives an incremental edit, it no longer switches to the Studio workbench as if a whole-app build had finished. The built-moment transition also checks the draft review, and it now skips one that says `kind: 'edit'`, even when the edit re-staged the `app` artifact (objectui#10109). The chat's local message cache also keeps that `kind` when it rebuilds the draft envelope, so an edit reloaded from the cache still reads as an edit. An `apply_blueprint` build, which carries no `kind`, moves to Studio as before. diff --git a/.changeset/10109-edit-envelope-not-built-app.md b/.changeset/10109-edit-envelope-not-built-app.md deleted file mode 100644 index 0fb4aae8bf..0000000000 --- a/.changeset/10109-edit-envelope-not-built-app.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/plugin-chatbot': minor ---- - -An incremental edit is no longer read as a whole-app build. An `apply_edit` result says `kind: 'edit'` on its envelope, and its `drafted[]` may list the `app` artifact the edit re-staged, because an `add_object` op re-stages it for the nav merge. An `apply_blueprint` build carries no `kind`. The chat now takes the producer's field as the only thing that separates the two, instead of guessing a build from which artifact types were staged (objectui#10109): - -- `detectBuiltAppPackage` returns `undefined` for an envelope that says `kind: 'edit'`, in both the drafted and the auto-publish (`status: 'published'`) postures. -- `DraftReview` has a new optional `kind?: 'edit'`, and `detectDraftResult` fills it from the envelope. The edit still gets its draft card, its items and its `packageId`, so one-click publish still works. -- `ChatbotEnhancedToolInvocation['draftReview']` (`ChatToolInvocation.draftReview`) is now typed as `DraftReview` instead of an inline copy of its fields, so it declares `kind` too. The two were field-identical before this change, and the published tool-invocation type now describes exactly what the chat mapper puts on it. -- `buildProgressFromDraftReview` builds no finished "Built X" panel for a draft review whose `kind` is `'edit'`, so a reloaded edit shows the same thing it showed live. - -An envelope without `kind` behaves as before. `DraftReview.kind` declares only the value these readers act on, and an envelope that says anything else leaves it unset. diff --git a/.changeset/10112-relatedlist-user-column-names.md b/.changeset/10112-relatedlist-user-column-names.md deleted file mode 100644 index be2e6eff98..0000000000 --- a/.changeset/10112-relatedlist-user-column-names.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -fix(plugin-detail): a related list resolves `user` columns to names, like every other list - -A record-detail related list drew a `user` column as the stored `sys_user` id — the -32-character opaque string — while the standalone list of the same object, same -record, drew the person's name. The field is not off-spec: `user` is a -reference-bearing type fixed to `sys_user` and a member of `@object-ui/core`'s -`EXPANDABLE_FIELD_TYPES`. One renderer diverged. - -Two halves, both now reading the shared family instead of naming types locally. - -The auto-fetch asked for no `$expand` at all, so every reference column arrived as -its bare foreign key. It now asks for the roots `buildExpandFields` derives — the -same canonical projection an ordinary list sends — restricted to the authored -columns when the caller named any, minus the parent relationship, which is removed -from every column list this component draws. The roots are FLS-gated on the OUTPUT, -the shape objectui#7215 / objectui#7230 ruled and `DetailView` already uses: asking -the server to resolve a reference discloses more than the bare key does. A child -object with no expandable column sends the byte-identical query it always sent. - -The batch label fallback — the path that serves rows a CALLER supplied, and a -backend that does not honour `$expand` — tested `lookup`/`master_detail` in a -private disjunction, two of the family's four members, so a primitive `user` id was -never gathered and never resolved anywhere else either. It now asks the family. A -`user` cell reads no `field.options`, so the resolved name reaches it as the record -shape it documents; the name still comes from the one batch map in this file, -resolved through the target object's declared `nameField` / `titleFormat`, so no -second resolver exists. - -⛔ Both halves are pinned on the RENDERED name, against a control that renders the -same column printing the stored id when resolution is made impossible — an absence -proves nothing until the presence has been seen on the same instrument. Identity -pins spy on the `has` of the object core exports, so a member-identical private -copy of the family fails where a membership check would pass on the defect. diff --git a/.changeset/10117-page-header-title-lookup-fallback.md b/.changeset/10117-page-header-title-lookup-fallback.md deleted file mode 100644 index 09b6faf866..0000000000 --- a/.changeset/10117-page-header-title-lookup-fallback.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -'@object-ui/components': patch ---- - -fix(components): `page:header` resolves a lookup title candidate instead of handing its expanded object to JSX - -A record whose declared name field was empty took the whole `page:header` block -down with "Objects are not valid as a React child" (React #31), leaving the red -"failed to render … Retry" panel where the H1 belongs while the rest of the page -rendered. The reported object declares `nameField: 'name'` over a -hook-computed readonly text field and a required `subject` lookup; a record -created by an admin never gets its `name`, so the header walked past it to -`subject` and put that field's **expanded reference object** into the heading. - -The header's record-chrome branch asked the unified ADR-0079 resolver with -`deriveFromRecordKeys: false` and then re-spelled the rung it had just switched -off as a raw `data?.name || data?.full_name || data?.title || data?.subject || …` -chain. That is a second implementation of the question `recordDisplayValueAt` -exists to answer, and it diverged from it on both of that function's own -clauses: raw `||` reads the **stored** value, so an expanded reference reached -JSX unchanged, and it counts a whitespace-only string as a value, so a name -field holding only spaces rendered a blank H1. - -⭐ The resolution was never missing from this tree. The breadcrumb resolves the -same record through the same resolver **without** `deriveFromRecordKeys: false`, -so each of its rungs runs through `recordDisplayValueAt` and on to the embedded -object's display chain — which is why it showed the business unit's name -correctly while the header beside it crashed. The copy is deleted and that rung -is now asked for instead of imitated. - -Three things change for an author: - -- a lookup or reference used as a title now shows the referenced record's - display name, resolved exactly as the breadcrumb and the detail grid resolve - it, and never as a raw object; -- an object that **names** its title field — a declared `nameField` / - `displayNameField`, or a type-aware derivation over its `fields` — no longer - borrows a different field's value when that field is empty. It degrades to - the header's existing `${objectLabel} ${id}` placeholder. The silent hop to - the next candidate was part of the defect, not merely how it was rendered, so - the fallback chain's behaviour is what changed. The record-key safety net - still runs in full for an object that names no title field at all, which is - the case it was added for; -- a non-string title candidate is reduced through that same display-value - authority before rendering. This is a backstop and deliberately last: on its - own it would have replaced the crash with a header quietly showing the wrong - field's contents. The remaining way one arrives is an author-supplied `title` - that is not a string, which the header's `interpolate` returns untouched. - -A whitespace-only value is now empty here for the same reason it is empty to -`recordDisplayValueAt`, so such a record shows the placeholder rather than a -blank heading. A record with a non-empty name renders exactly what it rendered -before. diff --git a/.changeset/10120-form-omits-fls-denied-fields.md b/.changeset/10120-form-omits-fls-denied-fields.md deleted file mode 100644 index 7586bedd08..0000000000 --- a/.changeset/10120-form-omits-fls-denied-fields.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/plugin-form': patch -'@object-ui/fields': patch ---- - -A form no longer submits — nor offers — a field the CALLER may read but not edit. - -**Clause-②: no** — no exported symbol is added, removed, renamed or retyped, no key on a published payload moves, and no accept set is relaxed. `sanitizeFormData` gains an optional third argument and `fieldWriteGate` / `applyFieldPermissions` are new, but `@object-ui/plugin-form` publishes `.` only, from `index.tsx`, which re-exports neither module — measured on the built `dist/index.d.ts`, where neither name appears. `LookupField`'s props are unchanged. What moves is what the client PUTS on the wire and which controls it draws. - -**What it was.** The platform refuses a write to a field the caller's permission set marks `editable: false`, and it cannot tell a round-trip of the value it just served from an attempted write. A form echoing an UNCHANGED `score` back is therefore a 403 for the whole save, even when the user touched only a field they *are* allowed to edit — so the standard edit form was unusable for any role with a field-level restriction on it. The list view's inline grid succeeded on the same record for the same user, because it sends only the changed cell. - -The verdict that answers 「may this caller edit this field」 already existed and one path already used it: `checkField(object, field, 'write')` in `@object-ui/permissions`, reading the server's `/me/permissions` grant. What had gone wrong is that each form container spelled its own COPY of the strip and of the render pass, and the family had drifted — the same defect class as objectui#10108, one layer up. Measured on one record with one permission set: the simple form and the modal withheld `score` while the drawer sent it, and the drawer rendered it as a live input while the other two rendered it disabled. One family, three answers; the third container carried neither half. - -**What changed, in observable terms.** - -- The field-level verdict now arrives at the ONE outbound filter as a predicate (`sanitizeFormData`'s `canEdit`), instead of as a strip loop written out after each container's call. ⚠️ `DrawerForm` previously sent every displayed field regardless of the caller's field permissions; it no longer does. `ObjectForm` and `ModalForm` already withheld the refused field, and still do — their loops were correct, they were just copies. -- The render pass is likewise one function for all three containers. ⚠️ `DrawerForm` previously drew a field the caller may read but not edit as a live input; it now draws it read-only and disabled, exactly as the other two already did. A field the caller may not READ is dropped, also as before. -- Both halves stay fail-open with no `PermissionProvider` / `MePermissionsProvider` mounted, unchanged: a standalone form, a designer preview and a guest surface have no resolvable principal, and the server still enforces. -- A lookup's selected chip no longer offers its remove ✕ when the field is disabled. ⚠️ This is how BOTH refusals reach the widget — a field the object declares `readonly` is folded into `disabled` by the form's section builder, and a field the permission set refuses is marked disabled by the pass above — so a reporter could previously clear a master-detail parent the server would then refuse to unset. The trigger and the browse button were already disabled; the chip's ✕ was the one control the gate had missed. The chips themselves stay: the value is readable, only the affordance goes. - -**Deliberately not here.** Submitting only DIRTY fields is objectui#10156, filed with its own risk argument (a false CLEAN silently drops a user's edit and returns 200). Naming the refused field in the 403 instead of the generic console message is owned by the producing side. diff --git a/.changeset/10129-action-param-field-backed-picker.md b/.changeset/10129-action-param-field-backed-picker.md deleted file mode 100644 index 9932454068..0000000000 --- a/.changeset/10129-action-param-field-backed-picker.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -'@object-ui/app-shell': minor -'@object-ui/core': minor -'@object-ui/i18n': minor ---- - -A field-backed action param reaches its record picker, and a param whose backing -field cannot be read is refused instead of rendered as an empty text box. - -An action declaring a `params` entry backed by a `lookup` field rendered as a bare -text input: no options, no typeahead, and no request for the referenced object on -the wire at all, because no picker was ever built. With the param `required`, the -action could not be launched from the UI — while the same field rendered a working -picker on a record form in the same build, off the same metadata. - -`resolveActionParams()` resolves a field-backed param against the `objects` list -its caller holds, and two of the console's own callers cannot hold the right one: -`ConsoleShell`'s root action runtime — the provider that exists so a `type: 'flow'` -`action:button` works outside the four object views — passes no objects at all, and -`DeclaredActionsBar` passes exactly one (none when driven by an `actions` prop). -With the owner object absent the param took the resolver's last-resort shape, and -for a field-backed param that shape is `text`: it declares no inline `type`, so -there is nothing else to fall back to. The object binding was never missing from -the client — this seam never asked the metadata store for it. - -- `useConsoleActionRuntime` now resolves field-backed params against the caller's - objects UNIONED with the console metadata store's, caller first (`withKnownObjects`), - after awaiting the object type so "this field does not exist" is an answer rather - than a boot race. A draft/preview overlay the caller carries still wins. -- The degradation is no longer anonymous. `resolveActionParams()` stamps - `unresolvedField: '.'` on a param whose backing field it could not - find and says so in dev. This is the half that made the defect invisible for a - whole version: by the time `paramToField()` sees such a param it IS a `text` - param, so `paramDegradesWithoutTarget()` answered false, no "no reference target" - warning fired, and even the "paste a record id" placeholder and help text did not - apply. -- `ActionParamDialog` refuses such a param: it renders an alert naming the - `.` pair in place of the control, logs one line per dialog opening - in every build, and disables Confirm so the action cannot be launched with a value - the dialog had no contract to collect. - -New localized string `actionDialog.unresolvedParam` in all ten locale bundles. The -`.` locator renders as its own node rather than an interpolation, so -an identifier is never re-ordered by a translation. diff --git a/.changeset/10132-dashboard-i18n-declared-not-resolved.md b/.changeset/10132-dashboard-i18n-declared-not-resolved.md deleted file mode 100644 index 38a3eac8a6..0000000000 --- a/.changeset/10132-dashboard-i18n-declared-not-resolved.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/plugin-dashboard': patch ---- - -fix(dashboard): a dashboard filter declaring `object` now resolves its translated labels; the axis-title half reaches no surface - -`@objectstack/spec` declares two dashboard surfaces translatable — a filter's `object` and an -axis `title` — and the Console resolved neither, so an author could set a key the contract -documents and nothing happened. They turned out to be **two defects, not one** — a key never -read, and a value that bypassed a resolver already in the tree — and they were fixed -separately. Only the first reaches an author in this release: see the note at the end. - -**1. `GlobalFilterSchema.object` was never read.** The spec's describe text for the key is -"Object whose `fields..` translation-bundle entry resolves this filter's field -label and option labels". `resolveDashboardFilterDefs` names the keys it copies onto a -`DashboardFilterDef` and this one was not among them, so the authored value could not reach a -renderer even in principle: a dashboard filter declaring `object` and no `label`, viewed on a -translated console, painted the RAW FIELD NAME and left its option labels in the authored -English. The definition now carries `object` through, and `DashboardFilterBar` resolves the -field label through `useSafeFieldLabel().fieldLabel` and the option labels through the same -object's `translateOptions` — the convention resolver every list and form already calls, which -is the "one resolver path" the key's own spec text asks for. No second resolver was written. -Precedence follows that resolver's signature: the translator's bundle wins, the authored label -is the fallback. A filter that names no `object` never reaches it and renders exactly as -before. - -**2. `ChartAxisSchema.title` bypassed a resolver two modules downstream.** The key is -`I18nLabel`, so an inline locale map parses, builds and validates — and `axisPresentation` -collapsed it with `labelText`, a first-string-in-KEY-ORDER pick. Measured both ways round on -one map: English to a `zh-CN` viewer and Chinese to an `en` viewer, decided by nothing but -which key the author typed first. `normalizeChartSchema` already resolves an axis title -through `pickLocalized` against the viewer's language, so the map only had to survive the -lowering. The fix forwarded it verbatim through `forwardedI18nLabel` — the neighbour in the -same module that already carries a chart's own `title` / `subtitle` / `description` for -exactly this reason — and that lowering was then removed in the same release (the note at the -end). - -This moves one entry of the objectui#4020 first-string-wins ledger. That ledger's -justification is "a locale-unaware pick a caller can OVERRIDE", which holds for a series -`label` — the report renderer outranks it with objectui#4020's three-level display name — and -never held for an axis title, which is spread onto the chart schema and drawn. `seriesPresentation` keeps the pick and -is still pinned. - -What an author sees change: a filter that opted in with `object` now shows its translated -field and option labels instead of the raw field name and English options. Nothing that omits -`object` renders differently, and point 2 changes nothing an author sees (below). - -⚠️ Point 2 reaches no surface in this release, which also carries objectui#11315 and -objectui#11372. `@objectstack/spec` 17.5.0 refuses `chartConfig.xAxis` / `yAxis` / `series` on -a dashboard widget, and the dashboard's dataset widget no longer reads them (objectui#11315), so -a dashboard draws no authored axis title at all, in any language. That widget was the only -caller of `axisPresentation` and `mergeAuthoredPresentation`, and objectui#11372 removes both -from `@object-ui/core` in the same release, so the fixed lowering never ships. The react -`ObjectChart` tier, which still authors its own axes, never went through that lowering: it hands -`xAxis` / `yAxis` to `normalizeChartSchema`, which resolves a locale-map axis title against the -viewer's language since objectui#8943 (released alongside this, under its own changeset). -`ObjectChart.axisTitleLocale-10132.test.tsx` in `@object-ui/plugin-charts` pins that surface at -two languages. diff --git a/.changeset/10145-row-cap-admits-only-numbers.md b/.changeset/10145-row-cap-admits-only-numbers.md deleted file mode 100644 index 3144432e1b..0000000000 --- a/.changeset/10145-row-cap-admits-only-numbers.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -'@object-ui/plugin-detail': minor ---- - -feat(plugin-detail): row caps on `record:activity`, `record:history`, `record:chatter` and `record:discussion` admit only a positive integer number, and a refused one warns - -`@objectstack/spec` declares `limit` on `RecordActivityProps` (which is also -`RecordChatterProps.feed`) and on `RecordHistoryProps` as -`z.number().int().positive()`, and refuses a string, a boolean or an array -outright. The renderers used to run `Number(value)` before their integer check, -so they also read `'5'` as 5, `' 5 '` as 5, `'0x10'` as 16, `true` as 1 and `[7]` -as 7: a second accepted set, wider than the contract (objectui#10145, ruled -STOP). - -Both resolvers (`normalizeLimit`, shared by activity, chatter and discussion, -and `normalizeHistoryLimit`) now admit only a value whose type is `number` and -which is a positive integer. Every other authored value falls back to the -block's default (20 for activity, chatter and discussion; 50 for history). The -renderer then logs one `console.warn` that names the block and spells the raw -value with its type (for example `declared limit: "5" (string)`). The warning -also fires for the fractional, zero, negative, `NaN` and infinite values these -blocks already refused silently. That matches the "always warn" ruling on -objectui#10097 and the three objectui#9925 read points. An absent `limit` is not -a refusal and stays silent. - -**Migration.** Stored metadata that spells a row cap as a string (for example -`limit: '5'`, or `feed: { limit: '5' }` on a chatter or discussion block) now -drops to the block's default and warns in the console, where it used to be read -as 5. Write the number instead (`limit: 5`). Publishing such metadata was -already refused by the spec, so this affects only bodies stored before that -check, or written around it. diff --git a/.changeset/10150-author-shape-header-ruling.md b/.changeset/10150-author-shape-header-ruling.md deleted file mode 100644 index ef9f4b38b5..0000000000 --- a/.changeset/10150-author-shape-header-ruling.md +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`: the docblock above `clientValidation`'s `AUTHOR_SHAPE_ONLY_TYPES` ended on a plan, to switch the `sharing_rule` edit gate on once the `_diagnostics` ingress was closed. That condition was met (`extractDraftBody` strips the read decorations through the spec's `stripReadDecorations`), the switch was put to the maintainer, and the 2026-09-20 ruling was option A: the edit door stays with the server. The docblock now records that ruling beside the condition, and keeps the measurement above it. A source-scan pin requires the docblock to name the ruling and the function that closed the ingress. - -Declared as releasing nothing because the emit was measured rather than assumed: `AUTHOR_SHAPE_ONLY_TYPES` is not exported, so neither it nor its docblock reaches the emitted `clientValidation.d.ts`; the emitted `.js` carries the comment, and its comment-stripped emit is identical to the base. No published behaviour changes (objectui#10150). diff --git a/.changeset/10155-record-blocks-capability-gate.md b/.changeset/10155-record-blocks-capability-gate.md deleted file mode 100644 index 7d899a92cb..0000000000 --- a/.changeset/10155-record-blocks-capability-gate.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -fix(plugin-detail): `requiredPermissions` on `record:details`, `record:highlights` and `record:related_list` is an ADR-0066 capability set, read fail-closed — it used to pass for every reader of the object - -These three record blocks carried the same block-level gate objectui#10058 -repaired on `record:quick_actions`, byte for byte, and were untouched by it. -Each evaluated every declared name through the permission context's -OBJECT-ACTION path, whose second argument is the closed object-action enum — -not the ADR-0066 system capability set the same word names on `action`, `app`, -`field` and `bulkAction`. - -Under the stock `/me/permissions` provider that path maps eight verbs (`read`, -`view`, `create`, `update`, `edit`, `delete`, `import`, `export`) and sends -everything else to the object's `allowRead` bit. So a declared gate naming a -capability nobody holds opened for every reader of the object, with no refusal, -no warning and no log — and five members of the enum itself (`manage`, `admin`, -`share`, `configure`, `execute`) were swallowed by the same tail, none of them -being in that map either. - -All three now read `hasCapabilities` over the reported `systemPermissions` and -gate fail-closed: an unheld or unrecognised capability hides the block. The -object name leaves the verdict, because a system capability is not -object-scoped — on `record:details` and `record:highlights` the old -`&& objectName` conjunct was a second silent fail-open, skipping the declared -gate entirely for a block rendered with no object name in its record context. - -Two calls deliberately do NOT move. `record:related_list`'s automatic -child-object read gate still asks the object-action path about `read`, which is -the question it means to ask, and `can()`'s own semantics are untouched -everywhere else. - -⚠️ Unchanged residual, shared with every other capability gate in the tree: a -provider that never REPORTS capabilities (`systemPermissions` absent — the -role-based `PermissionProvider`, or a backend predating ADR-0066) still opens -these gates. That is `hasCapabilities`'s ruled unreported-vs-empty doctrine -(objectui#4656) and this change does not move it. A REPORTED empty array is a -real answer and gates strictly. - -**Correction, 2026-09-30 (objectui#8649).** "Hides the block" above is wrong -about what the reader sees. When a declared capability is unheld or -unrecognised, the block's content is withheld and an insufficient-permissions -notice (`role="status"`) renders in its place, on all three blocks. That is -what the contract's `requiredPermissions` describe on these blocks says: "this -block does not render its content; wherever it would otherwise render, an -insufficient-permissions notice takes its place". Everything else above stands: -the capabilities the gate asks for, and its fail-closed verdict. The automatic -child-object read gate of `record:related_list` is a different gate, and it -does hide the section. diff --git a/.changeset/10156-edit-form-writes-only-changed-fields.md b/.changeset/10156-edit-form-writes-only-changed-fields.md deleted file mode 100644 index 91ea2e1e07..0000000000 --- a/.changeset/10156-edit-form-writes-only-changed-fields.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/plugin-form': patch -'@object-ui/types': patch ---- - -An edit form now writes only the fields that changed (objectui#10156). - -**Clause-②: no.** No exported symbol, type or prop changes. `@object-ui/plugin-form` publishes `.` only, from `index.tsx`, and `index.tsx` re-exports neither `sanitize` nor `masterDetailTx`. After a build, `dist/index.d.ts` names none of the new helpers. The change is in what the client sends, and ⚠️ in what a host `submitHandler` receives in edit mode (see below). - -**Before.** A master-detail child row already sent only the cells that differed from its loaded snapshot (objectui#10108). The other two edit payloads did not. The plain record edit `PATCH` and the parent operation of a master-detail batch sent every sanitized field on every save, including fields the user never touched. With the concurrency guard, a `409` followed by **Overwrite** therefore rewrote every field, not only the ones this user changed. - -**What changed, in observable terms.** - -- In edit mode, `ObjectForm`, `ModalForm` and `DrawerForm` compare their save with the record they read through `findOne`, and write only the fields that differ. The parent operation of a master-detail batch follows, because its header is a simple `ObjectForm`. -- There is one comparison, shared with the master-detail child rows. It sends anything it cannot prove unchanged. `null` and `undefined` count as the same value. `null` and `''` are different. So are `5` and `'5'`, a lookup id and its expanded object, a `Date` and a date string, and two objects whose keys come in a different order. A field the form changed by itself after the read, such as a cascade clear, is sent. -- A save with nothing changed still sends the full sanitized payload. It stays a real request, with the same concurrency guard and a real server record for `onSuccess`. -- A form that did not read the record itself still sends every field. That covers a create, a record supplied as `initialData`, and inline `customFields`. -- After a successful save, the form counts the fields it just wrote as saved. A form that stays open compares its next save with the record as it is now. Changing a field back to its first-read value is therefore still sent. -- The concurrency guard is unchanged by this rule. The update carries `ifMatch` = the `updated_at` the form read (after a save, a form that stays open sends the `updated_at` that save returned instead, objectui#10565), and a `409` still offers **Keep editing** or **Overwrite**. **Overwrite** now resends only the changed fields. -- ⚠️ A host `submitHandler` on an edit form receives the payload the form would have written. That is the changed fields, or the full sanitized payload when nothing changed. A host that needs the whole record must read it itself. In this repository, only `MasterDetailForm` passes a `submitHandler` to an edit form. Its header form receives the changed fields. Its row editor has no `recordId`, so it still receives every value. -- The JSDoc of `ObjectFormSchema.submitHandler` in `@object-ui/types`, and its copies on `ModalFormSchema` and `DrawerFormSchema`, now say what an edit-mode handler receives. - -**Not covered at this change.** The `tabbed`, `wizard` and `split` variants had save paths of their own and still sent every value they held. That included a master-detail header laid out `tabbed`, and a simple form whose mobile `stepper` option shows it one step at a time through the wizard. - -⚠️ **Dated note, 2026-09-25 — those variants have since been covered — objectui#10563.** Later in this same release the `tabbed`, `wizard` and `split` save paths, the `stepper` route and a master-detail header laid out `tabbed` write through the same sequence as the simple form: the same strip, and on an edit the same comparison against the record they read. The rest of this entry is kept as the reading of this change; the objectui#10563 entry states what those layouts now send. diff --git a/.changeset/10159-action-preview-reference-citation.md b/.changeset/10159-action-preview-reference-citation.md deleted file mode 100644 index e2008fa28c..0000000000 --- a/.changeset/10159-action-preview-reference-citation.md +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`: the docblock above `ActionPreview`'s `INHERITED_TARGET` quoted the action-param resolver as reading `referenceTo: param.reference ?? field.reference_to`. The resolver has read `field.reference` since objectui#6837 narrowed that read, and `reference_to` is a field-definition key `@objectstack/spec` refuses by name, so the comment pointed its reader at metadata the platform rejects. The quotation now matches the code, and a pin re-derives it from the docblock and requires it to occur, as whole tokens, in the resolver's comment-masked code. - -Declared as releasing nothing because the emit was measured rather than assumed: `INHERITED_TARGET` is not exported, so neither it nor its docblock reaches the emitted `ActionPreview.d.ts`; the emitted `.js` carries the comment, and no runtime token moved. No published behaviour changes (objectui#10159). diff --git a/.changeset/10163-line-items-field-write-gate.md b/.changeset/10163-line-items-field-write-gate.md deleted file mode 100644 index e87bf300ee..0000000000 --- a/.changeset/10163-line-items-field-write-gate.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -A `record:line_items` grid no longer offers a cell the CALLER may read but not edit (objectui#10163). - -**What it was.** `80c54122e` taught the record-form containers to render a field the caller's permission set marks `editable: false` as disabled, through one shared render pass. The line-items panel stayed outside that pass: it read `readonly` and nothing else, so on the same page the same column rendered as a live, editable cell — inviting an edit the server refuses. - -**What changed, in observable terms.** - -- The panel's columns now go through the same render pass the form containers use, adapted to the grid: a column the caller may read but not edit renders its cells locked (on loaded rows and on the entry row alike), and a column the caller may not read is omitted, exactly as the forms omit such a field. Columns the caller may edit are unchanged. -- Adding and removing lines are unchanged: they still follow the panel's `readonly`. -- With no permission provider mounted the grid is exactly as before — every cell editable. That fail-open posture is objectui#10161's and is not moved here; the server still enforces. - -**Clause-②: no** — no exported symbol is added, removed, renamed or retyped. The new column adapter lives in a module `@object-ui/plugin-form`'s entry does not re-export. No authored key changes meaning and no accept set is relaxed. - -**Not in this entry.** The master-detail form's own child grid (`object-master-detail-form`) is covered by the companion objectui#10163 entry. diff --git a/.changeset/10163-master-detail-field-write-gate.md b/.changeset/10163-master-detail-field-write-gate.md deleted file mode 100644 index fd7e499baf..0000000000 --- a/.changeset/10163-master-detail-field-write-gate.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -A master-detail form's child grid no longer offers a cell the CALLER may read but not edit (objectui#10163). - -**What it was.** The companion objectui#10163 entry routed the `record:line_items` panel's columns through the render pass the record-form containers share. The master-detail form's own child grid (`object-master-detail-form`) renders through the same line-items widget and read no field-level permission, so a child column the caller's permission set marks `editable: false` rendered as a live, editable cell — inviting an edit the server refuses. - -**What changed, in observable terms.** - -- Each child collection's columns now go through that same pass: a child column the caller may read but not edit renders its cells locked (on loaded rows and on the entry row alike), and a child column the caller may not read is omitted, exactly as the line-items panel does. Columns the caller may edit are unchanged. -- With no permission provider mounted the grid is exactly as before — every cell editable. That fail-open posture is objectui#10161's and is not moved here; the server still enforces. -- The per-row "expand to full form" editor is unchanged: it is a record form and already rendered through the form containers' pass. - -**Clause-②: no** — no exported symbol is added, removed, renamed or retyped, and no prop changes. No authored key changes meaning and no accept set is relaxed. diff --git a/.changeset/10166-record-form-save-during-upload.md b/.changeset/10166-record-form-save-during-upload.md deleted file mode 100644 index 83559d6450..0000000000 --- a/.changeset/10166-record-form-save-during-upload.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -'@object-ui/plugin-form': minor -'@object-ui/fields': minor -'@object-ui/i18n': minor ---- - -A record form can no longer be saved while an upload is still in flight (objectui#10166). - -A `file` / `image` value only becomes its fileId once the presigned upload settles. Until -now a record form had no notion of upload state at all, so a Save pressed during that -window wrote the record WITHOUT the attachment — and reported success. The user picked the -file, saw it listed and saved; there was no error, no warning, and the record looked saved. -Whoever noticed did so later, looking at a record that should have a file and does not. - -`onUploadingChange` (ADR-0059) already carried the signal, and had exactly one consumer, -`ActionParamDialog`. It could not have a second: that prop is per-widget, and a record form -hands a `fields` array to the `form` node renderer and never touches a widget, so there is -no point in the chain where it can attach a callback — and its upload controls can sit -inside a section, a tab or a line-items subform. - -`@object-ui/fields` therefore publishes the AGGREGATION beside the prop: `useUploadingScope` -(the host's "is anything below me uploading") and `UploadingScopeProvider`. -`useUploadingSignal` — also exported now, for widgets authored outside this repo — feeds -both sinks from the one call it already made, so the per-widget prop and the scope cannot -disagree, and a host that mounts no provider is unaffected. A widget that unmounts -mid-upload releases its slot, so a collapsing section cannot wedge Save shut. - -Nesting CHAINS rather than shadows: an inner scope gates its own Save AND reports itself to -the scope above. The direction is forced by `MasterDetailForm`, whose Save persists parent -and children in one batch while its rows are edited by nested `ObjectForm`s — a gate that -saw only the parent's uploads would refuse nothing while a child's attachment was in flight -and would still read as coverage. - -Every submit owner in `@object-ui/plugin-form` is gated: `ObjectForm`, `ModalForm`, -`DrawerForm`, `SplitForm`, `TabbedForm`, `WizardForm`, `MasterDetailForm`, and -`EmbeddableForm` through the `ObjectForm` it hosts. While an upload is in flight each -refuses the submit (which is also the keyboard-submit guard), labels Save "Uploading…", and -renders the reason as a sentence — `form.uploadInFlight`, new in all ten locale packs. The -hosts that own their Save button — `ModalForm`, `DrawerForm`, `MasterDetailForm`, and -`WizardForm`'s final step — disable it as well; the flat `ObjectForm`, `SplitForm` and -`TabbedForm` paths submit through the `form` node renderer in `@object-ui/components`, which -exposes no per-button disable, so there the refusal plus the label and the notice are what -the user meets. - -`WizardForm` is gated on its FINAL commit only. Moving between steps writes nothing, so -`Next` is deliberately untouched — but note that leaving a step unmounts its widgets, so an -upload in flight is released by the unmount and its value never reaches the record. That -loss predates this change and is not addressed by it. diff --git a/.changeset/10167-formpage-file-field-arm.md b/.changeset/10167-formpage-file-field-arm.md deleted file mode 100644 index 5f5e47e102..0000000000 --- a/.changeset/10167-formpage-file-field-arm.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/console': patch ---- - -fix(console): a `file` field on a FormView renders the shared upload control, not a text box - -`/f/:slug` and `/forms/:name` render through `FormPage`, whose hand-rolled input -switch had no `file` arm — so a `file` field fell through to the default text -input. Typing a filename into a text box uploads nothing, which made the -capability absent on those two routes rather than merely degraded. - -The arm does not hand-roll a second file control. It asks ADR-0059's resolver -(`resolveFormWidgetType` + `getLazyFieldWidget` in `@object-ui/fields`, the door -`@object-ui/app-shell`'s `ActionParamDialog` is already on) for the same widget -the record form renders, so the value this route submits is the one the other -renderer submits: the `sys_file` id the upload adapter minted, or the legacy -inline blob when the adapter surfaced none. - -Two supporting halves, both in the same file. The object field's declared -`multiple`, `accept` and `maxSize` now reach the widget — this app's narrowed -view of the object payload admitted none of the three, so the control would have -been single-file, unfiltered and unbounded whatever the author wrote. And submit -is blocked while an upload is in flight, which is what the widget contract's -`onUploadingChange` exists for: a file's value only becomes an id once the -adapter settles, so a submit that beats it stores nothing and still reports -success. - -⛔ The other field types this switch does not spell are untouched. Which ones -those are is enumerated on objectui#10167, for the separate decision about -whether this renderer should hold a switch at all. - -⚠️ **Dated note, 2026-09-27 — a no-id pick is now refused in the widget, not submitted as an inline blob — objectui#7699.** - -The paragraph above describes this route's write at the time it was written. Since objectui#7699, a pick whose adapter surfaced no id is refused in the widget and never submitted as an inline blob; the value this route submits is only ever the `sys_file` id the upload adapter minted, never the legacy inline blob. The rest of this entry is kept as the reading of this change; objectui#7699's own changeset states what a no-id pick does now. diff --git a/.changeset/10176-formpage-retired-type-pin.md b/.changeset/10176-formpage-retired-type-pin.md deleted file mode 100644 index eac8e32bec..0000000000 --- a/.changeset/10176-formpage-retired-type-pin.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Test-only in `@object-ui/console`: a new suite pins that a `FormPage` row whose `type` is a retired field-type spelling (objectui#4814's `owner`) renders the tombstone that refuses it visibly, and no editable control, on both the `/forms/:name` and `/f/:slug` routes (objectui#10176). The behaviour itself shipped with objectui#10457, which moved the page's field switch onto the shared resolver; this change adds only the test, and no package is released by it. diff --git a/.changeset/10178-formpage-required-marker-aria-hidden.md b/.changeset/10178-formpage-required-marker-aria-hidden.md deleted file mode 100644 index aca53d5c30..0000000000 --- a/.changeset/10178-formpage-required-marker-aria-hidden.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/console': patch ---- - -fix(console): `FormPage`'s required `*` no longer lands in the control's accessible name - -`/f/:slug` and `/forms/:name` render through `FormPage`, which draws the required -marker as a `*` inside the field's `label`. The label is the control's accessible -name, so a screen reader announced "Title *" instead of "Title". The marker is -now `aria-hidden`, the rule `ActionParamDialog` already follows (objectui#3299): -the requirement is announced as a state on the control, and the `*` is for -sighted users only. - -The text-like, number, date/time, select and textarea controls already carried -native `required`, and the `file` control `aria-required`, so they still announce -it. The checkbox control carried neither, so it now gets `aria-required`. It does not get native `required`: on a checkbox -that means "must be checked", and the required rule counts `false` as a value. diff --git a/.changeset/10179-formpage-shared-field-resolver.md b/.changeset/10179-formpage-shared-field-resolver.md deleted file mode 100644 index 380727d98c..0000000000 --- a/.changeset/10179-formpage-shared-field-resolver.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/console': minor ---- - -The form routes `/f/:slug` and `/forms/:name` render every field with the widget the shared field resolver names for it — the same widget the record form renders (objectui#10179, objectui#10177). - -Until now `FormPage` drew its controls with its own switch on the field type. The switch covered only some of the declared field types, and every other type rendered as a plain text box: `image`, `lookup`, `percent`, `richtext`, `signature` and more, with no error or warning. It also never read a field's `widget` key, so `object-ref`, `filter-condition` and `recipient-picker` could not be reached on these routes, and it ignored `multiple` on a `select`. - -Now each row goes through `resolveFormWidgetType` and `getLazyFieldWidget` from `@object-ui/fields`. An authored `widget` wins over `type`, and the form view's `widget` wins over the object field's. A `select` with `multiple: true` renders the multi-select widget. The row label reaches the widget according to the widget's own labelling declaration, so a required boolean is named by its label once, not twice. A required radio group is now reachable by its label and exposes its required state. - -Some behaviour changes with the widgets: - -- Required is announced with `aria-required` and not the native attribute, so the page checks required rows itself before submitting. It refuses a submit that leaves a visible, editable required row empty, and names the empty rows. `false` counts as a value. An untouched required boolean holds no value and is refused, as the record form refuses it. -- Values are whatever the shared widgets emit. For example, a multi-value select submits an array, and a date-time field submits the value the shared date-time widget produces. -- Field types that `@objectstack/spec` does not declare, such as `long_text`, `paragraph`, `integer`, `picklist` and `timestamp`, get the resolver's `text` fallback. Before, the old switch drew a dedicated control for them. -- The page shell is unchanged: public and internal loading, the submit target, the post-submit behaviour, `?recordId=` prefill, `redirect` and `visibleWhen`. diff --git a/.changeset/10179-textfield-maxlength.md b/.changeset/10179-textfield-maxlength.md deleted file mode 100644 index 26ab4f17da..0000000000 --- a/.changeset/10179-textfield-maxlength.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -`TextField` renders the declared `maxLength` as the `maxlength` attribute of its input, or of its textarea when the field has `rows` above 1 (objectui#10179). - -`FieldSchema` in `@objectstack/spec` declares `maxLength`, and `TextAreaField` already honoured it, but the single-line text widget never read it. Its DOM props pass through `toDomProps`, which forwards no `maxLength`, so no host could supply the limit either. Any host that renders the widget directly accepted input past the declared limit: the console's `/f/:slug` and `/forms/:name` form routes, `ActionParamDialog`, and `BulkActionDialog`. The record form was not affected, because it enforces the limit as a validation rule. A field that declares no `maxLength` renders no attribute, as before. diff --git a/.changeset/10180-wizard-next-keeps-upload.md b/.changeset/10180-wizard-next-keeps-upload.md deleted file mode 100644 index c646b383f9..0000000000 --- a/.changeset/10180-wizard-next-keeps-upload.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/fields': patch -'@object-ui/plugin-form': patch ---- - -A wizard no longer writes a record without a file whose upload was still running when the user -pressed Next (objectui#10180). - -To reproduce: pick a file on a wizard step, press Next before the upload finishes, then press -Create on the last step before the upload settles. The record was written WITHOUT the attachment -and the wizard reported success. - -The upload itself was never cancelled. `FileField` and `ImageField` do not abort an upload -when their step unmounts, and when it finishes the value still reaches the form. What went -missing was the upload's REPORT. A widget publishes "an upload is in flight" as its own -React state, so leaving the step unmounted the widget and ended the report while the -upload kept running. The final-commit gate objectui#10166 put on the wizard then read -"nothing uploading": Create was enabled and labelled "Create", and pressing it in that -window wrote the record before the file arrived. - -`FileField` and `ImageField` in `@object-ui/fields` now also hold the enclosing uploading -scope for the upload's own lifetime; `FileCell`, the line-item grid cell, does not. The hold -is taken when the upload starts and released once the upload settles, whether or not the -widget is still mounted: after the value has been handed to the form when it succeeds, and -on a failure too. While a file from an earlier step is still uploading, the wizard gives the -same answer objectui#10166's gate gives for any other in-flight upload. Create reads -"Uploading…" and is disabled, the wizard shows the reason it already gives, and a submit -that reaches it anyway is refused, not queued. A Create pressed once the upload settles -writes the record with the file. `Next` is not gated, and no new element or message is -introduced: the label and the reason are the ones objectui#10166 added. - -No exported symbol, prop or type changes. `useUploadingScope().anyUploading` now stays -true until an upload that `FileField` or `ImageField` started inside the scope has settled, -instead of going false when that widget unmounts. A widget that publishes only through the -exported `useUploadingSignal` still releases its report when it unmounts, as before, so an -upload such a widget leaves running after it unmounts is not visible to the scope. A hold -can last only as long as its upload is unsettled, which is the same limit a mounted widget's -report already has. diff --git a/.changeset/10183-date-only-shared-parse-step.md b/.changeset/10183-date-only-shared-parse-step.md deleted file mode 100644 index 961f73dcc3..0000000000 --- a/.changeset/10183-date-only-shared-parse-step.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/components': patch -'@object-ui/plugin-detail': patch -'@object-ui/app-shell': patch -'@object-ui/fields': patch ---- - -A date-only value now renders the calendar day it names, west of UTC, at four more places (objectui#10183). - -**Clause-②: yes** — `@object-ui/core` gains one export, `toDisplayDate(value)`: the parse step every date formatter in `utils/date-display.ts` already went through, now reachable by a caller that formats with its own `Intl` options or compares a value with today. Nothing else is added, removed, renamed or retyped, and `@object-ui/fields` does not re-export it. - -**What it was.** objectui#10110 repaired the shared date path: a date-only value such as `2026-08-01` is UTC midnight to the JavaScript engine, so reading it back in the viewer's zone lost a day west of UTC. The repair rebuilt such a value at local midnight inside the shared formatters, but four places never reached it. `data-table`'s default cell face parsed the string into a `Date` first, and the shared step leaves a `Date` alone. The record summary chip, the record History tab and the `date` cell's overdue colouring each parsed the value themselves. Measured in `America/Los_Angeles`: `2026-08-01` rendered `Jul 31` in a table cell, `2026年7月31日` on a zh-CN summary chip and `7/31/2026` in History, and a deadline falling today read `Today` in red. - -**What changed, in observable terms.** - -- A `data-table` cell with no cell renderer hands the string to `formatDate` / `formatDateTime`. This also covers a related list whose child object schema is unavailable, since its cells fall back to that face. -- The summary chip and the History tab take their `Date` from `toDisplayDate`. Their faces are unchanged: the chip keeps `dateStyle: 'medium'`, History keeps the locale's default numeric date. -- The `date` cell's overdue colouring compares the day `toDisplayDate` names, so a deadline falling today is no longer red west of UTC. The cell's text was already right, and its hover title is unchanged. -- ⚠️ The summary chip's and History's `datetime` arms share that parse, so they follow the shared path's rule: the value's shape decides, never the field's type. An instant still converts into the viewer's zone. A date-only value stored on a `datetime` field now reads as local midnight of its day, as `formatDateTime` already rendered it; before, it read as the previous evening west of UTC and as a morning hour east of it. - -In UTC every face is byte-identical to before. East of UTC every date face and the overdue colouring are too; only that `datetime`-arm reading of a date-only value moves there. diff --git a/.changeset/10184-record-verdict-memo-forgets-changed-record.md b/.changeset/10184-record-verdict-memo-forgets-changed-record.md deleted file mode 100644 index 19f70b8588..0000000000 --- a/.changeset/10184-record-verdict-memo-forgets-changed-record.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -'@object-ui/plugin-detail': patch -'@object-ui/plugin-grid': patch ---- - -fix(plugin-detail,plugin-grid): the record-grained write verdict is forgotten when -its record changes, and the row kebab's memo is per principal (objectui#10184). - -Two hooks ask the explain engine (`POST /api/v1/security/explain`) whether the acting -user may update or delete a record, and memoise the answer at module scope so -revisiting a record is free: `useRecordEditable` in `@object-ui/plugin-detail` (the -detail header, the drawer and the console record page) and `useRecordCrudVerdicts` in -`@object-ui/plugin-grid` (the list row's kebab). - -**Same principal, changed record.** objectui#10107 made the detail header's memo per -principal, but a verdict cached for one principal was still served after the record -changed under that same principal — ownership moved, a share granted or revoked — so -the record's new owner re-opening it in the same tab was still told no, and a -principal who had just lost access was still offered Edit. Both memos now listen to -the data-invalidation bus the writers already announce on (`notifyDataChanged`, and -every `DataSource` write through `useMutationInvalidationBridge`) and drop exactly -what a change stales, by the bus's own matching rule: a record-scoped change drops -that record's entries for both operations, an object-scoped change drops the -object's, `'*'` drops everything. A mounted hook asks again in place — the list only -for the rows that lost their answer — and an answer that was in flight when its -record changed is not cached. - -**The row kebab, cross-principal.** `useRecordCrudVerdicts` carried the identical -un-principalled memo objectui#10107 repaired in the detail header: keyed -`object:recordId:operation`, it answered the next principal to sign in in the same -tab from the previous one's verdicts, in both directions — a `false` hid the kebab's -Edit from a user the server lets write the row, and a `true` offered it to one the -server refuses. It now keys by the acting principal exactly as the detail header does -and drops the map when the principal changes, so the two surfaces keep answering a -record identically. - -What this does not make fresh, and says so at the site rather than implying it: a -grant or revocation made in another tab, by another user or by the server itself is -never announced in this tab, and a grant stored as a row of another object (a -record-share row, a permission-set assignment) is announced against that object, not -the record it grants — both land on the next page load. No lifetime constant was -added to paper over that. - -Unchanged: the fail-open contract on an unknown answer (ADR-0124 D1 — the server -enforces, the client is courtesy), the request shapes, the probes' authenticated -channel, and the memo itself while nothing changes. diff --git a/.changeset/10186-related-list-fls-select.md b/.changeset/10186-related-list-fls-select.md deleted file mode 100644 index 9522de6bed..0000000000 --- a/.changeset/10186-related-list-fls-select.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -fix(plugin-detail): a related list's row fetch drops a column the principal cannot read once the permission answer has loaded - -`RelatedList`'s auto-fetch sent no `$select`, so every field of every child row -was requested and a field that field-level security denies was dropped only at -the column layer, after its value had already crossed the wire. A list with -authored `columns` now sends a `$select` built from the authored columns that -pass the same redaction, parent-key and FLS gates the column layer applies (one -shared spelling of each), plus `id`, the `$expand` roots, and, once the child -schema has loaded, the fields its row predicates read (the child object's -`userActions` Edit/Delete overrides, its actions and the host's row actions), -plus the mobile card gallery's cover field when the child declares it and FLS -allows it. -FLS drops a denied column once the permission answer has loaded; a request sent -before it can still carry that column, the same deferral `ObjectGrid` has. That -is the projection shape `ListView` and `ObjectGrid` already send (objectui#6898, -objectui#3501). - -Graded as defence in depth: ObjectStack's server already strips denied fields -from every returned row (`FieldMasker`), so nothing leaked from that backend. The -projection matters for a backend that does not strip. - -An authored list whose every column is denied now asks for `id` (plus predicate -operands) rather than reading the emptied column list as "no restriction". - -Unchanged: a list that derives its columns, with no authored `columns` or with -redaction emptying them, still sends no projection. Its columns come from -`highlightFields` or the field walk, and both are chosen by the emptiness of the -rows fetched, so they are not known before the fetch. - -Behaviour to know about on the authored path: on a backend that honours -`$select`, rows now carry only the projected fields. A row action that reads a -row field through something other than a `visible` / `disabled` predicate or -`recordIdField`, such as a `defaultFromRow` parameter or a `{field}` token in its -URL, only gets that field if the projection already carries it (a column, `id`, -or another predicate's operand). `ListView` and `ObjectGrid` already behave this -way. - -⇒ Narrowed in this same release by objectui#10277: the harvest now also names -the row key a `defaultFromRow` parameter seeds from and every bare-identifier -`{field}` token in an action's `target`, through the same declared-field and FLS -gates, so on all three surfaces those two no longer rely on the projection -already carrying the field. (Noted here by the objectui#10277 seat, because this -body publishes verbatim into the CHANGELOG and the paragraph above would -otherwise describe a gap the same release closes.) diff --git a/.changeset/10188-app-shell-doc-menu-audience.md b/.changeset/10188-app-shell-doc-menu-audience.md deleted file mode 100644 index ce2b93c034..0000000000 --- a/.changeset/10188-app-shell-doc-menu-audience.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -feat(app-shell): the sidebar and `nav:menu` hide a `doc` entry the member may not read (objectui#10188) - -A `type: 'doc'` navigation entry is drawn only when the member can read what it opens: - -- a page — the member's `doc` list names it; -- a book — the member's `book` list names it, or the name is a package one of the member's - readable docs comes from (the implicit per-package book); -- a page in a book — both. - -Those lists are the server's per-member answers (ADR-0046 §6.7 prunes both), read through the -shell's metadata cache, once per type and only when the navigation holds a `doc` entry. No -`audience` is read in the browser. While a list is still loading, or failed to load, nothing -is hidden: the app the server sent stands. - -On a current server this changes nothing a member sees. The server's app read already leaves -such an entry out (objectstack#19790). The menu's own pruning is the defence in depth that -ruling keeps behind it, for an app document that still carries the entry. diff --git a/.changeset/10188-console-docs-direct-route.md b/.changeset/10188-console-docs-direct-route.md deleted file mode 100644 index 59809b9fe3..0000000000 --- a/.changeset/10188-console-docs-direct-route.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/console': minor ---- - -feat(console): the docs portal refuses a doc or book the member may not read, and opens a doc in the book that claims it (objectui#10188) - -- **A refusal, not "not found".** A member outside a doc's or a book's audience who opens its - direct URL — `/docs/DOC`, `/docs/BOOK` or `/docs/BOOK/DOC`, also under an app's - `/apps/PACKAGE/docs` — now sees "You do not have access to this documentation" with the - server's reason. Before, the flat routes said the doc "is not installed" and the reader said - "Failed to load documentation". The server answers such a member 401 / 403 and an absent - name 404; the portal now keeps the two apart. A segment the member's own lists do not answer - is asked about once, by name (the doc, then the book). A name nothing carries still shows - "Documentation not found". -- **The claiming book.** In a package with several books, a flat doc permalink (what a - `{ type: 'doc', doc }` menu entry links to) opens the page in the book that claims it, - with that book's sidebar. Before, it opened in the package's first book by label, where the - page is only an uncategorized orphan. A page no book of its package claims opens in the - package's first book, as before. diff --git a/.changeset/10188-doc-markdown-editor.md b/.changeset/10188-doc-markdown-editor.md deleted file mode 100644 index 64c86116ed..0000000000 --- a/.changeset/10188-doc-markdown-editor.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -feat(app-shell): Studio has a Markdown editor for `doc` items, with a live preview and book placement (objectui#10188) - -An admin can now write a documentation page in Studio. Creating or opening a `doc` -(ADR-0046) in the metadata admin shows a Markdown source pane beside a live preview, -rendered by the same `markdown` renderer the docs portal uses, so the page reads the way -readers will see it. Before, the generic form offered the body as a one-line text input -with no preview. - -The editor writes only keys `@objectstack/spec`'s `DocSchema` declares, and saves through -the standard metadata write door (`PUT /meta/doc/:name`) like every other type: - -- **Title and body** — the create form asks for the title (`label`), suggests the `name` - from it, and the body (`content`) is written in the source pane. -- **Locale variants** — a variant is an entry of `translations`, as the spec models it. - A new variant starts as a copy of the default body, because an empty variant is served - to that locale's readers as an empty page. -- **Book placement** — a book stores no members; a doc joins a book group through its own - `group` key (ADR-0046 §6.2.1). The editor lists every book's sections, writes the one - picked, and shows where the doc will appear, computed with the spec's `resolveBookTree`, - including placements a group's name or tag rule makes on its own. A book section key is - not unique to one book, so every book that uses the key is listed, and a public book is - marked as such. - -The metadata admin also has a label for the `doc` type in English and Chinese -("Documentation" / "文档"). diff --git a/.changeset/10188-layout-doc-target-guard.md b/.changeset/10188-layout-doc-target-guard.md deleted file mode 100644 index d201bc6a00..0000000000 --- a/.changeset/10188-layout-doc-target-guard.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/layout': minor ---- - -feat(layout): a host can hide a `doc` navigation entry the member may not read (objectui#10188) - -`NavigationRenderer`, `AppSchemaRenderer` and `hasVisibleNavigationItems` take an optional -`checkDocTarget` — a `DocTargetChecker`, asked `{ book, doc }` for each `type: 'doc'` entry. -An entry it answers `false` for is not drawn, is not collected into Favorites, and does not -make its area count as visible: it joins the one guard statement the other item guards -already share. Without it, `doc` entries draw as before. - -It is defence in depth. The server is the enforcer (ADR-0046 §6.7): its app read already -leaves out a `doc` entry the member may not read. This layer holds no audience rules, so the -host answers from the member's own doc / book reads. `DocNavTarget` and `DocTargetChecker` are -exported. `CapabilityChecker` is unchanged: it asks whether the runtime has a target, and this -checker asks whether the member may read it. diff --git a/.changeset/10190-drawerform-first-load-window.md b/.changeset/10190-drawerform-first-load-window.md deleted file mode 100644 index 8c910605e0..0000000000 --- a/.changeset/10190-drawerform-first-load-window.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): `DrawerForm` no longer paints an editable form before the record it edits has loaded - -Opening an edit drawer showed the form empty and editable while the record read -was still in flight, and when the record arrived it replaced whatever had been -typed there — the value was gone from the screen and from the save, with no -warning. The drawer already refused this when switching from one record to -another; it now refuses it on the first load too, keeping its loading state -until the record read lands. - -`DrawerForm` builds its fields and reads its record in two effects that both run -when the object schema arrives. The field-building effect used to end the -loading state unconditionally; it now leaves that to the record read whenever -one is outstanding. diff --git a/.changeset/10193-language-reset-on-owner-change.md b/.changeset/10193-language-reset-on-owner-change.md deleted file mode 100644 index 1347788587..0000000000 --- a/.changeset/10193-language-reset-on-owner-change.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/auth': minor -'@object-ui/app-shell': patch -'@object-ui/console': patch -'@object-ui/i18n': patch ---- - -fix(auth,app-shell,console): a browser that changes hands no longer keeps the previous account's UI language - -Both device language slots (`objectui-locale` and `objectui-locale-seed`) hold the -language of whoever last signed in on the browser. A boot resolves its language from -them before anyone is signed in. When the session then turns out to belong to someone -else (an SSO redirect back into the console, or a sign-in in another window), -`SessionUserScope.adopt` already purged both slots (objectui#5664). But the live -language had already been derived from them, and nothing re-derived it. A new account -with no `sys_user.locale` of its own therefore read the previous account's language -for its whole first session. - -- `@object-ui/auth` (new exports, hence minor): `getSessionOwnerChangeCount()` and - `subscribeSessionOwnerChange(listener)` report that the change-of-owner purge ran - in this page-load. They are held in memory, with no new storage key. - `SessionUserScope.adopt` now returns `true` when it purged a previous owner. -- `@object-ui/app-shell`: `useSignedInUserLocale` resets the UI language on an owner - change, the same way a boot of the swept storage would resolve it. It then - re-reads the new owner's `sys_user.locale`, which applies after the reset. -- `@object-ui/console`: `LocalizationFetchProvider` and the boot-time seed fetch no - longer write an answer that was requested before an owner change. Such an answer - describes the previous owner. -- `@object-ui/i18n` (docs only): the seed was documented as the "tenant's" locale. - It is the server's resolved locale for the signed-in caller: their own - `sys_user.locale`, else `Accept-Language`, else the deployment default. The docs - now say so, and declare what a visitor who has not signed in reads: the last - owner's language, until someone else signs in. diff --git a/.changeset/10199-related-list-filter-rule-array.md b/.changeset/10199-related-list-filter-rule-array.md deleted file mode 100644 index 5b68785aa8..0000000000 --- a/.changeset/10199-related-list-filter-rule-array.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`record:related_list`'s top-level `filter` is declared as the protocol's rule array on -the authoring face, not as `any` (objectui#10199). - -`RecordRelatedListComponentProps.filter` mirrored `@objectstack/spec`'s -`RecordRelatedListProps.filter` (declared there as `z.array(ViewFilterRuleSchema)`, -"Additional filter criteria for related records") as `any`. The face an author, or an -AI writing metadata, reads therefore said "anything" for a key the protocol -constrains. It now declares `ViewFilterRule[]`, the same type the interface already -imports for `add.picker.filter` (objectui#9964). - -**Breaking for TypeScript authors, released as `minor`** under this repo's -version-alignment rule (the fixed group's major follows `@objectstack`, so a break of -objectui's own surface is declared `minor` with the break spelled out here). Code that -annotates a value with `RecordRelatedListComponentProps` and assigns a non-array -`filter` to it stops compiling: an array of `[field, operator, value]` tuples, an -ObjectQL AST node such as `['and', …]`, a MongoDB-style record, a filter expression -string, or a single rule object outside an array. The protocol's parse already refuses -every one of those shapes on this key, so no metadata that could be published changes -meaning. - -Migration: author the rule array, `[{ field, operator, value }]`; the composed node is -runtime-only. - -The consumer keeps its wider type on purpose. `@object-ui/plugin-detail`'s -`RelatedList` still declares `ViewFilterRule[] | FilterNode` for the same key, because -`ElementDataSourceGate` writes the composed component-AND-view-AND-binding filter onto -it at runtime, after resolving a `dataSource` binding. That composed node is not an -authorable shape, so the authoring face does not publish it. Nothing changes at -runtime: `any` and `ViewFilterRule[]` are the same bytes, and the gate's write never -went through this interface. diff --git a/.changeset/10207-package-version-from-spec.md b/.changeset/10207-package-version-from-spec.md deleted file mode 100644 index 8103f4f0ae..0000000000 --- a/.changeset/10207-package-version-from-spec.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -The package dialog judges a version with the installed `@objectstack/spec`'s own `ManifestSchema` version field instead of a hand-copied regex, so it accepts exactly what the spec accepts. No change on spec 17.4.0; once a spec release adopts the SemVer 2.0.0 canon (objectstack#18697), prerelease and build versions such as `2.0.0-beta.1` are accepted without a change here. diff --git a/.changeset/10209-readonly-view-menus-not-empty.md b/.changeset/10209-readonly-view-menus-not-empty.md deleted file mode 100644 index eb6be31d5f..0000000000 --- a/.changeset/10209-readonly-view-menus-not-empty.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -fix(plugin-view): a read-only view's menus no longer open empty or on a leading separator - -`ManageViewsDialog`'s row `…` trigger rendered whenever a callback was wired, while -every entry under it was also gated on the view being editable. On a read-only row -with the console's props (no `onDuplicate`), the trigger opened an empty 180px strip of -popover. `ViewTabBar`'s tab dropdown and context menu drew each separator on its own -condition, so a read-only tab's menu opened on a separator above "Manage all views…"; -a read-only tab with no `onManageViews` opened an empty dropdown and an empty context -menu. - -Each menu now resolves its entries once. The trigger renders only when at least one -entry renders, and a separator is drawn only between two groups that both rendered. -Editable views keep every entry they had. `ManageViewsDialog` no longer offers Rename -(menu entry or double-click) when the host wires no `onRename`, since committing it -would call nothing. diff --git a/.changeset/10210-overlay-marker-only.md b/.changeset/10210-overlay-marker-only.md deleted file mode 100644 index 9b7639d969..0000000000 --- a/.changeset/10210-overlay-marker-only.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/data-objectstack': patch ---- - -Views that an earlier "Edit view config → Save" made read-only recover on read, and keep -their edits (objectui#10210). - -A view row now counts as a personalization overlay only when it carries the `_isOverride` -marker. The view list used to treat a flat row carrying `viewKind: 'list'` as an overlay -too, a shape guess kept for toolbar rows written before the marker existed. A config save -on a code-defined view stored exactly that shape, so the view dropped out of the saved -views and its tab turned read-only, for good once the draft was published. With the guess -retired, such a row reads back as the saved view it is: its tab is editable again and shows -what the save stored. Nothing is rewritten at rest; the next read is enough. - -⚠️ This exposes one class of row: overlay rows written before the marker -(objectui#4227, closed 2026-08-15) and never touched since. They have the same shape, so -they now also read as plain rows, and their frozen label, columns and filter copy covers -the code definition again. No deployment is named as holding one. diff --git a/.changeset/10210-view-config-save-envelope.md b/.changeset/10210-view-config-save-envelope.md deleted file mode 100644 index aee1e60c82..0000000000 --- a/.changeset/10210-view-config-save-envelope.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -Saving a view's config no longer turns the view read-only (objectui#10210). - -"Edit view config → Save" on a code-defined view used to store the flat view the -panel edits. The platform then copies `viewKind: 'list'` onto that row from the -code definition it shadows, and a flat row carrying `viewKind` was the shape the list -reader treated as a personalization overlay: the view dropped out of the saved views, -every mutating entry vanished from its tab menu except "Manage all views…", and -publishing the draft made that permanent. - -The save now stores the same ViewItem envelope — `{ name, object, viewKind: 'list', -label, config }` — that creating a view already stores, under the same view name as -before, so the view keeps all six menu entries through draft preview, publish and -later toolbar changes. Its `config` holds only the keys a list view declares (the -platform refuses an envelope whose `config` carries the panel's own `id` or -`isDefault`), and the view's default flag, pin, order, visibility and column widths -are kept beside it. - -Reopening the panel on a view with an unpublished change now resumes that change and -saves it back to the same view. Before, a stored envelope lost the view's identity on -the way into the panel and the next Save wrote nothing. A change saved before this -release is still stored flat and still resumes. - -Views that an earlier save already made read-only are repaired on read, edits kept, -by the `@object-ui/data-objectstack` change for objectui#10210: the list reader no -longer treats that shape as an overlay unless the row carries the `_isOverride` -marker. diff --git a/.changeset/10211-connector-refinement-behavioural-pin.md b/.changeset/10211-connector-refinement-behavioural-pin.md deleted file mode 100644 index 5100511cc5..0000000000 --- a/.changeset/10211-connector-refinement-behavioural-pin.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Test-only change to the app-shell binding-parity pin for `connector` (objectui#10211): it now asserts the ADR-0097 refinement by behaviour instead of counting `_zod.def.checks`, plus one comment-only sentence in `clientValidation.ts`. No published behaviour changes. diff --git a/.changeset/10220-format-hint-not-date-pattern.md b/.changeset/10220-format-hint-not-date-pattern.md deleted file mode 100644 index 0f722f32b3..0000000000 --- a/.changeset/10220-format-hint-not-date-pattern.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -fix(plugin-dashboard): a field's `format` is read as a date pattern only on a `date` / `datetime` field - -The dashboard table (`object-data-table`) and the record-detail drawer render a -value through `renderFieldValue`, whose date branch fired on any `format` string -containing one of the letters Y, M, D, H, m or s, whatever the field's type. A -text field hinted `format: 'email'` — which the shared cell-renderer resolver -promotes to a `mailto:` link — contains an `m`, so its address went to -`formatDate` and was painted as an em dash: the value disappeared. A text field -hinted `format: 'money'` holding a number rendered as a 1970 date, an -`autonumber` pattern with date tokens such as `ORD-{YYYYMMDD}-{00}` and a `time` -field's `HH:mm` rendered as an em dash, all with no error. - -The branch now runs only when the field's type is `date` or `datetime`. Those -fields render exactly as before. A field of any other type no longer takes the -date branch and falls through to the cell renderer its type and `format` hint -select; the currency and percent branches ahead of it are unchanged. A column whose field -type is unknown — no object-schema field and no `type` on the column — is no -longer date-formatted from its `format` alone: declare `type: 'date'` on the -column to keep the date face. diff --git a/.changeset/10221-currency-decimals-iso-minor-unit.md b/.changeset/10221-currency-decimals-iso-minor-unit.md deleted file mode 100644 index f375d46cbc..0000000000 --- a/.changeset/10221-currency-decimals-iso-minor-unit.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -'@object-ui/plugin-grid': minor -'@object-ui/plugin-dashboard': minor -'@object-ui/app-shell': minor ---- - -The grid summary footer and the dashboard metric tile take a currency amount's -decimal places from the currency, never from `scale`, and the field designer no -longer offers `Scale` on a currency field (objectui#10221). - -The currency arm of the grid column-summary footer (`useColumnSummary` in -`@object-ui/plugin-grid`) and the currency face of `ObjectMetricWidget` in -`@object-ui/plugin-dashboard` each took the number of decimal places from the -field's `scale`, with none when `scale` was absent. The currency list cell -never read `scale`. So a USD column declaring no `scale` totalled -`1234.5` as `$1,235` under cells reading `$1,234.50`, and a JPY field carrying -`scale: 4` showed `¥1,234.5000`. - -Both faces now format an amount in a resolved currency with `formatCurrency` -from `@object-ui/fields`, the list cell's own formatter, so footer, tile and -cell agree. The width is the resolved currency's own ISO 4217 minor-unit count: two -decimals for USD or CNY, none for JPY, three for KWD. A whole amount shows no -fraction (`$1,234`), as the cell does. When no currency resolves, the amount is -a plain number with two decimals, or none when it is whole, as the cell renders -it. Neither `scale` nor -`precision` is read on a currency. This follows the maintainer ruling recorded -on objectstack-ai/objectstack#19910 that a currency's decimal places are the -currency's, not a setting, and the ruling on objectstack-ai/objectstack#19629 -that takes `scale` off the `currency` type. The footer keeps its existing -tenant-locale fallback for a currency code `Intl` does not accept, and a metric -tile with an authored `format` pattern still renders that pattern. - -The field designer's numeric section (`ObjectFieldInspector` in -`@object-ui/app-shell`) no longer offers a `Scale` control on a `currency` -field. `number` and `percent` fields keep it. The `Precision` control stays on -all three: it writes the field-level `precision`, the total digit count of the -stored decimal, not a number of decimal places. - -**Behaviour change** for currency amounts on the footer and the tile, filed as -`minor` because this repo's fixed release group forbids `major`. Where the -field's `scale` differed from what the cell renders, the output moves: - -- `scale: 2` on a JPY field used to show `¥1,234.50` and now shows `¥1,235`. -- A USD field with no `scale` used to show `$1,235` for `1234.5` and now shows - `$1,234.50`. -- A whole USD amount under `scale: 2` used to show `$1,234.00` and now shows - `$1,234`, like the cells. - -Percent columns and fields still take their width from `scale`. - -**Migration.** Nothing to restate: a currency amount's decimal places follow its -currency. Delete `scale` from currency fields. A dashboard that wants a fixed -pattern on a metric tile declares it with `format`. - -⚠️ **Dated note, 2026-10-02 — the whole-amount sentences above were made false in this same release — objectui#11444.** -The sentences saying a whole amount shows no fraction (`$1,234`, "as the cell does"), that an amount with no currency resolved has no decimals when it is whole, and the bullet saying a whole USD amount under `scale: 2` now shows `$1,234`, no longer hold. Later in this release triage ruled that a currency's declared width, its ISO 4217 minor-unit count, is the protocol's convention, and `formatCurrency` stopped dropping the fraction of a whole amount (objectui#11444, comment 5946462862). The footer and the tile still take `formatCurrency` by reference, so they move with the cell: a whole USD amount reads `$1,234.00`, a whole amount with no currency resolved reads `1,234.00`, and a whole JPY amount still reads `¥1,234`. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10222-retire-timeline-metafields-reads.md b/.changeset/10222-retire-timeline-metafields-reads.md deleted file mode 100644 index 0b88a1cd0a..0000000000 --- a/.changeset/10222-retire-timeline-metafields-reads.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/plugin-timeline': minor -'@object-ui/plugin-list': minor ---- - -Retire the undeclared timeline `metaFields` reads in both packages (objectui#10222). - -The spec's `TimelineConfigSchema` is a strict object that declares no `metaFields` member and -refuses one, yet `ObjectTimeline` read it (through an `as any` cast) to pick the chip fields -beside each title, and `ListView` read it three times: two field collectors put the listed -fields into `$expand` / `$select`, and the status / priority auto-projection was skipped when -the list was present. All four reads are deleted. - -**Behaviour change:** a stored interface-page view carrying `options.timeline.metaFields` falls -back to the default card labels (the built-in `status` / `priority` chips, limited to the fields -the object declares), and the fields that list named are no longer fetched for it. No such view -has been found; the stored rows are not censused. A timeline without the key renders and fetches -exactly what it did before, because `ListView` now projects `status` / `priority` for every -timeline view. - -`cardFields` stays the reserved spelling if authored timeline chip fields are ever asked for; -nothing is declared. diff --git a/.changeset/10223-lookup-candidates-expand.md b/.changeset/10223-lookup-candidates-expand.md deleted file mode 100644 index 84822ea889..0000000000 --- a/.changeset/10223-lookup-candidates-expand.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): a lookup's candidate queries expand the reference columns they display - -Opening a lookup field's dropdown sent the candidate query without `$expand`. -Every reference column the dropdown previews under each candidate (by default -the referenced object's leading `highlightFields`) therefore arrived as a bare -foreign key, and the lookup cell renderer fetched each related record on its -own: one extra request per candidate per such column, on every open. The -browse-all picker (`RecordPickerDialog`) did the same once per table row. - -Both queries now ask for `$expand` on the reference columns they display, -chosen by `buildExpandFields` from `@object-ui/core` (the rule the list views -apply to their visible columns): the dropdown's previewed columns, and the -picker's columns other than its id column. The dropdown's recently-used rail -asks for the same expansion. Related records in the expanded columns now -render with no request per row. - -Field-level security gates that list the way it gates the other -`buildExpandFields` call sites: once the permission policy has loaded, a -reference column the user may not read on the referenced object is left out of -`$expand`; before the policy loads, nothing is filtered. `@object-ui/fields` -now depends on `@object-ui/permissions` for that check. A reference column -from a backend that ignores the parameter still arrives as a bare id and is -resolved one by one as before. A column the policy denies is not drawn at all, -and a field it denies is not shown in an option's label or in the picker's -title column (objectui#10373). - -`buildExpandFields` covers `user` columns as well as `lookup`, -`master_detail` and `tree`. A previewed `user` column therefore now shows the -person, as the picker table and the list views do, where it used to show the -raw id marked as unresolved. - -What the dropdown and the picker hand onward is built from each row with its -expanded relations collapsed back to ids, through `toPredicateRecord` from -`@object-ui/core`. That covers option labels, `titleFormat` titles, the -committed value, and the records passed to `onSelectRecord` and -`onSelectRecords`, so none of them carries an expanded object. One difference -remains: `toPredicateRecord` returns ids as strings, so a numeric foreign key -in an expanded column reaches those callbacks in its string form. diff --git a/.changeset/10224-quick-actions-permissions-text.md b/.changeset/10224-quick-actions-permissions-text.md deleted file mode 100644 index 9efee30e3c..0000000000 --- a/.changeset/10224-quick-actions-permissions-text.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -fix(plugin-detail): `record:quick_actions.requiredPermissions` publishes what the gate does — the contract's shared record-block describe, verbatim - -The `record:quick_actions` registration described `requiredPermissions` as "Hide -the whole bar unless the user holds these permissions". The renderer does not -hide the bar. It reads the ADR-0066 capability set, and when a declared -capability is missing it draws an insufficient-permissions notice where the bar -would be. When the client cannot resolve capabilities (no permission provider, -or a backend that does not report `systemPermissions`) it renders the bar. - -`@objectstack/spec` 17.5.0 gives this key one describe, shared with -`record:details`, `record:highlights` and `record:related_list`, and those three -already publish it. The quick-actions input now publishes the same text. It is -carried by `sdui.manifest.json`, and at runtime by -`ComponentRegistry.getConfig('record:quick_actions').inputs`. No input name, -type or shape changes, and no rendering or gating behaviour changes. diff --git a/.changeset/10226-image-upload-failure-reported.md b/.changeset/10226-image-upload-failure-reported.md deleted file mode 100644 index 1f5b318d5e..0000000000 --- a/.changeset/10226-image-upload-failure-reported.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): a failed image upload is reported in `ImageField`, not swallowed - -Both upload paths of `ImageField` — the native picker and the crop dialog's -confirm — ran the upload inside `try … finally` with no `catch`. Both are -invoked fire-and-forget (React ignores the promise an `onChange` handler returns, -and the cropper does not await `onConfirm`), so a rejected upload (a network -error, a 413, a storage outage) showed the user nothing and escaped as an -unhandled promise rejection. - -A failed upload now renders the same translated `fields.file.uploadFailed` -message `FileField` shows for the same failure, in the widget's existing error -row. The failed image is not added: on the picker path the other picks of a -multi-select still upload and land, as in `FileField`; on the crop path the -original image stays and the dialog closes so the message is visible. diff --git a/.changeset/10232-display-locale-faces.md b/.changeset/10232-display-locale-faces.md deleted file mode 100644 index 7c0e887354..0000000000 --- a/.changeset/10232-display-locale-faces.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/plugin-ai': patch -'@object-ui/i18n': patch ---- - -Two display-locale faces now follow the session's display locale (objectui#10232). - -- `@object-ui/plugin-ai` is wired to `@object-ui/i18n` as a whole. The `nl-query`, - `ai-form-assist` and `ai-recommendations` components read their strings from a new - `ai.*` namespace, translated in all ten locale packs, instead of hard-coded English. - The `nl-query` history date, which was formatted in the machine's locale, and the - confidence and score percentages now format in the display locale - (`useDisplayLocale()`). The package's manifest now names `@object-ui/i18n`, which also - puts it inside the repo-wide machine-locale census. -- `@object-ui/app-shell`: the Studio home page's "recently viewed" times and the Data - pillar's last-saved time format in the display locale. They used to be handed - `useMetadataLocale()`, which picks the designer's string table and is `en-US` for every - language other than zh, so a de-DE session read US English. That hook's doc comment - now says it must never be used as an `Intl` locale. diff --git a/.changeset/10235-spec-translation-bundle-recognised-by-any-group.md b/.changeset/10235-spec-translation-bundle-recognised-by-any-group.md deleted file mode 100644 index 251d4a83d2..0000000000 --- a/.changeset/10235-spec-translation-bundle-recognised-by-any-group.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/i18n': patch ---- - -fix(i18n): a translation bundle with no field label is recognised as a spec payload (objectui#10235) - -The console's `loadLanguage` asks `isSpecTranslationData` whether the payload it fetched is a -`@objectstack/spec` `TranslationData`. On `true` it transforms the payload and namespaces it under -`app`, where `useObjectLabel` and the screen-flow runner read it; on `false` it returns the payload -untouched, for a mock or local-dev server that already speaks i18next namespaces. The predicate -answered `true` only when some `objects` entry carried `fields`, so a genuine bundle that translated -object labels, apps, pages, dashboards or flows — and no field label — took the untouched branch, sat -at the root of the i18next resource tree, and was read by nothing: every screen drew the authored -copy in every locale, with nothing reported. - -`isSpecTranslationData` now answers `true` for a payload carrying any top-level group of the served -translation document — `objects`, `apps`, `messages`, `globalActions`, `dashboards`, `datasets`, -`pages`, `flows`, `settings`, `metadataForms` or `settingsCommon` — whose value is an object. The -console's own tests walk that group list off `@objectstack/spec`'s `GetTranslationsResponseSchema`, -so a group the spec adds and the predicate does not know fails a test instead of being dropped. - -An already-namespaced i18next tree still takes the untouched branch: its top-level keys are namespace -names (`common`, an app namespace such as `crm`, or the `app` the transform itself emits), none of -which is a spec group, and no built-in locale pack namespace is spelled like one. A group-named key -holding a string or an array is not treated as a group. - -What a user sees change: in the console, an app whose translation bundle carries no field label now -shows its translated object names, app and navigation labels, dashboard and page titles, and -screen-flow wizard copy, where it used to show the authored copy. diff --git a/.changeset/10242-ru-ar-count-labels.md b/.changeset/10242-ru-ar-count-labels.md deleted file mode 100644 index d5e2207d38..0000000000 --- a/.changeset/10242-ru-ar-count-labels.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/i18n': patch ---- - -Russian now reads correctly at every count on the tab-count badge's accessible -name and the activity-feed reaction chip, and Arabic on the badge and the comment -thread's count and reaction tooltip (objectui#10242). - -Each of these surfaces picks its `…One` key at exactly one and the plain key at -every other count. Two slots cover English. They do not cover Russian, which needs -three noun forms for whole numbers, or Arabic, which needs more. Where the plain key -held a single noun form, it was wrong at some of the counts it serves. A Russian tab -badge read `2 элементов` at two (the language needs `2 элемента`) and -`21 элементов` at twenty-one (it needs `21 элемент`), and a Russian reaction chip -read `2 реакций` at two. The Arabic badge, comment count and reaction tooltip used -the plural form for three to ten, which is wrong at two and from eleven up. - -The count-not-one half of these five values is now a count label that reads -correctly at any number: - -- `ru` `common.itemCount`: `Элементов: N` -- `ru` `detail.reactionCount`: the emoji, then `Реакций: N` -- `ar` `common.itemCount`: `عدد العناصر: N` -- `ar` `collaboration.commentCount`: `عدد التعليقات: N` -- `ar` `collaboration.reactionCount`: `عدد التفاعلات: N` - -That is the device objectui#10024 used for `search.resultsCountPlural`, and the one -Russian's `collaboration.commentCount` and `collaboration.reactionCount` already -use. The singular halves, the key set, the call sites and the other eight packs are -unchanged. - -⚠️ **Dated note, 2026-10-02 — superseded in this release — objectui#11445.** -Later in this same release the `…One` / plain-key switch on `common.itemCount`, -`detail.reactionCount`, `collaboration.commentCount` and -`collaboration.reactionCount` gave way to one count family per key in all ten -packs: a numeric count picks the noun form its CLDR category needs (`ru` -`2 элемента`, `21 элемент`), the `…One` siblings left every pack, and the count -labels above remain only on the base key, which answers a call made without a -count. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10247-retire-async-export-job-path.md b/.changeset/10247-retire-async-export-job-path.md deleted file mode 100644 index edf9a375ff..0000000000 --- a/.changeset/10247-retire-async-export-job-path.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/components': minor ---- - -**BREAKING: the unimplemented async export-job path is removed from `@object-ui/types` and `@object-ui/components`** - -What left: - -- `@object-ui/components`: the `useExportJob` hook with its `UseExportJobOptions` - and `UseExportJobReturn` types, and the `ExportProgressDialog` component with - its `ExportProgressDialogProps` type. -- `@object-ui/types` (the root entry and the `./data` subpath): the optional - `DataSource` members `createExportJob`, `getExportJobProgress`, - `cancelExportJob` and `getExportJobDownloadUrl`, and the types - `ExportJobStatus`, `ExportJobFormat`, `CreateExportJobRequest`, - `CreateExportJobResult` and `ExportJobProgressInfo`. None of them had a zod - mirror. - -Why: ruling letter A on objectstack#17158 decided to retire the export-job API -contract family from `@objectstack/spec`, because nothing serves it and -`IExportService` has no provider. The ruling sequences the objectui side first: -this change retires objectui's consumer side, rather than keeping it alive with -local copies of the spec's types (objectui#10247). The spec-side retirement -comes after this change; until it lands, `@objectstack/spec` still exports the -export-job contracts. - -No `DataSource` in this repository implemented any of the four methods. That -was measured at `d7de5348` over every class that implements `DataSource` and -every test double typed as one under `packages/`, `apps/` and `examples/`, with -the synchronous `exportDownload` member as the control that did match. So -`useExportJob` could only ever report `isSupported: false` here, and no runtime -behaviour in this repository changes. - -⚠️ Implementers and importers outside this repository are NOT MEASURED. Code -that imports any name above from `@object-ui/types` or `@object-ui/components` -no longer compiles, and a host `DataSource` that implements the four methods is -no longer called by anything in objectui. There is no replacement API: nothing -serves the spec's export-job contracts and `IExportService` has no provider; -objectstack#17158 (ruling A) retires them from `@objectstack/spec` after this -lands. - -The synchronous export path is unchanged: `DataSource.exportDownload` and its -`ExportDownloadRequest` (csv / json / xlsx), and the grid's client-side -fallback. - -Marked `minor`, not `major`, per the version-alignment convention in AGENTS.md; -the break is real and is stated here. diff --git a/.changeset/10250-self-querying-views-toolbar-state.md b/.changeset/10250-self-querying-views-toolbar-state.md deleted file mode 100644 index 83244c6790..0000000000 --- a/.changeset/10250-self-querying-views-toolbar-state.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/plugin-list': patch -'@object-ui/plugin-gantt': minor -'@object-ui/types': minor ---- - -On `tree` and `chart` list views, the toolbar's Filter control and the `UserFilters` -chips now narrow the view, and on a `gantt` list view the toolbar's Search box now -narrows the chart (objectui#10250). - -These three views run their own query instead of drawing the rows `ListView` fetched. -The tree and chart nodes carried only the authored `filter`, and the gantt node carried -no search term, so each control changed `ListView`'s own fetch and nothing on screen. - -- The `tree` node and the object-bound `chart` node now carry the same effective filter - `ListView`'s own fetch sends, as the `gantt` node has since objectui#10037. The value - keeps its identity while its content is unchanged, so re-rendering the list does not - re-query the view. -- `ObjectGanttSchema` declares two optional keys, `search` and `searchableFields`. - `ObjectGantt` sends `search` as `$search` and, only alongside a term, - `searchableFields` as `$searchFields` — the pair a list's own query sends. A `gantt` - list view writes both from its toolbar Search box and the view's `searchableFields`. - -Unchanged: the toolbar state still does not reach the query of a `chart` view bound to a -semantic `dataset`, and the toolbar Search box still does not reach the `tree` or `chart` -query. objectui#10326 stops offering that Search box on `tree` and `chart` views. diff --git a/.changeset/10254-sections-customfields-drawer-modal.md b/.changeset/10254-sections-customfields-drawer-modal.md deleted file mode 100644 index e896916f1d..0000000000 --- a/.changeset/10254-sections-customfields-drawer-modal.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/plugin-form': minor ---- - -fix(plugin-form): `customFields` members render inside explicit `sections` on the drawer, modal, tabbed, wizard and split arms - -The registered description of `object-form.customFields` is one sentence for -every `formType`: "Field definitions merged over the set generated from object -metadata." With explicit `sections`, an `object-form` with `formType: 'drawer'`, -`'modal'`, `'tabbed'`, `'wizard'` or `'split'` (and a `DrawerForm`, `ModalForm`, -`TabbedForm`, `WizardForm` or `SplitForm` mounted directly) built every field a -section names from the object schema alone, so a member naming that field was -dropped: its label, its `required` and the rest of its definition never reached -the form. The default arm already drew the member. - -Those five arms now take a section field's definition from the member naming -it, through the same lookup the default arm's merge uses; a field no member -names is built from the object schema as before. This holds for a bare field -name and for a spec `{ field }` entry, whose own overrides still apply on top -of the member. Over a member, the widget changes only when the entry restates -`type`. A section naming a field that only a member supplies now renders that -member, where it used to render a plain text input labelled with the field -name. A member that no section lists is still not drawn when `sections` are -given, as on the default arm. `TabbedFormSchema`, `WizardFormSchema` and -`SplitFormSchema` now declare `customFields`, as `DrawerFormSchema` and -`ModalFormSchema` already did. - -Unchanged: the rules for what a section entry may override, which still differ -between the default arm and the other five. diff --git a/.changeset/10257-dataset-filter-read-half-holds.md b/.changeset/10257-dataset-filter-read-half-holds.md deleted file mode 100644 index 418ea00b81..0000000000 --- a/.changeset/10257-dataset-filter-read-half-holds.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the Studio dataset-filter inspector no longer opens a stored condition as an -editable row it cannot keep, so editing ANOTHER row can no longer drop or rewrite it -(objectui#10257) - -The inspector opened two kinds of stored condition in a dataset's or a measure's filter as -editable rows, and the builder could hold neither. It saves on every change, so an edit to -a DIFFERENT row changed them silently: - -- **An incomplete value**, such as `{ $eq: '' }`, `{ $in: [] }`, `{ $ne: '' }`, - `{ $nin: [] }`, a `null` comparand, or the implicit `{ field: '' }`, `{ field: null }` - and `{ field: [] }`. The save path drops a row with no value as unfinished, so the stored - condition disappeared. For `{ $in: [] }` that widened the dataset from no rows to every - row. -- **An operator the column's filter menu does not offer**, such as `$in` on a date or - number column, `$gt` / `$gte` / `$lt` / `$lte` on a text column, or `$exists` / `$null` - on a boolean column. The operator control was drawn blank, and touching the row's field - picker switched it to `equals`, which stored a different filter. - -A filter like that now goes to the Source tab, as `$or` and nested groups already do. The -bridge checks every stored row two ways: the save path must keep it, and the column's -filter menu must offer its operator. A column listed without a type, or not listed at all, -is checked against the text operators, because the menu draws those for both. This is the -check objectui#10062 added for `$between`, now applied to every operator. A read with no -field list skips the menu check, as before. - -A filter the builder can hold still opens in the builder and saves back unchanged, and the -save path itself is unchanged. - -Two consequences to know about: - -- The objectui#9382 entry says that a `$gt` / `$lt` the column's menu cannot settle (an - unknown type, a column absent from the field list, or a menu offering neither reading) - reads back through the fixed table. It still settles on that operator. But when a field - list is given, no menu that leaves it unsettled offers `greaterThan` or `lessThan`, so - that filter now goes to the Source tab instead of opening under a blank operator control. -- The field list is empty until the base object's fields have loaded, and it stays empty - if they cannot be loaded. Until the fields load, a filter using an operator the text - operators lack (for example `$in` on a select column, or `$gt` on a number column) - shows the Source-tab note instead of the builder. `$between` has shown the note this way - since objectui#10062. diff --git a/.changeset/10274-action-icon-auto-trigger.md b/.changeset/10274-action-icon-auto-trigger.md deleted file mode 100644 index 7549c7ce84..0000000000 --- a/.changeset/10274-action-icon-auto-trigger.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/components': patch ---- - -An `action:icon` now runs an action it receives with `autoTrigger` set, the same -way `action:button` and `action:menu` do (objectui#10274). - -`action:bar` renders an inline action authored `component: 'action:button'` or -`'action:icon'` with the renderer that value names. So an action authored with -`component: 'action:icon'` reached `action:icon` with -the host's `autoTrigger` flag on it, and `action:icon` ignored the flag. A -`?runAction=` deep link to a list toolbar action shown as an icon was therefore -consumed (removed from the URL) and ran nothing, with no notice. - -`action:icon` now calls the same shared auto-trigger hook as the other two -renderers: - -- It runs the action once, through its own click handler, so confirm dialogs, - parameter dialogs and toasts apply exactly as they do on a click. Re-renders do - not run it again. -- If the action's own declared `visible` hides the icon, the action is not run. - A warning toast names the action, and development builds log a console - diagnostic, as the other two renderers do (objectui#4191). diff --git a/.changeset/10275-listview-fls-emptied-select.md b/.changeset/10275-listview-fls-emptied-select.md deleted file mode 100644 index 8556239439..0000000000 --- a/.changeset/10275-listview-fls-emptied-select.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -fix(plugin-list): a list view whose every authored column is denied by field-level security still sends a `$select` - -`ListView`'s `$select` builder drops the authored columns the principal cannot read. When that left no column, it returned no projection, so the request carried no `$select` key and asked the server for every field of the object, the denied ones included. An emptied column list was read as "no restriction", the reading objectui#7215 fixed on `$expand` (objectui#10275). - -The builder now asks whether the author declared any column, not whether any column survived the permission gate. An authored list that field-level security empties projects to `id` plus the fields the builder already adds through its FLS-gated routes (the platform columns every object carries excepted, as before): the `$expand` roots, the view bindings (kanban, calendar, gallery, timeline and gantt fields), the grid's grouping fields, and the operands of the row predicates (conditional formatting; the `visible` / `disabled` predicates and `recordIdField` of the row actions, the bulk actions and the object's declared actions; the object's `userActions` overrides). A denied operand is not added back. That is the shape `ObjectGrid` and `RelatedList` (objectui#10186) send. - -Graded as defence in depth: ObjectStack's server strips denied fields from every returned row (`FieldMasker`), so nothing leaked from that backend. The projection matters for a backend that does not strip. - -Unchanged: a list with no authored `columns` (absent or an empty array) still sends no projection, a partially-denied list projects its surviving columns as before, and nothing is filtered before the permission answer has loaded. - -Behaviour to know about: on a backend that honours `$select`, a list whose every column is denied now receives rows carrying only the projected fields, as a list with one readable column already did. diff --git a/.changeset/10276-currency-fraction-digits-not-precision.md b/.changeset/10276-currency-fraction-digits-not-precision.md deleted file mode 100644 index 617209f903..0000000000 --- a/.changeset/10276-currency-fraction-digits-not-precision.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@object-ui/fields': minor ---- - -`CurrencyField` takes its fraction digits from the currency, never from the -field-level `precision` (objectui#10276). - -`@objectstack/spec` declares a field's `precision` as "Total digits -(non-negative integer)" — the `p` of a `decimal(p, s)` column, so a -DECIMAL(18,2) amount is `precision: 18, scale: 2`. The currency edit widget -passed that count to `Intl` as the number of decimal places, so a currency -field declaring `precision: 18` rendered eighteen decimal places, offered a -`step` of `0.000000000000000001` and rounded typed input to eighteen places on -blur. The currency cell renderer does not read `precision` and is unaffected. - -The widget's one width is now the resolved currency's own ISO 4217 minor-unit -count — two decimals for USD or CNY, none for JPY, three for KWD — and it drives -the read-only display, the input's `step` and the blur rounding alike. A field -with no resolvable currency keeps two decimals. The widget does not read `scale` -for the width either (it never did), in line with the ruling on -objectstack-ai/objectstack#19629 that takes `scale` off the `currency` type. - -**Behaviour change** for currency fields that declare `precision`: the declared -value no longer sets the decimal places shown, the `step`, or the blur rounding. -Where it differed from the currency's own digit count (or from two decimals on a -field with no currency), the output moves: `precision: 2` on a JPY field used to -show `¥1,234.50` and now shows `¥1,235`; `precision: 0` on a USD field used to -show `$1,235` and now shows `$1,234.50`. This reverses the "an explicitly -authored `precision` still wins" rule objectui#4361 published, under the -maintainer ruling recorded on objectstack-ai/objectstack#19910 that a -currency's decimal places are the currency's, not a setting. Fields that declare -no `precision`, or one equal to the currency's own digit count, render exactly -as before. - -**Migration.** Nothing to restate: a currency field's decimal places follow its -currency. Keep `precision` only as the total digit count of the stored decimal. diff --git a/.changeset/10277-harvest-defaultfromrow-target-tokens.md b/.changeset/10277-harvest-defaultfromrow-target-tokens.md deleted file mode 100644 index c391233f6a..0000000000 --- a/.changeset/10277-harvest-defaultfromrow-target-tokens.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/core': patch ---- - -fix(core): a list's `$select` now carries the field a row action's `defaultFromRow` param seeds from and the `{field}` tokens of its `target` - -`listViewPredicates` is the harvest `ListView`, `ObjectGrid` and `RelatedList`'s -authored path use to decide which fields a projected row must carry. It read an -action's `visible` / `disabled` predicates and its `recordIdField`, but not two -other row keys an action reads. On a backend that honours `$select`, a field -named only there was absent from the row, and nothing said so: - -- a param with `defaultFromRow: true` bound to a field no column shows opened - the console's param dialog blank, because the param is seeded only when the - row has the key; -- a `{field}` token in an `api` action's `target` was filled with an empty - string by the console's `api` handler. - -For each action on the view's row, bulk and object action lists, the harvest now -also names: - -- the row key a `defaultFromRow` param seeds from: its `field` when it declares - one, its `name` otherwise. That is the precedence the param seeding reads, so - a `teamId` param bound to `field: 'team_id'` asks for `team_id`; -- every `{field}` token in `target` whose content is a bare identifier, the - grammar the console's `api` handler fills from the row. A dotted path, an - expression and the runner's `${param.X}` / `${ctx.X}` tokens are not filled - from the row that way, and are not harvested. - -A param key that is not a bare identifier is dropped, as a `recordIdField` is. -Every harvested name still passes each consumer's existing gates before it -reaches `$select`: the check against the object's declared fields and the -platform columns every record carries, and field-level security on a declared -field once the permission answer has loaded. diff --git a/.changeset/10280-slider-tooltip-single-or-list.md b/.changeset/10280-slider-tooltip-single-or-list.md deleted file mode 100644 index 03614ab313..0000000000 --- a/.changeset/10280-slider-tooltip-single-or-list.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types): `slider` and `tooltip` single-or-list keys follow their read sites (objectui#10280, objectui#7759 group B) - -Three keys that `@objectstack/spec` does not declare, where the zod mirror accepted a -spelling the TypeScript declaration refused. Each now matches what its renderer reads. - -- **`SliderSchema.defaultValue` is now `number | number[]` (wider).** The `slider` - renderer turns a single number into a one-item list, so both spellings render. The - mirror already accepted both, and the TypeScript declaration now does too. Code that - writes the key keeps compiling. Code that reads it must now handle a single number; the - in-repo renderer already does. -- **BREAKING (authoring): `SliderSchema.value` is retired on both faces.** No renderer - reads it: the `slider` renderer reads `defaultValue`, `max`, `min` and `step`, and the - form-control DOM whitelist drops `value` from the props it passes on. An authored `value` - rendered nothing. The mirror now refuses it by name with a message that points at - `defaultValue`, and the TypeScript member is `value?: never`. To migrate, write the - initial position as `defaultValue`. -- **BREAKING (authoring): `TooltipSchema.content` no longer accepts a list.** The renderer - puts `content` straight into a React child position without rendering it through - `renderChildren`, so a list of nodes failed to render with "Objects are not valid as a - React child". The mirror now accepts `string | SchemaNode`, the same as the declaration, - which has not changed. To migrate, put a list under `children`, which the renderer does - render as a list. - -Marked `minor` under this repo's version-alignment rule (`major` is reserved for -following an `@objectstack` major); the breaking authoring changes are named above. diff --git a/.changeset/10286-mirror-groups-cd-settled.md b/.changeset/10286-mirror-groups-cd-settled.md deleted file mode 100644 index 6cb9e1dacb..0000000000 --- a/.changeset/10286-mirror-groups-cd-settled.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -'@object-ui/types': minor ---- - -fix(types): settle four mirror-vs-declaration disagreements from objectui#7759 groups C and D - -Each of these keys had a zod mirror that accepted something its TypeScript -declaration refused, or the other way round. Each is now settled by the -objectui#7759 ruling: where the spec declares a key, both faces follow the spec; -where it does not, the renderer's read site decides. - -- `FilterField.operators` (inside `FilterBuilderSchema.fields`) now states the - spec's canonical filter vocabulary on both faces: `VIEW_FILTER_OPERATORS` from - `@objectstack/spec/ui`, twenty members. The declaration used to offer - `is_empty` / `is_not_empty` and the mirror `is_null` / `is_not_null`, so each - face refused a spelling the other accepted. Both faces now accept all four, - plus `icontains`, `before`, `after` and `between`. -- `ContainerSchema.maxWidth` no longer parses `true`. The key is not in the spec, - and the `container` renderer draws no max-width class at all for `true` (not the - default `max-w-xl`, and not the `max-w-none` that `false` gives). The - declaration never admitted it. -- `HeaderBarSchema.variant` is retired on both faces (ADR-0049). The key is not in - the spec, and the `header-bar` renderer reads no variant: every spelling - rendered the same header. The declaration offered `floating` and the mirror - `transparent`. The mirror now refuses the key by name, and the declaration types - it `never`. - -- `FormSchema.mode` (the plain `form` node) is retired on both faces, under the - objectui#7759 ruling's D1-(ii). The spec declares no `form` node; its - `create` / `edit` / `view` belongs to `object-form`. Nothing read the key on a - `form` node: every spelling rendered the same form. The declaration offered - `edit` / `read` / `disabled`, the mirror `create` / `edit` / `view`, and - neither was honoured. The mirror now refuses the key by name and points at - `object-form`, whose `mode` (`ObjectFormSchema.mode`) is unchanged and live. - For a non-editable basic form, set `disabled`. The renderer is unchanged: a - document that skips validation and still carries `mode` gets the same stray - `mode` attribute on the rendered `form` element as before. A validated - document can no longer carry the key, so it no longer reaches the DOM that way. - -Breaking, but only for documents the renderer ignored anyway: a `container` with -`maxWidth: true`, a `header-bar` with any `variant`, or a `form` with any `mode` -now fails validation. Delete the key. For a form, use `object-form` or `disabled` -if the mode was meant to do something. diff --git a/.changeset/10287-navigation-designer-doc-type.md b/.changeset/10287-navigation-designer-doc-type.md deleted file mode 100644 index 457e6b739a..0000000000 --- a/.changeset/10287-navigation-designer-doc-type.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/plugin-designer': patch -'@object-ui/i18n': patch ---- - -fix(plugin-designer): the Navigation Designer has an entry for the spec's `doc` navigation item type - -objectstack#19789 added a `doc` member to the spec's navigation item union (an -item that targets a book and/or a doc). `NAV_TYPE_META` in `NavigationDesigner` -is keyed by that spec-derived union, so objectui stopped compiling against -`@objectstack/spec` built from objectstack `main`, and every row reads its badge, -colour and icon from that map. The map now has a `doc` entry (a `BookOpen` icon, -its own colour and the `appDesigner.navTypeDoc` label key). The key has an -English fallback in the designer's defaults and a translation in all ten locale -packs. - -The map is typed `Record` so it compiles both -against the pinned `@objectstack/spec`, which predates `doc`, and against -objectstack `main`. The `| 'doc'` goes away at the pin bump that ships `doc`. -`doc` is not added to the quick-add buttons: an empty `doc` item fails the spec's -book-or-doc requirement, and authoring one is objectui#10188. diff --git a/.changeset/10288-config-bag-data-object-source.md b/.changeset/10288-config-bag-data-object-source.md deleted file mode 100644 index 0021a08075..0000000000 --- a/.changeset/10288-config-bag-data-object-source.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/react': minor ---- - -fix(react): a data object in a node's `properties` / `props` bag reaches the renderer whole, even when it carries a `source` field - -`SchemaRenderer` evaluates each value of a node's config bag (`properties`, and its legacy alias `props`) one by one, and handed every value to `ExpressionEvaluator.evaluate`. That call unwraps ANY object with a string `source` to that bare string before it does anything else. So an authored data object that merely had a field called `source` was silently replaced by that one string: an `action:button` with `properties.bodyExtra: { source: 'web', campaign: 'spring' }` sent `"web"` to the action runner instead of the object, with no error and no warning. The same object written at node level, which no loop visits, always arrived intact. - -This was never one key's problem. Every object-valued input on those two bags took the same path, including values keyed by field name: form `defaultValues` / `initialValues`, a declarative `patch`, filter `values` and a detail view's `data`, where a field named `source` is ordinary. - -On a key outside the predicate chain, an object now reaches `evaluate` only when it is an Expression envelope in `@objectstack/spec`'s sense, meaning it carries a string `dialect` (the spec's `ExpressionSchema` requires one). Every other object is handed to the renderer exactly as authored. - -**Behaviour change, stated plainly.** The only value whose meaning changes is an object on a non-predicate config-bag key that has a string `source` and no string `dialect`. It used to collapse to its evaluated `source`; it now arrives as the object. Everything else evaluates as before: - -- strings are still interpolated; -- a `{ dialect: 'template', source: '${…}' }` envelope still resolves to its value; -- the predicate keys (`visible`, `visibleWhen`, `visibleOn`, `visibility`, `hidden`, `hiddenOn`, `disabled`, `disabledOn`, `enabled`) are unchanged: a CEL envelope is still preserved for the canonical engine (objectui#9100 / #9107), and a dialect-less `{ source }` on them is still evaluated, the form `ExpressionWire` declares for `visible` / `hidden` / `disabled`; -- `params` is still walked leaf by leaf (objectui#7867). - -Declared as a minor (Clause-②): nothing in the published API is added or removed, but what an authored value evaluates to changes for one shape. `ExpressionEvaluator.evaluate`'s signature admits a dialect-less `{ source }`, and these loops handed it every value except a `params` bag and a CEL envelope on a predicate key. So `{ source: '${…}' }` on a config-bag key outside the predicate chain and `params` now arrives as the object, uninterpolated, and the unevaluated-expression diagnostic does not report the `${…}` inside it. To keep such a value evaluated, write the bare string `'${…}'` or `{ dialect: 'template', source: '${…}' }`; both still interpolate on that path. The spec's envelope always carries `dialect`, and `@object-ui/core`'s `isRuntimeDefault` already reads a dialect-less `{ source }` as a literal value. diff --git a/.changeset/10289-action-params-properties.md b/.changeset/10289-action-params-properties.md deleted file mode 100644 index c18f870923..0000000000 --- a/.changeset/10289-action-params-properties.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -'@object-ui/components': minor -'@object-ui/app-shell': minor ---- - -feat(components)!: an action node's static values ride `properties.params`; `params` is only the input list - -**Breaking (objectui#10289, ruling A).** An action's `params` has one meaning: -the `ActionParam[]` list of inputs to collect from the user before the action -runs. That is how `UIActionSchema.params` and `@objectstack/spec` 17.4.0's -`ActionSchema.params` declare it. The SDUI node envelope declares no -node-level `params` key. `action:button` and `action:icon` now read a node's -static execution values from `properties.params` only. They forward those -values to the action runner as `params`, where handlers such as -`navigate_create` / `navigate_edit` read `objectName` / `recordId`. - -- A node-level `params` **object** is no longer read as values. It is - ignored, and a development build logs one warning per action that names - `properties.params`. -- A node-level `params` **array** (`ActionParam[]`) still works: it is - forwarded as `actionParams` and opens the params dialog. `action:icon` now - routes it the same way `action:button` does. -- Both channels can appear on one node: an `action:bar` member can carry - inputs in `params` and values in `properties.params`. Under `SchemaRenderer`, - the `properties` hoist copies `properties.params` over a node-level `params`. - -**Migration.** Move the object unchanged from node-level `params` to -`properties.params`: - -```json -{ "type": "action:button", - "properties": { "label": "Edit", "actionType": "navigate_edit", - "params": { "objectName": "account", "recordId": "${record.id}" } } } -``` - -Templates in `properties.params` are evaluated as before (objectui#10282), so -`${record.id}` still resolves on a record page. A `type: "api"` request payload -belongs in `bodyExtra`. - -**Census, taken before the change.** 13 in-repo sites wrote a node-level -`params` object on an `action:button` / `action:icon` node: - -- 4 examples in published docs: the record-edit-modes guide and the - `@object-ui/app-shell` README, 2 each; -- 2 in the `navigate_*` handler comment in app-shell `AppContent`; -- 7 in tests that authored it as expected behaviour. - -12 moved to `properties.params`. The remaining one is a test case that now -pins the object form as not read. No JSON metadata under `examples/` or `apps/` -used the object form, and neither did the published `skills/` tree. Stored -metadata outside this repository was not measured. - -Not changed here: the pending objectui#7867 changeset shows a node-level -`params` example. As of this release that form is not read; use -`properties.params`. diff --git a/.changeset/10290-container-member-params-evaluated.md b/.changeset/10290-container-member-params-evaluated.md deleted file mode 100644 index e8d1f97fc6..0000000000 --- a/.changeset/10290-container-member-params-evaluated.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/components': patch -'@object-ui/react': minor ---- - -fix(components): an action container's members evaluate `properties.params` the way a top-level `action:button` does - -A member of `action:bar`, `action:group` or `action:menu` never passes through -`SchemaRenderer`, so the evaluation that resolves `"recordId": "${record.id}"` -in a node's `properties.params` did not run for it. On a record page an -`action:bar` member drawn inline handed its `navigate_edit` handler the raw -`${record.id}` text, and a member that the bar placed in its overflow menu, or -an `action:group` / `action:menu` item, did not forward its `properties.params` -at all. - -Each container now evaluates its members' `properties` with the evaluator and -scope `SchemaRenderer` uses: `action:bar` where it composes an inline member, -and `action:group` / `action:menu` when they run an item. A container member's -static values therefore reach the handler as a top-level `action:button`'s do, -with one difference: the development-build unevaluated-expression diagnostic -runs in the `SchemaRenderer` memo, so it does not report an unresolvable -template on a container member. An item that carries an `ActionParam[]` input -list forwards both, as `action:button` does. A node-level `params` object is -still not read as values (objectui#10289). The one exception is unchanged from -objectui#10462: an `action:group` / `action:menu` item of `type: 'api'` still -forwards it as the request payload (objectstack#5777 window), unless the item -also carries a `properties.params` bag, which now takes precedence. - -`@object-ui/react` exports `useConfigBagEvaluator()` for this. It returns a -function that applies the `SchemaRenderer` memo's `properties` evaluation (the -same per-key rule and the same `record` / `current_user` / `page` scope) to a -config bag rendered without `SchemaRenderer`. It is not a second template -engine. Its plain half, `evaluateConfigBagInScope()`, is exported beside -`SchemaRenderer`. Both are built from the module-scope scope builder and -per-key rule that the memo itself calls. - -Declared as a minor (Clause-②, widening): `@object-ui/react` gains two public -exports, `useConfigBagEvaluator` and `evaluateConfigBagInScope`. Nothing is -removed or renamed. diff --git a/.changeset/10291-cleared-scalar-saves-null.md b/.changeset/10291-cleared-scalar-saves-null.md deleted file mode 100644 index c1bd6abd2d..0000000000 --- a/.changeset/10291-cleared-scalar-saves-null.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/fields': minor -'@object-ui/components': minor ---- - -fix(fields,components): a single select or radio emptied by a cascade clear is now saved — as `null` - -When a controlling field changes and a single select or radio no longer offers -its current value, the cascade clear empties it. It emptied it to `undefined`, -and the JSON transport omits an own `undefined` key (`@objectstack/client`'s -`data.update` sends `body: JSON.stringify(data)`). So the user saw the field -emptied, pressed Save, and the stored value survived and came back on refresh — -on the record page's inline edit (reachable since objectui#7190) and in forms -alike. The multi-value clear beside it wrote a real `[]` and was saved; the two -disagreed. - -Both clears that can empty a scalar now write `null`, the write contract's -"clear the stored value" (an absent key means "leave it unchanged"): - -- `SelectField` and `RadioField` (`@object-ui/fields`) emit `onChange(null)`. - This covers every host that renders them: inline edit, `ObjectForm` and the - other form variants. -- The form renderer's own cascade clear (`@object-ui/components`) sets `null`. - It runs independently of the widgets and is the only clear for a field no - option widget renders: a field `visibleWhen` keeps unmounted, or the built-in - `select` branch. The clear-on-hide effect in the same file already wrote - `null` for the same reason. - -`SelectField` also renders a `null` value as "nothing chosen": it shows the -placeholder, as an empty string does. Before this change a raw `null` painted a -blank trigger. - -A multi-value clear still writes its array. A select nobody touched is still not -staged: no invented `null` reaches a save, so a server default is not -suppressed. Required validation, the master-detail dirty diff and the create -form's default omission already treat `null` and `undefined` as the same blank, -so none of them changes. diff --git a/.changeset/10293-calendar-date-values.md b/.changeset/10293-calendar-date-values.md deleted file mode 100644 index 49b645076f..0000000000 --- a/.changeset/10293-calendar-date-values.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/components': minor ---- - -`CalendarSchema.defaultValue` / `.value` cross the JSON/TS boundary once (objectui#10293, objectui#7759 ruling D1-(iii)). - -- `@object-ui/types`: the declaration is now `Date | string`, the same set the zod mirror accepts. JSON authors an ISO 8601 date string; TypeScript callers may still pass a `Date`. Breaking for TypeScript only: the `Date[]` arm is gone from the declaration, so a `Date[]` passed to a `multiple`-mode calendar no longer type-checks. The mirror never accepted a list, and the renderer still forwards one unchanged at runtime. -- `@object-ui/components`: the `ui:calendar` renderer coerces a string `value` / `defaultValue` to a `Date` at its read site, through `toDisplayDate` from `@object-ui/core`. A date-only string such as `2026-09-15` now selects the 15th in every time zone. Before, it selected the 14th west of UTC. `Date` values and date-time strings select the same day as before. diff --git a/.changeset/10295-tooltip-content-is-text.md b/.changeset/10295-tooltip-content-is-text.md deleted file mode 100644 index f241df1a53..0000000000 --- a/.changeset/10295-tooltip-content-is-text.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types): `TooltipSchema.content` is text only, on both faces (objectui#10295) - -**BREAKING (authoring):** a node authored at a tooltip's `content` is now refused. -Author rich content under `children`, the tooltip's rich-content slot: - -```json -{ "type": "tooltip", "trigger": { "type": "button", "label": "Hover me" }, - "children": { "type": "text", "content": "Rich body" } } -``` - -Both the TypeScript declaration and the zod mirror accepted `content` as -`string | SchemaNode`. The tooltip renderer places `content` directly in the -tooltip body, without `renderChildren`, so a node there crashed the tooltip with -"Objects are not valid as a React child". `@objectstack/spec` declares no tooltip -node, so the key follows its read site: the declaration is now `content?: string`, -and the mirror refuses a non-string (`invalid_type` at `content`) with a message -that names `children`. objectui#10280 had already refused the list arm for the same -reason. A tooltip whose `content` was a node never rendered, so no working document -changes behaviour. - -When both are authored, a non-empty `content` wins and `children` is not rendered; -that is how the renderer reads them today, and it is now written into the -declaration's JSDoc and the tooltip docs. diff --git a/.changeset/10296-detail-view-field-options-authoring.md b/.changeset/10296-detail-view-field-options-authoring.md deleted file mode 100644 index f069dea3e6..0000000000 --- a/.changeset/10296-detail-view-field-options-authoring.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types)!: `DetailViewFieldSchema.options` is the spec's authoring `SelectOptionSchema` (objectui#10296) - -The zod mirror of a detail-view field's `options` carried an inline option shape -that admitted a number or boolean `value` — which the TypeScript declaration -(`SelectOptionMetadata[]`) refuses — and silently stripped every other key. It -now reads `SelectOptionSchema` from `@objectstack/spec/data` by reference, per -ruling F1 on objectui#7759: a structural mirror points at the spec's AUTHORING -schema, never at the declaration's runtime read model. - -BREAKING for authored detail-view metadata that the old shape let through: - -- `value` must be the spec's `SystemIdentifierSchema`: a string matching - `^[a-z][a-z0-9_.]*$`, at least two characters long. So `open`, `in_progress` - and `order.created` are accepted, while `Open`, `1st`, `a-b` and `o` are - refused. A number or boolean `value` is refused with `invalid_type`; write it - as an identifier string. -- `icon` and `disabled` on an option are refused by name (`unrecognized_keys`), - as the spec refuses them on object metadata. They were stripped silently - before, so no renderer ever received them from this surface. -- `description`, `default` and `visibleWhen` are now accepted as the spec - declares them, where before they were stripped. -- A bare-string `visibleWhen` is canonicalized in the PARSE OUTPUT to the - spec's envelope `{ dialect: 'cel', source }`. An authored envelope passes - through unchanged. (objectui's own form select option keeps the bare string; - this surface follows the spec.) -- A `visibleWhen` envelope without `dialect` (objectui's wire spelling - `{ source }`) is refused, as is an empty string. On the installed spec - 17.4.0 a whitespace-only string is still accepted; the next spec release - refuses it. - -The TypeScript declaration is unchanged. The one remaining difference between the -two faces, the `visibleWhen` envelope, is recorded in the parity ledger as an -expected divergence against the read model. diff --git a/.changeset/10301-refuse-impossible-datetime-day.md b/.changeset/10301-refuse-impossible-datetime-day.md deleted file mode 100644 index 06a086bfa6..0000000000 --- a/.changeset/10301-refuse-impossible-datetime-day.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/core': patch -'@object-ui/fields': patch ---- - -fix(core,fields): a date-time written on a calendar day that does not exist is refused, not rolled into another day - -`2026-02-30T10:00:00Z` names a day February does not have. The engine parses it anyway and rolls the surplus forward, so it rendered as `Mar 2, 2026, 10:00 AM`: a real day nobody wrote, with nothing to say the stored value was wrong. objectui#10026 made the shared date path refuse such a day on a date-only value; this extends the same refusal to a value that carries a time. - -- **`toDisplayDate` returns an Invalid Date for an ISO date-time whose leading `YYYY-MM-DD` is not a real calendar day** (the `isRealCalendarDate` judgement). The day is read from the stored string as written, so a real day written with an offset — `2026-02-28T23:30:00-05:00`, which is March 1st in UTC — is not refused, and a real date-time renders exactly as before. `formatDateTime`, `formatDate` and `formatRelativeDate` render `—` for such a value, `formatDateTimeCompactParts` returns `null`, and a dataset measure over it renders the same `—`: each function's existing answer for an unparsable value. -- **`@object-ui/fields`:** the `datetime` and `date` cells, the readonly `date` widget and a date-returning `FormulaField` show the shared "No value" placeholder for such a value, and the readonly `datetime` widget shows `—`, exactly as each does for an unparsable value. -- **The sub-grid (`GridField` / `LineItemsField`) `date` and `datetime` columns read the shared parse step instead of building their own `Date`.** A value that step refuses shows the stored string, this surface's existing face for a value it cannot parse: an impossible day in either column (`2026-02-30`, which the `date` column still rolled into March after objectui#10026), and an out-of-range month (`2026-13-45`, which the `date` column rendered as `Feb 14, 2027`). A `date` value with a year below 100 (`0026-08-01`) now renders that year, as the `date` cell does, instead of 1926. diff --git a/.changeset/10304-calendar-selection-modes.md b/.changeset/10304-calendar-selection-modes.md deleted file mode 100644 index 46a02728cc..0000000000 --- a/.changeset/10304-calendar-selection-modes.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/components': minor ---- - -`ui:calendar`: the selection shape follows `mode` (objectui#10304). - -- `@object-ui/types`: `CalendarSchema.value` / `.defaultValue` (and the `UiCalendarSchema` mirror) now admit one day, a list of days, or a `{ from, to }` range, where a day is an ISO 8601 date string or a `Date`. The zod mirror pairs each shape with its mode: `single` (the default) takes one day, `multiple` a list, `range` a `{ from, to }` object with `to` optional and no other key. Breaking for documents that validated before: a single day under `mode: 'multiple'` or `mode: 'range'` is now refused at the key, where it used to pass validation and then crash the node (`multiple`) or select nothing (`range`). -- `@object-ui/components`: the `ui:calendar` renderer reads each mode's shape and coerces every day in it through `toDisplayDate`, so date-only strings in a list or a range select the days they name in every time zone. A range now selects its days. A value whose shape does not fit its mode selects nothing instead of throwing, and is not reshaped. diff --git a/.changeset/10321-named-view-kanban-groupby-refused.md b/.changeset/10321-named-view-kanban-groupby-refused.md deleted file mode 100644 index a3912a9677..0000000000 --- a/.changeset/10321-named-view-kanban-groupby-refused.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -"@object-ui/types": minor ---- - -**A named view's stray `kanban.groupBy` on an `object-view` document is now refused by name, with the message the `list-view` route already gives.** - -The objectui#8365 ruling (option B, maintainer 「8365 同意」) refuses a stored -view's `kanban.groupBy` loudly, at the read door of the view, pointing at -`groupByField`. PR objectui#9236 installed that refusal on the `list-view` route -only. A named view is the second route: `ObjectViewSchema.listViews` is -unmirrored, so nothing `ListViewSchema` declares reaches it, and -`safeValidateSchema` accepted `listViews.KEY.kanban.groupBy` green in either -nesting and kept the key. - -`ObjectViewSchema` gains a second named-view check on the same door, beside the -one that refuses the two retired calendar spellings (objectui#8355). It refuses -`groupBy` in a named view's `kanban` block and in its legacy `options.kanban` -bag. The issue is `custom` at `listViews.KEY.kanban.groupBy` or -`listViews.KEY.options.kanban.groupBy`, and its message is the same string the -`list-view` route gives: "Unrecognized key(s) on this kanban configuration: -`groupBy`. Did you mean `groupBy` → `groupByField`?", followed by the same -explanation. Write `groupByField` (or the deprecated `groupField`). - -⚠️ **Dated note, 2026-09-28 — `listViews` has since been mirrored, and the -`options.kanban` bag is refused whole — objectui#7928.** Later in this same release -`ObjectViewSchema.listViews` became the protocol's strict `ObjectListViewSchema` record, -by reference, so "`ObjectViewSchema.listViews` is unmirrored" above no longer holds. The -protocol now refuses `listViews.KEY.kanban.groupBy` itself (`unrecognized_keys` at -`listViews.KEY.kanban`), and this check still adds its `custom` issue at -`listViews.KEY.kanban.groupBy`, with the same message. It no longer judges the legacy -bag: the record refuses a named view's `options` whole (`unrecognized_keys` at -`listViews.KEY`, naming `options`), so nothing reports -`listViews.KEY.options.kanban.groupBy`. `.changeset/7928-listviews-by-reference-fold.md` -(PR objectui#10821) states what ships; the text above is kept as the reading of this change. - -The protocol agrees on this route too. Measured on `@objectstack/spec` 17.4.0 -when this change was made, `ViewSchema` refuses `listViews.KEY.kanban.groupBy` -as an unrecognized key exactly as `ListViewSchema` refuses `kanban.groupBy`, -with a dark control (`groupByField` and `columns` alone) accepted on both. The -spec refuses a named view's `options` bag outright, as it does a `list-view`'s, -so refusing `options.kanban.groupBy` here is no stricter than the protocol. - -**Breaking, in the sense worth stating explicitly** (shipped `minor`: this repo -never declares `major`, and every package sits in one `fixed` group). An -`object-view` document whose named view carries `kanban.groupBy`, in either -nesting, now **fails validation** where it used to pass: any pipeline running -`safeValidateSchema` over it (objectui's own `objectui validate` does) reports -one issue per written key, naming the key and the replacement. What the board -renders does not change here: `generateViewSchema` already drops the key and -resolves the lane from `groupByField` (objectui#9242). - -Not changed, deliberately: `listViews` stays unmirrored. The door declares no -value type, puts no key in the shape, requires no `columns`, and refuses neither -an undeclared sibling in the kanban block nor the legacy `options` bag itself; -the value type `listViews` should enforce is objectui#7928's. `groupBy` is not -honoured as an alias (the ruling rules that out), and `groupBy` on the generated -`object-kanban` node, the lane key `ObjectKanban` reads, is untouched. - -⚠️ **Dated note, 2026-09-28 — what a written key now reports, and what the record now -refuses — objectui#7928.** Later in this same release the named-view record became the -protocol's own, by reference. A `groupBy` in a named view's `kanban` block now reports -two issues, the protocol's `unrecognized_keys` and this entry's pointer; one in the -`options.kanban` bag reports only the refusal of `options`, which names neither `groupBy` -nor `groupByField`. So "one issue per written key, naming the key and the replacement" -no longer holds. `ObjectViewSchema` now declares the value type the paragraph above -defers to objectui#7928: `listViews` is in its shape, a named view needs `columns`, and -the record refuses an undeclared sibling in the kanban block and the `options` bag. This -entry's check now adds its message to a document the record already refuses. -`.changeset/7928-listviews-by-reference-fold.md` (PR objectui#10821) states what ships; -the text above is kept as the reading of this change. diff --git a/.changeset/10326-toolbar-search-withheld-tree-chart.md b/.changeset/10326-toolbar-search-withheld-tree-chart.md deleted file mode 100644 index a1b803c3f1..0000000000 --- a/.changeset/10326-toolbar-search-withheld-tree-chart.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -On `tree` and `chart` list views, the toolbar no longer offers Search (objectui#10326). - -Both views draw what they query for themselves, and neither query carries a search -term: the tree's own `find` sends its filter, its row ceiling and its expansions, and -the chart's queries, aggregate or dataset, take no term at all. A term typed there -changed `ListView`'s own fetch, behind the record count and the export, and nothing -the view drew. - -- The Search control is not rendered while a `tree` or `chart` view is on screen, - whatever the chart is bound to. An authored `userActions.search: true` does not bring - it back on those views. Grid, kanban, calendar, gallery, timeline, map and gantt views - keep it as before. -- A term that is already set, whether the host restored it at mount through - `initialSearchTerm` or the user typed it on another view before switching, is not - applied to `ListView`'s own fetch or export while a `tree` or `chart` view is on - screen. The term is kept rather than cleared: switching back to a view that offers - Search applies it again, and `onSearchChange` is not called for the switch. diff --git a/.changeset/10327-dataset-chart-view-filter.md b/.changeset/10327-dataset-chart-view-filter.md deleted file mode 100644 index aecc4e5792..0000000000 --- a/.changeset/10327-dataset-chart-view-filter.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-list': minor ---- - -A `chart` list view bound to a semantic `dataset` takes its scope from the dataset: -a view filter on it is now refused at authoring, and its toolbar no longer offers -filter controls (objectui#10327). - -The dataset shape of the list view's chart builds a node with no filter: the chart -queries the dataset through `queryDataset` with its dimensions and measures, and a -dataset's fields need not be the list object's. So a view filter written on such a -view was accepted and silently dropped, and the chart drew unfiltered totals that -read as filtered ones. The toolbar Filter builder and the filter chips reached only -the list's own fetch of the object's rows, never the chart. - -**New refusal (`@object-ui/types`).** `ListViewSchema` refuses `filter` — and the -legacy `filters` alias — on a view with `viewType: 'chart'` whose chart block (`chart`, -or the legacy `options.chart` bag when no `chart` is declared) names a `dataset`. The -issue is a `custom` one at the written key, and its message ends with the remedy: a -dataset chart's scope is written in the dataset. An empty filter array, a chart bound -to the list object, and a view of another kind that only offers a switch to a dataset -chart are all still accepted. - -**Toolbar (`@object-ui/plugin-list`).** While a dataset-bound chart is on screen, the -Filter builder and the `userFilters` chips are not rendered. A chart bound to the list -object keeps both, because its node carries the effective filter. - -What an author sees change: a dataset chart view that declared a `filter` now fails -validation with the remedy above instead of drawing unfiltered numbers. Put the scope -in the dataset. No example, app or doc in this repository declared such a view; the -search is on the pull request. diff --git a/.changeset/10330-ai-recommendations-carousel-retired.md b/.changeset/10330-ai-recommendations-carousel-retired.md deleted file mode 100644 index b56d3ffa8e..0000000000 --- a/.changeset/10330-ai-recommendations-carousel-retired.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-ai': minor ---- - -Retire `carousel` from `AIRecommendationsSchema.layout` and from the -`ai-recommendations` designer enum (objectui#10330, ADR-0049 enforce-or-remove). - -**Breaking, deliberately, and scored `minor` per this repo's convention** (a -`major` in the fixed group would push every package off `@objectstack`'s cadence; -`scripts/check-changeset-no-major.mjs` enforces it). - -- FROM `layout?: 'list' | 'grid' | 'carousel'` TO `layout?: 'list' | 'grid'`. - A TypeScript node that sets `layout: 'carousel'` is now a compile-time error. -- The `ai-recommendations` registration no longer offers `Carousel` in its - `layout` enum, so the designer stops suggesting it. - -The value was declared and offered but never implemented: `AIRecommendations` -renders only `grid` specially, so `carousel` always rendered as a list, with no -warning. Runtime behaviour does not change. A stored JSON node that still carries -`layout: 'carousel'` renders the list layout, exactly as before. - -Migration: replace `layout: 'carousel'` with `layout: 'list'` (what it rendered) -or `layout: 'grid'`. diff --git a/.changeset/10331-console-dates-display-locale.md b/.changeset/10331-console-dates-display-locale.md deleted file mode 100644 index 9fe7f9c12c..0000000000 --- a/.changeset/10331-console-dates-display-locale.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -Three console dates now follow the display locale, not the UI language (objectui#10331). - -- The installed-packages list's "Installed …" date, the marketplace catalog cards' relative - published time ("3 days ago") and the cloud-connection panel's "Since" date take their - locale from `useDisplayLocale()`. They used to format with the UI language, so a regional - display locale was ignored: an English UI with a `de-CH` display locale read `3/4/2020` - where it now reads `4.3.2020`, and "3 days ago" where it now reads "vor 3 Tagen". -- None of the three falls back to the machine's locale or to a literal `'en'` any more. The - installed date used to fall back to the machine's locale when the UI language was empty. diff --git a/.changeset/10334-dashboard-daterange-spec-authoring.md b/.changeset/10334-dashboard-daterange-spec-authoring.md deleted file mode 100644 index 9db28f75fc..0000000000 --- a/.changeset/10334-dashboard-daterange-spec-authoring.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`DashboardComponentSchema.dateRange` now takes `@objectstack/spec`'s -`DashboardSchema.dateRange` authoring shape by reference on both faces -(objectui#10334, objectui#7759 group F). - -`dateRange` left `DASHBOARD_SPEC_EXCLUDED`, so the Zod validator and the -TypeScript interface both project the spec member instead of restating it. - -**Breaking (validator only):** the validator used to accept any string as -`dateRange.defaultRange` and silently strip unknown keys inside `dateRange`. -It now gives the spec's verdict: - -- a `defaultRange` outside `DATE_RANGE_DEFAULT_RANGES` (the spec's date presets - plus `custom`) is refused with `invalid_value` at `dateRange.defaultRange`. - Before, a typo such as `last_7_dayz` parsed green and then resolved to no - default window at render time; -- any key other than `field`, `defaultRange` and `allowCustomRange` is refused - with `unrecognized_keys` at `dateRange`. The spec's refusal names the - canonical key for its known aliases (`preset` / `range` / `default` → - `defaultRange`, `dateField` / `fieldName` → `field`, `allowCustom` / - `custom` → `allowCustomRange`). - -The TypeScript type is unchanged in effect: `defaultRange` was already bound to -the spec's `DateRangeDefaultRange`. The validator still writes no default into -a parsed document, as for every imported spec schema. diff --git a/.changeset/10337-widget-input-serializer-key-list.md b/.changeset/10337-widget-input-serializer-key-list.md deleted file mode 100644 index be1a72fefd..0000000000 --- a/.changeset/10337-widget-input-serializer-key-list.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/types': patch ---- - -docs(types): the `WidgetInput` divergence docblock lists the serializer's key list with `of` (objectui#10337) - -Clause 2 of the `WidgetInput` docblock said `sdui-parser`'s manifest serializer forwards -six keys per input and listed them without `of`. `manifestFromConfigs` has forwarded `of` -since objectui#8067, so a reader of the published declaration learned that `of` is not -published when it is. The clause now reads "a fixed key list per input, `of` included -since objectui#8067" and lists all of them, the uncounted wording `ComponentInput`'s own -docblock in `base.ts` already uses. The clause's conclusion is unchanged: none of the -five tombstoned `ComponentInput` keys is on that list. Comment only, with no type or -runtime change. diff --git a/.changeset/10339-daterange-spec-default.md b/.changeset/10339-daterange-spec-default.md deleted file mode 100644 index 04ae8a08bb..0000000000 --- a/.changeset/10339-daterange-spec-default.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/core': minor ---- - -fix(core): a dashboard `dateRange` that omits `defaultRange` now takes the spec's declared default preset (objectui#10339). - -`@objectstack/spec` declares `DashboardSchema.dateRange.defaultRange` with `.default('this_month')`, but -`resolveDashboardFilterDefs` treated an omitted `defaultRange` as "no filter", so a dashboard authored as -`dateRange: { field: 'created_at' }` rendered unfiltered while the platform's parse of the same document said -`this_month`. The read site now applies the spec default, read from the spec's own `dateRange` schema rather -than a copied string. - -**Behaviour note:** an authored `dateRange` with no `defaultRange` now opens filtered to `this_month`, matching -the spec. An explicit `defaultRange` — `custom` included — is unchanged, and a dashboard with no `dateRange` at -all still gets no built-in date filter. diff --git a/.changeset/10343-lookup-option-label-order.md b/.changeset/10343-lookup-option-label-order.md deleted file mode 100644 index c4f7ca2df8..0000000000 --- a/.changeset/10343-lookup-option-label-order.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): a lookup option's label ranks the field's `displayField`, then the referenced object's `nameField`, then `titleFormat` — the ADR-0079 order the record page follows - -⚠️ Behaviour change: which text a lookup dropdown option (and the chip it -leaves behind) shows. The inherited lookup branch of ruling C1 on -objectui#9436, tracked as objectui#10343. - -- **Before.** `LookupField`'s option label rendered the referenced object's - deprecated `titleFormat` first, above the object's declared `nameField` and - above the lookup field's own `displayField`. The same record read one way on - its record page and in its lookup cell, and another way in the dropdown - that picks it. -- **After.** The label is `@object-ui/core`'s `getRecordDisplayName` with the - field's declared `displayField` as its `titleField`, the same call the lookup - cell renderer already makes: the field's declared `displayField`, then the - object's `nameField` (and its deprecated aliases), then `titleFormat`, then - type-aware derivation. A `nameField` blank on the record still falls through - to the template, and an object that declares only a `titleFormat` still - renders it. -- **The widget's `name` default no longer outranks the object.** A lookup field - that declares no `displayField` still reads `name` for quick-create and the - picker's display column, but in the option label that guess now sits below - the object's declarations, as `@objectstack/spec` describes the default - ("the referenced object's name/title"). Without the object's schema the - label reads `name` first, as before. -- **Templates render through the shared renderer.** The widget's private copy - of the template renderer is gone. A `{{field}}` placeholder now renders as - its `{field}` twin, as the `titleFormat` describe says every title renderer - does, where the option used to show the value inside a stray pair of braces. - -**Upgrade effect.** An option label moves when the referenced object declares -a `nameField` and a `titleFormat` that renders something else, or when a -lookup field without a `displayField` points at an object whose `nameField` -is not `name` and whose records also carry a `name` value. objectui#10486 -moved the browse-all record picker's display column onto the same resolver, -so on such an object the picker and the dropdown read the same label. diff --git a/.changeset/10345-action-bar-menu-group-placement.md b/.changeset/10345-action-bar-menu-group-placement.md deleted file mode 100644 index 60c473a967..0000000000 --- a/.changeset/10345-action-bar-menu-group-placement.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -'@object-ui/components': patch ---- - -An `action:bar` member authored with `component: 'action:menu'` or -`component: 'action:group'` now renders, and a `?runAction=` deep link to it now -runs it (objectui#10345). - -`action:bar` used to hand such a member, alone, to the `action:menu` or -`action:group` renderer. Both read their actions from `schema.actions`, which a -single action does not carry, so they rendered nothing. The action vanished from -the toolbar with no error, and a deep link to it was consumed from the URL and -ran nothing. - -On an `action:bar`, an action's `component` now says where it goes, as the -spec's comment on the key says ("Defaults to 'button' or 'menu_item' based on -location, but can be overridden"): - -- `action:menu` puts the action in the bar's one overflow ("More") menu, however - few actions the bar has. It does not use one of the `maxVisible` inline slots, - which is how `page:header` already reads the key. In the menu, the actions - that did not fit in `maxVisible` come first, then the menu-placed ones, each - in the bar's order, then the separator and the system actions. -- `action:group` renders the action inline, as an ordinary action button, in a - button group with the `action:group` members next to it in the inline row. A - different inline action between two of them starts a new group. Each grouped - action still counts toward `maxVisible`. - -A moved action keeps its own `visible`, `disabled` and `requiredPermissions` -gates, and a deep link to it runs once, as it does for an inline action. -`action:button` and `action:icon` members render as before. diff --git a/.changeset/10354-grid-fixed-currency-cell-footer.md b/.changeset/10354-grid-fixed-currency-cell-footer.md deleted file mode 100644 index 2a5dae8668..0000000000 --- a/.changeset/10354-grid-fixed-currency-cell-footer.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@object-ui/plugin-grid': patch ---- - -A fixed-currency field shows its own currency in the grid cell and in the -column-summary footer, not the tenant's (objectui#10354). - -`@objectstack/spec` refuses a field-level `currency`, so a fixed currency is -declared as `currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'JPY' }`. -`resolveFieldCurrency` reads `currencyConfig.defaultCurrency`, but `ObjectGrid` -never handed it that key. On the three configured-column paths (`columns` as -objects, `columns` as field names, and inline rows with a `fields` projection) -the cell's field metadata carried `currency`, `precision` and `scale` but not -`currencyConfig`, and `useColumnSummary` carried no `currencyConfig` into the -footer. In a USD tenant, a JPY-fixed amount of 1234 read `$1,234` in both -places, while the grid's auto-generated columns and the currency cell given the -whole field definition read `¥1,234`. - -Those cells now receive the field's `currencyConfig` as declared, and -`useColumnSummary` passes the field's `currencyConfig` to the same resolver, so -the cell and the footer show the same currency. A field without -`currencyConfig` still shows the tenant currency. The `fieldMetadata` parameter -type of `useColumnSummary` gains an optional `currencyConfig` member, typed as -the spec's own `CurrencyConfig`. The footer reads `currencyConfig` from the -field only: `ListColumnSchema` declares no such column key. - -**Behaviour change.** On those paths, a field whose `currencyConfig` is in -`fixed` mode now shows `currencyConfig.defaultCurrency` in the cell and the -footer where it used to show the tenant currency. A field in `dynamic` mode -still shows the tenant currency, because `resolveFieldCurrency` reads -`currencyConfig.defaultCurrency` only in `fixed` mode (objectui#10422). The -grid's auto-generated columns already showed a fixed field's currency. diff --git a/.changeset/10355-grid-currency-minor-unit.md b/.changeset/10355-grid-currency-minor-unit.md deleted file mode 100644 index 21522f5f16..0000000000 --- a/.changeset/10355-grid-currency-minor-unit.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -'@object-ui/fields': minor ---- - -The line-item grid (`GridField` / `LineItemsField`) no longer gives a currency -cell a default of two decimal places or a default `¥` symbol. A currency column -without a `scale` now uses its currency's own decimal places (objectui#10355). - -A computed `currency` column (for example `amount = quantity * unit_price`) was -rounded to the column's `scale` before the value was written back into the row, -and to two decimals when the column had no `scale`. That default gave every -currency two decimals: a yen amount was stored with cents yen does not have -(JPY 3 × 1234.5 stored `3703.5`), and a dinar amount lost its third digit -(KWD 3 × 1.2345 stored `3.7`). The display fell back to a literal `¥` whatever -the currency was. - -The grid now resolves its currency through `resolveFieldCurrency`. That is the -tenant default, since a grid column declares no field-level currency key. A -currency column's decimal places are: - -- its authored `scale`, when it has one. The stored value already used it, and - the display now does too. The spec's `InlineGridColumnSchema.scale` declares - it for a computed numeric or currency result; -- otherwise that currency's ISO 4217 minor unit, which replaces only the old - default of two: whole yen for JPY, two places for USD, three for KWD; -- otherwise none. With neither a `scale` nor a resolved currency, the computed - value is stored as computed, not at an invented two places. - -The same places decide the stored value of a computed currency cell and how a -currency cell is shown, both the computed cell and the list form-factor. The -cell shows the resolved currency, and the editable currency cell shows that -currency's own symbol. With no currency resolved there is no symbol. An -authored `prefix` still replaces the symbol. An authored `scale` above the -engine's limit of 100 is clamped and reported on the display too, as it -already was for the stored value (objectui#10071). - -`computeRow` takes the tenant currency as a new optional third argument. Called -without it, a currency column with no `scale` is stored unrounded. - -**Behaviour change** for grids with currency columns and no `scale`: a computed -cell is stored and shown at the currency's minor unit instead of two places, in -line with the ruling on objectstack-ai/objectstack#19910 that a currency's -decimal places are the currency's. A USD tenant's grid used to read `¥1,234.57` -and now reads `$1,234.57`. Columns with an authored `scale`, and `number` -columns, round as before. - -⚠️ **Dated note, 2026-09-29 — one sentence above was made false in this same release — objectui#11073.** -The sentence saying an authored currency `scale` above 100 "is clamped and reported on the display too" no longer holds. Later in this release this repository began resolving `@objectstack/spec` 17.5.0, which refuses a `scale` above 100 at the declaration, and the objectui#10071 clamp that sentence relied on was retired with it. The display now uses the authored width as it is, as the stored value does. Everything else above is unchanged. - -⚠️ **Dated note, 2026-09-30 — a currency column's `scale` is no longer read, reversed in this same release — objectui#10783.** -The first item of the list above ("its authored `scale`, when it has one") and the sentence saying columns with an authored `scale` round as before no longer hold for a `currency` column, and neither does the 2026-09-29 note just above, which is about that same authored width. Later in this release the grid stopped reading `scale` on a currency column: `@objectstack/spec` 17.5.0 refuses it on a column that declares `type: 'currency'`, and the currency's ISO 4217 minor unit now decides the stored and the shown width whatever `scale` the column carries. A `scale` on a `number` column is unchanged. Everything else above is unchanged. diff --git a/.changeset/10356-metric-count-not-currency.md b/.changeset/10356-metric-count-not-currency.md deleted file mode 100644 index 6e7d3b8e52..0000000000 --- a/.changeset/10356-metric-count-not-currency.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/plugin-dashboard': minor ---- - -fix(plugin-dashboard): a metric tile counting rows over a currency field shows a plain number, not money - -`ObjectMetricWidget` decided to dress its number as money from the aggregated -field's TYPE alone, so `aggregate: { field: 'amount', function: 'count' }` over a -`currency` field showed `$3` for three records — a number of rows read as an -amount. The grid footer already reads the same count on a currency column as a -plain `3`. - -The field's unit now applies only to an aggregate that answers in it: `sum`, -`avg`, `min` and `max` keep the currency face exactly as before (the list cell's -own `formatCurrency`), while `count` and `count_distinct` render as plain, -locale-formatted numbers. The same rule withholds a `percent` field's pattern -from a count, so three rows no longer read `3%` either — the footer's rule for a -percent column. - -Visible behaviour change for dashboards that count over a currency or percent -field: the tile loses its currency symbol or percent sign. An authored `format` -or `currency` on the tile is the author's declaration and is not second-guessed. diff --git a/.changeset/10360-titleformat-dedupe-rendered-fields.md b/.changeset/10360-titleformat-dedupe-rendered-fields.md deleted file mode 100644 index 2163179508..0000000000 --- a/.changeset/10360-titleformat-dedupe-rendered-fields.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -fix(plugin-detail): `record:details` no longer prints a row directly under an H1 that shows the same value when a `titleFormat` collapses onto a field outside the fixed candidate list (objectui#10360) - -**What changed for a user.** On an object with no declared name pointer, the -record page H1 is the rendered `titleFormat`. When a placeholder is blank the -template collapses onto the one field that still has a value, so -`"{contract_no} - {name}"` with a blank `name` renders `HT-2026-003`. The -details grid used to keep the "Contract No" row, printing `HT-2026-003` again -directly under the H1. That row is now hidden, as a collapsed template's row -already was when the field was `name`, `title`, `subject` or another candidate. - -**What did not change.** The comparison is the one ruled on objectui#8351 -(option B): a row is hidden only when its value EQUALS the rendered title, never -because a `titleFormat` exists. A composite title such as -`HT-2026-013 - Acme Corporation` is no field's value and still hides no row. Two -placeholders holding the same value render a composite too, so both rows stay. -The candidate list (the ADR-0079 resolver rungs and six literal names) is still -scanned first, and a candidate that matches still wins, so no row that was -hidden before is hidden differently now. The declared-pointer branch -(objectui#9436) still runs first and never consults the template. - -**How a field counts as rendered.** After the candidates, the dedupe compares -the H1 against each record field whose value equals it and that the template -actually rendered. "Actually rendered" is asked of `formatTitleTemplate` itself, -by blanking that one field and rendering again, not of a second placeholder -parser, so it agrees with the renderer on `{{…}}` placeholders, whitespace -inside the braces and dotted lookup paths. A lookup whose display name happens -to equal the H1, but whose dotted placeholder rendered nothing, keeps its row. -At most one row is hidden. diff --git a/.changeset/10367-required-marker-three-forms.md b/.changeset/10367-required-marker-three-forms.md deleted file mode 100644 index 5ee23d4c4d..0000000000 --- a/.changeset/10367-required-marker-three-forms.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/plugin-designer': patch ---- - -fix(app-shell, plugin-designer): three more forms keep the required `*` out of the control's accessible name - -A flow screen's input fields (`ScreenView`), the metadata-admin `SchemaForm` and -the `AppCreationWizard` basic step each drew the required marker as a bare `*` -inside the label that names the control. A screen reader therefore announced -"Title *" instead of "Title", and none of those controls reported that it was -required. - -The marker is now `aria-hidden`, the rule `ActionParamDialog` and `FormPage` -already follow (objectui#3299, objectui#10178): the `*` is for sighted users, and -the requirement is announced as `aria-required` on the control. Each marker also -carries `data-required-marker="true"`, the same locator the shared form -renderer's marker uses. - -- `ScreenView`: every field control (text, number, email, date, textarea, - checkbox and select) carries `aria-required` when the field is required. -- `SchemaForm`: the marker is hidden in the default row, in the boolean row, and - in a grid repeater's column header, which names every cell below it. The - controls `SchemaForm` renders itself (select, switch, number and text inputs, - textarea, the comma-separated list input and the JSON editor) carry - `aria-required` from the same flag that draws the marker. -- Metadata-admin widgets: `WidgetProps` gains an optional `required` member, and - `SchemaForm` passes the same flag to a registered widget, in a row and in a - grid cell. Ten of the eleven `labelling: 'control'` widgets put it on their - control as `aria-required`: `ref:object`, `ref:component`, `object-selector`, - `field-selector`, `field-ref`, `view-ref`, `icon`, `color-input`, - `string-tags` and `secret`. `filter-builder` does not, because its control is - a plain button, where ARIA does not allow `aria-required`. -- Colour picker: `ColorVariantPicker` takes an optional `required` and puts - `aria-required` on its radio group, and the `color-picker` widget passes the - field's flag through. Its other callers pass nothing, so they are unchanged. -- `AppCreationWizard`: the App name and Title inputs carry `aria-required`. - -Native `required` is not added anywhere, so no browser validation appears beside -each form's own required check. diff --git a/.changeset/10368-required-marker-real-span.md b/.changeset/10368-required-marker-real-span.md deleted file mode 100644 index 60a7c8f254..0000000000 --- a/.changeset/10368-required-marker-real-span.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/components': patch ---- - -fix(components): the required asterisk no longer enters a field's accessible name (objectui#10368) - -`FieldContainer`, `element:text_input` and the `input`, `textarea`, `checkbox` and `select` renderers drew the required asterisk as CSS generated content (an `::after` utility) on the field's label. The accessible-name computation includes generated content, so where that label is associated with its control, Chromium named a required field labelled "Title" as "Title*". A pseudo-element cannot carry `aria-hidden`. - -The asterisk is now a real `span` with `aria-hidden="true"` and `data-required-marker`, the shape the form renderer's `FormLabel` already uses, so it stays out of the name. It keeps the same colour and spacing. Every control keeps the required state it had before: the native `required` attribute, or `aria-required`. Validation does not change. - -The `select` renderer's label is not associated with its trigger, so its name never contained the asterisk; its marker changes shape only. The generated-content utility these labels used is no longer compiled into `style.css`. - -For test suites that render these fields: Testing Library's exact-string `getByLabelText('Title')` matches the label's whole text, and that text now includes the hidden `*`, so it no longer finds a required field. `getByRole('textbox', { name: 'Title' })` does, because it computes the accessible name. diff --git a/.changeset/10370-listview-map-location-select.md b/.changeset/10370-listview-map-location-select.md deleted file mode 100644 index 43734b1eff..0000000000 --- a/.changeset/10370-listview-map-location-select.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/plugin-list': minor ---- - -fix(plugin-list): a map list view requests the fields its markers are drawn from - -`ListView` builds its `$select` projection from the authored columns plus each -view kind's per-row bindings. Kanban, calendar, gallery, timeline and gantt each -had an arm there; the map had none, and the candidate keys named none of its -bindings. A map view whose columns omit the location field therefore asked for -`id` plus those columns, and on a backend that honours `$select` every row -arrived without coordinates: a map with no markers, and no error. - -The request shape changes: a map view now also requests the fields `ObjectMap` -reads off each row — `locationField`, or the `latitudeField` + `longitudeField` -pair, plus `titleField` and `descriptionField`. They are read through the same -resolver the map render branch and the view switcher already use (the spec's -view-level `map` block merged per key over the `options.map` bag), so a bag value -the view-level block shadows is not requested. A coordinate or title binding that -names a lookup is also expanded, as the map's own fetch already does; the -description binding is requested but not expanded, because the marker popup -renders it as text and cannot draw an expanded record there. - -Every one of these fields passes the same checks as the other view bindings: a -field the current user may not read is never requested, and a name the object -does not declare is never sent. diff --git a/.changeset/10373-fields-display-fls.md b/.changeset/10373-fields-display-fls.md deleted file mode 100644 index d89f836b24..0000000000 --- a/.changeset/10373-fields-display-fls.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): the lookup dropdown and record picker stop showing fields field-level security denies, and PeoplePicker's `$expand` is gated - -A lookup field's dropdown and its browse-all picker (`RecordPickerDialog`) -filtered their `$expand` through field-level security, but not what they -draw. Once the permission policy had loaded, a column the user may not read -on the referenced object was still previewed under each dropdown candidate, -and still headed and rendered in every picker row. A denied relation column, -left out of `$expand`, arrived as a bare id, and the lookup cell renderer then -fetched each related record on its own. A denied display field still labelled -every option, and a `titleFormat` template still printed every field it -named. - -Both now treat those fields the way `RelatedList` treats its columns: once the -policy has loaded, a column the user may not read on the referenced object is -not previewed in the dropdown, and is neither headed nor rendered in the -picker. The picker's display column is gated like any other column. Its id -column never is, and when the policy leaves no other column to draw, the -picker draws the id column so that every row can still be told apart and -chosen. A `renderGrid` slot on the picker receives the same columns. Before -the policy loads, nothing is filtered, and the columns are re-derived when it -arrives. - -An option's label is built from the row with the denied fields removed, -the same row ObjectStack's `FieldMasker` already serves, so on that backend -labels do not change. A denied display field therefore falls through to the -next source of a label, ending at the record id, and a `titleFormat` template, -in the dropdown's labels and in the picker's display column, leaves a denied -field's slot empty. The label is a display value only: the committed value is -unchanged, the records the picker hands to `onSelectRecords` are unchanged, -and the option the dropdown hands to `onSelectRecord` still carries the served -row's other fields beside its label. - -`PeoplePicker`, which a lookup opens when its field sets `picker: 'search'`, -derives its `$expand` from dotted `subtitle` paths such as -`primary_business_unit_id.name` when no `expand` is passed, and that list had -no permission check. Once the policy has loaded, a relation the user may not -read on the object the picker queries is now left out of `$expand`, whether -the list was derived from the subtitle paths or passed as `expand`. A subtitle -segment that goes through a relation left out shows nothing, as it does when a -backend ignores `$expand`. - -This is defence in depth: ObjectStack's `FieldMasker` already removes the -fields a user may not read from the rows it returns. The change matters for a -backend that does not. diff --git a/.changeset/10375-comment-and-inbox-dates-display-locale.md b/.changeset/10375-comment-and-inbox-dates-display-locale.md deleted file mode 100644 index af2e48f5ff..0000000000 --- a/.changeset/10375-comment-and-inbox-dates-display-locale.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/collaboration': patch -'@object-ui/console': patch ---- - -Two more dates now follow the display locale, not the UI language (objectui#10375). - -- `CommentThread` (`@object-ui/collaboration`): a comment seven or more days old shows an absolute - date, and that date now takes its locale from `useDisplayLocale()`. It used to format with the UI - language, so a regional display locale was ignored: an English UI with a `de-CH` display locale - read `3/4/2020` where it now reads `4.3.2020`. With no display locale declared, and with no - provider mounted at all, the date renders as before, because the display locale then falls back - to the UI language. A malformed display locale still falls back to the runtime's own date format, - never to the raw ISO string. -- The approvals inbox (`@object-ui/console`): once a submitted, completed or history timestamp is - 30 days old (rounded to the nearest day), the inbox shows a date instead of "Nd ago", and that - date now takes the page's display locale in the same way. -- The relative wording ("just now", "5m ago", "3d ago") is unchanged on both faces and stays in the - UI language. diff --git a/.changeset/10377-calendar-designer-mode-enum.md b/.changeset/10377-calendar-designer-mode-enum.md deleted file mode 100644 index 4527accc9b..0000000000 --- a/.changeset/10377-calendar-designer-mode-enum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/components': patch ---- - -`ui:calendar`: the designer no longer offers `mode: 'default'` (objectui#10377). `CalendarSchema.mode` and the `UiCalendarSchema` mirror admit only `single`, `multiple` and `range`, so a document authored with `default` was refused on save; react-day-picker 10 has no such mode either, and under it the calendar dropped the authored selection and ignored clicks. The registration `inputs` enum now lists exactly the contract's modes. diff --git a/.changeset/10379-favicon-one-writer.md b/.changeset/10379-favicon-one-writer.md deleted file mode 100644 index 5030f755a9..0000000000 --- a/.changeset/10379-favicon-one-writer.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/console': patch ---- - -An app's own favicon no longer turns into the operator favicon after an in-app -navigation (objectui#10379). This is the favicon twin of the tab-title race that -objectui#8637 fixed. - -Two effects wrote the icon link, keyed on different inputs. The console's -`FaviconSync` was keyed on `useLocation()` and wrote the operator favicon (the -runtime config's `branding.faviconUrl`) on **every route change**. -`useAppShellBranding` writes the active app's `branding.favicon` from an effect -keyed on that URL, so it fires when the app's branding changes and not on -navigation. With an operator favicon configured, moving between two pages of the -same app ran only the route-keyed writer, and the operator's icon replaced the -app's until the user left the app. - -The repair is one writer, the same as for the title. `FaviconSync` no longer -writes the favicon, and it now writes nothing at all. Nothing else needed to -change: the operator favicon is on the icon link before React mounts, written by -the pre-boot script in `index.html` and by `main.tsx` from a runtime config that -`main.tsx` awaits before the first render. Since objectui#10040 the shell also -captures the icon it finds and restores it when it unmounts. So inside an app -with its own favicon the tab keeps that favicon, and leaving the app shows the -operator favicon again. An app without its own favicon shows the operator -favicon throughout, and a deployment with no operator favicon is unaffected. diff --git a/.changeset/10380-object-page-stored-options-bag.md b/.changeset/10380-object-page-stored-options-bag.md deleted file mode 100644 index a9fd7409b3..0000000000 --- a/.changeset/10380-object-page-stored-options-bag.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -A stored list view now renders the same on an interface page and on the object page when it carries a legacy `options` bag (objectui#10380). - -`@objectstack/spec`'s flattened list view overlay accepts a legacy `options` bag (`options.kanban`, `options.timeline`, `options.map`, …). The view write door judges each block in it key by key with that kind's own schema, and stores what it accepts. The interface page passed the bag to the list renderer and the object page dropped it, so the same saved view could show a timeline grouped by one field on one page and ungrouped on the other, or a map with markers on one page and without them on the other. - -- **Object page:** passes the stored bag to the list renderer as well. For each kind the bag carries, the view's own top-level block (`kanban`, `timeline`, …) still wins key by key, which is the precedence the spec declares for the bag. -- **Interface page:** a default binding that the page derives from the object (a kanban lane, a calendar or timeline date, a gallery cover, gantt dates) no longer fills a kind that the bag already carries. Before this change, that derived guess could outrank the view's own declaration. The derived `map` binding already followed this rule. - -A stored row whose bag still holds a key the door now refuses is shown as stored, the same way on both pages, until its next save. That save is refused, and the refusal names the key. diff --git a/.changeset/10382-provider-late-bundle-rerender.md b/.changeset/10382-provider-late-bundle-rerender.md deleted file mode 100644 index 3ca3721987..0000000000 --- a/.changeset/10382-provider-late-bundle-rerender.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -'@object-ui/i18n': minor ---- - -Translations that `I18nProvider` loads after mount now reach the readers already -on screen (objectui#10382). - -**The defect.** Both of the provider's asynchronous loads end in -`addResourceBundle`: the app bundle from `loadLanguage`, and the built-in -catalogue for the language the instance booted in. Each was followed by a "force -re-render" that set the provider's `language` state to the value it already held. -React bails out of a same-value update, so nothing re-rendered. A reader that drew -the fallback before the bundle arrived (an object label read through -`useObjectLabel`, for example) kept drawing the English source label until -something unrelated re-rendered it, with no error. The console wires -`loadLanguage` exactly this way, so whether authored translations appeared on -first load depended on timing. - -**What changed.** - -- `useObjectTranslation`, and every hook built on it (`useObjectLabel`, - `useSafeTranslation`, `useDisplayLocale`), now subscribes each reader to the - i18next store's `added` event through react-i18next's `bindI18nStore` option, - passed per call. Every store write hands readers a new `t`, so a reader that - memoises on `t`, or on a resolver built from it, recomputes too. -- The two same-value `setLanguage` calls are gone. The one after the app bundle - also set the context's `language` back to the boot language when the user had - switched while the bundle was in flight. The context now stays on the language - i18next is on. -- The built-in catalogue is written only when the merge adds a key. That effect - re-runs on every language change, and an unconditional write would re-render - every reader for nothing. -- A switch through the context's `changeLanguage` writes its bundles silently, - because the `languageChanged` that follows re-renders every reader once, in - the new language. - -**Behaviour you may notice.** - -- On first load, a reader re-renders once when the app bundle lands, and once - more if the built-in catalogue was not resident yet. Work keyed on `t` or on a - label resolver runs again at that moment. For example, a chart that resolves - group labels while it fetches will fetch again, so that its labels come from - the new bundle. -- A language switch still re-renders each reader once. -- Host code that calls react-i18next's own `useTranslation` directly, rather - than `useObjectTranslation`, is not subscribed. It keeps react-i18next's - default, which re-renders on `languageChanged` only. - -No export is added or removed. Marked `minor` rather than `patch` because the -first-load behaviour is observable. diff --git a/.changeset/10383-object-view-grid-delete-deletes.md b/.changeset/10383-object-view-grid-delete-deletes.md deleted file mode 100644 index e818ed6768..0000000000 --- a/.changeset/10383-object-view-grid-delete-deletes.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/plugin-view': minor ---- - -The grid's row Delete and bulk Delete now delete the record when `ObjectView` renders the grid itself — the registered `object-view` renderer, with no host list view (objectui#10383). - -`ObjectGrid` hands the clicked row, or the selection, to its `onDelete` / `onBulkDelete` consumer and leaves the delete to it. `ObjectView`'s two handlers ignored the record and only refreshed, so a Delete the grid offers by default asked no question, called `dataSource.delete` zero times, and the row was still there after the refresh. - -They now bind to the same record-delete core as the console's own object list (`recordDelete` from `@object-ui/core`), so the two paths behave the same: - -- a row Delete asks "Are you sure you want to delete this record?". A package-owned permission set (a `sys_permission_set` row whose `managed_by` is `'package'`) is asked the reset question instead, because deleting it resets it to its shipped baseline rather than removing it. A bulk Delete asks once for the whole selection ("Delete N selected records? This cannot be undone."); -- Continue calls `dataSource.delete(objectName, id)` for each record, then refreshes the grid, so the deleted rows are gone. Cancel deletes nothing; -- the outcome is reported with the console's toasts: "LABEL deleted successfully" (or the reset message for a package-owned permission set) / "Deleted N LABEL records", or "Failed to delete LABEL" (with the error message, and no refresh) / "N deleted, M failed". - -The confirm dialog is `ObjectView`'s own, in the console's dialog shape. Its texts reuse translation keys the console already resolves, so they read the same in every shipped language. Whether Delete is offered at all is unchanged. It is still the grid's own verdict, the same one the console list uses: `operations.delete`, the principal's delete grant, the object's lifecycle and `userActions`, its API operations and the per-record verdict. diff --git a/.changeset/10383-record-delete-core.md b/.changeset/10383-record-delete-core.md deleted file mode 100644 index 9b30d9c771..0000000000 --- a/.changeset/10383-record-delete-core.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@object-ui/core': minor ---- - -New export `recordDelete` — the one record-delete core that list hosts bind to, so a Delete behaves the same wherever it is offered (objectui#10383). - -`recordDelete.confirmText({ objectName, t }, record?)` returns the question to ask before deleting one record. `recordDelete.run(deps, request)` performs the delete and reports it: one record, or several deleted one call each and settled together, then a refresh and the success, failure or "N deleted, M failed" toast. `deps` carries the host's `objectName`, `label`, `t`, `toast`, `dataSource` and optional `onRefresh`, so `@object-ui/core` takes no i18n or toast dependency. `request` is the action runner's `delete` shape (`params.records`, or `params.recordId` with an optional `params.record`), and the result is what a runner `delete` handler returns: the toasts are the feedback, so no path returns an `error` except a request with no record id. - -ADR-0094 lives here: a `sys_permission_set` row whose `managed_by` is `'package'` is reset to its shipped baseline, not removed, so it is asked the reset question and gets the reset toast. The row passed in is read first, with a best-effort `findOne` when only the id is known. - -The console's object list (`@object-ui/app-shell` `useObjectActions`) and the registered `object-view` grid (`@object-ui/plugin-view`) both call it. The console's behaviour is unchanged: its handler code moved here with no behaviour change, including the returns that keep the runner from showing a second toast. diff --git a/.changeset/10384-pager-clamp-after-write.md b/.changeset/10384-pager-clamp-after-write.md deleted file mode 100644 index ed92b14e7a..0000000000 --- a/.changeset/10384-pager-clamp-after-write.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -`ListView` no longer strands a server-paginated grid on a page a write has emptied. When a refetch comes back with zero rows past page 1 and the server's `total` says the last page is lower, the pager steps back to that last page and fetches it, showing a loading state in between. Before, bulk-deleting every row of the last page (or a concurrent delete) left the list on that page with the first-run "no records yet" empty state, although earlier pages still had records. A write that leaves the current page non-empty keeps the page, and an object with no records still shows the first-run empty state on page 1. diff --git a/.changeset/10387-header-bar-unread-keys-retired.md b/.changeset/10387-header-bar-unread-keys-retired.md deleted file mode 100644 index a44b27174c..0000000000 --- a/.changeset/10387-header-bar-unread-keys-retired.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/types': minor ---- - -fix(types): retire the eight `header-bar` keys the renderer never read (objectui#10387) - -`HeaderBarSchema.title`, `logo`, `nav`, `left`, `center`, `right`, `sticky` and -`height` are retired on both faces (ADR-0049). None of them is in the spec, and -of the keys `HeaderBarSchema` declares for itself, the `header-bar` renderer reads -only `actions`, `crumbs`, `rightContent` and `search`. Rendered through the real -`SchemaRenderer`, a header with any of these keys was identical to one without -them. - -- The zod mirror (`HeaderBarSchema` in `@object-ui/types/zod`) now refuses each - key by name. The refusal says what the renderer reads instead. -- The TypeScript declaration types each key `never`. -- `logo` also stops disagreeing with itself: the declaration said an image URL - string and the mirror a node or node list. Neither rendered, and both are - refused now. - -Breaking, but only for documents the renderer already ignored. A `header-bar` -that carries any of the eight keys now fails validation and no longer -type-checks. To migrate, delete the key: - -- `title`: name the current page with the last entry of `crumbs`. -- `logo`: put brand content in `rightContent` or `actions`. -- `nav`: put links in `crumbs`, or use a `navigation-menu` / `sidebar` node. -- `left` / `center`: put custom content in `rightContent` or `actions`. -- `right`: use `actions` (a node list) or `rightContent` (one node). -- `sticky`: make the parent layout sticky; the header itself never was. -- `height`: remove it, and set the height with `className` instead (for example - `h-20 sm:h-20`). By default the header is `h-14`, and `sm:h-16` from the `sm` - breakpoint up. - -The in-tree examples that used these keys (`packages/types/examples/dashboard.ts`, -the `@object-ui/types` README and the ObjectOS integration guide) now use -`crumbs` and `actions`. diff --git a/.changeset/10392-registration-record-source-inputs.md b/.changeset/10392-registration-record-source-inputs.md deleted file mode 100644 index 386a5436f7..0000000000 --- a/.changeset/10392-registration-record-source-inputs.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch -'@object-ui/plugin-map': patch -'@object-ui/plugin-gantt': patch ---- - -fix(plugin-calendar, plugin-map, plugin-gantt): the registrations' `inputs` agree with the record-source rule - -All three blocks read their records from one of `data`, `staticData` and -`objectName` (in that order), and their `@object-ui/types` zod schemas enforce -"one of the three" through `requireRecordSource`. The designer-facing `inputs` -on the registrations disagreed with that rule in two ways: - -- `object-calendar` and `calendar` still declared `objectName` as required, so - the html tier's validator reported a `missing-required-prop` error on a - calendar authored on `staticData` or `data`, which the schema accepts and the - renderer draws. `objectName` is now declared without `required`, and its - description states the rule, as objectui#7470 did for map and gantt - (objectui#10392). -- `object-map`, `map` and `object-gantt` did not declare `data` or - `staticData`, so the validator reported a block authored on either as an - unknown prop. At this change both were declared on all three, on the schema's - own arms: `data` is a `{ provider, … }` data-source configuration (an object, - so a bare array there draws a type diagnostic, matching the schema), and - `staticData` is an array of records. Each description says what the renderer - does with the key, including that the map does not implement the `api` - provider (objectui#10394). - - ⚠️ **Dated note, 2026-09-25 — the bare `map` registration has since been - retired — objectui#10393.** Later in this same release `@object-ui/plugin-map` - stopped registering the bare `map` key (and its namespaced twin `view:map`), - so `map` declares nothing: a node authored `"type": "map"` resolves no - renderer, and the html tier reports it as `unknown-component`. The - `object-map` and `object-gantt` registrations keep both inputs exactly as - described above. The rest of this entry is kept as the reading of this - change; the objectui#10393 entry states what ships. - -The renderers' read order and the zod schemas are unchanged. The -`@object-ui/plugin-gantt` README sentence that listed the registration's inputs -is updated. - -**Correction, 2026-10-01 (objectui#11117).** "One of the three" now has an exception on all -three blocks: a block that declares none of them is accepted when its `dataSource.object` names -the object, because the registration's `ElementDataSourceGate` lands that name on `objectName`. -The `objectName` input description now says so. diff --git a/.changeset/10393-retire-bare-map-key.md b/.changeset/10393-retire-bare-map-key.md deleted file mode 100644 index 5bbdb87ba5..0000000000 --- a/.changeset/10393-retire-bare-map-key.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -'@object-ui/plugin-map': minor -'@object-ui/core': patch -'@object-ui/cli': patch -'@object-ui/console': patch ---- - -**BREAKING (node type key):** `@object-ui/plugin-map` no longer registers the bare -`map` node type key, and its namespaced twin `view:map` goes with it. A node -authored `"type": "map"` no longer resolves a renderer. Write -`"type": "object-map"` — the one spelling the plugin serves (objectui#10393, -executing the objectui#8008 family ruling of 2026-09-09 that retired the bare -`gantt` and `kanban` keys). - -**Why.** The registry mounted a `map` node while the published declaration refused -it: `ObjectMapSchema.type` is the literal `'object-map'` and `AnyComponentSchema` -has no `map` arm, so `safeValidateSchema` answered a `map` node with -`invalid_union` while the html tier accepted it. Two faces, opposite verdicts. -No schema face ever declared `map` as a component node type, so there is no arm -to turn into a named refusal: unregistering is the whole retirement, exactly as -it was for `gantt`. After it, the html tier (`validateTree` over the live -registry) reports a `map` node as `unknown-component`, matching the Zod face. - -**⛔ No stored document moves.** The string `map` names two different things at -two different layers, and only one of them is retiring: - -| layer | value | who writes it | retired? | -| --- | --- | --- | --- | -| stored `NamedListView.type` / `defaultViewType` | `"map"` | `CreateViewDialog`, persisted per tenant | **no — untouched** | -| node type key | `map`, `view:map` | hand-authored JSON | **yes** | - -`ObjectView` and `ListView` map a stored `map` view onto the node type they -render, and both already emit `object-map`, so every map view created through -the console keeps rendering. Nothing in a tenant database changes, and ⛔ nothing -should be migrated there. - -**What moved with it.** - -- `@object-ui/console` drops its lazy `map` / `view:map` registration stub; the - lazy `object-map` stub is unchanged. -- `@object-ui/core`: `recordSourceDataArmForType` no longer lists the `map` and - `view:map` rows, since no block is registered under either key. -- `@object-ui/cli`: the generated known-type list that `objectui check` reads no - longer contains bare `map`, so the check now reports `map` as an unknown - schema type in a file it recognises. ⚠️ `view:map` stays on - that list, because the opt-in protocol placeholder (`registerPlaceholders()` - in `@object-ui/components`) registers it — in the console a `view:map` node - renders that placeholder panel, not a map, and `objectui check` does not report - it as an unknown schema type in a file it recognises. A bare - `{ "type": "view:map" }` with no structural key is listed in `check`'s advisory - did-not-validate list instead, because `view:map` is on the known-type list and - `AnyComponentSchema` has no arm for it; that line does not say the node renders - a placeholder. Search documents for `view:map` directly. - -⚠️ **Dated note, 2026-09-25 — `objectui check` flags `map` only in a file it -recognises — objectui#10606.** This entry first said, unscoped, that the check now -flags bare `map`. `check` checks the `type` of each file it recognises, and a file -whose root carries an ObjectUI structural key (`children`, `className`, `body`, …) -is recognised by that key alone. A file with none of those keys is parsed against -the schema and recognised only if it validates; one that does not validate is -listed by name when its root `type` is on that known-type list, and is otherwise -counted as skipped. `map` is no longer on it, so `{ "type": "map" }` is -counted as skipped ("no ObjectUI recogniser admitted") and gets no unknown-type -line, while `{ "type": "map", "className": "h-64" }` gets one. `check` exits -non-zero on unreadable JSON only; the verdict is `objectui validate`'s: it refuses -`{ "type": "map" }` at `type` (`invalid_union`) and exits non-zero. - -The `@object-ui/plugin-map` README now describes one registered type, and its -sentence claiming a bare array under `data` reaches the in-memory adapter is -corrected: a bare array under `data` is not a record source on the map -(objectui#8348), so inline rows belong under `staticData`. The same false claim -is corrected on the two docs pages that carried it, `plugins/plugin-map.mdx` -and `fields/location.mdx`. - -**One pending entry in this same release is superseded in part.** The -objectui#10392 / #10394 entry (`10392-registration-record-source-inputs.md`) -says `object-map`, `map` and `object-gantt` gained `data` / `staticData` -inputs. It now reads as of its own change and carries a dated note naming this -card: `map` declares nothing after this retirement, while `object-map` and -`object-gantt` keep both inputs. diff --git a/.changeset/10396-missing-series-key-refusal.md b/.changeset/10396-missing-series-key-refusal.md deleted file mode 100644 index 7428b2ed84..0000000000 --- a/.changeset/10396-missing-series-key-refusal.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/plugin-charts': patch ---- - -A cartesian chart whose series are bound to a column no row carries now says so, naming the -column, instead of drawing an empty frame (objectui#10396). The tile renders the existing -`data-chart-error` placeholder with the new code `missing-series-key` and a sentence worded after -`missing-category-key`: "This chart cannot plot its series: no row has a `KEY` field." Several -missing keys are joined with "or". A console warning names the missing keys and the keys the rows -do carry, as the category refusal's warning does. - -The shape is objectui#8266's: a fieldless count projects its value as `count`, and a series bound to -`value` over those rows drew the category ticks and zero marks, silently. What now refuses, each of -which drew zero marks before: a bar / column / horizontal-bar / line / area / combo chart with rows, -when not one row carries ANY bound series key. That holds whatever else the chart declares: a -stack, a declared `min` / `max` or `stepSize`, or a second axis. - -What keeps drawing, unchanged: a chart where even one row carries the key; a chart where one bound -key is carried and another is not (the carried series draws); and a dotted key such as `a.b`, -which the chart resolves into nested rows. A dotted key is never judged missing, so a chart that -binds one stays silent even when it resolves nothing. A column no row carries beside a key that is -carried but has no numeric value (for example an all-boolean series) also stays silent, as before. - -Precedence: `missing-category-key` wins when the category key is missing too, and -`no-plottable-series` still owns a chart with no series at all. A key that IS carried but holds no -numeric value on any row keeps `no-numeric-value` (objectui#7195). Scatter, pie, donut, funnel, -treemap and radar never receive this code. diff --git a/.changeset/10397-header-bar-classname.md b/.changeset/10397-header-bar-classname.md deleted file mode 100644 index ce8987e037..0000000000 --- a/.changeset/10397-header-bar-classname.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/components': patch -'@object-ui/types': patch ---- - -`ui:header-bar` now applies an authored `className` to its root `header` element -(objectui#10397). - -`HeaderBarSchema` extends `BaseSchema`, whose `className` is the declared Tailwind -override channel, but the renderer's root carried a fixed class string. Rendered -through the real `SchemaRenderer`, a header with `className` was byte-identical to -one without it. - -The root now merges `className` after its own classes through `cn()` -(tailwind-merge), so an authored utility that conflicts with a default replaces it: -`h-20` replaces `h-14`. The merge is per variant, so `h-20` leaves `sm:h-16` in -place; write `h-20 sm:h-20` for one height at every width. Without `className` the -root's classes are unchanged. - -The scope class `SchemaRenderer` appends to a node's `className` for its -`responsiveStyles` rides the same channel, so a header's `responsiveStyles` now -reach its root too. Before, that class never arrived and the compiled rules matched -nothing. - -In `@object-ui/types`, the zod mirror's refusal messages for the nine retired -`header-bar` keys (`title`, `logo`, `nav`, `left`, `center`, `right`, `sticky`, -`height` and `variant`) said the renderer reads only `actions`, `crumbs`, -`rightContent` and `search` off the node. They now name the inherited `className` -as well. The `height` refusal said the renderer fixes the height; it now points at -`className` to change it. The `@deprecated` docs on the TypeScript declaration are -corrected the same way, and so is the read list in its `body` / `children` docs. -Only the text changes: every one of those keys is refused exactly as before. - -The docs page now lists `search`, `actions` and `rightContent` in its Schema block, -and gives the height as the code sets it: `h-14`, and `sm:h-16` from the `sm` -breakpoint up. - -Scored `patch`: a declared key that had no effect on this node now applies. diff --git a/.changeset/10399-record-picker-limit-precedence-text.md b/.changeset/10399-record-picker-limit-precedence-text.md deleted file mode 100644 index dc0df3dd60..0000000000 --- a/.changeset/10399-record-picker-limit-precedence-text.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@object-ui/components': patch ---- - -`element:record_picker`'s `limit` input description now states the row-cap precedence the -picker actually resolves (objectui#10399). It used to read `dataSource.limit ?? limit ?? 50` -with the binding winning outright, which skipped the named saved view's cap and, since -objectui#10016, was also false for a binding cap the contract refuses. The description now -names four sources in order (the binding's `limit`, the named view's row cap, the picker's -own `limit`, then 50) and says that a refused binding or view cap (`0`, a negative, a -non-integer) is treated as not authored and falls through. Text only: no behaviour change. diff --git a/.changeset/10404-undo-absent-field-not-null.md b/.changeset/10404-undo-absent-field-not-null.md deleted file mode 100644 index a671ee66d9..0000000000 --- a/.changeset/10404-undo-absent-field-not-null.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/app-shell': minor ---- - -fix(core): Undo of an `undoable` update no longer writes `null` over a field the row did not carry - -An `undoable` update records the prior value of every field it writes, read off -the row it ran on, so the success toast can offer Undo. On a list row projected -by `$select` (`ListView`, `ObjectGrid`, `RelatedList`), a written field that no -column shows was absent from the row. It was recorded as `null`, and Undo then -wrote `null` over the value it existed to restore: close a task from a grid that -shows only its name, press Undo, and its status became empty instead of `open`. - -Two changes: - -- The list harvest (`listViewPredicates`) now also names the fields an - `undoable` action writes: its `patch` keys, the key each param's value is - collected under (`name`, else `field`), and its `bodyExtra` keys. So a - projected row carries them, through the same gates as every harvested name: - a bare identifier, a field the object declares (or a platform column), and - field-level security once the permission answer has loaded. `recordId` is - not harvested; both writers strip it as the record's address. -- The capture never records an absent field as `null`, in `ActionRunner`'s - `operation: 'update'` path and in the console `api` handler's data-source - branch alike. When the row does not carry every written field (for example a - field the principal may write but not read), the action still runs, but it - offers no Undo: the success toast has no Undo button, nothing is pushed onto - the undo stack, and a console warning names the missing fields. A `null` the - row does carry is a real empty value and is still restored as `null`. - -Behaviour to know about: on a backend that leaves null-valued fields out of a -full record, an `undoable` update of such a field now offers no Undo instead of -one that restores it to empty. Absent and empty cannot be told apart there, and -no Undo is the side that cannot overwrite stored data. diff --git a/.changeset/10422-currency-mode-dynamic-tenant-default.md b/.changeset/10422-currency-mode-dynamic-tenant-default.md deleted file mode 100644 index 4286a961a1..0000000000 --- a/.changeset/10422-currency-mode-dynamic-tenant-default.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/i18n': minor ---- - -A currency field in `dynamic` mode shows the tenant's currency, not its -`currencyConfig.defaultCurrency` (objectui#10422). - -`@objectstack/spec` declares two currency modes: `fixed` (a single currency) and -`dynamic` (user selectable). Its field guidance says a field without a fixed -currency uses the tenant default at runtime. `resolveFieldCurrency` read -`currencyConfig.defaultCurrency` in either mode, so in a USD tenant a field -declaring `currencyConfig: { currencyMode: 'dynamic', defaultCurrency: 'EUR' }` -showed `€3,456` where it should show `$3,456`. An empty `currencyConfig`, which -the spec parses to a dynamic config with `defaultCurrency: 'CNY'`, showed -`CN¥`. - -The resolver now reads `currencyConfig.defaultCurrency` only when -`currencyMode` is `'fixed'`. Its precedence is: the explicit `currency`, then a -fixed `currencyConfig.defaultCurrency`, then the legacy top-level -`defaultCurrency`, then the tenant default. With none of these, it returns -`undefined` and the amount shows as a plain number. - -**Behaviour change.** Every face that resolves a currency through -`resolveFieldCurrency` changes together: the list cell, the field widget, the -metric tile, the detail summary chip, the gantt tooltip, and the grid's -configured cells and summary footer. On each of them, a field in `dynamic` mode -now shows the tenant currency. So does a `currencyConfig` that names no -`currencyMode`, because the spec's default mode is `dynamic`. To keep a field on -one currency, declare `currencyMode: 'fixed'`. A fixed field renders as before. - -The parameter type of `resolveFieldCurrency` gains an optional -`currencyConfig.currencyMode` member (`'dynamic' | 'fixed'`), which is the -spec's enum. diff --git a/.changeset/10423-mobile-card-field-currency.md b/.changeset/10423-mobile-card-field-currency.md deleted file mode 100644 index b8fa2c841c..0000000000 --- a/.changeset/10423-mobile-card-field-currency.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/plugin-grid': patch ---- - -fix(plugin-grid): the mobile card's amount line reads the field's own currency - -`ObjectGrid`'s mobile card summarises the row's amount on one line. That line -resolved its currency from the card's column draft, which carries neither -`currency` nor `currencyConfig`, so it always fell through to the tenant -currency. Under a USD tenant a field fixed to JPY -(`currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'JPY' }`) read `¥` -in the desktop cell and the summary footer (objectui#10354) but `$` on the phone -card of the same row. The line now resolves from the object schema's field def, -the same def the desktop cell reads, on every column shape. diff --git a/.changeset/10425-ru-ar-count-labels.md b/.changeset/10425-ru-ar-count-labels.md deleted file mode 100644 index 317c850b9c..0000000000 --- a/.changeset/10425-ru-ar-count-labels.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -'@object-ui/i18n': patch ---- - -Russian now reads correctly at every count on the list view's record-count bar, -and Arabic on that bar, the record picker's count, the activity-feed reaction chip, -the presence avatars' accessible name and overflow tooltip, and the full-page -search count while browsing (objectui#10425). - -Each of these surfaces picks its `…One` key at exactly one and the plain key at -every other count. Where the plain key held a single noun form, it was wrong at -some of the counts it serves. The Russian record-count bar read `2 записей` at two -(the language needs `2 записи`) and `21 записей` at twenty-one (it needs -`21 запись`). The Arabic values each held one noun form (the plural for three to -ten, or in `lookup.recordCount` the singular), while Arabic needs different forms -at two, at three to ten and from eleven up. - -The count-not-one half of these seven values is now a count label that reads -correctly at any number: - -- `ru` `list.recordCount`: `Записей: N` -- `ar` `list.recordCount`: `عدد السجلات: N` -- `ar` `lookup.recordCount`: `عدد السجلات: N` -- `ar` `detail.reactionCount`: the emoji, then `عدد التفاعلات: N` -- `ar` `collaboration.presentUserCount`: `عدد المستخدمين المتواجدين: N` -- `ar` `collaboration.moreUserCount`: `عدد المستخدمين الآخرين: N` -- `ar` `search.itemsAvailable`: `عدد العناصر المتاحة: N` - -That is the device objectui#10024 and objectui#10242 used, and the one Russian's -`lookup.recordCount` already uses. The singular halves, the key set, the call sites -and the other eight packs are unchanged. - -⚠️ **Dated note, 2026-10-02 — superseded in this release — objectui#11445.** -Later in this same release the `…One` / plain-key switch on `list.recordCount`, -`lookup.recordCount`, `detail.reactionCount`, `collaboration.presentUserCount`, -`collaboration.moreUserCount` and `search.itemsAvailable` gave way to one count -family per key in all ten packs: a numeric count picks the noun form its CLDR -category needs (`ru` `2 записи`, `ar` `3 سجلات`), the `…One` siblings left every -pack, and the count labels above remain only on the base key, which answers a -call made without a count. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10432-reseed-purge-error-code.md b/.changeset/10432-reseed-purge-error-code.md deleted file mode 100644 index 8ad8c54de7..0000000000 --- a/.changeset/10432-reseed-purge-error-code.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/i18n': patch ---- - -fix(app-shell): a cloud Re-seed / Purge refused with `ENVIRONMENT_KERNEL_UNAVAILABLE` now says why and stops offering the retry - -`reseedSampleData` and `purgeSampleData` kept only the text of a refusal and -dropped its error code. On a 500 that text is the control plane's withheld -generic sentence, so the package page showed the same message for every server -fault. That included a control plane with no environment kernel, where the two -actions can never succeed (cloud#2072). - -Both calls now return the code beside the text. When the code is -`ENVIRONMENT_KERNEL_UNAVAILABLE`, the package page says that this control plane -has no environment kernel and that the action must be run from the -environment's own runtime, and it disables both cloud sample-data actions for -the rest of the visit. Every other code, `INTERNAL_ERROR` included, keeps -today's message and leaves the actions enabled. The HTTP status handling is -unchanged. - -`@object-ui/i18n` carries the new sentence as `marketplace.detail.sampleDataKernelUnavailable` -in all ten locale packs. diff --git a/.changeset/10433-peoplepicker-fls-outputs.md b/.changeset/10433-peoplepicker-fls-outputs.md deleted file mode 100644 index 508e096388..0000000000 --- a/.changeset/10433-peoplepicker-fls-outputs.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): PeoplePicker rows and its selection tray, and a people lookup's chip, stop drawing fields field-level security denies - -A lookup field that sets `picker: 'search'` (every user field does by default) -opens `PeoplePicker`, whose rows show an avatar and a subtitle line built from -the field's `subtitle` paths, such as `primary_business_unit_id.name` and -`email`. Only the `$expand` those paths imply was filtered through field-level -security. Once the permission policy had loaded, a row still drew every -subtitle field and the avatar straight from the record the server returned, so -a field the user may not read on the queried object, such as `email`, still -showed. The multi-select tray drew the same avatar, and the field's selected -chips drew theirs from the configured avatar field, then from `image`. - -Now, once the policy has loaded, a row leaves out each subtitle path whose -field on the queried object the user may not read, and draws no avatar image -when the avatar field is denied: the initials show instead, and the row can -still be chosen. A path through a relation is judged by the relation field, so -it is left out even when a backend returns the related record without being -asked. The tray follows the same rule. A chip judges both keys it reads: the -configured avatar field, and `image`, which it falls back to. A readable -`image` still stands in for a denied avatar field. Before the policy loads, -nothing is withheld. The records the picker hands to `onSelectRecords` are -unchanged. - -This is defence in depth: ObjectStack's `FieldMasker` already removes the -fields a user may not read from the rows it returns. The change matters for a -backend that does not. diff --git a/.changeset/10434-record-title-fls.md b/.changeset/10434-record-title-fls.md deleted file mode 100644 index 7cf577ebde..0000000000 --- a/.changeset/10434-record-title-fls.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/plugin-detail': patch -'@object-ui/app-shell': patch ---- - -fix(plugin-detail,app-shell): a record's title no longer prints a field the viewer may not read (objectui#10434) - -`DetailView` hid the row of every field the loaded permission policy denies, -but it built its header title from the record as served. On a backend that -does not strip denied fields, a `titleFormat` token, a declared `nameField` or -a view `primaryField` that the policy denies therefore printed in the heading -while its row was hidden. The record page built its breadcrumb title the same -way, and the favourite and the "Recently Accessed" entry carry that title. - -Both titles are now built from the record with the denied fields removed. The -record id is always kept, so the `Record #` id floor still applies. A denied -field is read exactly as an absent one, and the title falls through to its -next source, the title ObjectStack's `FieldMasker` row already yields. No -placeholder stands in for a withheld value. A template with a denied token -renders what it renders when that field is empty. - -`record:details` hides the one body row that repeats the title, and it now -makes that choice from the same row. With the block's own header -(`showHeader: true`), the heading and that choice therefore read the same -record, and a denied title field no longer leaves the fallen-through title's -row printed directly under the heading. On the record page, `page:header` -now builds its heading from the same gated row (objectui#10499). ⚠️ Under a -`page:header` whose host hands it the record as served, the body now matches -what a stripping backend renders. The heading can still print the denied value -there, and the row hidden is then the one a stripping backend's heading would -show. - -Before a permission policy loads, and with no permission provider mounted, -nothing is removed and every title is unchanged. - -This is defence in depth: ObjectStack's `FieldMasker` already removes the -fields a user may not read from the rows it serves, so on that backend no -title changes. diff --git a/.changeset/10435-select-label-association.md b/.changeset/10435-select-label-association.md deleted file mode 100644 index 2a10481901..0000000000 --- a/.changeset/10435-select-label-association.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/components': patch ---- - -The `ui:select` form renderer's `label` now names its combobox (objectui#10435). - -Before, the renderer drew its `Label` with no `htmlFor` and the Radix -`SelectTrigger` with no `id`, and nothing set `aria-label` or -`aria-labelledby`. The trigger is a `button` with `role="combobox"`, a role -that takes no name from its content, so the placeholder and value text inside -it did not name it either: a labelled select's combobox had an empty accessible -name, and a screen reader announced an unnamed combobox. - -The fix is the shape `element:record_picker` landed for the same defect -(objectui#5771): the trigger gets the node's `id`, and the label gets `htmlFor` -to it. A labelled select authored with an `id` is now named by its label, and a -required one's name leaves out the `*`, because the required marker is an -`aria-hidden` element (objectui#10368). A select authored without an `id` -is unchanged: the renderer mints no id, so its caption stays unassociated, as -on the sibling `input` and `textarea` renderers. diff --git a/.changeset/10437-retire-default-upgrade-url.md b/.changeset/10437-retire-default-upgrade-url.md deleted file mode 100644 index 15cac8f7b2..0000000000 --- a/.changeset/10437-retire-default-upgrade-url.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the environment entitlement dialog renders no upgrade CTA when the control plane sends no upgrade URL - -The dialog shown when an environment create is gated by plan or capacity -(`DEV_ENV_PLAN_LOCKED` / `DEV_ENV_LIMIT`) filled a missing `upgrade_url` (403 -path) or `upgradeUrl` (entitlement summary) with a client-side default, -`/settings/billing`. The CTA is a full-page anchor resolved against the -control-plane origin, and no router serves that path: the Console declares -`settings` only under `/organizations/:slug`, and the control plane mounts its -console under `/_console`. A user who clicked "Upgrade plan" landed nowhere. - -The default is gone (objectui#10437). The upgrade destination is the control -plane's to name. When it sends one, the CTA links to it verbatim, exactly as -before. When it sends none, the dialog still explains the gate but offers no -link, which is the rule objectui#7273 set for the tenant Console's upgrade -exit. The entitlement state no longer carries a synthesized URL either: its -`upgradeUrl` is the summary's value or absent, and the row-derived and unknown -states have none. diff --git a/.changeset/10439-storage-usage-banner.md b/.changeset/10439-storage-usage-banner.md deleted file mode 100644 index e9047711b1..0000000000 --- a/.changeset/10439-storage-usage-banner.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/app-shell': minor -'@object-ui/i18n': minor ---- - -Show the environment admin a storage-capacity banner from the tenant runtime's own -storage verdict (objectui#10439, the objectui half of cloud#2135). - -`GET /api/v1/usage/storage` already served the verdict the upload and bulk-import -guardrail refuses with (`warn` from 80%, `blocked` at 100%) and the two figures -`usedMb` / `limitMb`. Nothing in the console rendered them, so an environment could -fill up with no warning and learn it was full only when an upload failed. - -- **`warn`**: a banner with the used and limit figures, for example "850 MB of - 1,024 MB used". -- **`blocked`**: the banner says storage is full and uploads and imports are paused, - that existing data is untouched, and links to the control plane to upgrade. The link - is left out on a runtime that names no upstream cloud. -- **Anything else** (`ok`, `unknown`, `unlimited`, an endpoint that cannot be read or - answers off-contract) renders nothing. - -The banner reads the served verdict. It never compares the figures with each other or -with a threshold, so it shows what the guardrail enforces. It is mounted in -`ConsoleShell` beside the read-rate report and has the same audience: only a workspace -admin sees it, and only a workspace admin's session issues the request. The two -banners share one request to the endpoint. Neither banner is exported from the package -entry. - -`@object-ui/i18n` gains the five `console.storageUsage.*` keys in all ten locale packs. diff --git a/.changeset/10442-date-faces-display-locale.md b/.changeset/10442-date-faces-display-locale.md deleted file mode 100644 index 7e012dbd44..0000000000 --- a/.changeset/10442-date-faces-display-locale.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/components': patch -'@object-ui/app-shell': patch -'@object-ui/plugin-gantt': patch -'@object-ui/plugin-calendar': patch ---- - -Four more date faces now follow the display locale, not the UI language (objectui#10442). - -Each one takes its locale from `useDisplayLocale()` instead of the UI language. With an English UI and -a `de-CH` display locale, a date that used to read `3/4/2020` now reads `4.3.2020`. With no display -locale declared, the display locale falls back to the UI language, so these dates render as before. - -- `data-table` (`@object-ui/components`): the ISO date and datetime cells. -- The record page's History tab (`@object-ui/app-shell`): the `date` and `datetime` values in each - field diff. -- `ResourceWorkload` (`@object-ui/plugin-gantt`): the column labels and the cell tooltips. With no - language at all it used to fall through to the machine's locale; it now gets the display locale's - own last resort. -- `CalendarView` (`@object-ui/plugin-calendar`): the default locale for the header, the weekday - columns and the day cells. An explicit `locale` prop still wins over the display locale. diff --git a/.changeset/10447-one-title-interpolator.md b/.changeset/10447-one-title-interpolator.md deleted file mode 100644 index 13bedc303c..0000000000 --- a/.changeset/10447-one-title-interpolator.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/core': patch -'@object-ui/components': patch ---- - -One `titleFormat` interpolator for the record title (objectui#10447, objectui#10446). - -`@object-ui/core`: `formatTitleTemplate` now judges a placeholder empty the way `recordDisplayValueAt` does: trim, then empty. A whitespace-only value used to count as resolved, so `{contract_no} - {name}` with a blank `name` rendered `HT-2026-003 -` in `formatTitleTemplate` and in `getRecordDisplayName`'s `titleFormat` rung, and so on every surface backed by that resolver. It now renders `HT-2026-003`. Both functions run one shared implementation of the rule, so a resolved placeholder renders the same trimmed display string `recordDisplayValueAt` returns. The exported signatures are unchanged. - -`@object-ui/components`: the record page H1 (`page:header`) renders its `titleFormat` rung through core's `formatTitleTemplate`, the function `getRecordDisplayName` and `record:details`' H1 dedupe already use, instead of its own interpolation and separator cleanup. Visible changes on that rung: - -- An expanded lookup token renders its display name: `{account} - {deal_no}` reads `Acme - Q3-042` where the H1 used to drop the lookup and read `Q3-042`, so `record:details` no longer prints the row it wrongly treated as distinct from the heading. -- A comma left by an empty placeholder is stripped: `{deal_no}, {code}` with no `code` reads `Q3-042`, not `Q3-042,`. -- A template none of whose placeholders resolves no longer shows its literal text (`Session — {user_id}` with no user used to read `Session`); the H1 walks on to the next rung, as `getRecordDisplayName` does. -- A select token still reads as its translated option label: the label is applied to a copy of the record before core renders it. - -The rungs' order is unchanged. `page:header`'s own `title` and `subtitle` templates keep their existing interpolation. - -This supersedes how two earlier changesets, still pending in the same release, describe the `titleFormat` rung; each now carries a dated note naming this card. objectui#9436 (the declared pointer outranks `titleFormat` in `page:header`) said the template kept the header's own interpolation. objectui#9174 (`interpolate()`'s no-token fast path) listed the record-title `titleFormat` among `interpolate()`'s callers. Both describe the header as it was at their change; from this release the rung renders through `formatTitleTemplate`. diff --git a/.changeset/10448-designer-invalid-not-published-flags.md b/.changeset/10448-designer-invalid-not-published-flags.md deleted file mode 100644 index ff7495e18c..0000000000 --- a/.changeset/10448-designer-invalid-not-published-flags.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): two more designer unknown-value flags read in the designer's locale - -Two designer pickers still wrote their unknown-value flag as an English template -literal, so a zh-CN author read untranslated English on an otherwise Chinese -inspector: the approver membership-tier select flagged a stored tier outside its -vocabulary `(invalid)`, and the Hook inspector's object picker flagged a selected -object the live catalog does not list `(not published)`. - -Both flags now come from the designer's string catalogue through the same -`engine.form.flaggedValue` template the other unknown-value flags use. Two rows -sit beside `engine.form.notFound` and `engine.form.deprecated`: -`engine.form.invalid` and `engine.form.notPublished`, each in en and zh. zh shows -the value followed directly by its full-width-bracketed flag. The en-US text is -unchanged. - -The membership-tier select has no `locale` prop, so it follows the designer's -active language through `useMetadataLocale()`. The Hook inspector uses the -`locale` it already receives. diff --git a/.changeset/10456-objectmap-description-lookup.md b/.changeset/10456-objectmap-description-lookup.md deleted file mode 100644 index 193d4fa27b..0000000000 --- a/.changeset/10456-objectmap-description-lookup.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/plugin-map': patch ---- - -A map marker's description no longer crashes the popup when `descriptionField` names a lookup. - -`ObjectMap` copied the raw `descriptionField` value onto each marker. The popup and -the mobile record sheet put that value in JSX, and the search box called -`.toLowerCase()` on it. A lookup is a field like any other, and `ObjectMap`'s own -object fetch expands every declared relation, so a lookup-typed description arrived -as `{ id, name }`. React then threw `Objects are not valid as a React child` on the -first marker click. A number or a boolean description made the search box throw as -soon as anyone typed. - -The marker transform now derives the description once, as a display string, through -`@object-ui/core`'s `recordDisplayValueAt`. That is the resolver the marker title -already uses for an authored `titleField`. The popup, the mobile record sheet and -the search all read that one string: - -- an expanded lookup shows its display name; -- a bare id shows as itself, as before; -- a number or a boolean shows as its string, so `false` now appears where the old - truthiness gate dropped it; -- an empty or whitespace-only value, or an expanded record with no display name, - shows no description line. - -No schema or spec key changes. `ObjectMap.descriptionDisplay-10456.test.tsx` pins -each case above. diff --git a/.changeset/10462-action-entry-object-params.md b/.changeset/10462-action-entry-object-params.md deleted file mode 100644 index 03cbb6225e..0000000000 --- a/.changeset/10462-action-entry-object-params.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/components': patch ---- - -fix(components): spec action entries stop forwarding an object `params` as values on non-`api` types - -This finishes ruling A on objectui#10289 for the spec action-entry surfaces: an -action's `params` is only the `ActionParam[]` list of inputs to collect from the -user. `action:button` / `action:icon` already follow it. Now `element:button`'s -inline `action`, `action:group` items, `action:menu` items and `page:header`'s -header actions follow it too (objectui#10462). - -- An ARRAY `params` is forwarded to the runner as `actionParams`, the input list. - `action:group` and `action:menu` used to forward it under `params`. The runner - read both spellings the same way, so param collection behaves as before. -- An OBJECT `params` on any action type except `api` is no longer forwarded as - `ActionDef.params` values. A development build logs one warning per action, - and production is silent. `page:header` still stashes the current record - under `params._rowRecord`; only the authored object is left out. -- An OBJECT `params` on a `type: 'api'` action is unchanged. The objectstack#5777 - window keeps the runner reading it as the request payload, with its own - warning naming `bodyExtra`, until 18. - -The spec already refuses an object `params` at the authoring door, so only -metadata that skipped validation is affected. diff --git a/.changeset/10463-dashboard-field-currency-config.md b/.changeset/10463-dashboard-field-currency-config.md deleted file mode 100644 index 45197fc31f..0000000000 --- a/.changeset/10463-dashboard-field-currency-config.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -A fixed-currency field shows its own currency in the dashboard table widget and -in the record drawer it opens, not the tenant's (objectui#10463). - -`@objectstack/spec` refuses a field-level `currency`, so a fixed currency is -declared as `currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'JPY' }`. -`buildFieldMeta`, the helper both `ObjectDataTable` and `RecordDetailDrawer` -build their field metadata with, read only the flat `currency` and -`defaultCurrency` keys and never `currencyConfig`. In a USD tenant, a JPY-fixed -amount of 1234 read `$1,234` in the table cell and in the drawer, while the -grid and the metric tile read `¥1,234` for the same field. - -`buildFieldMeta` now resolves the field's currency through -`resolveFieldCurrency` from `@object-ui/i18n`, the resolver the grid, the -metric tile and the currency cell already share. A column's own `currency` -still wins over the field's. The resolver is called without the tenant -default, so a column `format` that starts with a currency symbol still wins -over the tenant currency, as before. - -**Behaviour change.** In the dashboard table widget and the record drawer, a -field whose `currencyConfig` is in `fixed` mode now shows -`currencyConfig.defaultCurrency` where it used to show the tenant currency. A -field in `dynamic` mode, or with a `currencyConfig` that names no -`currencyMode`, still shows the tenant currency, because the resolver reads -`currencyConfig.defaultCurrency` only in `fixed` mode (objectui#10422). A field -that carries both a fixed `currencyConfig` and the legacy top-level -`defaultCurrency` now shows the fixed code, which is the resolver's order. diff --git a/.changeset/10466-inline-edit-draft-read-rule.md b/.changeset/10466-inline-edit-draft-read-rule.md deleted file mode 100644 index 2ae94bc025..0000000000 --- a/.changeset/10466-inline-edit-draft-read-rule.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/react': patch ---- - -Correct the read rule in the `InlineEditContextValue.draft` doc comment (objectui#10466). - -It told hosts to read a field's live value as `draft[name] ?? data[name]`. That read -falls back to the saved value when the draft value is `null` or `undefined`. A field the -user emptied is an own draft key with an empty value, and so is a single select or radio -emptied by a cascade clear, which stages `null` since objectui#10291. A host that followed -the comment showed the value the user had just removed, and handed it back to an option -widget that pruned it, which pruned it again on every render (the loop objectui#7190 fixed -on the highlights strip). - -The comment now teaches the own-key read: take the value from the staged record -`{ ...data, ...draft }`. An own draft key wins even when its value is empty -(`null`, `undefined`, `''`), and the saved value is read only when the key is absent. The -comment ships in `dist` typings and is what a host author sees on hover. No runtime -behaviour changes. A source-text pin keeps the comment from teaching a fallback read again. diff --git a/.changeset/10471-tombstone-names-resolved-spelling.md b/.changeset/10471-tombstone-names-resolved-spelling.md deleted file mode 100644 index 747ce38891..0000000000 --- a/.changeset/10471-tombstone-names-resolved-spelling.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -The retired-field tombstone now names the spelling it was resolved under, not -the live `type` of the field it is handed (objectui#10471). - -A retired spelling can reach the tombstone through an authored `widget`, which -wins over `type` in both form hosts. A field such as -`{ type: 'user', widget: 'owner' }` was therefore answered by the `owner` -tombstone, but the tombstone re-derived its spelling from the field and said -"Field type `user` was retired": it named a LIVE type as retired, dropped the -migration prescription for `owner`, and logged nothing to the console. - -`getLazyFieldWidget` and the `field:` registrations made by -`registerAllFields()` now hand out a tombstone bound to the retired key they -resolved, one component per spelling. `RetiredFieldTombstone` reads a new -optional `retiredFieldType` prop first and falls back to the field's `type` only -when it is absent, so a host that renders it directly with a field whose `type` -is the retired spelling behaves as before. - -The retired-type table itself is unchanged. The registry entry under -`field:owner` is now the bound tombstone rather than `RetiredFieldTombstone` -itself, so code that compared the registry entry by identity against -`RetiredFieldTombstone` should compare what it renders instead. diff --git a/.changeset/10472-formpage-widget-degrades-to-type.md b/.changeset/10472-formpage-widget-degrades-to-type.md deleted file mode 100644 index d1704610f7..0000000000 --- a/.changeset/10472-formpage-widget-degrades-to-type.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/console': patch ---- - -fix(console): a `FormPage` field whose `widget` names nothing registered renders its `type`, not a text box - -The spec's `FieldSchema.widget` declares that the override names a registered -field component and "Degrades to the `type` renderer when unregistered". -`FormPage` took an authored `widget` whenever one was present and handed it to -`resolveFormWidgetType`, which answers a spelling nothing registers with the -`text` widget. So a `select` field carrying a `widget` that no widget is -registered under (on the object field or on the form view) rendered a -free-text input, and the user could type a value the picklist never offered. - -The `widget` leg now asks the same shared resolver whether the spelling names -anything, and falls through to the arity and `type` legs when it does not. -The select renders its select. A registered widget still wins over the type, a retired spelling -still reaches its tombstone, and an alias the resolver knows keeps resolving -as before. No list of widgets was added: the answer is the resolver's own. diff --git a/.changeset/10474-datetime-editor-impossible-day.md b/.changeset/10474-datetime-editor-impossible-day.md deleted file mode 100644 index e8aedf3038..0000000000 --- a/.changeset/10474-datetime-editor-impossible-day.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/fields': patch -'@object-ui/i18n': patch ---- - -fix(fields): the editable date-time faces no longer roll a stored impossible day into a real one - -`toDateTimeInputValue` let a `Z`, offset or date-only spelling fall through to -`new Date(...)`, which accepts a day of 01-31 for every month and rolls the -surplus forward: a stored `2026-02-30T10:00:00Z` reached the `datetime-local` -control as `2026-03-02T10:00`, and an edit could save that day back. The read -faces already refuse such a value (objectui#10026, objectui#10301). - -The adapter now asks the same judgement (`isRealCalendarDate`) of the day AS -WRITTEN, before any conversion, in every spelling, and `fromDateTimeInputValue` -never re-emits a nonexistent day as a rolled one. A `datetime-local` control can -paint a nonexistent day only blank (measured in Chromium), so the editable -`DateTimeField` and the sub-grid's editable `datetime` cell leave the control -empty, mark it `aria-invalid`, and name the stored string beside it with the new -`fields.dateTime.impossibleDay` sentence (all ten packs). Nothing is written until -the user picks a new value; a real date-time and a zone-less value behave as before. diff --git a/.changeset/10475-default-arm-section-builder.md b/.changeset/10475-default-arm-section-builder.md deleted file mode 100644 index 1e604d763a..0000000000 --- a/.changeset/10475-default-arm-section-builder.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): the default `object-form` layout draws a section's members in the order the section lists them, and applies each section entry's overrides - -With explicit `sections` and no `formType`, `ObjectForm` resolved each -section's members with a name filter over the form's field list. The members -came out in the order of that list (top-level `fields`, or the object's own -field order), not in the order the section wrote them, and a section entry -written as a spec `FormFieldSchema` object (`{ field: 'note', label: …, -required: true }`) kept only its `visibleOn`, `colSpan` and `span`. Every other -override was dropped without a warning. An authored `required: true` was -therefore not enforced, and `label`, `readonly`, `hidden`, `helpText`, -`placeholder`, `options`, `min` / `max`, `widget` and `visibleWhen` did nothing. -The `drawer`, `modal`, `tabbed`, `wizard` and `split` layouts already honoured -all of them, so the same `sections` block laid out differently depending on -`formType`. - -The default layout now builds sections the way the other five do. Members -render in the section's order, and every entry override applies: `required` -refuses an empty submit, and `visibleWhen` hides the member until the record -satisfies it. Two things stay as they were. First, a section member that the -top-level `fields` does not list is still dropped, with its console warning, -because the two keys intersect. Second, at this change the form's own field -definition remains the starting point for an override, so an override does not -lift a managed object's field lock, and field-level security still hides or -locks each member. The same fix reaches `object-master-detail-form`, whose -parent form renders through this layout. - -⚠️ **Dated note, 2026-09-25 — the managed-object field lock no longer rides the form's own field definition — objectui#10612.** -Later in this same release the lock moved out of this layout's field generator -into the one field-gate step every layout draws its fields through, after the -section builder and together with field-level security. An override still does -not lift the lock, but the reason is now that the lock is applied after the -override, on every layout, rather than that it rides the definition the -override starts from. The rest of this entry is kept as the reading of this -change. diff --git a/.changeset/10478-filter-condition-value-protocol-rule.md b/.changeset/10478-filter-condition-value-protocol-rule.md deleted file mode 100644 index 2f00e6898e..0000000000 --- a/.changeset/10478-filter-condition-value-protocol-rule.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -'@object-ui/types': minor ---- - -fix(types): a `filter-builder` condition's `value` is judged against its `operator` by the protocol's own rule - -`FilterBuilderConditionSchema` declared `value: z.any()` and coupled nothing to the -operator. So `safeValidateSchema` (and `objectui check` / `objectui validate`) answered -green on filter conditions the protocol's `ViewFilterRuleSchema` refuses, such as -`{ field: 'amount', operator: 'between', value: 5 }` (objectui#10478). - -The condition now re-parses its `{ field, operator, value }` projection through -`ViewFilterRuleSchema` from `@objectstack/spec/ui` and reports the rule's issues as its -own, on the condition's `value`, with the spec's message. The spec's checks are not -restated here, so the mirror follows the rule of whichever `@objectstack/spec` release is -installed. With `@objectstack/spec` 17.4.0, the release this lockfile resolves when this -lands, that means: - -- `in` / `not_in` (and their aliases, such as `notIn`) take an array, and an absent value - is refused. An empty list `[]` is still accepted; -- `between` takes exactly two bounds, `[min, max]`. A scalar, one bound, three bounds and - the empty `[]` the builder draws for an untouched range row are all refused. A - half-filled range such as `[0, '']` has two bounds and is accepted; -- whatever the operator, the value must be of a type the rule takes: a string, number, - boolean, `null`, or an array of strings and numbers. An object, or an array holding a - boolean, `null`, an object or another array, is refused. - -The condition's `id`, which the builder needs and the spec rule does not declare, is kept -out of the projection, so it is still required and still accepted. A condition refused -for its `field`, `operator` or `id` reports only that issue. - -**Breaking in semantics:** a document with a condition the protocol already refused, and -that used to validate, now fails `safeValidateSchema` and `objectui validate`. The fix is -to author the value the operator takes. Released as `minor` under this repository's -version-alignment rule. The TypeScript types do not change: `FilterBuilderCondition.value` -stays `any`. - -⚠️ **Dated note, 2026-09-25 — `objectui check` does not fail such a document — -objectui#10524.** This entry first listed `objectui check` beside `objectui validate`. -`check` is an advisory sweep: it never parses against the schema a file whose root carries a structural key -(`children`, `className`, `body`, …), it lists a file with none of those keys by name when -the file does not validate, and it exits non-zero on unreadable JSON only. The verdict is -`objectui validate`'s. The "answered green" sentence at the top of this entry stays true -of `check`, before this change and after it. diff --git a/.changeset/10482-page-preview-reads-type.md b/.changeset/10482-page-preview-reads-type.md deleted file mode 100644 index ba1c47d19f..0000000000 --- a/.changeset/10482-page-preview-reads-type.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the page designer's preview decides "record page" from `type` alone (objectui#10482) - -`PagePreview` bound a sample record when a draft carried `type: 'record'` or -`pageType: 'record'`. `PageSchema` refuses `pageType` (an alias of `type`), and the -runtime resolver `usePageAssignment` reads `type` alone since objectui#9674, so a raw -draft carrying only the alias got a record preview that the runtime never gives it. -The preview now reads `type` alone: a draft whose only record marker is `pageType` -renders unbound, with no sample-record fetch. A `type: 'record'` draft binds exactly -as before. diff --git a/.changeset/10485-detail-section-declares-hideempty.md b/.changeset/10485-detail-section-declares-hideempty.md deleted file mode 100644 index 6ab98dbf88..0000000000 --- a/.changeset/10485-detail-section-declares-hideempty.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/plugin-detail': minor ---- - -An authored `detail-section` node now takes `hideEmpty`, and it reaches the section. - -`DetailSection` hides a section whose fields are all empty when -`section.hideEmpty` is `true`, but the `detail-section` registration did not -declare `hideEmpty` among its `inputs`, and the node adapter folds only declared -names into the section it hands the component. So an author who wrote -`hideEmpty` on the node was warned `unknown-prop "hideEmpty"` by the JSX-page -compiler's validator — which judges an authored page against these same -`inputs` — and an all-empty section still drew its heading and skeleton. - -The registration now declares `{ name: 'hideEmpty', type: 'boolean' }`, and the -adapter folds it like the other declared inputs. On this node, `true` hides an -all-empty section (no heading, no skeleton); omitted or `false`, the section -keeps its heading and label skeleton — the behaviour an unauthored node already -had, now stated in the input's description rather than changed. A non-boolean -`hideEmpty` now draws `type-mismatch` instead of `unknown-prop`. - -The omitted default is the node's own. `record:details` still resolves an -omitted `hideEmpty` to `true` on its own authored sections, which never pass -through this node; `detail-view` sections, like this node, apply no default. -What `true` and `false` mean is the same on all three. - -**Clause-②: yes** — the authoring surface of `detail-section` widens by one -key, `hideEmpty`, which the renderer already honoured. No other key's verdict -moves at this change: `name`, which the block neither declares nor reads, still -draws `unknown-prop`. No exported symbol is added, removed, renamed or retyped — the -package entry re-exports neither `DetailSectionNode` nor -`DETAIL_SECTION_NODE_INPUTS`. The tag is outside the public block tier, so the -generated `sdui.manifest.json` and `sdui-intrinsics.d.ts` never carried it and -do not change. - -⚠️ **Dated note, 2026-09-29 — `name` no longer draws `unknown-prop` on this node — -objectui#11044.** Later in this same release, `name` becomes a `where-undeclared` -base prop of the JSX-page compiler's validator: a base prop on every type that -declares no input of that name. `detail-section` declares none, so an authored -`name` on it now draws nothing, although the block still does not read it. The -sentence above is kept as the reading of this change; the objectui#11044 entry -states what ships. diff --git a/.changeset/10486-picker-column-display-name.md b/.changeset/10486-picker-column-display-name.md deleted file mode 100644 index 97af81c606..0000000000 --- a/.changeset/10486-picker-column-display-name.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/fields': minor ---- - -fix(fields)!: the record picker's display column labels a record the way the lookup dropdown does, and `RecordPickerDialog`'s `titleFormat` prop is replaced by `objectSchema` - -⚠️ Breaking change (marked `minor` under this repo's version policy): the -published `RecordPickerDialog` component's `titleFormat` prop is removed. Pass -`objectSchema`, the referenced object's schema, instead. Tracked as -objectui#10486, the picker half of the lookup branch of ruling C1 on -objectui#9436 (the field's own `displayField`, then the object's `nameField`, -then the deprecated `titleFormat`). - -- **Before.** The browse-all picker's display column rendered a bare - `titleFormat` string through its own single-brace renderer, above the - referenced object's `nameField` and above the lookup's declared - `displayField`. A double-brace template kept its outer braces. With no - template the column never read `nameField`: it showed the record's `name` - value, or nothing when the object has no `name` field. The dropdown option - for the same record showed the `nameField` value. -- **After.** When `objectSchema` is given, the display column renders - `@object-ui/core`'s `getRecordDisplayName(objectSchema, row, { titleField })`, - the call the dropdown's option label and the lookup cell renderer make: the - declared `displayField`, then `nameField` (and its deprecated aliases), then - `titleFormat`, then type-aware derivation. The row is the one the dropdown - labels from: relations collapsed to ids and fields the loaded policy denies - removed. The resolver's `Untitled` / `Record #id` floor is not used as a - title; such a record keeps its column's own value. -- **`displayField` is the declared value.** Pass the lookup's declared display - field, or leave it out when the field declares none. The display column is - still keyed on `'name'` when it is omitted, but only a declared value ranks - above the object's declarations. -- **The column moves for `nameField`-only objects too.** It now shows the - `nameField` value where it used to show the `name` value or a blank cell. -- Without `objectSchema` the display column renders its own value, as before. - `LookupField` passes the schema and the declared display field; no other - caller in this repository passed `titleFormat`. - -This change also corrects two pending changesets that described the picker -before it: the objectui#10343 one now says the picker's display column follows -the dropdown's resolver, and the objectui#6874 one names the current -`objectSchema={refObjectSchema}` pass, whose conclusion stands. diff --git a/.changeset/10487-lookup-hydrated-label-follows-schema.md b/.changeset/10487-lookup-hydrated-label-follows-schema.md deleted file mode 100644 index 20d6a481d3..0000000000 --- a/.changeset/10487-lookup-hydrated-label-follows-schema.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): a lookup value hydrated from a bare id is labelled from the referenced object's schema once it arrives (objectui#10487) - -A lookup that mounts already holding a value (an edit form opening an existing -record) fetches the referenced record to label its chip. It also asks for the -referenced object's schema, and nothing orders the two. When the record came -back first, the chip was labelled without the schema, on the `name` guess, and -it kept that label. The hydration cached a built option with its label frozen, -and the schema's arrival never rebuilt it. The dropdown, the read cell and the -record page read the object's declared `nameField` for the same record. So the -chip read `Acme` while its own dropdown option read `HT-001`, until the user -picked the record again, and a reload brought `Acme` back. - -The hydration now keeps the fetched rows and builds no label. The chip's option -is derived from those rows on every render through the same `recordToOption` -call, with the same inputs, that the dropdown uses. So its label follows the -schema when it arrives. It also follows the permission policy in force: a field -the policy denies after the chip was labelled (a policy that loads late) leaves -the chip's label as it leaves the dropdown's. The record is still fetched once, -and no remount is involved. When -the schema arrived while the record fetch was still in flight, the fetch used to -be cancelled and issued a second time; it is issued once now. diff --git a/.changeset/10493-data-uri-no-file-name.md b/.changeset/10493-data-uri-no-file-name.md deleted file mode 100644 index f154166706..0000000000 --- a/.changeset/10493-data-uri-no-file-name.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): an image, avatar or signature cell holding a `data:` URI no longer names its image with the base64 payload (objectui#10493) - -`readFileValue` took the text after a URL's last `/` as the file's display name. A `data:` URI -has no path, so a `data:image/png;base64,…` value was named `png;base64,…` (or a fragment of the -payload, when the base64 holds a `/`). The image cell uses a value's name as its `` alt, and -`SignatureField` stores `canvas.toDataURL('image/png')`, so every populated signature cell had -kilobytes of base64 as its alt, which a screen reader reads aloud. - -A `data:` URI now carries no display name, so `readFileValue` answers the caller's fallback name -for it, as a string value and as the `url` of an object value. The image cell (registered for -`image`, `avatar` and `signature`) now reads its images with no fallback name, so a value that -carries no name of its own gets the translated `fields.image.imageAlt` alt ("Image 1", numbered by -position) and the lightbox it opens gets the translated alt and title. Before this, such a value -was named with the untranslated literal `Image` on every locale. That applied to a bare `sys_file` -id too, which now also gets the translated alt. - -What an author or reader sees change: the alt of a data-URI or bare-id thumbnail in a read-mode -cell, and the file cell's link text for a data-URI value, which is now the translated file -fallback. Stored values do not change: the `data:` URI is still the `` `src` byte for byte. -A value that carries a name keeps it, whether from `name` / `original_name` or from an `https` or -`blob:` URL's last segment. diff --git a/.changeset/10496-header-bar-root-dom-props.md b/.changeset/10496-header-bar-root-dom-props.md deleted file mode 100644 index 8e5afa7b71..0000000000 --- a/.changeset/10496-header-bar-root-dom-props.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/components': patch -'@object-ui/types': patch ---- - -fix(components): `header-bar` puts its `BaseSchema` DOM channels on the root `header` (objectui#10496) - -The `header-bar` renderer was a function of the node alone, so the props every -component receives beside it never reached the element. An `ariaLabel` the author -declared ("Rendered as aria-label attribute") never became the banner landmark's -accessible name, and `style`, `id`, `testId` and the `data-obj-id` / -`data-obj-type` markers rendered exactly as if they had not been written. -objectui#10397 had made the root honour `className`, and nothing else arrived. - -The root now takes the same route as the other converged renderers: what it is -handed goes through `toDomProps`, the shared DOM whitelist in `@object-ui/core`, -and `style` is forwarded by name. So `ariaLabel` names the landmark, and `style`, -`id`, `data-testid` and `data-obj-*` land on the `header`. The keys the renderer -consumes (`crumbs`, `search`, `actions`, `rightContent`) and any key an author -invents stay off the DOM. `className` is unchanged: it is still merged after the -header's own classes. - -What an author sees change: - -- a `header-bar` with `ariaLabel` is announced by that name; -- `style`, `id` and `testId` now apply to the header; -- every rendered header carries `data-obj-type="header-bar"`, like other nodes. - -`@object-ui/types`: the refusal messages and doc comments for the retired -`header-bar` keys (`title`, `logo`, `nav`, `left`, `center`, `right`, `sticky`, -`height`, `variant`) said the renderer "takes no spread props". They now say what -it does: it forwards to its root only what the shared DOM whitelist admits, plus -`style`. None of those keys is on that whitelist, so none of them reaches the DOM, -and each is still refused by name. diff --git a/.changeset/10499-page-header-title-fls.md b/.changeset/10499-page-header-title-fls.md deleted file mode 100644 index c07b7653a0..0000000000 --- a/.changeset/10499-page-header-title-fls.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the record page heading no longer prints a field the viewer may not read (objectui#10499) - -The record page's heading is drawn by `page:header`, which builds it from the -record the page hands its blocks. The record page handed them the record as -served. On a backend that does not strip denied fields, a `titleFormat` token -or a declared `nameField` that the loaded permission policy denies therefore -printed in the heading, while the breadcrumb, the favourite and the -"Recently Accessed" entry already fell back to the next title source -(objectui#10434). - -The record page now hands its blocks the record with the denied fields -removed, the record id always kept. That is the same record the breadcrumb -title reads, and the record ObjectStack's `FieldMasker` already serves. The -heading reads a denied field exactly as an absent one and falls through to its -next source. A template with a denied token renders what it renders when that -field is empty. - -Under a denied single-field title, `record:details` already hid the `name` -row as the heading's duplicate while the heading printed the denied value, so -the readable name was on screen nowhere. The heading now shows that name, and -the hidden row is its duplicate again. - -Every other block of the record page reads the same record, so on a -non-stripping backend a denied field now reads as absent there too (a -`record.*` visibility predicate, the path's current stage, a quick action's -predicate), exactly as on a stripping backend. - -Before a permission policy loads, and with no permission provider mounted, -nothing is removed and the page is unchanged. This is defence in depth: on a -backend that strips denied fields, nothing changes. diff --git a/.changeset/10500-search-labels-read-gate.md b/.changeset/10500-search-labels-read-gate.md deleted file mode 100644 index 94ba5ffe24..0000000000 --- a/.changeset/10500-search-labels-read-gate.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/react': patch -'@object-ui/app-shell': patch ---- - -fix(react,app-shell): a search hit's label no longer prints a field the viewer may not read (objectui#10500) - -The ⌘K command palette, the full-page search results and the `global:search` -block label each record hit with `getRecordDisplayName`, and `useRecordSearch` -handed that resolver the record as served. On a backend that does not strip -denied fields, a `titleFormat` token or a declared `nameField` that the loaded -permission policy denies therefore printed as the hit's label. - -`useRecordSearch` takes a new optional `fieldReadPolicy` option: pass -`usePermissions()` from `@object-ui/permissions`. Once that policy is loaded, -each hit is labelled from its record with the denied fields removed, before any -`getDisplayName` resolver reads it. The record id is always kept, so the -`Record #` id floor still applies. A denied field is read exactly as an absent -one, and the label falls through to its next source, the label ObjectStack's -`FieldMasker` row already yields. When the policy finishes loading, a search -that is already showing runs again, so hits labelled before the policy loaded -are relabelled. The three app-shell search surfaces now pass the policy. The -record title (objectui#10434) and the lookup option label (objectui#10411) -follow the same rule. - -Without the option, before a policy loads, and with no permission provider -mounted, nothing is removed and every label is unchanged. A title the server -computed for a `searchAll` hit is still shown as the server sent it, and a -hit's `raw` payload is still the record as served. - -This is defence in depth: ObjectStack's `FieldMasker` already removes the -fields a user may not read from the rows it serves, so on that backend no -label changes. diff --git a/.changeset/10501-lookup-cell-read-gate.md b/.changeset/10501-lookup-cell-read-gate.md deleted file mode 100644 index e8ef9c2a53..0000000000 --- a/.changeset/10501-lookup-cell-read-gate.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): the lookup cell names the referenced record from the fields the viewer may read (objectui#10501) - -`LookupCellRenderer` names the record a lookup points at through the referenced -object's schema: the column's `displayField`, then the object's `nameField`, -then its `titleFormat`, then the type-aware derivation. It did that on the row -as served. On a backend that does not strip the fields a permission policy -denies (ObjectStack's `FieldMasker` does strip them), a `titleFormat` or -`nameField` naming a denied field printed that field's value in every list, -grid and detail cell that shows the lookup. The lookup editor's option label -already applied the rule (objectui#10411), as does the record title -(objectui#10434). - -The cell now resolves the name from the row with the fields the loaded policy -denies on the REFERENCED object removed; `id` and `_id` are kept. The name -falls through to the next source exactly as it does for the row a stripping -backend serves. Every shape the cell names a record from is covered: an -expanded record, a JSON-encoded reference, each chip of a multi-value cell and -the overflow chip's tooltip, and a bare id resolved on demand. With no policy -loaded, or no `PermissionProvider` mounted, the row is named as served, as -before. - -A bare id resolved on demand used to cache the resolved NAME. It now caches the -fetched record and schema, and the name is resolved on every render, the same -shape objectui#10487 gave the lookup editor's hydrated chip. So a policy that -loads or changes after the record arrived relabels the mounted cell, with no -second read of the record. diff --git a/.changeset/10506-named-view-context-tokens.md b/.changeset/10506-named-view-context-tokens.md deleted file mode 100644 index c958070033..0000000000 --- a/.changeset/10506-named-view-context-tokens.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -'@object-ui/plugin-view': patch -'@object-ui/core': patch ---- - -`ObjectView` resolves the spec's context tokens in the filters it hands on (objectui#10506). - -A per-user named list view, `{ field: 'owner', operator: 'equals', value: '{current_user_id}' }`, -reached the query with the literal token on the registered `object-view` node: this component -had no read of `@object-ui/core`'s `resolveFilterPlaceholders`, while the app-shell host resolved -the same view. - -The three authored filter segments (the active view's filter, `table.filter`, -`table.defaultFilters`) are now resolved once through that shared resolver, with the session -scope the host provides through `useFilterScope` (the console shell mounts `FilterScopeProvider` -from the signed-in user and the active organization). All three paths a filter leaves this -component by read the resolved segments: the query a non-grid view issues, the `object-grid` -schema handed to `ObjectGrid`, and the `list-view` schema handed to a host's `renderListView`. -The relative-date macros (`{today}`, `{current_quarter_start}`, …) resolve in the same call, in -the browser's local time, as they already did on the surfaces that call the resolver: the -app-shell host, `ObjectChart` and the dashboard widgets. (A directly authored `object-grid` or -`list-view` node calls it too, since objectui#10607.) Where they used to reach a backend that resolves them -itself, as the ObjectStack server does in the tenant's configured `localization.timezone` (UTC by -default), a browser whose local day differs from the server's day can now get a different day. - -A token the scope cannot resolve is left as written and the resolver warns once, which is the -resolver's own rule, so the filter is never widened. With no `FilterScopeProvider` mounted, what a -literal `{current_user_id}` then selects depends on the backend: the ObjectStack server resolves -it for a signed-in request and refuses the request otherwise (the REST face answers 401 at its -auth gate before the filter is read, and where a guest context reaches the engine the resolver -answers 400), and a backend with no resolver of its own matches no record. - -The resolved value is held against its inputs: the raw segments, compared by structure, and the -scope's three members (`currentUserId`, `currentOrgId`, `onUnresolved`), each compared on its own. -`ObjectGrid` and `ListView` key their fetch on the filter's identity, so a host that re-renders -without changing anything does not trigger a refetch. Date macros are resolved once and held until -the user, the organization or a segment changes, so `{now}` and `{today}` do not produce a new -value on every render of this component: that governs the query a non-grid view issues, the grid, -and a `renderListView` host that queries with the filter it is handed. The console's app-shell -host is not such a host: its `renderListView` resolves the active view's own filter itself -(`viewDef.filter ?? listSchema.filter`, with no filter segment in the schema it gives this -component; the active view's filter still reaches this component through the `views` prop), so -its date macros and its `'current-user'` fallback for a signed-out user are unchanged. A host that resolves the handed value again, as the app-shell's fallback would, changes -nothing: a resolved id or date no longer matches the placeholder pattern. With no user in scope, -this component's pass warns; the app-shell's own pass substitutes `'current-user'` silently, as -before, so the console's query is unchanged and the one difference is that warning. - -`@object-ui/core`'s two placeholder walks (`resolveContextTokens` and `resolveDateMacros`, both behind -`resolveFilterPlaceholders`) now return a non-plain object as the same instance instead of rebuilding -it from its own keys, so a `Date` comparand, which the spec admits, no longer comes back as `{}`; -plain and null-prototype objects are still walked. A non-plain object is a leaf whatever it is: a -class instance with own keys carrying a token is also returned as the same instance, no longer -copied and resolved. The contract review of this change found no in-repo caller that passes one. diff --git a/.changeset/10512-dataset-chart-applied-filter.md b/.changeset/10512-dataset-chart-applied-filter.md deleted file mode 100644 index 60e2282d63..0000000000 --- a/.changeset/10512-dataset-chart-applied-filter.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -On a `chart` list view bound to a semantic `dataset`, a user filter that is already set -no longer narrows `ListView`'s own fetch (objectui#10512). - -The toolbar withholds the Filter builder and the `userFilters` chips on such a view -(objectui#10327), but a filter group the host restored at mount through -`initialFilters`, or a group or chip set on another view before switching, was still -applied to `ListView`'s own fetch of the object's rows. That fetch still runs on the -chart and feeds the record-count bar, so the count was narrowed by a filter nothing on -screen showed or could clear. - -- While a dataset-bound chart is on screen, `ListView`'s fetch and its export apply - the view's own `filter` only; the toolbar's filter group and the chips are not sent. -- The held state is kept rather than cleared: switching back to a view that offers the - controls applies the same group again, and `onFilterChange` is not called for the - switch. -- A chart bound to the list object, and every other view, apply the toolbar's filter - group and the chips as before. A switch into a dataset chart with no user filter set - issues no new request. diff --git a/.changeset/10516-xaxis-presentation-gate.md b/.changeset/10516-xaxis-presentation-gate.md deleted file mode 100644 index 867b4255c9..0000000000 --- a/.changeset/10516-xaxis-presentation-gate.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/plugin-charts': patch ---- - -A chart's `xAxis` object is no longer dropped when it carries `min`, `max`, `stepSize`, -`logarithmic` or `position` without also carrying `title`, `format` or `showGridLines` -(objectui#10516). - -`normalizeChartSchema` kept the x-axis object only when one of those three hand-named keys -was present. Any other axis lost everything but its `field`, so a scatter authored with -`xAxis: { field: 'progress', min: 0, max: 200, stepSize: 50 }` drew the auto-fitted x -domain and ticks instead of the ones it declared, and nothing refused. The object is now -kept whenever it carries any key of the spec's `ChartAxisSchema` other than `field`. The -key set is the one the normalizer reads, not a second hand-written list. - -**User-visible render change.** A scatter whose `xAxis` declares `min` / `max` / -`stepSize` / `logarithmic` with no title, format or grid flag now draws the x scale it asked -for. That completes objectui#9675's x-axis repair for axes written that way. An `xAxis` -carrying only `field` renders as before. - -`position` on `xAxis` now survives normalization too, but at this change no renderer reads -it: the x axis draws along the bottom whatever it says. - -⚠️ **Dated note, 2026-09-25 — the renderer now reads `xAxis.position` — objectui#10587.** -Later in this same release the x axis takes the side `position` names where that axis can -run along it, and a side it cannot take draws the default side with a note naming the key. -The sentence above is kept as the reading of this change; the objectui#10587 entry states -what ships. diff --git a/.changeset/10518-object-chart-y-axis-declared.md b/.changeset/10518-object-chart-y-axis-declared.md deleted file mode 100644 index f612d96bd8..0000000000 --- a/.changeset/10518-object-chart-y-axis-declared.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`ObjectChartSchema` (and its TS twin) declares `xAxis` and `yAxis` as `@objectstack/spec`'s axis -config: `xAxis` is ONE `ChartAxisSchema` object and `yAxis` a list of them. The Zod mirror references -the spec schema, and the TS side is typed by the spec's `ChartAxis`. Until now both keys rode -`BaseSchema`'s passthrough unchecked (objectui#10518, ruling 5809510046, branch 2, declare). This is -the `object-chart` sibling of the objectui#7690 declaration on `ChartSchema`. - -- The spec declares both keys on this node. The `REACT_BLOCKS` entry for the `ObjectChart` react - block has `schemaType: 'object-chart'` and `schema: ChartConfigSchema`, and lists `xAxis` and - `yAxis` in its `dataProps`. -- Real producers write them. The objectstack showcase command-center page's dataset-bound charts - author `yAxis: [{ field, stepSize: 1 }]`, and its renewals-pipeline page writes - `xAxis: { field }` with `yAxis: [{ field, format }]`. Both still parse, unchanged. -- The spec's `.default()`s are not written into the parse output. An omitted `showGridLines` or - `logarithmic` stays omitted. -- `xAxis` is the object ONLY. There is no string arm and no fold onto `xAxisKey`: the bare-string - alias of objectui#7113 belongs to the `chart` node alone, and the spec's `ChartConfigSchema.xAxis` - has no string arm (seat decision on objectui#10518, option A). - -⚠️ Shipped as `minor`, not `patch`: documents that validated before now **refuse** (the accept set -narrows), and a narrowed accept set is breaking semantics, which this repo's version policy ships as -`minor`. Several of the refused documents draw a chart today; what the rest draw depends on the -chart type, on the rows, and on the node's other category and series sources: - -- An `xAxis` object with a malformed value (`min: 'zero'`, `position: 'middle'`), an undeclared - key (`grid`, `logScale`) or no `field`. It is refused as one issue at `xAxis` whose message carries - the spec's own diagnostic, including its alias hint. The renderer drops a malformed `min` or - `position` and never reads `grid` or `logScale`, so an object carrying them draws exactly what it - draws without them. An object with no `field` names no category of its own. -- An `xAxis` written as a bare column name (`xAxis: 'status'`), a list of axis objects, or any other - non-object value. It is refused with the remedy `xAxis: { field }`. The renderer's normalizer still - honours a bare string as a tolerance, and that is unchanged, but no producer on this node writes - one. A bare string names the category column exactly as `{ field }` does, so it draws what that - object draws. A list or any other non-object names no category, like an object with no `field`. -- A `yAxis` entry with a malformed value (`stepSize: 'big'`, `position: 'middle'`), an undeclared - key (`logScale`, `grid`) or no `field`. It is refused at the entry's own path. The renderer ignores - what it cannot read and uses the rest of the entry. An entry with no `field` names no column, so it - adds no series. -- A `yAxis` written as a single object or a bare column name. The renderer's normalizer honours - both as a tolerance. Neither is a member of the spec's list, and no producer on this node writes - either, so they are refused with a remedy (the reading objectui#7690 applied to - `ChartSchema.yAxis`). The normalizer is unchanged. It reads a single object as a one-entry list, so - a single object with no `field` adds no series either. - -A TS consumer that typed a bare-string `xAxis` onto an `ObjectChartSchema` value no longer compiles. -The one in-repo instance, a renderer-tolerance test fixture, now carries an explicit cast. - -No renderer changed. diff --git a/.changeset/10519-pageview-refresh-in-place.md b/.changeset/10519-pageview-refresh-in-place.md deleted file mode 100644 index 37389cc081..0000000000 --- a/.changeset/10519-pageview-refresh-in-place.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): a page action refreshes a custom page's data in place instead of remounting the page (objectui#10519) - -`PageView` used to key both of its render branches — the ADR-0047 interface list -and the `SchemaRenderer` page — on a counter it bumped after every successful -page-level action that asks for a refresh (an `api` call, a flow, a server -action, an undo, a screen-flow completion). Each such action therefore remounted -the whole page: scroll position, collapsed sections, tab state and in-progress -edits in every embedded block were lost, and every block refetched from scratch. - -The counter is gone. `PageView` now answers the console action runtime's -post-action refresh by declaring the change on the data-invalidation bus -(`notifyDataChanged` from `@object-ui/react`, with the unknown-scope -`objectName: '*'`, since a page binds no object). The embedded blocks that read -the bus refetch in place, once each: the object grid, chart, detail view, list -view, kanban, metric, calendar, gallery, timeline, gantt, map, tree, pivot and -data table, every `object-form` layout, `object-master-detail-form` (edit-mode -lines), `report` / `spec-report` over a dataset, a `dashboard`'s dataset table -widget and its `optionsFrom` filter options, an `object-view` drawn as a kanban, -calendar, gallery or timeline, `record:line_items` with an authored parent, and -the `element:number` / `element:repeater` / `element:record_picker` readers. An -`object-form` holding unsaved input keeps it and takes the re-read when it is -saved or reverted (objectui#10572), and a dashboard filter keeps its selected -value. A `kind: 'react'` page is no longer remounted either: its own read -re-runs in place when its effect names the `useDataInvalidation` nonce the page -scope injects (objectui#10887), and a read keyed on `useAdapter` alone is not -re-run by a page action. The page node's `context` is `{ params }` alone: -nothing read the `refreshKey` it also carried. No prop, export or schema key -changes. - -⚠️ **Dated note, 2026-10-02 — `spec-report` is retired — objectui#11440.** -Later in this same release `@object-ui/plugin-report` stopped registering `spec-report`, an alias of -`report`; a node of that type now resolves to nothing. So "`report` / `spec-report` over a dataset" -above now reads `report` over a dataset, the report embedded as `{ "type": "report", "report": { … } }`, -which re-reads in place as this entry says. `.changeset/11440-retire-spec-report.md` states what -ships. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10520-orphaned-console-pages.md b/.changeset/10520-orphaned-console-pages.md deleted file mode 100644 index eb439a1d1d..0000000000 --- a/.changeset/10520-orphaned-console-pages.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/console': minor ---- - -Framework navigation can now reach the console pages that the retired System Hub card wall used to be the only link to (objectui#10520). - -Navigation reaches a console page only through a `type: 'component'` item whose `componentRef` is a component-registry key, never through a console path. The console registers three new keys: - -- `audit:log` renders the Audit Log page. It stays beside the `sys_audit_log` object view because its detail drawer pretty-prints the before and after JSON of a change, which the object's record page shows as raw text. -- `ai:approvals` renders the AI Approvals page, which lists the whole AI pending-action queue. -- `developer:integrations` renders the Integrations & APIs page, which shows the environment's REST base URL, the generated REST endpoints of each business object and a cURL sample that sends the `x-api-key` header. - -The keys are additive. `/apps/:app/system/audit-log`, `/apps/:app/system/ai-approvals` and `/apps/:app/developer/integrations` still render their pages, so bookmarks and deep links keep working. The navigation entries that name the new keys belong to the framework, not to this package. - -**Breaking:** the Developer Hub page and its route, `/apps/:app/developer`, are removed. The hub was a wall of four cards, and each card's destination is now a registry key: `developer:api-console`, `developer:flow-runs` and `developer:public-forms`, which the framework's Studio app already names in its Developer group, and `developer:integrations`. A bookmark to `/apps/:app/developer` no longer shows the hub. Inside an app it now reaches the generic object route, which answers that no object named `developer` exists. With no apps configured it lands where it did before this change. The four routes under `/apps/:app/developer/` are unchanged. diff --git a/.changeset/10524-check-promise-text.md b/.changeset/10524-check-promise-text.md deleted file mode 100644 index 33f443b9bc..0000000000 --- a/.changeset/10524-check-promise-text.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/cli': patch -'@object-ui/types': patch ---- - -`objectui check`'s help line and six `@object-ui/types` comments no longer present `check` as a -validator (objectui#10524). - -- `@object-ui/cli`: `objectui --help` and `objectui check --help` described `check` as - "Validate schema files". It now reads "Advisory JSON file sweep; run objectui validate for a - verdict". `check` itself is unchanged. It sweeps the project's JSON files and recognises a - file whose root carries a structural key (`children`, `className`, `body`, …) by that key - alone, without parsing it against the schema. It parses against the schema only a file with - none of those keys, and lists it by name when its root `type` names a registered component but - the document does not validate. That list is advisory: `check` exits non-zero on unreadable - JSON only. The verdict is `objectui validate`'s: it parses one document against the published - schema, prints the schema's own errors and exits non-zero. -- `@object-ui/types`: the `ChatbotSchema.body` docblock said the retired key's refusal comes from - "a root parse (`objectui validate` / `objectui check`, …)". `body` is itself one of the - structural keys, so `check` never parses a `chatbot` document that authors it against the - schema. The docblock now names `objectui validate` alone and says why `check` does not deliver - the refusal. The two - `SemanticElementSchema` docblocks (the interface and its zod mirror) said a document was - refused by `objectui check`; they now name `objectui validate`, whose refusal it was. The - `ObjectGanttSchema.gantt` comments (the interface and its zod mirror) and the - `ObjectCalendarSchema` `sort` comment in the zod mirror said the refusal reaches the CLI's - `validate` / `check`; they now name `validate` alone. - -A help string and comments only: no command's behaviour, export, type or schema moves. diff --git a/.changeset/10528-grid-object-table-fetch.md b/.changeset/10528-grid-object-table-fetch.md deleted file mode 100644 index 9c46e20325..0000000000 --- a/.changeset/10528-grid-object-table-fetch.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -Fix: the editable dashboard grid (`dashboard-grid`, `DashboardGridLayout`) now -treats widgets whose data is `{ provider: 'object', object }` the way the -read-only `DashboardRenderer` already does (objectui#10528). Before this change -the grid turned a table, list or pivot widget with that config into a static -node with `data: []`. The tile showed an empty table or cross-tab and sent no -query. - -**Table and list widgets now fetch their rows.** The grid builds the same node -`DashboardRenderer` builds for the widget: an `object-data-table`, which loads -the object's rows through the data source. The props match too: - -- the provider's `filter` (or the widget's `filter`) reaches the query; -- the widget's `searchable` and `pagination` are honoured, and a `list` never - gets them; -- a row click opens the record in a drawer by default, as on the read-only - dashboard. `options.drillDown` still overrides this. In edit mode, dragging - still starts only from the drag handle. - -**Pivot widgets with that config now show the retired-widget placeholder.** -It is the same placeholder `DashboardRenderer` already shows for them ("This -widget uses a retired data format. Edit it to bind a dataset."). Under ADR-0021 -a pivot is bound to a dataset, and a dataset-bound pivot still renders as -before. - -Widgets bound to inline rows are unchanged, including static-data pivots. - -⚠️ **Dated note, 2026-10-02 — the `dashboard-grid` node key is retired — objectui#10859.** -Later in this same release objectui#10859 batch 8 (phase 2b) unregistered the `dashboard-grid` -node key. `DashboardGridLayout` is unchanged and stays exported, so this fix still holds wherever -a host mounts it; it is no longer reachable as a schema `type`. The rest of this entry is kept as -the reading of this change. - -⚠️ **Dated note, 2026-10-03 — the grid's static pivot node states its keys — objectui#11466.** At this change, "Widgets bound to inline rows are unchanged, including static-data pivots" held, and the grid's static-data pivot node spread the widget's `options` whole. Now that node states the keys `PivotTableSchema` declares and `PivotTable` draws, read from `options`, and no other option key reaches it. `.changeset/11466-dashboard-metric-node.md` states what ships. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10530-timeline-lookup-display.md b/.changeset/10530-timeline-lookup-display.md deleted file mode 100644 index efb36e5be4..0000000000 --- a/.changeset/10530-timeline-lookup-display.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/plugin-timeline': patch ---- - -A timeline no longer crashes when its `titleField` or `descriptionField` names a lookup. - -`ObjectTimeline` copied the raw `titleField` and `descriptionField` values onto each -item, and the renderer puts both in JSX. A lookup is a field like any other, and -`ObjectTimeline`'s own object fetch expands every declared relation, so a -lookup-typed title or description arrived as `{ id, name }`. React then threw -`Objects are not valid as a React child` as soon as the rows landed, and the whole -timeline failed to render. - -The item mapping now derives the title and the description once, as display -strings, through `@object-ui/core`'s `recordDisplayValueAt`, the resolver -`ObjectMap` uses for the same two slots: - -- an expanded lookup shows its display name; -- a plain string, a number or a bare id shows as before; -- a boolean shows as its string, where the old truthiness gate dropped `false` and - drew an empty line for `true`; -- a `0` shows inside its title or description line, where it used to be painted as - a bare character beside it; -- an empty or whitespace-only value, or an expanded record with no display name, - shows no line, and surrounding whitespace is trimmed. - -No schema or spec key changes. `ObjectTimeline.lookupDisplay-10530.test.tsx` pins -each case above. diff --git a/.changeset/10535-person-name-read-gate.md b/.changeset/10535-person-name-read-gate.md deleted file mode 100644 index 1fe60ad8e8..0000000000 --- a/.changeset/10535-person-name-read-gate.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): PeoplePicker rows, its selection tray and the read-only user cell stop drawing a person's name or avatar that field-level security denies - -`PeoplePicker` (the search-first picker every user field opens by default) -read each person's name straight from the record the server returned: the -field's display field, then `name`, `username` and `label`. Once the -permission policy had loaded, a name the user may not read on the queried -object still showed in the candidate row, in the multi-select tray chip, in -the avatar's alt text and in the chip's remove label. The read-only `user` -cell drew the name (`name`, then `username`) and the avatar (`image`) of an -expanded person the same way, in both its single and its multi-value form. - -Now, once the policy has loaded, a name field the user may not read is -skipped and the next readable one shows instead, the same fallback the lookup -field's option label already uses. When none is readable, the row and the -tray show their usual placeholder, and the cell shows `User`. The cell draws -no avatar image when `image` is denied: the initials show instead. The cell -judges the fields on the object the field's `reference_to` (or `reference`) -names, and on `sys_user` when it names none. A policy that loads or changes -later relabels what is already on screen. Before the policy loads, nothing is -withheld. The records the picker hands to `onSelect` and `onSelectRecords` -are unchanged. - -This is defence in depth: ObjectStack's `FieldMasker` already removes the -fields a user may not read from the rows it returns, and on those rows nothing -changes. The change matters for a backend that does not. - -⚠️ **Dated note, 2026-09-30 — the cell reads the person's object from `reference` alone — objectui#11070.** "the object the field's `reference_to` (or `reference`) names" above held when this change landed. Later in this same release objectui#11070 (round 4) narrowed `UserCellRenderer` to `reference`, with `sys_user` when it names none. The read gate is unaffected. `.changeset/11070-reference-to-round4.md` states what ships; the text above is kept as the reading of this change. diff --git a/.changeset/10537-simulator-assignment-envelope.md b/.changeset/10537-simulator-assignment-envelope.md deleted file mode 100644 index a83056691d..0000000000 --- a/.changeset/10537-simulator-assignment-envelope.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the flow designer's Debug run evaluates an assignment's CEL value envelope, as the runtime does - -An `assignment` node's `assignments` map value may be the CEL value envelope -`{ dialect: 'cel', source }`, the form the Assignments editor's "Write as a CEL -expression" toggle stores. The runtime evaluates it to a value. The Debug run used to -write the envelope object itself into the variable and report the step as done, so -`{ n: 2, doubled: { dialect: 'cel', source: 'n * 2' } }` left `doubled` holding the -object where the runtime gives `4`. - -- The Debug run now evaluates the envelope on the runtime's CEL engine - (`@objectstack/formula`), against the runtime's variable scope: bare names, `vars.*` - and `record.*`, with dotted keys nested. So `4` comes back, and the CEL stdlib - (`joinNonEmpty(rows.map(r, r.subject), ", ")`) computes. -- An envelope that fails (a CEL error, a dialect other than `cel`, a missing or blank - `source`) is not written. The step shows the error and the run stops on that node, - as it fails at runtime. -- Unchanged at this change: `{token}` strings still interpolate, numbers and plain - objects are still written as they are, and an envelope-shaped object in the legacy - `assignments: [{ variable, value }]` array or in a bare config is still the literal - object, as it is at runtime. - -⚠️ **Dated note, 2026-09-25 — a plain object is no longer always written as it is — -objectui#10615.** Later in this same release the Debug run walks a plain object or -array value the way the runtime's `interpolate` does, so a `{token}` string inside it is -interpolated; a token-free object is still written unchanged. The rest of this entry is -kept as the reading of this change; the objectui#10615 entry states what the Debug run -now does. diff --git a/.changeset/10538-cel-macro-bound-variable.md b/.changeset/10538-cel-macro-bound-variable.md deleted file mode 100644 index cf456161ad..0000000000 --- a/.changeset/10538-cel-macro-bound-variable.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the flow designer's "not in scope" warning no longer flags a CEL comprehension macro's own iteration variable (objectui#10538) - -`findUnknownRefs` read every root identifier in a CEL source as a flow variable, so the `r` in `rows.map(r, r.subject)` drew an amber "not in scope" warning. That included the assignment-value example in `@objectstack/spec`, `joinNonEmpty(rows.map(r, r.subject), "\n")`. The scanner now treats the first argument of `map`, `filter`, `exists`, `all` and `exists_one` as a variable bound inside that macro's own argument list. The same name used outside that list (after the closing parenthesis, or as another macro's receiver) is still checked as a root, and an unknown receiver is still flagged with its suggestion. The warning stays advisory; nothing about what blocks Save changes. diff --git a/.changeset/10545-filter-candidates-displayfield.md b/.changeset/10545-filter-candidates-displayfield.md deleted file mode 100644 index 2bd687c226..0000000000 --- a/.changeset/10545-filter-candidates-displayfield.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -fix(plugin-list): list filters label a lookup's values by the `displayField` the object definition declares (objectui#10545) - -Once a list view's object definition loads, the filter builder's candidates and -the toolbar's lookup filter read each lookup field's display field off that -definition. They read `display_field`, then `reference_field`, and never -`displayField`, the only one of the three `@objectstack/spec`'s `FieldSchema` -declares. So a spec-compliant lookup's display field never reached the value -picker, which fell back to its default, `name`. - -Both now read `displayField`, and only it. This is the same single spelling -`@object-ui/plugin-grid` reads off a definition. `FieldSchema` refuses the other -two: `display_field` with a rename to `displayField`, and `reference_field` with -a pointer to `referenceVia`. - -Behaviour change: a field definition that carries only the refused -`display_field` no longer sets the picker's display field, and neither does one -that carries only `reference_field`. The picker falls back to `name`. A stored -definition served through the ObjectStack adapter still works, because that -adapter folds `display_field` onto `displayField` when the schema is loaded. -A definition that reaches the list any other way, such as a host `DataSource` -or an `objectDef` passed straight to `UserFilters`, needs `displayField`. - -The two readers also stop reading `id_field` as the lookup's id column. -`FieldSchema` declares no id column for a lookup and refuses both `id_field` and -`idField`, so the picker now always keys a lookup by `id`, its default. A -definition that carried `id_field` used to make the picker match and emit that -column's values instead. - -Also (objectui#10547): before a list view's object definition loads, the filter -builder's candidates come from the view's declared `columns`, and that fallback -no longer reads `options` off a list column. `ListColumnSchema` refuses the key -with `unrecognized_keys`, so a spec-compliant view never carries it. A select -field's options now reach the filter builder only from the object definition, -once it loads, which is where they already came from after the load. diff --git a/.changeset/10559-picked-lookup-relabels.md b/.changeset/10559-picked-lookup-relabels.md deleted file mode 100644 index 143c6ed6ec..0000000000 --- a/.changeset/10559-picked-lookup-relabels.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): a lookup value picked before the referenced object's schema loads is labelled from that schema once it arrives (objectui#10559) - -A pick used to cache the option it was handed, with its label built at pick -time. A lookup asks for the referenced object's schema when it mounts, so a -record picked before that schema arrived was labelled on the `name` guess, and -the chip kept that label. The dropdown option for the same record read the -object's declared `nameField` once the schema arrived. So the chip read `Acme` -while its own dropdown option read `HT-001`. This held for a pick from the -dropdown, from the browse-all dialog and from quick-create. - -A pick now keeps the record's row instead of the option. The chip's option is -derived from that row on every render, through the same derivation the hydrated -value uses since objectui#10487, so its label follows the schema when it -arrives. The row a dropdown pick keeps is the candidate as served, with -relations collapsed to ids, as the dropdown builds its options. The browse-all -dialog and the search-first people picker keep the rows they hand back, and -quick-create keeps the created record. No record is fetched again to relabel -it, and no remount is involved. An authored static option keeps no row: its -chip resolves from the authored `options` list, which is consulted first. diff --git a/.changeset/10563-form-arms-write-payload.md b/.changeset/10563-form-arms-write-payload.md deleted file mode 100644 index 6e4e5167d4..0000000000 --- a/.changeset/10563-form-arms-write-payload.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/plugin-form': patch -'@object-ui/types': patch ---- - -The `tabbed`, `wizard` and `split` form layouts now write what the simple form writes (objectui#10563). - -**Clause-②: no.** No exported symbol, type or prop changes. The shared sequence lives in an internal module that `index.tsx` does not re-export. The change is in what the client sends, and ⚠️ in what a host `submitHandler` receives from these layouts (see below). - -**Before.** The simple form, `ModalForm` and `DrawerForm` strip a save before sending it, and on an edit they send only the fields that differ from the record they read (objectui#10108, `80c54122e`, objectui#10156). `TabbedForm`, `SplitForm` and `WizardForm` did neither. An edit sent every value the form held: `id`, `owner_id`, `created_by`, `updated_at`, formula columns, and fields the caller's field-level security refuses. The server answered with a `403` or an unknown-field refusal. A create seeded with a whole record, such as a copy of an existing one, posted those columns too. A simple form whose mobile `stepper` option shows it one step at a time renders through `WizardForm`, so it had the same defect. - -**What changed, in observable terms.** - -- In edit mode, the `tabbed`, `wizard` and `split` layouts and the `stepper` route write only the fields that differ from the record they read with `findOne`. They use the same comparison as every other layout. A save with nothing changed still sends the full stripped payload, with the same concurrency guard. -- On every save, create or edit, these layouts drop the fields a form never writes. That means server-owned columns, computed, formula and read-only columns, keys the object does not declare, and fields the caller's field-level security refuses. A field whose name is on the server-owned roster, such as `owner`, is not written even when an object declares it as an ordinary field. The other layouts already worked this way. -- A field the caller may read but not edit now renders disabled on these layouts, as on the others, also when a section names it by a bare string. Before, it rendered as a live input. With the strip above, a value typed there would have been dropped while the save reported success. -- After a save succeeds, a form that stays open compares its next save with the record as it now is. -- ⚠️ A host `submitHandler` on one of these layouts now receives, in edit mode, the payload the form would have written. That is the changed fields, or the full stripped payload when nothing changed. A master-detail header laid out `tabbed` therefore sends only its changed fields in the parent operation, as a `simple` header already did. -- With inline `customFields`, the object definition is not used for the strip, as on the simple form. An inline member may name a field the object does not declare, and its value is still sent. -- An empty field whose runtime default the server resolves is left out of the payload whenever the form has no persisted record: `mode: 'create'`, or no `recordId`. That is the rule the simple form and the seeding of these layouts already use. Before, these layouts left it out only when `mode` was `create`. -- The JSDoc of `ObjectFormSchema.submitHandler` in `@object-ui/types` no longer lists these layouts as exceptions. The copies on `TabbedFormSchema`, `SplitFormSchema` and `WizardFormSchema` now say what an edit-mode handler receives. diff --git a/.changeset/10564-master-detail-child-baseline.md b/.changeset/10564-master-detail-child-baseline.md deleted file mode 100644 index 6301cb8404..0000000000 --- a/.changeset/10564-master-detail-child-baseline.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -A master-detail edit form that stays open after a save no longer re-creates the line items it just created, re-deletes the ones it just deleted, or drops a line cell changed back to its first-read value (objectui#10564). - -**Clause-②: no.** No exported symbol, type or prop changes. The change is in what the form's next save sends. - -**Before.** The form diffed every save against the child rows it read when it opened. A host that keeps the form mounted after a save (an `onSuccess` that does not navigate away) therefore got: - -- a second copy of a line the first save created, because that row never learned its id and was created again on the next save; -- a second `delete` of a line the first save had already deleted; -- a lost edit when a line cell was changed, saved, and changed back to its first-read value: the second save sent no line operation and still reported success, and the server kept the first save's value. - -**What changed, in observable terms.** - -- After a successful edit save, the rows that save created take the ids the batch returned for them, and the collection's baseline takes on what the save wrote. The next save compares with the lines as they now stand. This is the same rule the parent record already followed after a save (objectui#10156). -- A save that fails advances nothing, neither the parent nor the lines, so a retry still sends every operation. -- The lines take no input while a save is in flight (objectui#10631), so nothing typed during a save can separate a line the save created from its id. -- Create mode is unchanged: a successful create still clears the lines and the header for the next entry. diff --git a/.changeset/10565-occ-token-after-save.md b/.changeset/10565-occ-token-after-save.md deleted file mode 100644 index 7d32993aa3..0000000000 --- a/.changeset/10565-occ-token-after-save.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -An edit form that stays open no longer meets the conflict dialog over its own earlier save (objectui#10565). - -**Clause-②: no.** No exported symbol, type or prop changes. The change is in which `ifMatch` an edit save sends. - -**Before.** Every edit layout (the simple form, `modal`, `drawer`, `tabbed`, `split` and `wizard`) sent `ifMatch` = the `updated_at` of the record it read with `findOne`, on every save. None of them refreshes that record after a save. The first save moves the stored `updated_at`, so the second save from the same open form sent a version the server no longer held. A server that enforces `ifMatch` answered `409 CONCURRENT_UPDATE`, and the user was offered **Keep editing** or **Overwrite** over a conflict with their own first save. - -**What changed, in observable terms.** - -- After a save lands, the next save of the same record from the same open form sends the `updated_at` that save returned, for every layout. The **Overwrite** retry counts as a save, so the save after it sends the version the overwrite returned. -- A genuine conflict still answers `409`: if someone else saves the record between two saves, the dialog still opens. -- If the form reads the record again and gets a different `updated_at`, the new read's token is sent. -- A record read without an `updated_at` is still saved without `ifMatch`. When a data source's `update` resolves without an `updated_at`, the next save sends the read's token, as before. -- What a save writes is unchanged: an edit still sends only the fields that differ from the record the form read (objectui#10156). diff --git a/.changeset/10567-date-only-impossible-day.md b/.changeset/10567-date-only-impossible-day.md deleted file mode 100644 index 3cfe3059b5..0000000000 --- a/.changeset/10567-date-only-impossible-day.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/fields': patch -'@object-ui/i18n': patch ---- - -fix(fields): the editable date-only faces no longer blank a stored impossible day silently - -`toDateInputValue` keeps a stored `2026-02-30` as written and never rolls it, -but an `` sanitises a day that does not exist to an empty -value (measured in Chromium). So `DateField` and the sub-grid's editable `date` -cell showed an empty control with no marker for a value that was stored. That -is a silent blank, which the direction of objectui#10026 rules out, and it is -the date-only half of objectui#10474. - -Both faces now judge the day as written with `isImpossibleStoredDay` (the check -objectui#10474 added). For such a day they hand the control an empty value, -mark it `aria-invalid`, and name the stored string beside it with the new -date-only sentence `fields.date.impossibleDay`, in all ten packs. The control's -`aria-describedby` points at that sentence. Nothing is written until the user -picks a new day, and picking a real day clears the marker. Real days and empty -values render as before. diff --git a/.changeset/10572-app-shell-external-refresh-same-commit.md b/.changeset/10572-app-shell-external-refresh-same-commit.md deleted file mode 100644 index 74403fe4f4..0000000000 --- a/.changeset/10572-app-shell-external-refresh-same-commit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -The object page reads the console's refresh counter (`externalRefreshKey`: record-form save, undo, redo) in the render that carries it, instead of copying it into its own counter one commit later (objectui#10572). The list now also re-reads on the data-invalidation bus, and undo and redo declare their change there in the same tick as the counter bump, so the delayed copy made one undo cost two list reads. Every reader of the page's refresh signal — the list, the saved-view and draft reads, the record count — still sees each external bump. diff --git a/.changeset/10572-plugin-calendar-reads-invalidation-bus.md b/.changeset/10572-plugin-calendar-reads-invalidation-bus.md deleted file mode 100644 index 853ad03773..0000000000 --- a/.changeset/10572-plugin-calendar-reads-invalidation-bus.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch ---- - -`object-calendar` re-reads its events when the data-invalidation bus (`notifyDataChanged` from `@object-ui/react`) reports a change to the object it queries (objectui#10572). A write that bypasses the data source — a page action over raw HTTP, a flow, a server action — fires no `onMutation`, so a calendar on a page used to show it only when the whole page was remounted. Inline and external events are still the host's to refresh. diff --git a/.changeset/10572-plugin-dashboard-reads-invalidation-bus.md b/.changeset/10572-plugin-dashboard-reads-invalidation-bus.md deleted file mode 100644 index a1634f26e8..0000000000 --- a/.changeset/10572-plugin-dashboard-reads-invalidation-bus.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -`object-metric` (`ObjectMetricWidget`) re-reads its value when the data-invalidation bus (`notifyDataChanged` from `@object-ui/react`) reports a change to the object it aggregates (objectui#10572). A write that bypasses the data source — a page action over raw HTTP, a flow, a server action — used to leave the tile stale until the whole page was remounted. diff --git a/.changeset/10572-plugin-form-reads-invalidation-bus.md b/.changeset/10572-plugin-form-reads-invalidation-bus.md deleted file mode 100644 index 72a58fe492..0000000000 --- a/.changeset/10572-plugin-form-reads-invalidation-bus.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -`object-form` in edit mode re-reads its record when the data-invalidation bus (`notifyDataChanged` from `@object-ui/react`) reports a change to that record, its object, or everything (objectui#10572). The re-read is gated on pristine: an untouched form refreshes in place without remounting, while a form holding unsaved input keeps both the typed values and the version token its edit started from, so a real conflict still surfaces at save. One held re-read is replayed once the edit is saved or the form returns to pristine. A change to another record of the object reads nothing. diff --git a/.changeset/10572-plugin-kanban-reads-invalidation-bus.md b/.changeset/10572-plugin-kanban-reads-invalidation-bus.md deleted file mode 100644 index 49a9c4652a..0000000000 --- a/.changeset/10572-plugin-kanban-reads-invalidation-bus.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/plugin-kanban': patch ---- - -`object-kanban` re-reads its cards when the data-invalidation bus (`notifyDataChanged` from `@object-ui/react`) reports a change to the object it queries (objectui#10572). A write that bypasses the data source — a page action over raw HTTP, a flow, a server action — fires no `onMutation`, so a board on a page used to show it only when the whole page was remounted. External, bound and inline cards are still the host's to refresh. diff --git a/.changeset/10572-plugin-list-reads-invalidation-bus.md b/.changeset/10572-plugin-list-reads-invalidation-bus.md deleted file mode 100644 index d9d1a15e0c..0000000000 --- a/.changeset/10572-plugin-list-reads-invalidation-bus.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -`list-view` re-reads its rows when the data-invalidation bus (`notifyDataChanged` from `@object-ui/react`) reports a change to the object it queries (objectui#10572). A write that bypasses the data source — a page action over raw HTTP, a flow, a server action — fires no `onMutation`, so a list on a page used to show it only when the whole page was remounted. The re-read keeps the list mounted; rows a host hands the list inline are still the host's to refresh. diff --git a/.changeset/10578-gantt-error-clears.md b/.changeset/10578-gantt-error-clears.md deleted file mode 100644 index d8a319d1db..0000000000 --- a/.changeset/10578-gantt-error-clears.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/plugin-gantt': patch ---- - -fix(plugin-gantt): a failed load no longer keeps `ObjectGantt` on its error screen after a later load succeeds - -`ObjectGantt` sets `error` when the current reload fails, and the render returns -the error screen early whenever `error` is set. Nothing ever cleared it. After one -failed load (a filter or sort change against a flaky backend, say), every later -load that succeeded still wrote its rows, but the chart stayed on the error screen -until the component remounted. - -The current reload now clears the error when it commits rows, whether it is a -changed query or a silent re-read of the same one (a data-invalidation, say). Those -rows answer the current query, so the earlier failure no longer describes the -screen. A superseded reload's answer is discarded under the existing `isCurrent()` -guard, and its clear is discarded with it, so it cannot remove an error the current -reload reported. - -The error is deliberately not cleared when a reload starts, although `ObjectGrid`'s -load clears there. A silent re-read can overtake a changed query and then fail -without reporting it. Had the changed query cleared the error when it started, the -chart would go back to an older query's rows with nothing to say they are stale. -Until rows that answer the current query land, the error stays on screen. Before the -first paint the loading placeholder still shows while a query is in flight. diff --git a/.changeset/10580-refresh-indicator-translated-name.md b/.changeset/10580-refresh-indicator-translated-name.md deleted file mode 100644 index b3f5a06ef6..0000000000 --- a/.changeset/10580-refresh-indicator-translated-name.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/components': minor -'@object-ui/plugin-grid': patch -'@object-ui/plugin-list': patch -'@object-ui/plugin-charts': patch -'@object-ui/plugin-dashboard': patch -'@object-ui/i18n': patch ---- - -BREAKING (`@object-ui/components`): `RefreshIndicator`'s `ariaLabel` prop is now required and has no default. It used to default to the English literal "Refreshing", so the progress bar on every view that passed no name was announced in English to screen-reader users in every locale (objectui#10580). A `RefreshIndicator` rendered without `ariaLabel` now fails to type-check. - -(The bump is `minor` by this repo's release model: objectui's major follows the `@objectstack` family major, and its own breaking changes ship as `minor` with the breaking semantics stated here.) - -Migration: pass the bar's accessible name from your own translation layer, for example `ariaLabel={t('grid.refreshing')}`. The component renders the string you pass as the bar's `aria-label` and does not translate it. - -`ObjectGrid`, `ListView`, `ObjectChart` and `ObjectDataTable` now name their refresh bar in the active locale. The grid and the list read the `grid.refreshing` and `list.refreshing` keys their pull-to-refresh text already uses. The chart reads `chart.refreshing` and the dashboard data table reads `dashboard.refreshing`, both with no English literal behind them, so a host that renders either one with no i18next instance at all gets the key itself as the bar's name. - -`@object-ui/i18n`: new keys `chart.refreshing` and `dashboard.refreshing` in every built-in locale pack. diff --git a/.changeset/10582-retire-column-width-config.md b/.changeset/10582-retire-column-width-config.md deleted file mode 100644 index 8dbd17b194..0000000000 --- a/.changeset/10582-retire-column-width-config.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-kanban': minor ---- - -**BREAKING (scored `minor` per this repo's version-alignment convention)** — -`ColumnWidthConfig` and its Zod mirror `ColumnWidthConfigSchema` are deleted -(objectui#10582, ADR-0049 enforce-or-remove). No schema key references the -type and nothing reads it, so a `ColumnWidthConfig` an author built was never -read by anything. - -**Why nothing was behind it.** The one key that carried the type, the -`'kanban'` arm's `columnWidths`, retired with that arm in this release -(objectui#8802). The one reader, the `useColumnWidths` hook in -`@object-ui/plugin-kanban`, was removed in this release too (objectui#8522). - -**What each package's published entry loses**, read off the 17.6.0 tarballs on -npm: - -- `@object-ui/plugin-kanban`: 17.6.0 exports `ColumnWidthConfig` from its - entry. There it is the package's own declaration, and `KanbanSchema` types - its `columnWidths` member with it. This release exports it no more. -- `@object-ui/types`: 17.6.0 exports neither `ColumnWidthConfig` nor - `ColumnWidthConfigSchema`. Both entered this package in this release, when - objectui#7664 moved the kanban dialect's declarations here, and both leave - before any version publishes them. For these two names, the objectui#7664 - entries in this release are superseded by this one. - -## Migration - -- `import type { ColumnWidthConfig } from '@object-ui/plugin-kanban'` no - longer resolves: TypeScript reports that the module has no exported member of - that name. Delete the import and the annotation that used it. Nothing - replaces the type, and removing it changes nothing at runtime, because a type - import is erased at compile time. -- The objectui#8522 entry in this same release says `ColumnWidthConfig` stays - exported from `@object-ui/types` and from `@object-ui/plugin-kanban`. That - was true of that change. This entry removes it from both. diff --git a/.changeset/10583-masked-cell-copy.md b/.changeset/10583-masked-cell-copy.md deleted file mode 100644 index 9449426ec1..0000000000 --- a/.changeset/10583-masked-cell-copy.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/components': patch -'@object-ui/plugin-grid': patch ---- - -Once the grid has its object schema, a masked grid field's raw value is withheld from copy, tooltip, inline edit, the client export and the mobile card, and a masked field is refused as a grouping key (objectui#10583). - -`@object-ui/fields` draws `password` and `secret` cells as `••••••`. In `object-grid` the -cell drew the mask, but the raw value still left through other paths: - -- `data-table`'s Ctrl+C / Cmd+C handler copied `String(row[accessorKey])` for every - focused cell. -- The cell's `title` tooltip carried the raw value, so a hover showed it and the DOM - held it. -- Inline edit, for a view-typed password column, seeded its editor with the raw value. -- The grid's client export wrote it: the CSV per column, the JSON as whole records. -- The mobile card printed the first column, and fields named like an amount or a - stage, raw. -- Grouping by a masked field printed its raw value as each group's label. - -This is the grid face of the disclosure the detail page closed in objectui#8440. - -- **`@object-ui/types`: new declared key `TableColumn.masked?: boolean`**, mirrored as a - typed `z.boolean()` on `TableColumnSchema` and refused on the static `table` column - (`StaticTableColumn`), like the other rich-only keys. Additive. -- **`@object-ui/components`: `data-table` obeys the flag on four paths.** On a `masked` - column: - - Ctrl+C / Cmd+C writes nothing to the clipboard. It still blocks the browser's own - copy, which would put a selected mask on the clipboard as bullets. - - The cell has no `title` tooltip. - - The built-in CSV export leaves the column out. It is left out, not blanked: a - column of empty strings would claim the records hold nothing. - - The column never enters inline edit, by Enter, click or double-click, and its cell - no longer takes the row's click as an edit. - - Columns without the flag copy, show, export and edit exactly as before. -- **`@object-ui/plugin-grid`: `ObjectGrid` sets the flag** at its column emit seam, from - `isMaskedFieldType()` (objectui#8686). It reads the column's type and, once the object - schema has loaded, the object-declared type as a narrow-only union, the same shape as - the detail page's `isMaskedDetailFieldType`. So a view that authors `type: 'password'` - masks a field the object declares as text from first paint, and a view that authors - `type: 'text'` over a `secret` field keeps the refusal once the schema has loaded. Once the object schema has loaded, the same rule leaves every masked - field of the grid's object out of the grid's client export (CSV and JSON, used when the - data source has no server export) and draws a masked field through its cell on the - mobile card. Once the object schema has loaded, it also refuses a masked field as a - grouping key: the entry is ignored, the other grouping levels - still apply, and a console warning names the field. Masking the group label was not - enough, because the groups would still show which records share a credential, in its - raw order. Unmasked columns, files and groupings are unchanged. - -**Not covered.** - -- The flag withholds; it does not draw. The mask comes from the producer's `cell` - renderer, and `data-table` draws a column with no `cell` as its value. -- The table's client-side search and sort still run over the raw values - (objectui#10657, which folded objectui#10658). -- A masked column's width is still sized from the raw value's length (objectui#10657, - which folded objectui#10658). -- On the host-fetched path (rows handed down as `data`, as `ListView` and `ObjectView` - do), the grid's guards and the cell's own mask depend on the object schema, which the - grid fetches after first paint. Until it arrives, and for good if that read fails (the - grid swallows the failure and keeps its heuristic column types), an untyped view column - over a `password` / `secret` field draws and hands out the raw value (objectui#10657, which folded objectui#10706). -- The server-streamed export (`exportDownload`) sends the masked columns as before and - relies on the server's masking. -- The client JSON export writes an expanded lookup record whole, so a credential field - of the related object is not pruned. The same holds for the table's CSV export of a - lookup column. -- The related list and `object-data-table` produce `data-table` columns too, and they do - not set the flag yet (objectui#10657). diff --git a/.changeset/10584-object-chart-series-describe.md b/.changeset/10584-object-chart-series-describe.md deleted file mode 100644 index 0558616f1b..0000000000 --- a/.changeset/10584-object-chart-series-describe.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/types': patch ---- - -docs(types): the `ObjectChartSchema.series` description says the copy omits the per-series `type`, and names `chartType` as its override - -The zod mirror's `.describe()` on `ObjectChartSchema.series` called the element -"the arm ChartRendererProps declares". Since objectui#8086 that arm also carries -a per-series `type`, which this copy does not declare, so the sentence was no -longer true member for member. It now says the copy is that `{ dataKey }` arm -minus its per-series `type`, and that the per-series family override on an -`object-chart` node is `chartType` (`bar` | `line` | `area`). - -The TypeScript docblock on the same member now says the omission is deliberate -rather than a lag: taking `type` up would widen a published accept set, and -that waits for a named producer that writes it on an `object-chart` node. - -⚠️ **Dated note, 2026-09-28 — `series` has since become two arms — objectui#10770.** Later -in this same release each `ObjectChartSchema.series` entry became ONE of two arms, on -both faces: the spec's `ChartSeriesSchema` (`{ name }`, by reference, the AUTHOR arm) or -the internal `{ dataKey }` arm. The `.describe()` and the docblock now describe both. So -"the copy is that `{ dataKey }` arm minus its per-series `type`" holds for the internal -arm only, and `chartType` is the per-series family override on that arm only: on a -`{ name }` entry the override is the spec's `type`, which an `object-chart` node now -accepts. The deliberate omission of `type` stands on the `{ dataKey }` arm, where the -zod mirror still strips it. `.changeset/10770-object-chart-react-tier-node.md` (PR -objectui#10802) states what ships; the text above is kept as the reading of this change. - -Wording only. The accepted shape does not move on either face: the element -type, its members and the mirror's parse result are what they were. diff --git a/.changeset/10585-hook-object-roster-state.md b/.changeset/10585-hook-object-roster-state.md deleted file mode 100644 index 50299564b6..0000000000 --- a/.changeset/10585-hook-object-roster-state.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -The Hook inspector's object picker stops calling a selected object "not -published", and stops telling the author to publish one, while its object -roster is still loading or after the fetch failed (objectui#10585). - -The picker made two claims from the object catalog: a selected object the -catalog does not list was flagged `(not published)`, and an empty list printed -"No objects found — publish an object, then pick it here." Both were read off -the list alone, and the list is empty while the fetch is in flight and after it -failed, exactly as it is for a catalog with no objects. So every selected -object was called unpublished, and the author was told to publish one, before -the catalog had answered; on a failed fetch the claims never cleared. - -`useObjectOptions` now reports a failure as its own fact: beside `options` and -`loading` it returns `error`, spelled the way `useObjectFields` spells it, and -`null` while in flight and after an answer. `options` and `loading` are -unchanged, so the action and page-block object pickers, which read only -`options` and fall back to a free-text input while it is empty, behave as -before. - -The Hook inspector folds `loading` and `error` through `rosterFrom`, the rule -the objectui#8862 / objectui#9651 family set for the designer's pickers: only -an answered roster may make a claim. - -- Answered: unchanged — a selected object the catalog does not list is flagged, - and an empty catalog prints the "publish an object" copy. -- In flight: a selected object is shown bare, and the empty list says it is - loading. -- Failed: a selected object is shown bare and stays toggleable, and a status - notice says the options could not be loaded and names the cause, with the - same localized title the designer's other pickers use for a failed catalog. diff --git a/.changeset/10586-inspector-strings-i18n-2.md b/.changeset/10586-inspector-strings-i18n-2.md deleted file mode 100644 index 06671f2571..0000000000 --- a/.changeset/10586-inspector-strings-i18n-2.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the hook and action inspectors, and the shared inspector defaults, read their words in the designer's locale (objectui#10586) - -`HookDefaultInspector` and `ActionDefaultInspector` rendered their section -titles, field labels, placeholders, hints, option labels and accessible names -as English literals. `InspectorComboField` and `_shared.tsx` fell back to -English defaults wherever a caller passed none: the combo's placeholder, -search box, empty state, loading text and "Use" row, and the shell's close -label, the reorder pair's names and the roster-failure notice. So a zh-CN -author read English inside an otherwise Chinese designer. - -The two inspectors now read the designer's own string catalogue under -`engine.inspector.hook.*` and `engine.inspector.action.*`, each row in en and -zh, from the `locale` their host already passes. The combo's words are new -`engine.inspector.combo.*` rows. The other defaults reuse existing rows -(`engine.form.selectEllipsis`, `engine.close`, `engine.inspector.reorder.*`, -`engine.form.optionsLoadFailedTitle`), and they follow the active language -through `useMetadataLocale()`. A label the caller passes still wins. The en-US -text is unchanged. Stored values, lifecycle event names, HTTP methods, code -samples and sample values are not words and stay as they were. diff --git a/.changeset/10586-inspector-strings-i18n.md b/.changeset/10586-inspector-strings-i18n.md deleted file mode 100644 index 34f03984d5..0000000000 --- a/.changeset/10586-inspector-strings-i18n.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): three designer inspectors read their words in the designer's locale (objectui#10586) - -`DatasetDefaultInspector`, `FlowReferenceField` (with the `ReferenceCombobox` it -wraps) and `ConditionBuilder` rendered their section titles, field labels, -placeholders, hints, option labels and accessible names as English literals, so a -zh-CN author read an English form inside an otherwise Chinese designer. - -Those strings now come from the designer's own string catalogue, under -`engine.inspector.dataset.*`, `engine.inspector.reference.*` and -`engine.inspector.condition.*`, plus the existing `engine.form.add` and -`engine.form.searchFields`, each with an en and a zh row. The dataset inspector -reads the `locale` its host already passes; the other two follow the active -language through `useMetadataLocale()`. The en-US text is unchanged. Stored -values, the `≥` / `≤` operator symbols, currency codes and decimal digits are not -words and stay as they were. diff --git a/.changeset/10587-xaxis-position.md b/.changeset/10587-xaxis-position.md deleted file mode 100644 index f4cb55685e..0000000000 --- a/.changeset/10587-xaxis-position.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/plugin-charts': patch ---- - -A chart's `xAxis.position` now places the x axis, and a side that axis cannot take is -refused with a note that names the key (objectui#10587). - -`position` is declared on `@objectstack/spec`'s `ChartAxisSchema`, which `xAxis` takes by -reference, and since objectui#10516 the normalizer keeps it on the x-axis object. No axis -read it, so `xAxis: { field: 'month', position: 'top' }` validated and still drew the axis -along the bottom. - -- **bar, line, area and scatter** (and a combo derived from its series' families): the x - axis runs across the plot. `top` draws it along the top; `bottom` draws it along the - bottom, the default. -- **horizontal-bar**: the `xAxis` object configures the category axis, which runs down the - plot there (its `format` already applied to that axis). `left` or `right` puts the - category axis on that side; the default stays the left. -- **A side the axis cannot take** (`left` / `right` across the plot, `top` / `bottom` on - horizontal-bar) draws the axis at its default side, and the chart shows a note under the - plot (`data-chart-note="x-axis-position"`) naming `xAxis.position`, the value, and the - side the axis was drawn on. The value still validates: `ChartAxisSchema` is shared by the - x and y axes, and this change does not narrow it. - -A top axis also mirrors its title and its rotated tick labels, so both stay on the far side -of the axis from the plot. - -**User-visible render change** only for a chart whose `xAxis` declares `position`. The -bottom / no-position controls in `ChartRenderer.xAxisPosition-10587.test.tsx` pin that a -chart declaring none still draws its x axis along the bottom with no note. diff --git a/.changeset/10591-tool-preview-api-console-link.md b/.changeset/10591-tool-preview-api-console-link.md deleted file mode 100644 index 33198a7cbe..0000000000 --- a/.changeset/10591-tool-preview-api-console-link.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/console': patch ---- - -The tool preview's "Open in API Console" link now opens the API console inside the current app, with the tool's execute request pre-filled (objectui#10591). - -The link pointed at `/developer/api-console?path=…`, a URL with no app segment. The console declares no route for it, so its catch-all redirected the author to `/`, the post-login landing, instead of the API console. The API console also read no query string, so the `path` the link carried was dropped even at the right URL. - -- `@object-ui/app-shell`: `ToolPreview` builds the link from the `developer:api-console` registry key inside the app in the URL, `/apps/APP/component/developer/api-console`. That is the path Studio's Developer navigation reaches the API console at. The query carries the tool's execute path (`/api/v1/ai/tools/NAME/execute`) and `method=POST`. The link is rendered through the router, so a console mounted under a base path (such as `/_console`) keeps it inside that mount, and it still opens in a new tab. When the preview is rendered with no router above it, or on a route that names no app, it draws no link. -- `@object-ui/console`: `ApiConsolePage` reads `path` and `method` from the query string once, when it mounts, and pre-fills the URL field and the method selector. It does not send the request. The preset works on both of the page's mounts: the `developer/api-console` route and the `developer:api-console` registry key. `path` is used only when it starts with `/api/`; an absolute URL such as `http://…`, a protocol-relative `//host` URL or any other value is ignored. `method` is read only together with an accepted `path`, in any letter case, and only when it is one of the verbs the method selector offers. Without an accepted `path` the page opens exactly as before. diff --git a/.changeset/10594-field-read-rule-core-export.md b/.changeset/10594-field-read-rule-core-export.md deleted file mode 100644 index 7436eefeec..0000000000 --- a/.changeset/10594-field-read-rule-core-export.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/fields': patch -'@object-ui/react': patch -'@object-ui/app-shell': patch -'@object-ui/plugin-detail': patch ---- - -`@object-ui/core` exports `withoutDeniedFields(record, policy, objectName, extraKeep?)`, the field-read rule for one record: the record as the viewer may read it on `objectName` (objectui#10594). - -Every field the loaded `policy` denies is removed, which leaves the row ObjectStack's `FieldMasker` already serves. `id`, `_id` and any key in `extraKeep` (a declared id field) are never judged. Before a policy loads, with no policy, with no object name, or for a value that is not an object, the record comes back as it is; when nothing is withheld the SAME object comes back. `policy` is structural (`isLoaded` and `checkField`), so `usePermissions()` from `@object-ui/permissions` satisfies it and `@object-ui/core` gains no dependency. - -The renderer's display surfaces that each carried a module-private copy of this rule now call the export, with no change in what they draw: - -- `@object-ui/fields`: the lookup cell's name and the user cell's name and avatar (the package entry), and the lookup editor's option label and search chip avatar (`LookupField`). -- `@object-ui/react`: `useRecordSearch`'s hit label under `fieldReadPolicy`. -- `@object-ui/app-shell`: the record page's title and the row its blocks read (`RecordDetailView`). -- `@object-ui/plugin-detail`: `DetailView`'s header title and `record:details`' title dedupe. The package-internal `withoutDeniedFields` module is removed; it was never a package export. diff --git a/.changeset/10594-record-picker-shared-field-read-rule.md b/.changeset/10594-record-picker-shared-field-read-rule.md deleted file mode 100644 index 21fbac7f1b..0000000000 --- a/.changeset/10594-record-picker-shared-field-read-rule.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -`RecordPickerDialog` builds its display column's title from the row that `withoutDeniedFields` from `@object-ui/core` returns, and its module-private copy of that field-read rule is deleted (objectui#10594). It was the last hand-written copy of the rule; the export is now its only definition. - -For a named object nothing the picker draws changes: a field the loaded policy denies is still removed before the title is built, and `id`, `_id` and the declared `idField` are still kept. The one change is an empty `objectName`: the copy judged every field but `id`, `_id` and the declared `idField` against `''`, while the export passes the row through, as the other surfaces do. The picker reads no records without an object name, so the change can show only in the single render after a host empties the object name of an open picker, before the rows of the previous object are cleared, and only in the display column. diff --git a/.changeset/10607-grid-list-filter-context-tokens.md b/.changeset/10607-grid-list-filter-context-tokens.md deleted file mode 100644 index 35cbccb0ba..0000000000 --- a/.changeset/10607-grid-list-filter-context-tokens.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -'@object-ui/plugin-grid': patch -'@object-ui/plugin-list': patch ---- - -A directly authored `object-grid` or `list-view` node resolves the spec's context tokens in its own filter (objectui#10607). - -`filter: [['owner', '=', '{current_user_id}']]` on an `object-grid` or `list-view` node authored -straight into a page, not reached through `object-view`, went out on `$filter` as the literal -token: neither package called `@object-ui/core`'s `resolveFilterPlaceholders`. Each now resolves -the node's own filter once through that shared resolver, with the session scope the host provides -through `useFilterScope` (the console shell mounts `FilterScopeProvider` from the signed-in user -and the active organization). On `object-grid` that is `filter` and its deprecated alias -`defaultFilters`: the resolved `filter` feeds the grid's query and its server-side export, and the -resolved alias feeds the query when `filter` is absent. On -`list-view` it is `filter`, and the resolved value feeds the list's query, the child view it -renders, the self-querying views (gantt, tree, chart), the export and the empty-state copy. -`object-view` has done this since objectui#10506; these two nodes, authored directly, had not. - -The relative-date macros (`{today}`, `{current_quarter_start}`, …) resolve in the same call, in -the browser's local time, as on the other surfaces that call the resolver. Where they used to -reach a backend that resolves them itself, as the ObjectStack server does in the tenant's -configured `localization.timezone` (UTC by default), a browser whose local day differs from the -server's day can now get a different day. - -A token the scope cannot resolve is left as written and the resolver warns once, which is the -resolver's own rule, so the filter is never widened. - -The resolved value is held against its inputs: the authored filter, compared by structure, and the -scope's three members (`currentUserId`, `currentOrgId`, `onUnresolved`), each compared on its own. -A re-render that changes none of them does not refetch, including one that rebuilds an equal -filter inline; a new signed-in user refetches with the new id. Date macros are therefore resolved -once and held until the scope or the authored filter changes, and a refetch for another reason -reuses the held value. `object-view` already hands these nodes a filter it has resolved -(objectui#10506); resolving that value again changes nothing, because a resolved id or date no -longer matches the placeholder pattern. - -On `object-grid`, the load effect now also refetches when the resolved `defaultFilters` changes (a -new signed-in user, or an in-place edit of the alias). It read that alias without keying on it -before. diff --git a/.changeset/10608-object-chart-legacy-axis-keys-retired.md b/.changeset/10608-object-chart-legacy-axis-keys-retired.md deleted file mode 100644 index 52ca9e35d9..0000000000 --- a/.changeset/10608-object-chart-legacy-axis-keys-retired.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types)!: `ObjectChartSchema.xAxisField` / `yAxisFields` / `aggregation` are retired on the `object-chart` node, each refused by name with the spec spelling as its remedy - -⚠️ Breaking, marked `minor` under this repo's version-alignment rule (a `major` -in the fixed group would move all of it off the `@objectstack` major). An -`object-chart` node that authors any of the three keys now FAILS to validate, -and a TypeScript literal typed as `ObjectChartSchema` that sets one no longer -compiles. - -The three are the LIST-VIEW chart block's vocabulary. The list-view relays -translate that block into `aggregate` / `xAxisKey` / `series` before they -compose an `object-chart` node, and nothing on the node's own render path -reads them: a node written with `xAxisField: 'status'` and -`yAxisFields: ['amount']` over static rows reached the chart with no category -key and no series, and on the inline `objectName` path it drew the -"no category axis" refusal. Yet both published faces declared the keys, so the -node type-checked and parsed green through `objectui validate` — every signal -said the axis was bound. - -Each key is now a `?: never` tombstone on the TypeScript face and a -`retirementTombstone()` on the zod mirror (ADR-0049; `BaseSchema` is -`.passthrough()`, so deleting the declarations would have KEPT an authored -value in silence rather than refused it). The refusal is an `invalid_type` -issue at the key's own path whose message names the key and the spelling to -write instead: - -- `xAxisField` → `xAxis: { field: 'status' }` (on the inline `objectName` - path the category is `aggregate.groupBy`); -- `yAxisFields` → `yAxis: [{ field: 'amount' }]`, one entry per value axis - (on the inline `objectName` path the measure is `aggregate.field`, and a - dataset-bound chart selects `values` by name); -- `aggregation` → `aggregate: { field, function, groupBy }` with the spec's - `function` vocabulary (a dataset-bound chart takes its aggregation from the - dataset's measures). - -Not touched: the list-view chart carriers keep these names — they are a -different node and they read them. A one-time producer census, recorded on the -card's pull request and not re-derived here, found no producer writing the -three on an `object-chart` node — in this repository, in the objectstack -showcase, or in hotcrm. - -Pinned in `packages/types/src/__tests__/object-chart-legacy-axis-keys-retired-10608.test.ts`. diff --git a/.changeset/10611-filter-ui-operator-retired.md b/.changeset/10611-filter-ui-operator-retired.md deleted file mode 100644 index 151ac2fbbe..0000000000 --- a/.changeset/10611-filter-ui-operator-retired.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types)!: `FilterUISchema.filters[].operator` is retired on the `filter-ui` node and refused by name - -⚠️ Breaking, marked `minor` under this repo's version-alignment rule (a `major` -in the fixed group would move all of it off the `@objectstack` major). A -`filter-ui` node whose `filters[]` entry authors `operator` now FAILS to -validate, and a TypeScript literal typed as `FilterUISchema` that sets it no -longer compiles. - -`filter-ui` never read a per-filter operator. Its renderer picks each control -from `type` and reports a change as a field → value record with no operator in -it: a host `onChange` function receives that bare record, and only the authored -window event wraps it, as `detail: { values }`. It does no matching of its own. -Yet both published faces declared the key (the mirror as a seven-member enum, -the TypeScript face as the same union) and the docs page taught it. So -`operator: 'gt'`, a member of that enum, type-checked and parsed green through -`objectui validate`; a nonsense id was refused by the enum and did not -type-check; and both rendered and emitted exactly what a filter without it -does. - -The member is now a `?: never` tombstone on the TypeScript face and a -`retirementTombstone()` on the zod mirror (ADR-0049). The `filters[]` entry is -a plain object schema that strips an undeclared key, so deleting the -declaration would have dropped an authored value in silence rather than refused -it. The refusal is an `invalid_type` issue at the entry's own path -(`filters.N.operator`). No replacement key is named, because nothing in this -component implements operators: remove the key. How each value is matched is up -to the host that consumes the change. - -The `filter-ui` docs page no longer lists `operator` in its Schema block and -states the retirement. A one-time census, recorded on the card's pull request -and not re-derived here, found no producer that writes the key and no reader -that honours it. - -Pinned in `packages/types/src/__tests__/filter-ui-operator-retired-10611.test.ts`. diff --git a/.changeset/10612-form-arms-managed-lock.md b/.changeset/10612-form-arms-managed-lock.md deleted file mode 100644 index 10e02f5af1..0000000000 --- a/.changeset/10612-form-arms-managed-lock.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -Every `object-form` layout now locks a managed object's fields, as the simple form does (objectui#10612). - -**Clause-②: no.** No exported symbol, type or prop changes. The shared step lives in `fieldWriteGate.ts`, an internal module that `index.tsx` does not re-export. What changes is which inputs the `drawer`, `modal`, `tabbed`, `split` and `wizard` layouts draw enabled. - -**Before.** ADR-0092 D4 locks a form on a managed object: when the object's CRUD affordance for the form's mode is closed, every field is disabled. The affordance comes from the object's `managedBy` bucket, its `userActions` opt-in (`create` on a create form, `edit` on an edit form) and the server's effective API operations. Only the simple form applied this lock, inside its own field generator. The `drawer`, `modal`, `tabbed`, `split` and `wizard` layouts drew live inputs on, for example, a `managedBy: 'better-auth'` object with no `userActions.create`, and the server then refused the save. The layouts disagreed with each other on the same object for the same user. - -**What changed, in observable terms.** - -- The `drawer`, `modal`, `tabbed`, `split` and `wizard` layouts, flat or sectioned, now disable every field of an object whose affordance for the form's mode is closed. This covers a managed bucket that does not open the mode, and any object whose `create` or `update` the server's effective API operations deny. The simple form did this already. -- The lock and field-level security now run as one step that every layout calls on the fields it has resolved. A field the caller may not read is dropped, and a field they may read but not edit is locked, on every layout, as before. -- ⚠️ On the simple form, an inline `customFields` member, and a section entry already written as a full field definition, are now locked with the rest of a managed object's fields. The lock used to be set only on the fields the simple form generated from the object, so those two escaped it. -- The lock sets `disabled` only, as it did on the simple form, and the submit button stays on screen on every layout. The server's write guard is still what refuses the write. The notice that explains the lock, and the wizard's disabled Next, come with objectui#11000. diff --git a/.changeset/10614-file-name-bare-percent.md b/.changeset/10614-file-name-bare-percent.md deleted file mode 100644 index f8c974706e..0000000000 --- a/.changeset/10614-file-name-bare-percent.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): a file URL whose last segment holds a bare `%` renders, named by its raw segment (objectui#10614) - -`readFileValue` names a file value that carries no name of its own after the last -segment of its URL, decoded with `decodeURIComponent`. A segment that is not a -valid percent-encoding (`https://cdn.example.com/100%.png`, or -`{ url: 'https://cdn.example.com/a%zz.pdf' }`) made that decode throw -`URIError: URI malformed`, and the throw left `readFileValue` during render. -`FileValueSchema.url` is a plain string, so such a value passes the contract. - -What a user saw: every face that reads the value (the `file`, `image` and -`signature` cells, `FileField`, `FileCell`, `ImageField`, and a gallery's cover) -threw while rendering. Under `SchemaRenderer` the nearest error boundary caught it, -so one such value replaced a whole grid table, valid rows included, or a whole -gallery with the "failed to render" panel. - -The decode is now guarded once, in the one helper that performs it: on `URIError` -the name is the raw segment (`100%.png`, `a%zz.pdf`). A valid escape decodes as -before (`report%20q3.pdf` is named `report q3.pdf`), and a value that carries its -own `name` or `original_name` is unaffected. diff --git a/.changeset/10615-simulator-cel-guards.md b/.changeset/10615-simulator-cel-guards.md deleted file mode 100644 index bb3b483d1d..0000000000 --- a/.changeset/10615-simulator-cel-guards.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the flow designer's Debug run evaluates edge guards as CEL and interpolates nested assignment values, as the runtime does - -**Guards.** A decision's edge guards ran on `@object-ui/core`'s expression evaluator, -which is not CEL. The runtime evaluates them on `@objectstack/formula`'s CEL engine, so -the Debug run could take a different branch than a real run: -`size(rows) > 0` failed with `"size" is not a function` and took the default branch, -`n == "2"` was true for `n = 2`, `7 / 2` was `3.5`, and `vars.n` / `record.n` were not -defined while `data.n` was. - -- A guard is now evaluated on the same engine and variable scope the Debug run already - uses for an assignment's CEL value envelope: bare names, `vars.*` and `record.*`, - dotted keys nested, no `data` root. A value counts as true when it is truthy, as at - runtime. -- A guard the runtime refuses or cannot evaluate stops the run on the decision, with the - error, and no branch is taken, the default included. A CEL fault fails the run there - at runtime; a refused guard is refused at registration, before any node runs. - That covers a CEL error on the live values (an unknown variable, `data.n`), a guard - that does not parse as CEL (a `{var}` or `${…}` template), an envelope in a dialect - other than `cel`, a blank guard, and a value that is not a condition shape (a - boolean). Before, the Debug run recorded the error on the edge and took the default - branch. -- A guard shape the edge's `condition` schema refuses is refused too: an empty string, - an envelope with an empty or missing `source` (`{ dialect: 'cel', source: '' }`, an - `ast`-only envelope) and `null`, which used to read as "no condition" and take the - default branch, and an envelope with no `dialect` (`{ source: 'n == 2' }`), which used - to be evaluated and take its branch. The installed spec 17.4.0 admits an `ast`-only - envelope and a whitespace-only guard at parse; objectstack main refuses both, and the - Debug run follows main. -- Unchanged at this change: an edge whose condition is omitted is still reported as - "Branch has no condition." and not taken, and when several guards are true the Debug - run still takes the first. - -**Assignments.** A `{token}` inside a nested object or array value of an `assignments` -map was left as written. The Debug run now interpolates values the way the runtime's -`interpolate` does: - -- arrays and plain objects are walked, property values interpolated, keys not; -- a whole-token string keeps the token's type (`'{n}'` gives `2`), and a token naming no - variable gives `undefined` (it used to stay as the literal `'{missing}'`); -- a token inside a longer string gives `''` for no value and JSON for an object; -- `{order.amount}` walks into an object variable and `{list.1}` indexes an array. - -The runtime's `NOW()` / `TODAY()`, `$User.*`, function and arithmetic tokens are not -modelled; a whole-token string holding one is kept as written. At this change, inside a -longer string such a token renders as `''`, as it did before; the runtime renders its -value. - -⚠️ **Dated note, 2026-09-25 — an edge with no condition is taken, and an embedded -unmodelled token is kept — objectui#10692.** Later in this same release the Debug run -leaves every node the way the runtime's `traverseNext` does: an out-edge with no -condition and no `isDefault` is always taken (it is no longer reported as "Branch has -no condition."), and several true guards still take the first. An unmodelled token -inside a longer string is kept as written, as a whole-token one is, and the step names -it. The rest of this entry is kept as the reading of this change; the objectui#10692 -entry states what the Debug run now does. diff --git a/.changeset/10616-view-handler-event-names-through-renderer.md b/.changeset/10616-view-handler-event-names-through-renderer.md deleted file mode 100644 index 1d3c6d2d14..0000000000 --- a/.changeset/10616-view-handler-event-names-through-renderer.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -`filter-ui`, `sort-ui` and `view-switcher` no longer crash when an authored -document sets their event-name key (`onChange`, or `onViewChange` on the -switcher). - -These keys hold the NAME of a `CustomEvent` dispatched on `window` -(objectui#6124). `SchemaRenderer` also passes these keys through to the component -as React props, so the authored string reached the component's callback prop -of the same name. The component called that prop, so the first interaction -threw `TypeError: onChange is not a function` (or `onViewChange`) and the event -was never dispatched. This form rendered through `SchemaRenderer` crashed: - -```json -{ "type": "sort-ui", "fields": [{ "field": "name" }], "onChange": "myapp:sort-changed" } -``` - -The three controls now call the prop only when it is a function, and dispatch -the event named on the schema. The listener below receives `e.detail.sort` -(`e.detail.values` for `filter-ui`, `e.detail.view` for `view-switcher`): - -```js -window.addEventListener('myapp:sort-changed', (e) => e.detail.sort); -``` - -A React host that passes a function through `SchemaRenderer` is unaffected. -Its function is called first with the new value. The authored event, if one is -named, is then dispatched as before. diff --git a/.changeset/10623-readers-follow-invalidation-bus.md b/.changeset/10623-readers-follow-invalidation-bus.md deleted file mode 100644 index a7f1df497a..0000000000 --- a/.changeset/10623-readers-follow-invalidation-bus.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/plugin-timeline': patch -'@object-ui/plugin-list': patch -'@object-ui/plugin-map': patch -'@object-ui/components': patch ---- - -Five more page blocks re-read when the data-invalidation bus (`notifyDataChanged` from `@object-ui/react`) reports a write to the object they read (objectui#10623). These blocks read neither `onMutation` nor the bus, so any write — through the data source or past it (a page action over raw HTTP, a flow, a server action) — showed only when something remounted them. Each fetch effect now names the `useDataInvalidation` nonce for its object; an unscoped change (`'*'`) matches too, and a change to another object does not. - -- `@object-ui/plugin-timeline`: `object-timeline` re-reads its rows; a canvas that already shows rows stays mounted while the re-read runs. -- `@object-ui/plugin-list`: `object-gallery` re-reads its cards; collapsed groups stay collapsed. -- `@object-ui/plugin-map`: `object-map` re-reads the markers it is showing without its loading placeholder, so the map stays mounted and the camera stays where the user left it. If that re-read fails, the last markers stay on the map and the failure is logged to the console, as `ObjectGantt`'s background refresh does. A changed query still shows the placeholder and re-fits the camera, even when a bus event arrives with it. Two older faults in the same fetch are fixed as well: a slow earlier answer can no longer overwrite a newer one, and a load that succeeds now takes the map off an earlier error screen. -- `@object-ui/components`: `element:number` re-reads its aggregate and `element:repeater` its rows. - -Rows a host hands these blocks (`data`, `bind`, authored `items`, an inline `value` set) are still the host's to refresh; only the blocks' own queries follow the bus. diff --git a/.changeset/10625-core-native-date-adapters.md b/.changeset/10625-core-native-date-adapters.md deleted file mode 100644 index 8ef6f8d2fe..0000000000 --- a/.changeset/10625-core-native-date-adapters.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/core": patch ---- - -`@object-ui/core` now exports the native date/time control adapters `toDateInputValue`, `toDateTimeInputValue`, `fromDateTimeInputValue` and `isImpossibleStoredDay` (objectui#10625). They moved down from `@object-ui/fields` unchanged, next to `isRealCalendarDate`, so the data table in `@object-ui/components` can use the same set instead of private copies. Their behaviour is unchanged: a stored day that does not exist (such as `2026-02-30`) is never rolled to a real one. diff --git a/.changeset/10625-data-table-impossible-day.md b/.changeset/10625-data-table-impossible-day.md deleted file mode 100644 index aca12eda76..0000000000 --- a/.changeset/10625-data-table-impossible-day.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/components": patch ---- - -The data table's inline date editors no longer roll or silently blank a stored day that does not exist (objectui#10625). A `datetime` column holding `2026-02-30T10:00:00Z` used to open on 2 March, so an edit of only the minutes saved that day; a `date` column holding `2026-02-30` opened empty with no marker. Both editors now use the shared adapters from `@object-ui/core`, the same ones the form's date widgets use. For such a value the control is empty, marked `aria-invalid`, and described by a notice that names the stored value (the existing `fields.date.impossibleDay` and `fields.dateTime.impossibleDay` messages). Pressing Enter without an edit keeps the stored value as it was. Real dates open and save as before. diff --git a/.changeset/10625-fields-native-date-reexport.md b/.changeset/10625-fields-native-date-reexport.md deleted file mode 100644 index 11ed8dc180..0000000000 --- a/.changeset/10625-fields-native-date-reexport.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/fields": patch ---- - -The native date/time control adapters (`toDateInputValue`, `toDateTimeInputValue`, `fromDateTimeInputValue`) now live in `@object-ui/core`, and `@object-ui/fields` re-exports them unchanged (objectui#10625). Imports from `@object-ui/fields` keep working and name the same functions, and the date widgets behave as before. diff --git a/.changeset/10625-inline-date-impossible-day.md b/.changeset/10625-inline-date-impossible-day.md deleted file mode 100644 index a72c4bbda0..0000000000 --- a/.changeset/10625-inline-date-impossible-day.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@object-ui/plugin-detail": patch ---- - -The detail page's inline date editor no longer blanks a stored day that does not exist without saying so (objectui#10625). A `date` field holding `2026-02-30`, or a `datetime` field holding `2026-02-30T10:00:00Z`, used to open an empty date input with no marker and no notice. The inline editor now uses `@object-ui/fields`' `DateField` for `date` and `datetime` fields, so it behaves like the form editor: the control is empty, marked `aria-invalid`, and described by a notice that names the stored value. Nothing is written until the user picks a day. A real date opens and saves as before (the edit is re-emitted as a full ISO timestamp at local midnight). diff --git a/.changeset/10631-master-detail-save-in-flight.md b/.changeset/10631-master-detail-save-in-flight.md deleted file mode 100644 index b4841c9b15..0000000000 --- a/.changeset/10631-master-detail-save-in-flight.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -A master-detail form no longer takes input into its lines, or sends a second batch, while its save is in flight. A slow save can no longer write the same records twice, or leave the lines it created without their ids (objectui#10631). - -**Clause-②: no.** No exported symbol, type or prop changes. The line-item grids are given the `disabled` prop they already had. - -**Before.** - -- Save re-armed 1.5 s after it was clicked, whatever the batch was doing. With a batch slower than that, a second click sent a second batch built from the same baseline. In edit mode the lines that save created were created twice; in create mode the whole document, parent and lines, was. -- The lines stayed editable during the save. A line the save creates takes the id the batch returns for it only while it is still the row object the batch was built from, and a grid with a sort field (a child field named `position`, `sort_order`, `sequence`, `line_no`, `line_number` or `sort`) replaces every row object on any change. One keystroke in such a grid during the save left every line the save created without its id, and the next save deleted and re-created all of them. -- A save started by submitting the header form without the Save button (an implicit submission, when the header has a single text input) left Save and the lines enabled, and a second such submit sent a second batch. - -**What changed, in observable terms.** - -- Save stays disabled and reads "Saving…" until the batch succeeds or fails. A failed batch re-enables it, and the refusal is shown as before. The 1.5 s release is kept for a submit that never reaches the batch, such as a header that fails validation, so Save is never left stuck. -- While a save is in flight every line-item grid is disabled: no cell takes input, and there is no empty trailing row, add, duplicate, remove or reorder. An open row editor ("expand to full form") is disabled too, "Apply" included. Both take input again once the save has settled. -- A header-form submit that arrives while a batch is in flight is refused and sends nothing. The host's `onError` hears of it, and the save that is running keeps Save disabled until its own outcome. -- The header fields stay editable during the save. In edit mode an edit made there is kept and sent by the next save; in create mode the header still clears for the next entry once the create lands. -- The `record:line_items` panel's grid is disabled while its own save is in flight. That panel reloads its rows once the save lands, so a line edited in the meantime used to be overwritten by the reload, with the panel reading clean. diff --git a/.changeset/10633-gantt-silent-overtake.md b/.changeset/10633-gantt-silent-overtake.md deleted file mode 100644 index 3836c8781a..0000000000 --- a/.changeset/10633-gantt-silent-overtake.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/plugin-gantt': patch ---- - -fix(plugin-gantt): a silent re-read that overtakes a changed query now reports that query's failure - -`ObjectGantt` re-reads in two modes. A changed query (a sort, filter or search -change) reports a failure on the error screen. A silent re-read of the same query -(a data-invalidation, the toolbar refresh, or the read-back after a drag, resize or -inline edit) only logs a failure and keeps the last good rows, because those rows -still answer that query. - -Only the newest re-read may commit, so a silent re-read that starts while a -changed query is still in flight makes that query's run stale. The re-read reads -the changed query too. When it failed, the chart kept the rows of the query before -the change, with no error and no refreshing state. Those rows answer neither query -the user asked for. - -A silent re-read that overtakes a changed query in flight now takes over that -query's report: its failure shows the error screen, as the changed query's own -failure would. The report passes on if another silent re-read overtakes it, and it -is released when the current re-read settles. The same holds for a silent re-read -that overtakes the initial load, which used to leave an empty chart with no error. -A silent re-read with nothing pending still only logs a failure and keeps its rows. -No prop or export changes. diff --git a/.changeset/10634-objectchart-groupby-category-forward.md b/.changeset/10634-objectchart-groupby-category-forward.md deleted file mode 100644 index 16b01cd86e..0000000000 --- a/.changeset/10634-objectchart-groupby-category-forward.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -'@object-ui/plugin-charts': patch ---- - -An object-bound `object-chart` that names its category with `aggregate.groupBy` alone now draws that -category, instead of being refused with `missing-category-key` (objectui#10634). - -A node with `objectName`, `aggregate: { field: 'amount', function: 'sum', groupBy: 'stage' }` and -`series`, and no `xAxisKey` or `xAxis`, passed `ObjectChart`'s absent-category screen (objectui#8168), -whose remedy lists `aggregate.groupBy` first. The schema `ObjectChart` then handed to `ChartRenderer` -carried no category key, so the chart floored it on `'name'`, found no `name` column in the grouped -rows, and refused. The author had followed the refusal's own remedy and was refused again, over a key -they never wrote. - -`ObjectChart` now forwards the category when the author named it only through `groupBy`. The key it -forwards is the column the aggregate projects its group under, per the contract's result-column -convention (`chartAggregateResultKeys` in `@objectstack/spec/ui`): the `groupBy` string, or -`alias ?? field` for the structured `{ field, dateGranularity?, alias? }` node. This is the same -column the dashboard relays already bind (objectui#8269). An `alias` therefore binds the aliased -column the rows carry, not the underlying field. - -What does not change: - -- An authored category axis always wins. The forward fills an absent slot only, and asks this - package's own axis resolution whether one is authored: `xAxisKey`, a spec-shape `xAxis: { field }`, - or a bare string `xAxis`. It never writes over any of them. -- Charts that draw authored rows (`data`, or a `bind` scope) are unchanged, with or without - `objectName`. Their rows never went through the aggregate, so `groupBy` says nothing about their - columns. -- Dataset-bound charts (ADR-0021) are unchanged. They take their category from their dimensions. -- The absent-category refusal fires on exactly the same nodes as before. diff --git a/.changeset/10636-objectview-record-count-singular.md b/.changeset/10636-objectview-record-count-singular.md deleted file mode 100644 index 6cec395d9e..0000000000 --- a/.changeset/10636-objectview-record-count-singular.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/i18n': patch ---- - -The console's record-count footer, drawn under the list when a record is open -beside it in split navigation, now reads `1 record` at one record instead of -`1 records` (objectui#10636). - -The footer rendered one key, `console.objectView.recordCount`, at every count. -It now picks the new `console.objectView.recordCountOne` at exactly one record -and `console.objectView.recordCount` at every other count, the same switch the -list view's record-count bar uses. Every built-in pack words the pair the way it -words the list bar's `list.recordCount` / `list.recordCountOne`, so the footer -and the bar count the same records in the same words. In Japanese, Korean and -Chinese, which have no separate singular, the two values are the same string. - -Russian and Arabic also read correctly at other counts now. The count-not-one -value held one noun form: Russian read `2 записей` at two and `21 записей` at -twenty-one, and Arabic used the singular noun at every count. Both now use the -count label their list bar already uses, `Записей: N` and `عدد السجلات: N`, -which is right at any number. At one record they read `1 запись` and `1 سجل`. - -⚠️ **Dated note, 2026-10-02 — superseded in this release — objectui#11445.** -Later in this same release the `console.objectView.recordCountOne` / -`console.objectView.recordCount` switch gave way to a -`console.objectView.recordCount` count family in all ten packs, worded like -`list.recordCount`'s: the footer calls the family key with `{ count }`, -`console.objectView.recordCountOne` left every pack, and `ru` and `ar` read a -noun form at each count (`2 записи`, `3 سجلات`) where the count label stood. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10637-image-alt-translated.md b/.changeset/10637-image-alt-translated.md deleted file mode 100644 index eb46ed90ac..0000000000 --- a/.changeset/10637-image-alt-translated.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): the image field widget names an image that carries no name of its own with the translated `fields.image.imageAlt`, not the literal `Image` (objectui#10637) - -`ImageField` read its images with the untranslated literal `'Image'` as the fallback name, so a -value with no name of its own (a bare `sys_file` id, or a `data:` URI) was named `Image` on every -locale. Its `` alt, the read-mode enlarge button's accessible name and the lightbox it opens -all read that word, and the translated `fields.image.imageAlt` fallback never ran. - -`ImageField` now reads its images with no fallback name, as the image cell has since -objectui#10493. A nameless image gets the translated alt ("Image 1" in `en`, numbered by -position) in read mode and edit mode, the enlarge button's name embeds that alt, and the lightbox -gets the translated alt and the translated preview title. A value that carries a name keeps it. -The cropper's output file name for a nameless image is now the widget's own fallback -(`image-0.png` for the first image), where it was `Image`. Stored values do not change. diff --git a/.changeset/10638-interface-page-view-field-keys.md b/.changeset/10638-interface-page-view-field-keys.md deleted file mode 100644 index f869421c49..0000000000 --- a/.changeset/10638-interface-page-view-field-keys.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): an interface page's source view now hides and orders its columns - -An ADR-0047 interface list page (`InterfaceListPage`) builds its list schema -from the view its `interfaceConfig.sourceView` names, and carried that view's -`columns`, `filter`, `sort` (and its other keys) but not its `hiddenFields` or -`fieldOrder`. A -source view that authored either still showed every column of its `columns`, in -`columns` order: accepted, served, then dropped at the page. Both keys now reach -`ListView` beside the view's `columns`, which composes them as it always has — -`columns` projects, `hiddenFields` subtracts, `fieldOrder` sorts what survives, -and a surviving column it does not list sorts last (objectstack#15184). - -The two keys travel with the view's column list, as one unit: - -- A page that defines its own `columns` uses that list as it stands, and neither - view key applies. The page config has no spelling of either key, and its own - `columns` are not inherited from any view. This also keeps a design-mode column - drag in place: the drag saves the order it shows as the page's `columns`, and a - view `fieldOrder` would otherwise sort it back. -- A view whose `columns` is empty declares no projection, so the page derives - the object's default columns and neither key applies. diff --git a/.changeset/10639-readonly-password-empty.md b/.changeset/10639-readonly-password-empty.md deleted file mode 100644 index 5291853d8f..0000000000 --- a/.changeset/10639-readonly-password-empty.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): a readonly `password` field with no value now says "No value" (objectui#10639) - -The readonly branch of the `PasswordField` widget never read its value. It drew -the eight-dot mask for every input, `null` included, so on a readonly form or -detail surface a credential that was never set looked exactly like one that is -set. - -An empty value now renders the shared `EmptyValue` affordance, whose accessible -name is "No value". "Empty" is the rule the `password` cell has used since -objectui#8678: `null`, `undefined`, `''` and `[]` are empty. `{}` and a -whitespace-only string are stored values and keep the mask. - -A stored value renders exactly what it rendered before: the same mask, in the -same element. The value is still never printed. The editable widget is -unchanged. diff --git a/.changeset/10640-agent-preview-chat-link.md b/.changeset/10640-agent-preview-chat-link.md deleted file mode 100644 index d07f954fcc..0000000000 --- a/.changeset/10640-agent-preview-chat-link.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -The agent preview's "Try in chat" link now opens the agent's chat page instead of redirecting to the home page (objectui#10640). - -The link pointed at `/console/ai/agents/NAME/chat`. The console declares no route beginning with `/console`, so its catch-all redirected the author to `/`. As a plain anchor it also ignored the base path the console is mounted under. - -`AgentPreview` now builds the link as `/ai/NAME?new=1`, the agent chat route the console declares, asking the chat page for a new conversation. The agent segment comes from `agentRouteName`, so a built-in agent uses its friendly name (such as `build`) and a custom agent uses its own name. The link is rendered through the router, so a console mounted under a base path (such as `/_console`) keeps it inside that mount, and it still opens in a new tab. When the preview is rendered with no router above it, as in the designer gallery, it draws no link. diff --git a/.changeset/10645-api-console-preset-lazy-route-readiness.md b/.changeset/10645-api-console-preset-lazy-route-readiness.md deleted file mode 100644 index 104f43bb37..0000000000 --- a/.changeset/10645-api-console-preset-lazy-route-readiness.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Test-only change in `@object-ui/console`, no package released: the route-table cases of `ApiConsolePage.requestPreset-10591.test.tsx` now wait for the API console's lazy route to leave its loading frames before their existing `findBy*`, instead of spending the default 1000 ms window on the module loader. The standalone `developer/api-console` case failed that window intermittently on a saturated CI shard (objectui#10645). No published behaviour changes. diff --git a/.changeset/10654-yaxis-position-honoured.md b/.changeset/10654-yaxis-position-honoured.md deleted file mode 100644 index a05df53c72..0000000000 --- a/.changeset/10654-yaxis-position-honoured.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -'@object-ui/plugin-charts': patch ---- - -A chart's `yAxis[].position` now places each value axis, and `horizontal-bar` lays out and -binds its axes (objectui#10654, the y-side twin of objectui#10587; objectui#10655 folded in). - -`position` is declared on `@objectstack/spec`'s `ChartAxisSchema`, which each `yAxis` entry -takes, and the normalizer keeps it. No axis was placed by it: it only chose which entry -configured the right-hand axis a combo always draws (and the value format of a right-bound -series), and how the normalizer bound the series it derives from the entries. So a lone -`position: 'right'` entry drew its axis on the left, `top` / `bottom` passed in silence, a second -entry was always the right-hand axis, and with no `series` a first entry at `right` took both -derived series to the right-hand axis. - -- **Where each entry is drawn.** `placeYAxes` (in `normalizeChartSchema`) is the one place a y - side is resolved; the normalizer binds each series it derives from the entries with the same - call, so a derived series plots against its own entry's axis. - - bar (`column`), line, area, combo and scatter: `left` / `right`. Scatter draws one y axis, - the first entry's. - - horizontal-bar: the value axes run across the plot, so `bottom` / `top`; a series' - `yAxis: 'left'` binds the bottom axis and `'right'` the top one. - - A lone entry's axis is drawn on the side it names. With two entries each is drawn on the - side it names, and an entry that names no side takes the side the other left free. - - **Both entries naming the same side:** the first keeps it and the second is drawn on the - other side, with a note naming `yAxis[1].position`. `yAxis[0]` is already the primary axis - (its `showGridLines` governs the horizontal grid), and declaration order is the one - tie-break an author can read off the metadata. - - A side a value axis cannot take is refused: the entry is placed as if it named none, and - the chart shows a note under the plot (`data-chart-note="y-axis-position"`) naming - `yAxis[N].position`, the value and the side the axis was drawn on. `ChartAxisSchema` is - shared by both axes and is not narrowed. -- **horizontal-bar.** Two entries draw two value axes, along the bottom and the top, and the - bars bind to them; they were bound to `yAxisId`s the branch never rendered, and bars were - dropped. `xAxis.title` is drawn on the category axis, and the `yAxis` title is laid out for an - axis running across the plot, under it at the bottom and over it at the top. -- **Grid and annotations** bind to the rendered left value axis whenever the value axes carry - ids (a combo always; bar, line, area and horizontal-bar with two entries). They were bound to - an axis id those charts do not render: a two-entry chart's horizontal grid lost its per-tick - lines and its `axis: 'x'` annotations, a combo with fewer than two entries drew no annotation, - and a two-entry horizontal-bar dropped its `axis: 'y'` annotations. -- **A right-hand value axis** lays its title out on the far side of its tick labels, the left - layout mirrored, as a top x axis mirrors the bottom one. - -**User-visible render change** for a chart whose `yAxis` entries declare `position`, a -horizontal-bar with an axis title or two `yAxis` entries, the grid and annotations of two-entry -and combo charts, and the title of every right-hand value axis. -`ChartRenderer.yAxisPosition-10654.test.tsx` pins each row against its `bar` control. diff --git a/.changeset/10657-components-masked-client-paths.md b/.changeset/10657-components-masked-client-paths.md deleted file mode 100644 index c5ab9e55e9..0000000000 --- a/.changeset/10657-components-masked-client-paths.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/components': patch ---- - -`data-table` no longer searches, sorts or sizes a `masked` column by its raw value (objectui#10657, which folded objectui#10658). - -`TableColumn.masked` already withheld a credential column's raw value from the keyboard -copy, the cell tooltip, the CSV export and inline edit (objectui#10583). Three more of the -table's own paths still read it: - -- The client-side search matched a term against it, so typing a substring answered - "does the credential contain this?", one character at a time. -- The sort ordered the rows by it, from the header and from the header menu. Under - manual sorting the header asked the host to do the same. -- The automatic width was estimated from its length, so the column grew with the - credential. - -On a `masked` column now: - -- The client-side search leaves the column out of its predicate. -- Its sort is disabled: the header does not sort and shows no sort indicator, the header - menu offers no sort, with client and manual sorting alike, and a client sort already - set on the column (before its producer set the flag) stops ordering the rows. -- Its automatic width is sized from its header, never from its values. - -Columns without the flag search, sort and size exactly as before. This reaches every host -that runs the table's search and sort in the browser: `object-grid` over inline data or -while grouped, `object-data-table`, and any `data-table` authored directly. - -This is defence in depth. The real guard is still the server: ObjectStack's read mask -replaces `secret` and `password` values with its mask before they reach the browser. With -`manualSearch`, the table searches nothing itself, so what the host's search matches is up -to the host and its server. - -The pending objectui#10583 changeset lists the client-side search, the sort and the width -under "Not covered", and says the related list and `object-data-table` do not set the flag -yet. Those entries no longer hold once this change ships with it. diff --git a/.changeset/10657-fields-masked-cell-renderer-export.md b/.changeset/10657-fields-masked-cell-renderer-export.md deleted file mode 100644 index 21d85361ca..0000000000 --- a/.changeset/10657-fields-masked-cell-renderer-export.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/fields': minor ---- - -`MaskedCellRenderer`, the mask a `password` / `secret` cell draws, is now exported, so a table that cannot type a column yet draws it WITHHELD instead of as text (objectui#10657, which folded objectui#10706). - -**New export `MaskedCellRenderer`.** It is the component the standard `password` and -`secret` cells already resolve to: `••••••` for a value that is set, the empty-value mark -for one that is not. Its `field` prop is optional, because it reads only whether a value -is present. It is the shipped mask, not whatever is registered for `password` at the -time, so a host override of a masked type does not change what a withheld cell draws. - -`object-grid`, the related list and `object-data-table` use it for a column whose type is -not known yet: while the object's field types are loading, or after their read failed, -they draw such a column as this mask rather than as its value. - -`registerFieldRenderer('api_token', MaskedCellRenderer)` now masks a type the same way -the `getCellRenderer('password')` form does, and `isMaskedFieldType('api_token')` answers -`true` for it. Nothing that already resolves changes. diff --git a/.changeset/10657-plugin-dashboard-masked-data-table.md b/.changeset/10657-plugin-dashboard-masked-data-table.md deleted file mode 100644 index baebc6cb59..0000000000 --- a/.changeset/10657-plugin-dashboard-masked-data-table.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -`object-data-table` sets `TableColumn.masked` on its columns, so a `password` / `secret` column no longer copies, exports, searches, sorts or sizes by its raw value (objectui#10657, which folded objectui#10658). - -The dashboard table widget draws a `password` / `secret` cell as `••••••`, but it never set -the flag the table reads. So the table handed the raw value out anyway: Ctrl+C / Cmd+C on -the masked cell, its tooltip, the CSV export, the search box (which runs in the browser -here) and the header sort all read it, and the column's width grew with it. - -The widget now sets the flag on every column whose cell is drawn as a mask, from -`isMaskedFieldType()` in `@object-ui/fields` over the column's authored `type` and the -object's field type (a narrow-only union: a column authored as `text` over a `secret` -field keeps the flag), for declared and derived columns alike. - -It fails closed. Bound and inline rows are drawn before the object definition arrives, and -a failed read never delivers one. In that window the widget cannot tell a masked column -from any other, so it sets the flag on every column: no cell copies, shows a tooltip or is -exported, the search matches nothing, no header sorts, and widths come from the headers. -Not covered: in the same window a field the object declares as `password` / `secret` is -drawn as text, because the mask comes from that declaration. - -This is defence in depth. The real guard is still the server: ObjectStack's read mask -replaces `secret` and `password` values with its mask before they reach the browser. diff --git a/.changeset/10657-plugin-dashboard-withheld-draw.md b/.changeset/10657-plugin-dashboard-withheld-draw.md deleted file mode 100644 index 2ea72f966b..0000000000 --- a/.changeset/10657-plugin-dashboard-withheld-draw.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -`object-data-table` no longer draws an untyped column as text while the object definition is loading or after its read failed: it draws the mask instead (objectui#10657, the objectui#10706 class at this producer). - -A cell here draws from the column's authored `type`, or the object's. Bound and inline -rows are drawn before the object definition arrives, and a failed read never delivers -one, so in that window a column that authors no `type` drew its value as text, a -`password` / `secret` field included. objectui#10657's first change already set -`TableColumn.masked` on every column in that window, but the flag withholds; it does not -draw. - -Now, in that window, a column with no `type` of its own is drawn as the mask -(`MaskedCellRenderer` from `@object-ui/fields`), declared and derived columns alike, and -stays so when the read failed: fail closed, never back to text. A column that authors its -`type` draws from it, and a column with a `cell` of its own draws what that `cell` -returns. Once the definition lands, each column draws from its declared type as before. - -The record drawer a row opens (record drill-down) drew the clicked record's fields from -the same unknown types, so after a failed read it printed a `password` / `secret` field -as text too. In that window it now draws every value as the mask. - -The pending objectui#10657 `object-data-table` changeset says a `password` / `secret` -field is still drawn as text in that window; that no longer holds once this change ships -with it. - -This is defence in depth. The real guard is still the server: ObjectStack's read mask -replaces `secret` and `password` values with its mask before they reach the browser. diff --git a/.changeset/10657-plugin-detail-masked-related-list.md b/.changeset/10657-plugin-detail-masked-related-list.md deleted file mode 100644 index 4ae355fca3..0000000000 --- a/.changeset/10657-plugin-detail-masked-related-list.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -`RelatedList` sets `TableColumn.masked` on the columns it hands its table, so a `password` / `secret` column no longer copies, shows or sorts by its raw value (objectui#10657). - -The related list draws a `password` / `secret` cell as `••••••`, but it never set the flag -the table reads. So the table handed the raw value out anyway: Ctrl+C / Cmd+C on the masked -cell copied the credential, the cell's tooltip carried it, a click on its header sorted the -list by it (the table's headers drive this list's own sort), and the column's width grew -with it. - -The list now sets the flag on every column whose cell is drawn as a mask, from -`isMaskedFieldType()` in `@object-ui/fields` over the column's authored `type` and the -object's field type (a narrow-only union: a column authored as `text` over a `secret` -field keeps the flag). It applies to authored columns, bare field names and the columns -the list derives on its own. - -It fails closed. While the object definition is still loading, or after its read failed, -the list cannot tell a masked column from any other, so it sets the flag on every column: -in that window no cell copies or shows a tooltip, and no header sorts. Not covered: in the -same window a field the object declares as `password` / `secret` is drawn as text, -because the mask comes from that declaration. - -Also not covered: the list's own filter box (opt-in `filterable`) matches against every -field of a row, and its sort buttons (`type: 'list'` with `sortable`) sort by any column, -masked ones included. - -This is defence in depth. The real guard is still the server: ObjectStack's read mask -replaces `secret` and `password` values with its mask before they reach the browser. diff --git a/.changeset/10657-plugin-detail-withheld-draw.md b/.changeset/10657-plugin-detail-withheld-draw.md deleted file mode 100644 index 92c158ab36..0000000000 --- a/.changeset/10657-plugin-detail-withheld-draw.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -The related list no longer draws a cell as text while its object definition is loading or after its read failed: it draws the mask instead (objectui#10657, the objectui#10706 class at this producer). - -The list draws a cell from the object's field type, never from a column's authored -`type`. While the definition was in flight, and for good after its read failed, no column -had a cell, so the table drew every value as text, a `password` / `secret` field -included. objectui#10657's first change already set `TableColumn.masked` on every column -in that window (no copy, tooltip or header sort), but the flag withholds; it does not -draw. - -Now, in that window, every column without a `cell` of its own is drawn as the mask -(`MaskedCellRenderer` from `@object-ui/fields`), and stays so when the read failed: fail -closed, never back to text. A column whose `cell` the author supplied draws what that -`cell` returns. Once the definition lands, each column draws from its declared type as -before. - -The cost: while the definition is loading, and for good after a failed read, the list -shows masks where it used to show values. The pending objectui#10657 related-list -changeset says a `password` / `secret` field is still drawn as text in that window; that -no longer holds once this change ships with it. - -This is defence in depth. The real guard is still the server: ObjectStack's read mask -replaces `secret` and `password` values with its mask before they reach the browser. diff --git a/.changeset/10657-plugin-grid-masked-client-paths.md b/.changeset/10657-plugin-grid-masked-client-paths.md deleted file mode 100644 index 6c6f6e54ca..0000000000 --- a/.changeset/10657-plugin-grid-masked-client-paths.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/plugin-grid': patch ---- - -On `object-grid`, a masked column is now also left out of the table's client-side search, never sorted by, and sized from its header (objectui#10657, which folded objectui#10658). - -`object-grid` already set `TableColumn.masked` on every column whose field is drawn as a mask -(objectui#10583). Where the grid lets the table search and sort in the browser (inline -`data`, or a grouped view), the table still matched a search term against the raw value, -sorted by it from the header and the header menu, and sized the column from its length. -The table now refuses all three for a masked column (`@object-ui/components`); the grid's -own source is unchanged, and its README no longer lists these under "Not covered". - -What stays not covered on the grid is unchanged: the host-fetched path's window before the -object schema arrives (objectui#10706's row of objectui#10657), the server-streamed export, -and expanded lookup records in the client JSON export. - -This is defence in depth. The real guard is still the server: ObjectStack's read mask -replaces `secret` and `password` values with its mask before they reach the browser. diff --git a/.changeset/10657-plugin-grid-withheld-first-paint.md b/.changeset/10657-plugin-grid-withheld-first-paint.md deleted file mode 100644 index 1966c1d38c..0000000000 --- a/.changeset/10657-plugin-grid-withheld-first-paint.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/plugin-grid': minor ---- - -`object-grid` no longer draws an untyped column as text before its object schema has loaded: the column is WITHHELD until it has, and stays withheld when the read fails; a host can hand the grid the field types it holds (`objectFields`) so there is no such window (objectui#10657, which folded objectui#10706). - -On the host-fetched path (rows handed down as `data`, as `ListView` does) the rows paint -before the grid's own `getObjectSchema` read lands. An untyped view column takes its type -from that schema, so until it arrived a column over a `password` / `secret` field drew -the raw value as text and handed it out (copy, tooltip, the grid's client export, the -mobile card), and grouping by it printed the value as the group label. A failed read was -swallowed as non-fatal, leaving the column in the clear for the life of the grid. - -- **Withheld.** While an object-bound grid (an object name, and a data source that can - answer `getObjectSchema`) has no field types in hand, a column with no `type` of its - own is drawn as the mask (`MaskedCellRenderer` from `@object-ui/fields`), carries - `TableColumn.masked`, is left out of the grid's client export, is drawn through its cell - on the mobile card, and cannot be a grouping key (the entry is ignored without a - warning until the types are known; a masked field is still warned about). No type is - inferred for it from its name or values meanwhile. It stays withheld when the read - fails: fail closed, never back to text. A column that authors its own `type` draws - from it, as it did. A grid with no `getObjectSchema` to wait for is unchanged. -- **The record panel** a row opens under overlay navigation (drawer, modal, split, - popover) with no declared fields in hand printed every value of the record, inferred - from its value and name. While the types are unknown it now draws each value as the - mask as well. -- **New prop `objectFields` on `ObjectGrid` (`ObjectGridComponentProps`).** The object's - field catalogue, handed down by a host that has already read the definition. The grid - answers every field-type question from it until its own read lands, so the columns - draw from their declared types at first paint and nothing is withheld. It is a runtime - prop only: `SchemaRenderer` strips an `objectFields` key authored in the schema - (objectui#8818), so no view author can hand the grid a catalogue. - -The pending objectui#10583 changeset lists the host-fetched window under "Not covered", -and the pending objectui#10657 grid changeset says that window stays not covered. Neither -holds once this change ships with them. - -This is defence in depth. The real guard is still the server: ObjectStack's read mask -replaces `secret` and `password` values with its mask before they reach the browser. diff --git a/.changeset/10657-plugin-list-grid-object-fields.md b/.changeset/10657-plugin-list-grid-object-fields.md deleted file mode 100644 index 10379f3b47..0000000000 --- a/.changeset/10657-plugin-list-grid-object-fields.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -`ListView` hands its grid the object's field types together with the rows, so the grid draws a `password` / `secret` column masked from its first paint (objectui#10657, which folded objectui#10706). - -`ListView` fetches the rows and hands them to `object-grid` as `data`, and those rows -painted before the grid's own read of the object definition settled. In that window an -untyped column over a `password` / `secret` field had no type: it drew the raw value, and -since `object-grid` now withholds such a column instead, it would draw the mask for every -untyped column until the read lands. `ListView` reads the object definition before it -fetches the rows, so it now passes the definition's fields to the grid as `objectFields` -with them, and the grid has no window at all. Only the grid view is handed it. When the -definition could not be read, nothing is passed and the grid withholds on its own. diff --git a/.changeset/10657-types-masked-doc.md b/.changeset/10657-types-masked-doc.md deleted file mode 100644 index cdf588dfe4..0000000000 --- a/.changeset/10657-types-masked-doc.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/types': patch ---- - -`TableColumn.masked`'s documentation and its zod `describe()` text now list every path the table withholds, and name the three producers that set the flag (objectui#10657, which folded objectui#10658). - -The table now also leaves a masked column out of its client-side search, disables its -sort and sizes it from its header (`@object-ui/components`), and `RelatedList` and -`object-data-table` now set the flag as `object-grid` does. The JSDoc and the -`describe()` text on `TableColumnSchema.masked` said the opposite, so they are rewritten. -The docs also state the fail-closed window the related list and `object-data-table` keep -while the object definition is loading or after its read failed, and what that window -does not cover. No type or schema shape changes. diff --git a/.changeset/10657-types-withheld-doc.md b/.changeset/10657-types-withheld-doc.md deleted file mode 100644 index f79b9a38a1..0000000000 --- a/.changeset/10657-types-withheld-doc.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/types': patch ---- - -`TableColumn.masked`'s documentation describes withheld columns: a column whose type is not known yet is drawn as the mask and carries the flag (objectui#10657, which folded objectui#10706). - -The JSDoc said that the related list and `object-data-table` still draw a `password` / -`secret` field as text while their object definition is loading or after its read -failed, and that `object-grid` draws an untyped column's raw value on its host-fetched -path until its object schema arrives. Neither holds any more: each of the three producers -now draws such a column as the mask and sets the flag on it, and `object-grid` takes the -field types from a host that has them (`objectFields`). The JSDoc is rewritten to say so. -The pending objectui#10657 `@object-ui/types` changeset says these docs state what that -window does not cover; once this change ships with it, they state what it withholds -instead. No type or schema shape changes. diff --git a/.changeset/10659-modalform-first-load-window.md b/.changeset/10659-modalform-first-load-window.md deleted file mode 100644 index d95162e789..0000000000 --- a/.changeset/10659-modalform-first-load-window.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): `ModalForm` no longer paints an editable form before the record it edits has loaded - -Opening an edit modal showed the form empty and editable while the record read -was still in flight. When the record arrived it replaced whatever had been -typed, and the save that followed sent the whole record with its original -values. The value was gone from the screen and from the save, with no warning. -The modal now keeps its loading state until the record read lands, as the edit -drawer has done since objectui#10190. - -`ModalForm` builds its fields and reads its record in two effects that both run -when the object schema arrives. The field-building effect used to end the -loading state unconditionally. It now leaves that to the record read whenever -one is outstanding, through the same check the drawer uses, which both -containers now share. diff --git a/.changeset/10662-onviewchange-reference-row.md b/.changeset/10662-onviewchange-reference-row.md deleted file mode 100644 index 77686f2e3b..0000000000 --- a/.changeset/10662-onviewchange-reference-row.md +++ /dev/null @@ -1,21 +0,0 @@ ---- ---- - -Docs and comments only (objectui#10662). No package is released: no type, no -accept set and no runtime behaviour changes. - -- `content/docs/api/schema-reference.md`: the `ViewSwitcherSchema` table taught - `onViewChange` as an "Expression or callback invoked on view change". The key - is declared as the NAME of a `CustomEvent` dispatched on `window` with - `detail: { view }` (objectui#6124), and an expression or a function is not - that contract. The row now says what the declaration says. `apps/site` is - private and in the `ignore` list, so nothing under `content/` ships. -- `@object-ui/types` (`views.ts`): the JSDoc of `ViewSwitcherSchema.onViewChange`, - `FilterUISchema.onChange` and `SortUISchema.onChange` said the key was read - in the control "as `new CustomEvent(schema.KEY, …)`". Since objectui#10616 - that expression lives only in `notifyViewHandlerChannels` - (`plugin-view/src/viewHandlerChannels.ts`), which all three controls call. - Each docblock now names that function as the dispatcher and keeps the - control as the read site. The docblocks are emitted into `views.d.ts` as - documentation on the same members, and `views.ts` is type-only, so no - emitted JavaScript changes; hence the empty declaration. diff --git a/.changeset/10663-calendar-error-clears.md b/.changeset/10663-calendar-error-clears.md deleted file mode 100644 index a1b05ea7f5..0000000000 --- a/.changeset/10663-calendar-error-clears.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch ---- - -fix(plugin-calendar): a failed load no longer keeps `ObjectCalendar` on its error screen after a later load succeeds (objectui#10663) - -`ObjectCalendar` set `error` when its fetch failed, and the render returns the -error screen early whenever `error` is set. Nothing ever cleared it. Every later -load that succeeded still wrote its events, but the calendar stayed on the error -screen until it remounted. Since objectui#10572 the calendar re-reads on every -data-invalidation event, so one failed background re-read was enough. - -The current run of the fetch now clears the error when it commits rows, on each -of its commit branches: those rows answer the current query, so the earlier -failure no longer describes the screen. This is the rule objectui#10578 set for -`ObjectGantt`. The clear sits inside the run's existing `isMounted` guard, so a -superseded run cannot clear the current run's error. The error is not cleared -when a run starts; it stays until rows land. - -Rows a parent hands over through `data` clear it too, beside the row-ceiling -reset that already sits there for the same reason: those rows are not the query -that failed. - -A failed background re-read is still reported: the calendar has no silent mode, -so it shows the error screen rather than keeping the last good events, and the -next re-read that succeeds takes the screen back. diff --git a/.changeset/10663-kanban-error-clears.md b/.changeset/10663-kanban-error-clears.md deleted file mode 100644 index 38a78d4ba0..0000000000 --- a/.changeset/10663-kanban-error-clears.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/plugin-kanban': patch ---- - -fix(plugin-kanban): a failed load no longer keeps `ObjectKanban` on its error screen after a later load succeeds (objectui#10663) - -`ObjectKanban` set `error` when its fetch failed, and the render returns the -error screen early whenever `error` is set. Nothing ever cleared it. Every later -load that succeeded still wrote its cards, but the board stayed on the error -screen until it remounted. Since objectui#10572 the board re-reads on every -data-invalidation event, so one failed background re-read was enough. - -The current run of the fetch now clears the error when it commits cards: those -cards answer the current query, so the earlier failure no longer describes the -screen. This is the rule objectui#10578 set for `ObjectGantt`. The clear sits -inside the run's existing `isMounted` guard, so a superseded run cannot clear -the current run's error. The error is not cleared when a run starts; it stays -until cards land. - -A failed background re-read is still reported: the board has no silent mode, so -it shows the error screen rather than keeping the last good cards, and the next -re-read that succeeds takes the screen back. diff --git a/.changeset/10663-timeline-error-clears.md b/.changeset/10663-timeline-error-clears.md deleted file mode 100644 index 0d5e9b5684..0000000000 --- a/.changeset/10663-timeline-error-clears.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/plugin-timeline': patch ---- - -fix(plugin-timeline): a failed load no longer keeps `ObjectTimeline` on its error screen after a later load succeeds (objectui#10663) - -`ObjectTimeline` set `error` when its fetch failed, and the render returns the -error screen early whenever `error` is set. Nothing ever cleared it. Every later -load that succeeded still wrote its rows, but the timeline stayed on the error -screen until it remounted. Since objectui#10623 the timeline re-reads on every -data-invalidation event, so one failed background re-read was enough. - -The current run of the fetch now clears the error when it commits rows: those -rows answer the current query, so the earlier failure no longer describes the -screen. This is the rule objectui#10578 set for `ObjectGantt`. The error is not -cleared when a run starts; it stays until rows land. - -Only the current run writes the error at all. A run that a newer one has -superseded can no longer clear the current run's error, or put the error screen -over the current run's rows. - -A failed background re-read is still reported: the timeline has no silent mode, -so it shows the error screen rather than keeping the last good rows, and the -next re-read that succeeds takes the screen back. diff --git a/.changeset/10664-data-table-filter-bar.md b/.changeset/10664-data-table-filter-bar.md deleted file mode 100644 index 5a2d647767..0000000000 --- a/.changeset/10664-data-table-filter-bar.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -The dashboard's `object-data-table` reads its rows once per mount, already expanded, and a dashboard filter re-reads its options when `optionsFrom.filter` changes (objectui#10664). - -- `object-data-table` loaded the object definition in an effect of its own and listed it among the fetch effect's dependencies, so every object-bound mount issued two `find` calls, the first without `$expand`. It now reads the definition through `useSettledSchema` from `@object-ui/react` and its query waits until that read settles; a failed read, or an adapter with no `getObjectSchema`, still loads the rows, unexpanded. Its expansion also depends on `columns`, which did not re-run the read: adding a lookup column to a mounted table now re-reads with the new `$expand`, and relabelling a column does not. -- The filter bar's option list sends `optionsFrom.filter` on both of its reads, the dataset query and the record fallback, but did not re-read when only that filter changed. It now does, and an equal filter in a new object does not re-read. diff --git a/.changeset/10664-map-reads-once.md b/.changeset/10664-map-reads-once.md deleted file mode 100644 index 3e0960bf7e..0000000000 --- a/.changeset/10664-map-reads-once.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/plugin-map': patch ---- - -An `object-map` block reads its records once per mount, and that read already carries the lookup expansion (objectui#10664). - -The map loaded the object definition in an effect of its own and listed it among the fetch effect's dependencies. The definition lands after the first query, so every mount issued two `find` calls, the first without `$expand`. Switching the bound object also sent the new object's query with the previous object's expansion. The map now reads the definition through `useSettledSchema` from `@object-ui/react`, and its object query waits until that read settles, the way `object-timeline` (objectui#7895) and `object-gallery` (objectui#7903) already do. A definition read that fails, or an adapter with no `getObjectSchema`, settles with no definition, so the map still loads, unexpanded. Host rows (`data`) and an inline `value` set are not held. diff --git a/.changeset/10664-object-view-table-sort.md b/.changeset/10664-object-view-table-sort.md deleted file mode 100644 index fccbcc5d7d..0000000000 --- a/.changeset/10664-object-view-table-sort.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -The object view's own read for a non-grid view (calendar, kanban and the other views it fetches for) re-reads when `table.sort` changes (objectui#10664). - -That read falls back to `table.sort` for its `$orderby` when neither the named view nor the active view declares a sort, but a change to `table.sort` alone did not re-run it, so the view kept the old order. It now keys the read on that sort's content, so an equal sort in a new array does not re-read. diff --git a/.changeset/10664-repeater-picker-sort-key.md b/.changeset/10664-repeater-picker-sort-key.md deleted file mode 100644 index a0740fc644..0000000000 --- a/.changeset/10664-repeater-picker-sort-key.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/components': patch ---- - -`element:repeater` and `element:record_picker` re-read their rows when the sort they send changes (objectui#10664, folding objectui#10665). - -Both blocks put their sort on `$orderby` (the repeater's `properties.sort`; the picker's `properties.sort` or its `dataSource` binding's `sort`), but neither re-ran its read when only the sort changed, so a bound sort control or a live preview kept showing the old order. Each now keys its read on the sort's content, the way it already keys on the filter's, so an equal sort in a new array does not re-read. diff --git a/.changeset/10666-filter-token-sweep.md b/.changeset/10666-filter-token-sweep.md deleted file mode 100644 index 39f3445338..0000000000 --- a/.changeset/10666-filter-token-sweep.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/react': minor -'@object-ui/plugin-calendar': patch -'@object-ui/plugin-gantt': patch -'@object-ui/plugin-kanban': patch -'@object-ui/plugin-map': patch -'@object-ui/plugin-timeline': patch -'@object-ui/plugin-tree': patch -'@object-ui/plugin-detail': patch -'@object-ui/plugin-form': patch -'@object-ui/plugin-list': patch -'@object-ui/components': patch -'@object-ui/types': patch ---- - -Every data node that sends its own authored `filter` into a query now resolves the spec's context tokens first (objectui#10666). With `filter: [['owner', '=', '{current_user_id}']]` these nodes used to send the literal token; they now send the signed-in user's id, and `{current_org_id}` resolves to the active organization: - -- `object-calendar`, `object-map` and `object-tree`, on both the object query and the inline (`provider: 'value'`) query; -- `object-gantt`, `object-kanban` and `object-timeline`; -- `record:related_list` and `record:line_items`, where the node's own filter is combined with the parent-record condition; -- the `element:repeater`, `element:number` (both the `aggregate` filter and the `find` fallback) and `element:record_picker` page elements. - -`list-view`, `object-grid` and `object-gallery` already did this, and are unchanged. - -**New in `@object-ui/react`: `useResolvedFilter(filter, scope)`.** Pass it a node's authored filter and `useFilterScope()`. It resolves the filter through `@object-ui/core`'s shared `resolveFilterPlaceholders` and holds the result: re-rendering with an equal filter (even one rebuilt inline on every render) hands back the same value, so a fetch effect keyed on it does not run again, while a structurally different filter or a change of signed-in user or organization resolves again. A filter with no token to resolve is handed back as the value you passed in. The hold is the one `list-view` and `object-gallery` used privately; `plugin-list` now imports it from here, and no second copy remains in that package. - -What changes for an app: - -- A filter with no placeholders reaches the query as before, unchanged. -- Nodes that re-queried whenever the host rebuilt an equal filter inline (`object-calendar`, `object-gantt`, `object-kanban`, `object-map`, `object-tree`) no longer issue those redundant queries. -- Date macros such as `{today}` in these nodes' own filters are now resolved in the browser's local time, as they already are for `list-view`, `object-grid` and `object-view`. Before, they reached the server as literals, and the server resolved them in the tenant's time zone. - -`@object-ui/types`: the `filter` docblocks on `ObjectMapSchema`, `ObjectTreeSchema`, `ObjectGanttSchema`, `ObjectCalendarSchema`, `ObjectKanbanSchema`, `ObjectChartSchema` and `ObjectGallerySchema` (and the matching zod descriptions) no longer say the filter is forwarded verbatim; they say its context tokens are resolved first. No type changes. diff --git a/.changeset/10666-gallery-filter-context-tokens.md b/.changeset/10666-gallery-filter-context-tokens.md deleted file mode 100644 index b7387da134..0000000000 --- a/.changeset/10666-gallery-filter-context-tokens.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -A directly authored `object-gallery` node now resolves the spec's context tokens in its own `filter` (objectui#10666). With `filter: [['owner', '=', '{current_user_id}']]` the gallery used to send the literal token on `$filter`; it now sends the signed-in user's id, and `{current_org_id}` resolves to the active organization. The filter goes through `@object-ui/core`'s shared `resolveFilterPlaceholders`, against the scope `FilterScopeProvider` supplies, the same call `list-view` and `object-grid` have made since objectui#10607. The resolved value is held and compared by structure, so re-rendering with an equal filter issues no extra query, and a change of signed-in user queries again. A filter without placeholders reaches the query unchanged. A gallery rendered as a `list-view` child was already handed a resolved filter, and nothing changes for it. - -Date macros such as `{today}` in a directly authored gallery's filter are now resolved in the browser's local time, as they already are for `list-view`, `object-grid` and `object-view`. Before this change they reached the server as literals, and the server resolved them in the tenant's time zone. diff --git a/.changeset/10668-calendar-quick-create-display-locale.md b/.changeset/10668-calendar-quick-create-display-locale.md deleted file mode 100644 index 1f84bf7305..0000000000 --- a/.changeset/10668-calendar-quick-create-display-locale.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch ---- - -The calendar's quick-create dialog now formats its date with the same locale as the month grid (objectui#10668). - -`ObjectCalendar`'s quick-create dialog used its `locale` prop as is. When no host passed one, that was -`undefined`, so the dialog's date and time followed the machine's locale while the grid beside it -followed the display locale. The dialog now uses the grid's rule: an explicit `locale` prop still wins, -and otherwise the dialog reads `useDisplayLocale()`. With an English UI and a `de-CH` display locale, -clicking 18 March now opens a dialog reading `On 18. März 2020`. diff --git a/.changeset/10668-gantt-timeline-display-locale.md b/.changeset/10668-gantt-timeline-display-locale.md deleted file mode 100644 index ab78095454..0000000000 --- a/.changeset/10668-gantt-timeline-display-locale.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/plugin-gantt': patch ---- - -The gantt timeline now follows the display locale, not the UI language (objectui#10668). - -`GanttView` takes its date locale from `useDisplayLocale()` instead of the UI language. This covers the -timeline's column and band headers, the toolbar's period label, the task list's start and end dates, -a bar's hover card, and the dates shown while a bar is dragged. With an English UI and a `de-CH` display locale, a week column that used to read -`3/2` now reads `2.3.`, the same locale `ObjectGantt`'s tooltips and `ResourceWorkload` already use in -the same chart. With no display locale declared, the display locale falls back to the UI language, so -the timeline renders as before. With no language at all, it used to fall through to the machine's -locale; it now gets the display locale's own last resort. diff --git a/.changeset/10668-home-inbox-relative-times-display-locale.md b/.changeset/10668-home-inbox-relative-times-display-locale.md deleted file mode 100644 index 6a1999d3ce..0000000000 --- a/.changeset/10668-home-inbox-relative-times-display-locale.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -The relative timestamps on Home and in the inbox bell now follow the display locale, not the UI language (objectui#10668). - -Home's action centre and activity card, and the bell's notification rows, notification groups and -activity rows, take their locale from `useDisplayLocale()` instead of the UI language. The -Marketplace's and Studio home's relative times already did. With an English UI and a `de-CH` display -locale, a notification from three days ago now reads `vor 3 Tagen`, where it used to read -`3 days ago`. With no display locale declared, the display locale falls back to the UI language, so -these timestamps render as before. diff --git a/.changeset/10668-i18n-gantt-binding-premise.md b/.changeset/10668-i18n-gantt-binding-premise.md deleted file mode 100644 index 91afedd02d..0000000000 --- a/.changeset/10668-i18n-gantt-binding-premise.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Test-only change in `@object-ui/i18n`: the residue-namespaces suite now checks that `GanttView` takes `t` from `useGanttTranslation()` by pattern, since `GanttView` no longer takes `language` (objectui#10668). No published behaviour changes. diff --git a/.changeset/10682-form-error-clears-2.md b/.changeset/10682-form-error-clears-2.md deleted file mode 100644 index 9a30a082d9..0000000000 --- a/.changeset/10682-form-error-clears-2.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): the line-items panel clears its load error when a later load commits rows (objectui#10682, objectui#10683) - -The `record:line_items` panel (`LineItemsPanel`) shows one banner, written by a -failed load and by a failed save. Only the start of a save cleared it, so after -a failed load the banner stayed over the rows a later load drew, and after a -failed save it stayed over the rows a later load put in place of the edits it -was about. Now only the current load writes that banner. When it commits rows it -clears the banner, whether it holds a failed load's message or a failed save's. -A load that fails shows its own failure instead. A load that another has -superseded (another parent record, say, while it was in flight) neither raises -the banner nor clears it. This is the rule objectui#10578 set for `ObjectGantt`: -the error is cleared when the current load commits, never when a load starts. diff --git a/.changeset/10682-form-error-clears.md b/.changeset/10682-form-error-clears.md deleted file mode 100644 index d62acc588e..0000000000 --- a/.changeset/10682-form-error-clears.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): a failed read no longer keeps a record form on its error screen after a later read of the same kind succeeds (objectui#10682) - -Every layout `ObjectForm` routes to (its default layout, `DrawerForm`, -`ModalForm`, `SplitForm`, `TabbedForm` and `WizardForm`) reads the object -schema and then the record before it draws, and shows its error screen ahead of -the form whenever a load error is set. Both reads wrote that one error and -nothing ever cleared it. After one failed read, a later read that succeeded -still wrote its values, but the form stayed on the error screen until it -remounted. Since objectui#10572 the default layout also re-reads its record in -place when the data-invalidation bus reports a change to that record, to its -object as a whole, or to everything, and holds that re-read while the form has -unsaved input. So one failed background re-read was enough. - -Each form now keeps the failure of each read apart and shows the error screen -while either is set. A read's failure is cleared when a later run of the same -read commits. A record read that succeeds clears an earlier record failure and -never a schema failure: after a failed schema read, a record read can only run -over a schema read earlier, for another object or data source. This is the rule -objectui#10578 set for `ObjectGantt`, applied per read. Only the current run of each read writes its failure, so a superseded -read can neither clear the current failure nor raise its own over the current -values. The error is not cleared when a read starts; it stays until that read -commits. - -A failed background re-read is still reported: no form has a silent mode, so it -shows the error screen rather than keeping the last good values, and the next -re-read that succeeds takes the screen back. diff --git a/.changeset/10684-reference-rail-superseded-parent.md b/.changeset/10684-reference-rail-superseded-parent.md deleted file mode 100644 index 2070fe2fad..0000000000 --- a/.changeset/10684-reference-rail-superseded-parent.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -fix(plugin-detail): a `record:reference_rail` block shows the related rows of the record on screen, not an earlier record's answer that arrived late (objectui#10684) - -The reference rail applies its answers while it is mounted, whichever run -started the read. When the record changed while a read for the previous record -was in flight, that answer could arrive after the current record's answer and -replace its rows. It could also settle first and clear the entry's skeleton -while the current record's read was still in flight. - -An answer is applied now only while the record and entries it was read for are -still the ones on screen, so a read for the previous record is dropped when it -arrives. A re-render for the same record starts no new read, so the answer in -flight still lands. diff --git a/.changeset/10684-report-attachments-superseded-read.md b/.changeset/10684-report-attachments-superseded-read.md deleted file mode 100644 index 4c11b532f4..0000000000 --- a/.changeset/10684-report-attachments-superseded-read.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the report view and the `record:attachments` block show the answer to their current read, not an earlier answer that arrived late (objectui#10684) - -`ReportView` read its report's rows with no check that the read was still the -current one. When the report changed while a read was in flight (another report -on the same route, a config-panel edit or a metadata refresh), the earlier -answer could arrive after the current one and replace its rows. Its data effect -now drops an answer once a newer run has started. - -The attachments panel behind `record:attachments` wrote its list and its loading -status on every refresh. When the record changed while a read was in flight, the -previous record's attachments could replace the current record's list, or -settle first and end the loading state while the current read was still out. -Each refresh now takes a run number, and only the newest one writes the list and -the status. diff --git a/.changeset/10684-timeline-superseded-rows.md b/.changeset/10684-timeline-superseded-rows.md deleted file mode 100644 index 7c3ff752d2..0000000000 --- a/.changeset/10684-timeline-superseded-rows.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/plugin-timeline': patch ---- - -fix(plugin-timeline): an `object-timeline` block shows the rows of its current query, not an earlier answer that arrived late (objectui#10684) - -`ObjectTimeline` numbers the runs of its fetch, but only its `error` writes read -that number (objectui#10663). The rows and the loading flag were written by every -run. When the query changed while a read was in flight (a new filter, sort or -object, or a data-invalidation re-read), the earlier answer could arrive after -the current one and replace the current rows. An earlier read that settled first -also cleared the loading skeleton while the current read was still in flight. - -Only the current run writes the rows and clears the loading flag now. An answer -from a superseded run is dropped when it arrives. The current run still clears -the loading flag on every exit, including a failed read. diff --git a/.changeset/10685-drilldown-per-block.md b/.changeset/10685-drilldown-per-block.md deleted file mode 100644 index 5e1243edad..0000000000 --- a/.changeset/10685-drilldown-per-block.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-dashboard': patch ---- - -`object-data-table` refuses `drillDown.filter`, `.maxRows`, `.report` and `target: 'navigate'`, and `object-pivot` refuses `drillDown.mode` (objectui#10685) - -**Breaking for authored metadata, graded `minor` by this repo's convention (AGENTS.md: a -breaking change here is `minor`, never `major`):** `object-data-table` no longer accepts -`drillDown.filter`, `drillDown.maxRows`, `drillDown.report` or `drillDown.target: 'navigate'` -on either published face — the TypeScript `ObjectDataTableSchema.drillDown` and its zod -mirror, the door `objectui validate` / `safeValidateSchema` run — so a stored JSON table -config that parsed green before is refused by name now. Each refusal names the key and the -blocks that do read it. None of the four was ever read by this block. Migration: delete the -key; for the drill target write `'drawer'` or `'dialog'`. `enabled`, `mode`, `title` and -`columns` are accepted exactly as before. - -Its row drills to the one record it already is, so a drilled list's filter, row cap and -report had nothing to act on, and `'navigate'` was drawn as a drawer. Before this change the -table's zod mirror took the shared `DrillDownConfigSchema` and accepted all four. - -`object-pivot` is refused at the TypeScript door only. A stored JSON pivot config carrying -`mode` is still accepted and ignored at render, as it was before: neither `object-pivot` nor -`PivotTableSchema` has a zod mirror, so no validator in this repository reads the members of -a pivot's `drillDown`. `mode` never had a read site on a pivot. Every pivot click point is an -aggregated bucket (a cell, a row or column header, or a total), so the block always drills -through, and `mode`, which chooses drill-to-record for a clicked row, had nothing to choose. - -- `@object-ui/types` adds two per-block shapes beside `ObjectMetricDrillDownConfig`, both - published on the root entry `@object-ui/types` and on the `@object-ui/types/data-display` - subpath. Each tombstone's docblock names the blocks that do read the key. - - `ObjectDataTableDrillDownConfig`: `DrillDownConfig` with `filter?: never`, - `maxRows?: never` and `report?: never`, and `target?: 'drawer' | 'dialog'`. - `ObjectDataTableSchema.drillDown` is typed with it, and the `drillDown` member of its zod - mirror (`@object-ui/types/zod`) refuses the same members by name. - - `ObjectPivotDrillDownConfig`: `DrillDownConfig` with `mode?: never`. -- The shared `DrillDownConfig` keeps every member for the blocks that read them. Its `mode` - docblock now names only `object-data-table` instead of charts, pivot tables and metric - cards, none of which read it. -- `@object-ui/plugin-dashboard` types `ObjectPivotTable`'s `schema.drillDown` with - `ObjectPivotDrillDownConfig`, and the component reads its drill config through that type - instead of through `any`. `ObjectDataTable`'s prop is `ObjectDataTableSchema`, so it takes - the table's shape with it. - -TSX code now fails to compile in two places. The first is a refused member inside -`ObjectDataTableSchema.drillDown`, or inside `ObjectPivotTable`'s `schema.drillDown`. The -second is a value typed as the shared `DrillDownConfig` handed to either. Delete the key. -Runtime rendering is unchanged. - -⚠️ **Dated note, 2026-09-28 — the plain `pivot` node has a mirror now — objectui#10859.** -Later in this same release `PivotTableSchema` (the `pivot` node, not `object-pivot`) gains a -zod mirror whose `drillDown` is the shared `DrillDownConfigSchema`, so a validator does read -the members of a `pivot` node's `drillDown`, and accepts `mode` there, as `DrillDownConfig` -declares it. `object-pivot` still has no mirror, so what the paragraph above says of a stored -`object-pivot` config stands. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-09-29 — the `pivot` node refuses `drillDown` whole now — objectui#10932.** -Later in this same release `drillDown` was retired on the `pivot` node on both faces: -`PivotTableSchema.drillDown` is a `?: never` tombstone, and the `pivot` arm of the zod mirror -declares it as a `retirementTombstone()`, which refuses the key by name whatever it holds -(`invalid_type` at `drillDown`). So "a validator does read the members of a `pivot` node's -`drillDown`, and accepts `mode` there" in the 2026-09-28 note above no longer holds: the -validator refuses the whole key before reading any member, so it accepts no `mode` on a `pivot` -node. Nothing ever drilled a `pivot` node; a pivot drill is authored on `object-pivot`, whose -`drillDown` type, `ObjectPivotDrillDownConfig`, refuses `mode` at the TypeScript door, as this -entry says. `object-pivot` still has no zod mirror, so what this entry says of a stored -`object-pivot` config stands. `.changeset/10932-pivot-drilldown-retired.md` (PR objectui#10972) -states what ships; the text above is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-02 — `object-pivot` has a zod arm now — objectui#11440.** -Later in this same release `object-pivot` gained an arm in `@object-ui/types/zod`, -`ObjectPivotBlockSchema`, whose `properties.drillDown` is this entry's per-block shape: the shared -drill config with `mode` refused by name (`invalid_type` at `properties.drillDown.mode`). So "A -stored JSON pivot config carrying `mode` is still accepted" and "neither `object-pivot` nor -`PivotTableSchema` has a zod mirror, so no validator in this repository reads the members of a -pivot's `drillDown`" above, and "`object-pivot` still has no zod mirror" in the 2026-09-29 note, no -longer hold: `safeValidateSchema` and the strict face refuse that `mode`. -`.changeset/11440-arm-passing-types.md` states what ships. The rest of this entry is kept as the -reading of this change. diff --git a/.changeset/10689-grid-harvest-inputs-refetch.md b/.changeset/10689-grid-harvest-inputs-refetch.md deleted file mode 100644 index ef0cd7b012..0000000000 --- a/.changeset/10689-grid-harvest-inputs-refetch.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/plugin-grid': patch ---- - -`object-grid` re-reads its rows when an input its query reads changes: a `conditionalFormatting` rule, a row or bulk action def, or the view's `searchableFields` (objectui#10689). - -The grid puts each predicate operand of its `conditionalFormatting` rules and its row and bulk action defs into `$select`, and sends `searchableFields` as `$searchFields` beside a search term, but its load effect did not re-run when any of them changed. So a rule added to a mounted grid never had its field fetched, and the rule never matched. The effect now keys on the operand names and on the `$searchFields` it sends, both by content, so an equal value in a new array, or a change the query cannot see such as a rule's colour, does not re-read. diff --git a/.changeset/10689-list-harvest-inputs-refetch.md b/.changeset/10689-list-harvest-inputs-refetch.md deleted file mode 100644 index 0eb756bd41..0000000000 --- a/.changeset/10689-list-harvest-inputs-refetch.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/plugin-list': patch ---- - -`list-view` re-reads its rows when a `conditionalFormatting` rule, a row action def or a bulk action def adds a field its predicates read (objectui#10689). - -The list puts each predicate operand of those three into `$select`, but its fetch effect did not re-run when any of them changed. So a rule added to a mounted list never had its field fetched, and the rule never matched. The effect now keys on the operand names by content, so an equal value in a new array, or a change the query cannot see such as a rule's colour, does not re-read. diff --git a/.changeset/10690-related-list-reads-once.md b/.changeset/10690-related-list-reads-once.md deleted file mode 100644 index 3902698bba..0000000000 --- a/.changeset/10690-related-list-reads-once.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -A related list reads its rows once per mount, after its child object's definition settles, so a multi-valued relationship's first query is already the `$contains` membership form (objectui#10690, auto-adjudicated B by triage). - -`RelatedList` loaded the child object's definition in an effect of its own, and its row fetch did not wait for it. The definition decides the relationship's arity, `$expand` and `$select`, so a child whose definition moved any of them was read twice per mount. For a multi-valued relationship the first query was the bare equality that `driver-sql` refuses with `400 INVALID_FILTER` (objectui#7299). The list now reads the definition through `useSettledSchema` from `@object-ui/react`, and its row fetch waits until that read settles, the gate `object-map` and `object-data-table` use (objectui#10664). An adapter with no `getObjectSchema`, or a definition read that fails, settles with no definition, so the list still loads its rows with the equality form. On the raw-URL fallback, a multi-valued relationship is now refused before any request is sent. Switching the list to another object queries with that object's definition, never the previous one's. A failed definition read is now reported by `useSettledSchema` on `console.error`, where the list used to warn on its own. diff --git a/.changeset/10691-third-yaxis-note.md b/.changeset/10691-third-yaxis-note.md deleted file mode 100644 index aeebf3faec..0000000000 --- a/.changeset/10691-third-yaxis-note.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/plugin-charts': patch ---- - -A chart's `yAxis` entry after the second now carries a note naming it, instead of going unused -in silence (objectui#10691). - -`@objectstack/spec` declares `ChartConfig.yAxis` as an uncapped list, so a third entry -validates; a bar (`column`), line, area, combo or `horizontal-bar` chart draws at most two value -axes, one per slot. Such an entry drew no axis and no note, while its `title`, `format`, `min` -and `max` went unused and a series derived from it plotted against the right-hand axis. - -- **The note.** Every entry after the second gets a `p role="note" - data-chart-note="y-axis-undrawn"` under the plot, in the `ChartFootnote` channel the - `x-axis-position` / `y-axis-position` notes use. It names `yAxis[N]` and, when the chart - declares neither `series` nor `categories`, the axis its `field` is plotted against: the one - in the right-hand slot (the top one on `horizontal-bar`), and the entry drawn there. -- **One answer.** `placeYAxes` lists the entries it draws on no axis (`undrawn`), with the slot - a series derived from one binds to. The normalizer binds that series from the list, and the - renderer writes the note from it. The binding itself is unchanged: the right-hand slot, as - before. -- **Not narrowed.** The accepted count does not move, and the chart is not refused: the spec - owns the `yAxis` face. - -A chart with two entries or fewer, a `scatter` chart (it draws one y axis), and a family that -draws no value axis render as before. diff --git a/.changeset/10692-debug-run-routing-parity.md b/.changeset/10692-debug-run-routing-parity.md deleted file mode 100644 index e958d431d9..0000000000 --- a/.changeset/10692-debug-run-routing-parity.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the flow designer's Debug run leaves every node and gates screen fields the way the runtime does, and keeps unmodelled template tokens as written - -**Routing.** The Debug run chose a node's successors by its own rules: a decision took -its first true guard or its default and never an edge with no condition, and every other -node took all of its out-edges without reading their conditions. The runtime's -`traverseNext` has one rule for every node, so the Debug run showed paths a real run -would not take. It now leaves every node the runtime's way: - -- An out-edge with a `condition` is guarded. It is taken when the guard is true, and a - guard that is refused or fails stops the run on that node, whatever the node is. -- An `isDefault` edge with no condition is taken only when no guard was true. An edge - with both `isDefault` and a `condition` is guarded: the condition wins, as at runtime. -- Every other out-edge is always taken, a decision's included. A decision with an edge - that has no condition and a default edge now takes both when no guard is true; it used - to report "Branch has no condition." and take only the default. -- A node that takes nothing ends its branch, and the run completes, as a real run does. - It used to fail the run with "No branch matched and there is no default branch." -- A `fault` edge is never walked as an ordinary successor. What a fault edge does when a - node fails is still not modelled: the Debug run stops there. -- A decision that declares `config.conditions` picks the first entry whose `expression` - is true (CEL, as the runtime evaluates it) and takes only the out-edges labelled with - that entry's `label`. When none is true the branch is `default`, which an out-edge - labelled `default` or the `isDefault` edge claims; when no out-edge claims the branch, - every out-edge is considered and the step says so, as the runtime logs it. The Debug - run used to ignore `config.conditions`. -- An approval resumed with a decision goes through the same rules on the out-edges that - decision's label selects. -- Kept: when several guards are true the first is taken. The runtime takes every true - one; objectstack#15429 is pending. - -**Screen fields.** A screen field's `visibleWhen`, in the Studio screen preview and at the -Debug run's screen pause, was evaluated on `@object-ui/core`'s expression evaluator, which -is not CEL, and a predicate it could not evaluate left the field shown. It now goes -through the same CEL call as the edge guards, over the same variables (bare names, -`vars.*`, `record.*`): `size(tags) > 0` with an empty `tags` and `vars.n == 2` with -`n = 3` now hide the field. A predicate that cannot be evaluated (a variable that is not -set, a CEL error) hides the field, which is how the runtime reads it when a screen is -resumed; the Debug run's screen step names each field hidden that way. A `{var}` brace -is no longer rewritten to a bare name: `registerFlow` refuses it in this bare-CEL slot, -so the field is hidden. A non-string `visibleWhen` is refused the same way. A blank -`visibleWhen` still shows the field, and a blank decision-branch `expression` still reads -as `false`: that is the installed spec 17.4.0 reading. objectstack main refuses both at -`registerFlow`, so such a flow never runs there. - -⚠️ **Dated note, 2026-09-27 — the Studio no longer decides a screen field's visibility up -front — objectui#10743.** Later in this same release the screen preview and the Debug run's -screen pause hand `visibleWhen` to `ScreenView` raw, and the flow runner's own renderer -decides it live over the screen's declared fields and the values being collected — the -spec's scope, "evaluated by the CLIENT against the screen's live collected values". A -predicate that cannot be evaluated is no longer read as hidden by the Studio: one that -references a name that is not a field on this screen is an error on the screen step, and -whether the renderer shows or hides its field is `ScreenView`'s fallback (objectui#8069). -The rest of this entry is kept as the reading of this change; the objectui#10743 entry -states what the Studio now does, and that the runtime's resume door still reads the run's -variables until objectstack-ai/objectstack#20178 lands. - -**Template tokens.** A `NOW()`, `$User.*`, function or arithmetic token inside a longer -string rendered as `''`, so `'at {NOW()}'` became `'at '` where the runtime writes the -time. The Debug run still does not model these tokens; it now keeps them as written, -inside a longer string as for a whole token, and the assignment step names each one. A -call to a function the runtime does not know fails the node at runtime; the Debug run -keeps it and runs on. diff --git a/.changeset/10694-empty-columns-no-projection.md b/.changeset/10694-empty-columns-no-projection.md deleted file mode 100644 index 7ae4657c9f..0000000000 --- a/.changeset/10694-empty-columns-no-projection.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): on the object route, a view that declares no `columns` applies neither `hiddenFields` nor `fieldOrder` (objectui#10694) - -`ListViewSchema.columns` says "An empty list declares no projection, so neither -of them applies: which columns show is then left to the renderer". That text is -`@objectstack/spec` source at objectstack `origin/main` (objectstack#19598). It -is not in the released 17.4.0. - -`ObjectView` draws the object's default columns into a grid-like view that -declares none. It then applied that view's `hiddenFields` and `fieldOrder` to -those defaults, so the defaults came out with columns removed and re-sorted. -Now both keys apply only when the view, as authored, declares a non-empty -`columns`. A view with no `columns` key reads the same as `columns: []`. This is -the same gate `InterfaceListPage` already puts on a source view (objectui#10638), -so a view composes one way on both routes. - -The view config panel starts its draft from the columns on screen, so on such a -view its draft holds the drawn defaults. Those do not count as declared, after -an edit to another field or after Discard. Only `columns` the admin changes in -the panel count, and then both keys apply in the preview. - -The hide-column toggle follows the seat ruling on the card (comment -5839344270, option B): - -- On a system view that declares no `columns`, the toggle is session-only. It - hides the column for this session and writes nothing. That holds after an - edit to another field or a Discard in the view config panel. Before this - change the toggle wrote an overlay `hiddenFields`, and nothing would read that - back now. A system view's overlay cannot carry `columns` either. -- The author's remedy is to declare `columns` on the view. After that, the - toggle persists as before. -- A saved view keeps persisting as before. Its write is the whole view, with - the drawn columns included, so the reload reads a view that declares them. diff --git a/.changeset/10696-inspector-literals-read-existing-keys.md b/.changeset/10696-inspector-literals-read-existing-keys.md deleted file mode 100644 index a26b010df9..0000000000 --- a/.changeset/10696-inspector-literals-read-existing-keys.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): eight inspector words that already had a catalogue row read it, so zh-CN authors see Chinese there (objectui#10696) - -A few designer inspector props passed an English literal although the designer's -own string catalogue already carried the same English under a key with a zh row. -So a zh-CN author read English on an otherwise Chinese inspector: - -- the dashboard widget inspector's filter-binding field picker, whose search box - read `Search fields…`; it now reads `engine.form.searchFields`, the row the - dataset inspector's field pickers already read; -- the view inspector's object picker, whose search box read `Search objects…`; it - now reads `engine.inspector.dataset.searchObjects`, the row the dataset - inspector's object picker already reads; -- the field inspector's lookup `dependsOn` chips, whose remove buttons were named - `Remove NAME`; they now read `engine.form.removeNamed`; -- the field inspector's lookup and roll-up filter rows, whose value input read - `value`; it now reads `engine.inspector.condition.valuePlaceholder`, the row the - condition builder's value input reads; -- the flow edge inspector's decision-branch picker, whose custom entry read - `— Custom —` and whose unnamed branches read `Branch N`; they now read - `engine.inspector.flowEdge.branchCustom` (the row the approval-branch picker - beside it already reads) and `engine.flowRegion.branchN`; -- the flow node inspector's container › region › node breadcrumb for a node - nested in a `try_catch` or `parallel` region, whose region crumb read `Try`, - `Catch` or `Branch N`; it now reads `engine.flowRegion.try`, `.catch` and - `.branchN` through the same `displayRegionLabel` the canvas region header - already reads, so the canvas and the inspector show the same word. `Body` and - an authored branch name pass through as before. - -No catalogue row is added or changed, and the en-US text is unchanged. - -⚠️ **Dated note, 2026-09-27 — a loop body's crumb reads a row — objectui#10748.** Later in -this same release the loop-body region crumb reads its own new row, `engine.flowRegion.body`, -through the same `displayRegionLabel`, so under zh-CN it no longer passes `Body` through; an -authored branch name still does. The rest of this entry is kept as the reading of this change; the -objectui#10748 entry states what the crumb now does. diff --git a/.changeset/10701-agenda-retirement-citations.md b/.changeset/10701-agenda-retirement-citations.md deleted file mode 100644 index ee8b3eba54..0000000000 --- a/.changeset/10701-agenda-retirement-citations.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/types': patch ---- - -The `'agenda'` retirement text now points at a record a reader can open -(objectui#10701). Three zod `describe` strings — `CalendarViewSchema.view`, -`ObjectCalendarSchema.defaultView`, and the list-view `calendar` config's -`defaultView` — cited issue numbers that answer 404; they now end -`('agenda' was retired)`, because that sentence stands without a pointer. The -`CalendarViewMode`, `CalendarViewModeSchema`, `CalendarViewSchema` and -`ObjectCalendarSchema.defaultView` docblocks, and the `CalendarViewMode` row of -the schema reference, now cite the two landing commits instead: `b55a34647` -(`CalendarViewMode`) and `ed8df3e50` (`defaultView`). - -Wording only: no accepted value, type or runtime behaviour changes. The same -pointer repair in `@object-ui/plugin-calendar` (the docblock above the shared -`object-calendar` inputs) is comment-only and declares no release. diff --git a/.changeset/10712-fields-record-query-cannot-query-reset.md b/.changeset/10712-fields-record-query-cannot-query-reset.md deleted file mode 100644 index f308da9005..0000000000 --- a/.changeset/10712-fields-record-query-cannot-query-reset.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): `useRecordQuery` commits nothing once it can no longer query, and a pending debounced search never runs an older query (objectui#10712) - -`useRecordQuery`, the query kernel behind `LookupField`, the people picker and -`RecordPickerDialog`, cleared its records when `enabled` went false (a dialog -closing), but a read still in flight at that moment was the latest run: its -answer committed over the cleared state, and the loading state stayed on until -it landed. `reset()` had the same gap. When `objectName` or `dataSource` went -null nothing was cleared at all, so the previous object's records stayed and a -read in flight committed. - -Now the reset applies whenever the hook can no longer query (`enabled` false, -or no data source or object name) and on `reset()`: it supersedes any read in -flight, so that read's answer commits nothing, ends the loading state, drops a -pending debounced search and clears the query state. - -The debounced `setSearch` timer also ran the query it was armed with. A filter, -object, data-source or page-size change inside the debounce window already -re-ran the query with the typed term; the timer then ran the older query too, -and as the latest call its answer won, so the results shown were for the -previous filter. Now a pending debounced search is dropped when the query -changes. No prop, export or option changes. diff --git a/.changeset/10712-fields-record-query-latest-answer.md b/.changeset/10712-fields-record-query-latest-answer.md deleted file mode 100644 index ed28347e5a..0000000000 --- a/.changeset/10712-fields-record-query-latest-answer.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): `useRecordQuery` shows the answer to its latest query when an earlier answer lands late (objectui#10712, objectui#10713) - -`useRecordQuery`, the query kernel behind `LookupField`, the people picker and -`RecordPickerDialog`, runs a query when the page, sort or filter changes, when -the debounced search fires, and on `refetch`. A later query can start while an -earlier one is still in flight. Every answer was committed, and every query -ended the loading state when it settled. So an earlier query's answer that -landed last replaced the current results (a user who typed or filtered faster -than the server answered saw the results for an earlier term), and one that -landed first ended the loading state while the current query was still -pending. - -Now only the latest query commits its records, total or error, and only it ends -the loading state. No prop, export or option changes. diff --git a/.changeset/10712-plugin-form-line-items-superseded-run.md b/.changeset/10712-plugin-form-line-items-superseded-run.md deleted file mode 100644 index 20eaeb43ec..0000000000 --- a/.changeset/10712-plugin-form-line-items-superseded-run.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): the line-items panel commits only the answer to its current load, a save only to the parent it was issued for, and holds a same-parent reload while it has unsaved edits (objectui#10712) - -The `record:line_items` panel (`LineItemsPanel`) loads its rows again whenever -the parent record or a load input changes. When a load was superseded by a -newer one while it was in flight (the host moved the panel to another parent, -say), its answer still landed. Landing last, it replaced the current parent's -lines (since objectui#10740 the rows it brought were refused as another -parent's, so the current lines were gone either way); landing first, it ended -the loading state and drew the grid while the current load was still pending. -Now a superseded load commits nothing: not the rows, not the end of the loading -state. - -The panel's save reloaded the rows through the `load` it captured when Save was -clicked. A save that landed after the panel had moved to another parent -re-read the old parent, its lines were then committed into the new parent's -panel (and, since objectui#10740, refused there behind the placeholder), and -its failure was written over the new parent's panel. Now a save reloads only -while the parent it saved is still on screen, reading the panel's current -inputs (sort, limit, filter) rather than the ones captured at the click, and a -save whose parent has left the screen neither re-reads nor reports. - -A change to a load input other than the parent (sort, limit or filter) re-read -the rows while the author had unsaved lines, and the read's commit discarded -those lines with no signal. Now, as the default record form already does for -its own background re-read, the panel holds such a change while it has unsaved -edits for the current parent: no read is issued, the edited lines stay drawn -and saveable, and the next read that runs (the post-save reload, a parent move, -or the commit of a same-parent read that was in flight) carries the change. -While a change is held, the grid shows the rows under the previous sort, filter -or limit until the panel saves, with no signal. A change while the panel is -clean, a parent move, and a change of adapter or child object still read as -before. No prop, export or schema key changes. diff --git a/.changeset/10712-plugin-form-superseded-read-guard.md b/.changeset/10712-plugin-form-superseded-read-guard.md deleted file mode 100644 index 8504e49c77..0000000000 --- a/.changeset/10712-plugin-form-superseded-read-guard.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): a record form keeps what its current read committed when an earlier read lands late (objectui#10712) - -Every layout `ObjectForm` routes to (its default layout, `DrawerForm`, -`ModalForm`, `SplitForm`, `TabbedForm` and `WizardForm`) reads the object -schema and then the record before it draws. When the form is pointed at -another record or object while a read is in flight, that earlier read is -superseded, but two of its writes still landed: - -- The default layout and `WizardForm` wrote a superseded record read's values - over the current record's. If the previous record's answer landed last, the - form showed the previous record's values under the new record id. If it - landed first, it ended the loading state while the current read was still - pending. The other four layouts already ignored such an answer. -- All six layouts wrote a superseded object-schema read over the current one. - After an `objectName` or data-source change, the previous object's schema - could land last, and the current record was then drawn against the previous - object's fields. A superseded schema read that failed also ended the loading - state while the current one was pending, on the four layouts whose failure - branch ends it. - -Now a superseded read commits nothing: not the values, not the schema, and not -the end of the loading state. Each read's failure is still reported only by -its current run, as objectui#10682 set. No prop, export or schema key changes. diff --git a/.changeset/10715-form-arms-read-invalidation-bus.md b/.changeset/10715-form-arms-read-invalidation-bus.md deleted file mode 100644 index eab03aac43..0000000000 --- a/.changeset/10715-form-arms-read-invalidation-bus.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): every `object-form` layout re-reads its record on the data-invalidation bus (objectui#10715) - -`object-form` in edit mode re-reads its record when the data-invalidation bus -(`notifyDataChanged` from `@object-ui/react`) reports a change to that record, -its object, or everything, gated on pristine (objectui#10572). Until now only -the default layout did. With `formType` set to `drawer`, `modal`, `split`, -`tabbed` or `wizard`, the form kept the record as first read: after a change -another writer announced on the bus, `findOne` stayed at one call on each of -the five, while the default layout read again. - -The five layouts now read the bus by the default layout's rule, which is stated -once in the package: a pristine form re-reads in place, without remounting; a -form holding unsaved input keeps the typed values and the version token its -edit started from, and replays one held re-read once the edit is saved or the -form returns to pristine; a change to another object, or to another record of -the object, reads nothing; a create form reads nothing. The re-read runs -through each layout's own record read, so a re-read a later one has superseded -commits nothing (objectui#10712). - -Two layouts have state of their own. A wizard also holds the re-read while a -step submitted with Next carries an answer not yet saved, so a re-read never -discards it, and a re-read never moves the wizard off its current step. A -closed drawer or modal reads while closed and opens on the fresh values, with -no further read on open. No prop, export or schema key changes. diff --git a/.changeset/10719-retire-phase35-validation-types.md b/.changeset/10719-retire-phase35-validation-types.md deleted file mode 100644 index e77ed18100..0000000000 --- a/.changeset/10719-retire-phase35-validation-types.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/types': minor ---- - -⚠️ **BREAKING (scored `minor` per this repository's version-alignment -convention) — `@object-ui/types` no longer exports the eight "Phase 3.5" -validation types (objectui#10719).** - -Removed from the package root: `AdvancedValidationSchema`, -`AdvancedValidationRule`, `ValidationRuleType`, `ValidationFunction`, -`AsyncValidationFunction`, `ValidationContext`, `AdvancedValidationResult` and -`AdvancedValidationError`. - -They were the type half of `@object-ui/core`'s `ValidationEngine`, a client-side -field-rule engine with a snake_case rule vocabulary of its own. That engine was -retired under ADR-0049 enforce-or-remove (maintainer ruling A on objectui#7659), -and the same reason covers its types: nothing in this repository or in the -ObjectStack framework reads them. They are removed with no deprecation window. - -**Replacement:** client-side field validation is declared on the field. A form -field's `validation` key is typed `FieldValidationRules`, whose `validate` -member takes a custom check, and `buildValidationRules(field)` from -`@object-ui/fields` compiles field metadata (`required`, length and value -bounds, `pattern`, and the checks a field's type implies) into react-hook-form -rules. There is no one-to-one port of an `AdvancedValidationSchema` object: a -host that typed its own rules with these names declares those constraints on -the field metadata instead, or keeps its own types. - -Not affected: `FieldValidationRules`, `FieldValidationFunction`, the -object-level rule union `ObjectValidationRule` and its variants, and -`DesignerValidationRule` stay exported. - -⚠️ Out-of-repository consumers are NOT MEASURED. This package is published, and -the zero-reader reading behind the ruling covers this repository and the -ObjectStack framework only; a host application that imports any of the eight -names stops compiling on upgrade. - -⚠️ **Dated note, 2026-10-02 — `DesignerValidationRule` is retired in this release too — objectui#11434.** -Later in this same release objectui#11434 retired `DesignerFieldDefinition.validationRules` on both faces and removed its element type `DesignerValidationRule` from the exports, so the sentence above that lists it among the names that stay exported no longer holds for it. `FieldValidationRules`, `FieldValidationFunction` and `ObjectValidationRule` still stay exported. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10720-grid-columns-docs.md b/.changeset/10720-grid-columns-docs.md deleted file mode 100644 index 37785253e9..0000000000 --- a/.changeset/10720-grid-columns-docs.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@object-ui/layout': patch ---- - -`ResponsiveGrid`'s component docblock no longer attributes its column map to the -spec's retired `BreakpointColumnMapSchema` (objectstack#11027 retired it; objectui#7580 -re-homed the six-key shape as this package's own `BreakpointColumnMap`). The docblock -now names that local type. Text only: no member is added and no behaviour changes. diff --git a/.changeset/10721-scatter-yaxis-note.md b/.changeset/10721-scatter-yaxis-note.md deleted file mode 100644 index 09876aba06..0000000000 --- a/.changeset/10721-scatter-yaxis-note.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/plugin-charts': patch ---- - -A `scatter` chart's `yAxis` entry after the first now carries a note naming it, instead of -going unused in silence (objectui#10721). - -`@objectstack/spec` declares `ChartConfig.yAxis` as an uncapped list, so a second entry -validates; a `scatter` chart draws one value axis, the first entry's. objectui#10691 gave the -bar (`column`), line, area, combo and `horizontal-bar` charts a note for each entry after the -second, and left `scatter` as it was: with `series` authored, a second or later entry drew no -axis and no note, and its `title`, `format`, `min` and `max` went unused. - -- **The note.** Every entry after the first gets a `p role="note" - data-chart-note="y-axis-undrawn"` under the plot, in the `ChartFootnote` channel - objectui#10691's note uses. It names `yAxis[N]` and the one axis the chart draws, `yAxis[0]`. - It says nothing about a series derived from the entry: with neither `series` nor - `categories`, two entries that carry a `field` are refused as before - (`data-chart-error="scatter-multi-series"`). -- **One answer.** The scatter slice moved into `placeYAxes`, which now takes the chart family, - so the renderer and the normalizer place the same entries. A series the normalizer derives - from an entry after the first now binds to the slot the one axis is drawn in, where it used to - bind as if the chart drew two axes. A scatter reads no series binding and measures its one - series against that axis, so what it draws does not move. -- **Not narrowed.** The accepted count does not move, and the chart is not refused: the spec - owns the `yAxis` face. - -A `scatter` chart with one entry, and every other family, render as before. diff --git a/.changeset/10722-date-fns-display-locale.md b/.changeset/10722-date-fns-display-locale.md deleted file mode 100644 index dfdfc0aae3..0000000000 --- a/.changeset/10722-date-fns-display-locale.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/components': patch ---- - -fix(components): the date pickers and every `Calendar` read the display locale (objectui#10722) - -`useDisplayLocale()` is what every date renderer formats with, and the `Intl` -faces have read it since objectui#10442 and objectui#10668. The date-fns and -react-day-picker faces never did. They take a date-fns `Locale` object, not the -BCP-47 tag the hook returns, and with none they answered in date-fns `enUS` under -every display locale and every UI language: under a `de-CH` display locale the -form date picker read `March 4th, 2020`, and its calendar `March 2020` over -`Su Mo Tu …`. - -Now the form date picker (`type: 'date-picker'`), the `DatePicker` component and -every `Calendar` mounted without a `locale` (the `ui:calendar` renderer, both -pickers' popovers, and the ones `CalendarView` and `DashboardFilterBar` mount) -read the display locale: `4. März 2020`, and `März 2020` over `Mo Di Mi …`. - -- **The week start follows the locale.** A calendar under a display locale whose - week begins on Monday (`de`, `fr`, `en-GB`, …) now starts on Monday. That is - the display locale's own reading; an `en-US` session still starts on Sunday. -- **`format` keeps its meaning.** `DatePickerSchema.format` is still a date-fns - pattern and is still honoured as written. Its textual tokens (`PPP`, `MMMM`, - `EEEE`, …) are now spelled in the display locale; a numeric pattern such as - `yyyy-MM-dd` reads as before. -- **A `locale` a caller passes to `Calendar` still wins.** -- **English sessions read exactly as before.** `en` and `en-US` resolve to the - same `enUS` every face read until now. - -The tag is resolved against date-fns's own locale codes: as given, then with the -region and script CLDR's likely subtags give it, then its bare language (`de-CH` -reads `de`, `zh` reads `zh-CN`). A tag date-fns has no locale for reads `enUS`. -Each locale is loaded on demand, one `import()` per locale, so no locale is in -this package's bundle and an app fetches only the one its session reads. The -first paint of a session whose locale has not loaded yet reads `enUS`, then -re-renders once the locale arrives; later mounts read it straight away. diff --git a/.changeset/10726-wizard-swap-loading.md b/.changeset/10726-wizard-swap-loading.md deleted file mode 100644 index eb98ee95aa..0000000000 --- a/.changeset/10726-wizard-swap-loading.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): a wizard goes back to its loading state when it is pointed at another record (objectui#10726) - -When a mounted `WizardForm` in edit mode was given another `recordId`, it kept -drawing the previous record while the new record was read. The previous -record's values stayed on the current step and could be edited, so anything -typed in that window was typed into the previous record's values while the form -already stood for the new record. - -The wizard now does what `DrawerForm`, `ModalForm`, `SplitForm` and -`TabbedForm` already do: a change of record takes it back to the loading state -until the new record's answer lands. Only a change of record does this. A -wizard whose record read runs again for the same record, for example because -the caller rebuilt `initialValues`, stays on screen. A create wizard never goes -back to loading. - -The current step, the completed-step marks and the step error marks carry over -a record change, as before. No step draws a value of the previous record once -the new record lands, since every step reads its values from the new record's -answer. No prop, export or schema key changes. diff --git a/.changeset/10727-context-menu-sortable.md b/.changeset/10727-context-menu-sortable.md deleted file mode 100644 index cf6adb7540..0000000000 --- a/.changeset/10727-context-menu-sortable.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/components': patch ---- - -`data-table`'s header context menu no longer offers Sort ascending / Sort descending on a column declared `sortable: false` (objectui#10727). - -The header of such a column already refused a sort: no pointer cursor, no click, no -indicator. Its context menu did not ask the column, only whether the table sorts at all, so -the same column could still be sorted from the menu. The menu now offers its sort entries -exactly where the header sorts, through the same check over the same column, so the two -controls cannot disagree. A `masked` column stays without sort entries, as before. - -This reaches every host that marks a column unsortable. `object-grid` does so for a column -the server cannot honestly order by, a relational column or an unmaterialized `formula` -column, and its menu turned that withheld sort into a refetch naming the field. On a backend -that serves no per-column sortability, a platform that answers `400 INVALID_SORT` refused -the formula column's refetch and the grid showed the error in place of its rows. Sortable -columns keep both menu entries, with client and manual sorting alike. diff --git a/.changeset/10728-plugin-detail-related-list-masked-filter-sort.md b/.changeset/10728-plugin-detail-related-list-masked-filter-sort.md deleted file mode 100644 index 93b0ace6e3..0000000000 --- a/.changeset/10728-plugin-detail-related-list-masked-filter-sort.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -'@object-ui/plugin-detail': patch ---- - -`RelatedList`'s own filter box and sort no longer read a masked column's raw value (objectui#10728). - -The related list draws a `password` / `secret` cell as `••••••` and, since objectui#10657, -flags the column `masked` on the table it renders. The table obeys the flag in its own -search and sort, but the list has a filter box and a sort of its own, and both still read -the raw value: - -- The opt-in filter box (`filterable`) matched the term against every field of a row, so - typing a substring of the credential kept its row. -- The sort buttons of a `list` card (`sortable`) were offered on every column, and sorted - the rows by a masked one. - -Both now read the same `masked` flag the list puts on its columns: - -- The filter box matches the term against the columns the list shows that are not masked. -- A masked column gets no sort button. A sort by it is refused, including one the embedded - table asks for (in a server-paged list that sort would be sent to the server as - `$orderby`). In a list that sorts in the browser (one that is not server-paged), a sort - set on a column before it was flagged also stops ordering the rows. -- While the object definition is still loading, or after its read failed, every column is - flagged, so in that window the filter box keeps no row and no sort button is offered. - -Narrowing, stated: the filter box used to match any field a row carries. It now matches -only the columns the list shows, so a term that matches only a field no column shows no -longer keeps a row. This is the rule the table's own search already follows. - -Columns without the flag filter and sort exactly as before. - -Not covered: - -- An authored `sort` (the list's `defaultSort`) that names a masked field is still sent to - the server as `$orderby` on a server-paged list. -- On a server-paged list, a sort the user set on a column before that column was flagged - is still sent to the server as `$orderby` with each page the list fetches, until the - user sorts by another column. The column is flagged after the sort only when the - `columns` or the object of a list already on screen change (a direct React consumer of - `RelatedList`); `record:related_list` sets both once per block, so it does not reach - this. - -The pending objectui#10657 related-list changeset lists the filter box and the `list` -card's sort buttons under "Also not covered". That entry no longer holds once this change -ships with it. - -This is defence in depth. The real guard is still the server: ObjectStack's read mask -replaces `secret` and `password` values with its mask before they reach the browser. diff --git a/.changeset/10731-console-map-mock-bare-specifier.md b/.changeset/10731-console-map-mock-bare-specifier.md deleted file mode 100644 index 1c401dec54..0000000000 --- a/.changeset/10731-console-map-mock-bare-specifier.md +++ /dev/null @@ -1,10 +0,0 @@ ---- ---- - -Test and devDependency only, no package released: `apps/console`'s filter-context-token sweep -(`filterContextTokensSweep-10666.test.tsx`) mocks `react-map-gl/maplibre` by its bare specifier, -and `@object-ui/console` declares `react-map-gl` as a devDependency at `plugin-map`'s range so -that specifier resolves from the app to the same store instance `plugin-map` imports. The previous -mock named a relative path into `packages/plugin-map/node_modules`, which exists only after -install, so the pre-install `Inert vi.mock Specifier Check` read it as resolving to no file and -`main` went red (objectui#10731). Nothing under `dist/` or `plugin.js` changes. diff --git a/.changeset/10735-html-tier-manifest.md b/.changeset/10735-html-tier-manifest.md deleted file mode 100644 index 28dc8acd9f..0000000000 --- a/.changeset/10735-html-tier-manifest.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/sdui-parser': minor -'@object-ui/components': minor ---- - -feat(core,sdui-parser): the published manifest declares the html tier's registered intrinsic elements, marked `tier: 'html'` — `div` stays out - -A `kind:'html'` page may author the everyday HTML tags its renderer registers — -the flow/inline set of `html-elements.tsx` (h1–h6, p, a, lists, emphasis, -figure/img/hr/br, time, address, cite, q), `span`, `table`, `label` and the seven -sectioning tags — and the console has rendered such pages all along. The -published `sdui.manifest.json` never said so: it was the curated `PUBLIC_BLOCKS` -vocabulary alone, so the objectstack CLI gate, which whitelists an html page's -tags from that manifest, refused every plain HTML tag as `forbidden-tag` on -pages the renderer accepts (200 ledgered findings over the three shipped showcase -pages). The maintainer ruled A on objectstack#20112: the producer declares the -set, exactly as the registry declares it, and `div` stays deprecated. - -**What moves for a consumer.** `ComponentRegistry.getPublicConfigs()` — the -read both manifest producers serialise — now returns the curated tier AND the -html tier's intrinsic elements, the latter from the new `HTML_TIER_INTRINSICS` -roster (`@object-ui/core`) and each stamped `tier: 'html'` in the projection. -`manifestFromConfigs` carries that one value into a new optional -`ManifestComponent.tier` (`@object-ui/sdui-parser`), so the regenerated -`sdui.manifest.json` grows by the roster (47 entries, each with its registered -`inputs` and its child slot declared exactly where the registration renders a -child list — the void tags `img` / `hr` / `br` declare none) and -`sdui-intrinsics.d.ts` types them. A reader that whitelists tags by key — the -objectstack gate — needs no change and accepts the tags. A reader that means the -CURATED vocabulary filters on the stamp: `generateBlockList` now sections the -html tier under its own count, and the `kind:'react'` JSX scope skips stamped -entries (`@object-ui/components`, `react-page.tsx`), so no `P` / `A` / `Img` -wrapper is injected into react pages — on that tier a lowercase `

` is React's -own element. - -**What does not move.** `PUBLIC_BLOCKS` is unchanged and the two rosters are -pinned disjoint; every curated manifest entry serialises byte-identically -(`tier` is written as exactly `'html'` or omitted). `div` is not declared: the -gate keeps refusing `

` on an html page, and `box` remains the JSON -surface's replacement. `code` is not declared either — the bare `code` key is -the `field:code` widget's namespace fallback, not an element renderer — nor is -`kbd`; both are recorded, with reasons, in the console's exclusion ledger. -No registration changes; `html-elements.tsx` is untouched. - -⚠️ **Dated note, 2026-09-27 — `code` has since joined the roster — objectui#10756.** At this change the roster held 47 tags and `code` was undeclared because the bare key was the `field:code` widget's fallback; `html-elements.tsx` now registers `code` as a sanitised passthrough (`ui:code`), `@object-ui/fields` registers the widget with `skipFallback` so it keeps only `field:code`, and the manifest declares `code` with `tier: 'html'` — 48 html-tier entries. `div` and `kbd` are still out. The rest of this entry is kept as the reading of this change. - -The manifest the framework ships regenerates from objectui's built tree at the -pin (its `gen-sdui-manifest-node.mjs`); its lockstep copy of `manifestFromConfigs` -must take this port for the stamp to reach that file — until then the tags are -declared there without the marker, which the gate treats identically. diff --git a/.changeset/10740-line-items-held-for-another-parent.md b/.changeset/10740-line-items-held-for-another-parent.md deleted file mode 100644 index 488473bd69..0000000000 --- a/.changeset/10740-line-items-held-for-another-parent.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): the line-items panel neither draws nor saves the lines it holds for another parent record (objectui#10740) - -The `record:line_items` panel (`LineItemsPanel`) holds one set of rows, replaced -when a load commits. When the host moved the panel to another parent record -without a remount and that parent's load failed, the previous parent's lines -stayed on screen, edits included, drawn editable with Save enabled; Save then -wrote them under the new parent's id, moving another record's lines to it. A load -that declined for the new parent (a refused filter) drew the decline's own notice -but left the same Save enabled over the same held rows. - -Now the panel records which parent its held rows belong to, wherever the rows are -written: a load's commit, or an edit made before any load settled. While that -parent is not the current one, no held line is drawn (after a failed load a -placeholder stands where the grid would be, under the failure's banner; after a -refused-filter decline that filter's own notice stands there, as before; after a -lost-adapter decline the placeholder stands alone), the Save button is off, and a -save sends nothing. A load for the current parent that commits -takes the grid back. Unchanged: a load for the new parent that succeeds replaces -the rows as before, and a re-load of the same parent that fails keeps the -author's unsaved edits drawn, editable and saveable under that parent. diff --git a/.changeset/10743-studio-screen-visiblewhen-live.md b/.changeset/10743-studio-screen-visiblewhen-live.md deleted file mode 100644 index f780f434e9..0000000000 --- a/.changeset/10743-studio-screen-visiblewhen-live.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the Studio screen preview and the Debug run decide a screen field's `visibleWhen` live, through the flow runner's own renderer, over the screen's declared fields - -**What was wrong.** The Studio's screen preview (`ScreenPreview`) and the Debug run's screen -pause judged each field's `visibleWhen` once, up front, against the run's variables — the -reading the runtime's resume door takes when a screen is resumed — dropped every field they -judged hidden and stripped the predicate from the ones they kept. A predicate over a sibling -screen field, the only shape any shipped producer writes (`createOpportunity == true` in the -flows guide, `discount > 0` in the console sample), names a value the run does not hold at -the pause, so the field was judged hidden and stayed hidden however the author ticked or -typed: the preview's checkbox changed state and nothing appeared. Where the flow's own -variable of the same name was declared `false`, as the guide recommends, the field was judged -`false` and frozen just the same. Measured through the real `FlowSimulator` and -`ScreenPreview` on both sample shapes, with a no-predicate field as the control. - -**What changed.** The spec declares the contract: `ScreenFieldSpec.visibleWhen` is "bare CEL -over the screen's own field names", "evaluated by the CLIENT against the screen's live -collected values — not by the server". The Studio now follows it with one client evaluator: - -- `buildScreenSpec` keeps every authored field and carries its `visibleWhen` raw, as the - runtime `screen` executor sends it to the client. `ScreenView` — the renderer the flow - runner uses — decides it live over the screen's declared fields and the values being - collected, so ticking the sibling checkbox or typing a discount above zero reveals the - field in the preview exactly as it does for the end user, and the "N fields hidden by - their visible when condition" hint follows the values. -- The Studio no longer has an evaluator of its own for this key: `isFieldVisibleWhen`, - `fieldVisibility` and the simulator's `evalVisibleWhen` are removed. `buildScreenSpec` - takes no `variables`; `hiddenFieldCount` takes the built spec and the collected values. -- The Debug run's screen step judges SCOPE, never value: `unevaluableVisibleWhen` names, as - an error on the paused step, a field whose predicate references an identifier that is not - a field declared on this screen (a run variable such as `needsApproval == true`, the - runtime's `vars.*` root), does not parse as CEL (a `{var}` brace), or is a shape - `registerFlow` refuses — with the nearest declared field where one is close. A predicate - over a sibling field (`discount > 0`, `record.discount > 0`) is not reported; it used to - be named as "hidden because it could not be evaluated". A comprehension's iteration - variable (`["a","b"].exists(t, t == note)`) is bound, not a root, and is not reported. -- The Problems panel (`flow-expr-problems.ts`) judges the `screen` node's `fields[].visibleWhen` - column by that same rule instead of the flow scope: it used to warn that `discount` "is not - a reference in scope at this step" on the sibling-field shape and stay silent on a run - variable; it now warns on the run variable (`needsApproval` is not a field on this screen) - and is silent on the sibling. Every other expression slot keeps the flow scope. -- The screen field inspector's `visibleWhen` placeholder is a sibling-field example - (`createOpportunity == true`); it used to read `stage == "review"`, a run-variable shape. -- `ScreenView` exports `screenPredicateScope`, unchanged, so the Studio reads the bare roots a - predicate may name off the renderer's own scope; only the `record` namespace, which the - renderer binds inside `evalFieldPredicate`, is restated by name. - -**What did not change.** Whether the renderer shows or hides a predicate it cannot evaluate -is `ScreenView`'s fallback and objectui#8069's open question; the Studio now renders through -that fallback and rules no direction of its own. The runner (`ScreenView`, `FlowRunner`) has -no behaviour change. - -**The server side.** The runtime's resume door (`refuseInvalidScreenInput` in -`@objectstack/service-automation`) still evaluates `visibleWhen` over the run's variables -with the submitted values layered on top; narrowing it to the declared scope, and refusing -an undeclared identifier at `registerFlow` and `objectstack validate`, is -objectstack-ai/objectstack#20178 and is not on objectstack main at this change. Until it -lands, a predicate over a run variable is an error in the Studio and shown by the runner, -while the server enforces its `required` only when the run's variables make the predicate -true, and waives it when they make it false or leave it unevaluable. - -**Still on the flow scope.** The inline inspector's `visibleWhen` cell (`FlowObjectListField`) -still offers the flow scope picker and its inline note still reads the flow scope, so on the -sibling-field shape it says "`discount` is not a reference in scope at this step" while the -Problems panel and the Debug run are silent, and says nothing on a run variable the other two -report; aligning that cell is a follow-up outside this change. - -⚠️ **Dated note, 2026-09-27 — the inline `visibleWhen` cell reads the screen's declared fields -— objectui#10772.** Later in this same release the inline inspector cell for a `screen` node's -`fields[].visibleWhen` column follows the same rule: its picker offers the roots -`screenPredicateRoots` admits (the screen's declared fields and `record`), and its inline note -is `screenVisibleWhenScopeError`'s, so it is silent on the sibling-field shape and names a run -variable (`needsApproval` is not a field on this screen) as the Problems panel and the Debug -run do. The paragraph above is kept as the reading of this change; the objectui#10772 entry -states what the cell now does. diff --git a/.changeset/10746-joined-report-clears-binding.md b/.changeset/10746-joined-report-clears-binding.md deleted file mode 100644 index 77793c7ffa..0000000000 --- a/.changeset/10746-joined-report-clears-binding.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): switching a report to `joined` clears the container binding it hides (objectui#10746) - -Studio's report inspector committed `{ type: 'joined' }` alone when the type picker moved -to `joined`, and in the same render hid its dataset / values / rows / columns / chart -controls, while the spec's own `reportForm` hid the whole "Dataset binding" section -(`order` included) through `visibleWhen: "data.type != 'joined'"`. A report that was -bound first and switched second kept every one of those keys invisibly. `ReportSchema`'s -joined arm refuses a container `dataset` / `rows` / `columns` / `values` (PR -objectstack#20160: "a `joined` report selects per block — move `KEY` onto `blocks[]`, or delete it") -and has always refused a container `order`, so the save was refused at a path no control -on the Properties tab could reach; only the JSON source tab could delete the key. - -The type picker now drops `dataset`, `values`, `rows`, `columns`, `chart` and `order` -in the same patch that commits `type: 'joined'` — an `undefined`-valued key, the same -spelling the inspector's own chart panel and its sibling inspectors already clear with, -which the host's shallow spread turns into an own key holding `undefined` and -`JSON.stringify` omits on the wire. Only keys the draft actually carries are named, so an -unbound report's switch stays the one-key patch it always was. `runtimeFilter` and -`drilldown` are kept: the joined branch reads both. Switching between two non-joined -types keeps the binding; switching away from `joined` restores nothing — the author -re-binds. `blocks` is never touched. The clear holds for the patch and for the save that -follows it. At this change the metadata-admin editor rebuilds its draft as the served draft -spread over `layered.effective` (on load, after each save and after publish), and -`effective` is the published layer, so a report whose PUBLISHED version was bound gets those -keys back in the draft after the first draft save until it is published, and a report already -saved `joined` with stale keys is not repaired on load. Both are the host's -draft-over-baseline merge, objectui#10765. - -⚠️ **Dated note, 2026-09-27 — that merge has since been removed — objectui#10765.** Later in -this same release the metadata-admin editor takes a served draft as-is instead of spreading -it over the published layer, so the clear holds across the refresh after the save and through -publish. A report already saved `joined` with stale keys is still not repaired on load; the -author deletes them from the JSON tab. The rest of this entry is kept as the reading of this -change; the objectui#10765 entry states what the editors now do. diff --git a/.changeset/10747-calendar-locale-tag.md b/.changeset/10747-calendar-locale-tag.md deleted file mode 100644 index 8aef3d6ba0..0000000000 --- a/.changeset/10747-calendar-locale-tag.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/components': minor ---- - -feat(components): `Calendar` takes a `localeTag`, a BCP-47 tag it reads in place of the display locale (objectui#10747) - -A `Calendar` with no `locale` reads the session's display locale -(objectui#10722). A caller that formats its other dates with a tag of its own -had no way to hand the calendar that tag: `locale` takes a date-fns `Locale` -object, which a caller outside this package can only build with date-fns and a -resolver of its own. - -`localeTag` takes the tag and resolves it through the same chain as the display -locale: `de-CH` reads date-fns `de` (caption `März 2020` over `Mo Di Mi …`), and -a tag date-fns has no locale for, or a malformed one, reads `enUS`. - -- **An explicit tag wins over the display locale.** With no `localeTag`, a - `Calendar` reads the display locale exactly as before. -- **A date-fns `locale` object still wins over both.** -- **No new export.** The input is the whole addition; the resolver stays - private to this package. - -`minor`, not `patch`: this adds an input to a published component, which is new -API surface, not a fix to an existing one. diff --git a/.changeset/10747-calendar-popover-locale.md b/.changeset/10747-calendar-popover-locale.md deleted file mode 100644 index 7ac6eeeb58..0000000000 --- a/.changeset/10747-calendar-popover-locale.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch ---- - -fix(plugin-calendar): `CalendarView`'s header date popover reads the same locale as its grids (objectui#10747) - -`CalendarView` formats its header and its month, week and day grids with one -locale: an explicit `locale` (an `object-calendar` node's authored `locale` -arrives this way), else the display locale. The header's date popover mounted -`Calendar` with no locale, so it read the display locale even when the grids -read another one. Under an `en-US` display locale with `locale: 'de-CH'`, the -header read `März 2020` and the popover under it read `March 2020` over -`Su Mo Tu …`. - -The popover now passes its grids' locale to `Calendar` as `localeTag`, so both -faces read `März 2020`, and the popover's week starts on Monday. With no -`locale`, both read the display locale, as before. This package takes no -date-fns dependency: the tag is resolved inside `@object-ui/components`. diff --git a/.changeset/10748-inspector-words-gain-zh-rows.md b/.changeset/10748-inspector-words-gain-zh-rows.md deleted file mode 100644 index 528840640c..0000000000 --- a/.changeset/10748-inspector-words-gain-zh-rows.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): designer inspector words that had no catalogue row gain en-US and zh-CN rows, so zh-CN authors see Chinese there (objectui#10748) - -objectui#10696 moved the inspector literals whose English already had a row. The -rest had none, so a zh-CN author still read English on an otherwise Chinese -inspector. Each now reads an `engine.*` row — a new one, except four -lookup-operator words that reuse the condition builder's rows — and each en row -carries the English the literal did, so en-US renders the same words: - -- the dashboard widget inspector's type select (`KPI Metric` … `Pivot Table`, - `engine.inspector.widget.type.*`; the stored `type` does not move), its two - empty-state messages, and the `Widget N` name of an untitled widget, which the - dashboard inspector's widget list reads too; -- the field inspector's lookup and roll-up filter operators: `= equals`, - `≠ not equals`, `> greater than` and `< less than` read the condition - builder's own `engine.inspector.condition.op.*` rows with the symbol kept - outside the word, and `≥ at least`, `≤ at most`, `contains`, `in (any of)` - and `not in` read new rows of that family; -- the flow edge inspector's decision-branch picker, whose catch-all branch ended - in ` · default`; -- the flow node inspector's nested-node breadcrumb, whose accessible name read - `nested node location` and whose loop-body crumb read `Body` (now - `engine.flowRegion.body`, through the same `displayRegionLabel` that already - translates `Try` / `Catch` / `Branch N`), and its Advanced (JSON) box, which - refused a non-object with `Must be a JSON object`; -- the variable data-picker: its button, search box and empty text, its section - headings (`Flow variables`, `Upstream outputs`, `Loop item`, `Trigger record`, - and the approval picker's `Current record (live at node entry)` and - `Trigger snapshot (at submit)`), and the muted detail beside a reference - (`variable · TYPE`, `trigger record · OBJECT`, `record values before the - change`, `prior LABEL`, `prior value`, `pre-update row`); -- the client-side expression shape errors under an expression field, a decision - branch and an edge condition (a template brace inside CEL, a non-CEL dialect, - unbalanced parentheses or brackets). The code inside each message reads the - same in every locale. - -References, type names, object names and field labels inside those words are -code or author data and are unchanged. diff --git a/.changeset/10756-html-tier-code-element.md b/.changeset/10756-html-tier-code-element.md deleted file mode 100644 index 4d324e7762..0000000000 --- a/.changeset/10756-html-tier-code-element.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -'@object-ui/components': minor -'@object-ui/core': minor -'@object-ui/types': minor -'@object-ui/fields': minor -'@object-ui/cli': minor ---- - -feat(core,components): the html tier registers and declares `code` — `inline` on a `kind:'html'` page renders its text instead of the `field:code` editor - -`renderers/basic/html-elements.tsx` called `code` "registered elsewhere", but the -only bare `code` registration was the `field:code` widget's namespace fallback: a -code editor reading `value`, with no declared inputs and no child slot. The -console's html-tier compile whitelists `ComponentRegistry.getKnownTypes()`, so -`inline` on an html page compiled, resolved to the editor, and the -authored text was dropped — while `pre`, `strong` and `em` rendered their -children through the passthrough, and `span` through its own renderer. The -published manifest (objectui#10735) left `code` undeclared for the same reason, -so the objectstack gate refused the tag the renderer mis-drew. - -**What moves for a consumer.** - -- `@object-ui/components` — `code` joins the `TAGS` loop of `html-elements.tsx`: - registered `ui:code`, sanitised like its siblings, declaring `className` and the - `children` slot. An html author's `` now renders a real `code` element with - its text. -- `@object-ui/fields` — **BREAKING (authoring): the bare `code` key no longer - resolves to the code-editor widget.** `code` joins `FIELD_TYPES_SKIP_FALLBACK`, - so the widget is registered `field:code` only. A node authored as bare - `{ "type": "code", "value": … }` now renders the html tier's `code` element (it - draws `children`, not `value`); in a registry without `@object-ui/components` - the bare key resolves to nothing. Migration: `{ "type": "code" }` becomes - `{ "type": "field:code" }`. Form fields of type `code` resolve through the - `field:` namespace and render the same editor as before. Released as `minor` - under objectui's version policy; a breaking change never declares `major`. -- `@object-ui/core` — `code` joins `HTML_TIER_INTRINSICS`, so `getPublicConfigs()` - projects it stamped `tier: 'html'` and the regenerated `sdui.manifest.json` - grows by one entry (the html tier declares 48 tags where objectui#10735 - declared 47); `div` and `kbd` stay undeclared. -- `@object-ui/types` — `HtmlElementSchema` (zod and TS) names `code`, keeping the - JSON-surface declaration equal to the registration, as the objectui#8499 pin - requires — so `AnyComponentSchema` (and `objectui validate`) now accepts - `{ "type": "code" }`, which it refused before. -- `@object-ui/cli` — `packages/cli/src/utils/known-schema-types.ts` regenerates - from the registrations and gains `ui:code`, so `objectui validate` and - `objectui check` recognise it as a known schema type (the objectui#9533 and - objectui#6416 precedent). - -The `kind:'react'` scope skips stamped entries, so no `Code` wrapper is injected -on react pages. The framework's tracked manifest regenerates at its next -`.objectui-sha` bump (objectstack#20112's port list); nothing there changes here. diff --git a/.changeset/10757-div-deprecated-html-tier.md b/.changeset/10757-div-deprecated-html-tier.md deleted file mode 100644 index d7be6ec5a5..0000000000 --- a/.changeset/10757-div-deprecated-html-tier.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -'@object-ui/components': minor -'@object-ui/core': patch -'@object-ui/sdui-parser': patch ---- - -feat(components): `div` is deprecated on the html tier too — a `kind:'html'` page that authors `
` is refused at compile time, and the error names `box` - -Executes the maintainer's ruling A on objectstack#20112 ("`div` stays -deprecated") in the renderer. Until now the published manifest left `div` out of -the html tier, so `os validate` refused a `
` page as `forbidden-tag`, while -the console compiled and rendered the same page. `div`'s registration declared -the deprecation for the JSON surface only, and its renderer exempted nodes the -html parser emitted (objectui#4000). - -**What moves for a consumer.** - -- **BREAKING (authoring): a `kind:'html'` (or legacy `kind:'jsx'`) page that - authors `
` or `` no longer renders.** The html compile fails, and - like every compile error this fails the whole page: the console shows the - "HTML page failed to compile" panel. Each refusal is the parser's - `forbidden-tag` sentence, followed by the declared replacement guidance, which - names `box`. Migration: retype `
` to ``. `box` renders the same - element with the same `className` and no layout of its own. -- `div`'s registration now declares `deprecated.surfaces: ['json', 'html']`, so - `ComponentRegistry.deprecationFor('div', 'html')` answers the declaration - (with the unchanged `replacement`) instead of `undefined`. The html compile - derives what it refuses from `deprecationFor(type, 'html')`, the registration's - declaration, rather than from a list of tag names. -- The `div` renderer no longer exempts nodes carrying html-tier provenance, and - its dev-build notice now says it applies to JSON-authored nodes and html pages - alike. The migration bullets are unchanged. -- `span` is unchanged: it is still deprecated on the JSON surface only, and it - still compiles on html pages. - -Semver: `minor`, not `major`, per this repository's version-alignment rule. The -breaking semantics are stated above. - -**Published declaration text (prose only, no behaviour change).** - -- `@object-ui/core`: the emitted `dist/registry/Registry.d.ts` carries the - rewritten `ComponentDeprecation` and `deprecationFor` docblocks, where `span` is - now the worked example of a json-only deprecation and `div` is stated to name - both surfaces. `dist/registry/html-tier-intrinsics.d.ts` carries the rewritten - `HTML_TIER_INTRINSICS` docblock: its `div` bullet and the sentence describing the - console's html-tier whitelist. -- `@object-ui/sdui-parser`: the emitted `dist/provenance.d.ts` carries the - rewritten file-header sentence, where `span` is now the example of a tag that - stays html-tier vocabulary. diff --git a/.changeset/10758-named-view-protocol-members.md b/.changeset/10758-named-view-protocol-members.md deleted file mode 100644 index 17189da182..0000000000 --- a/.changeset/10758-named-view-protocol-members.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -`ObjectView`'s host delegation reads the rest of a named view's protocol members off the named view (objectui#10758). - -A host that composes `ObjectView` with both `listViews` and its own `renderListView` receives a `list-view` node for the active view. Twenty-three members the protocol declares on a named view (`ObjectListViewSchema`) never came off the named view on that node: the delegation took them from the host `views` entry or the object-view node only, so a named view authoring one of them was accepted and rendered with some other value. This is bucket ① of the objectui#7924 ruling. - -Each of them is now read off the active named view first, then the host `views` entry, then the node where that rung already read it: - -- list chrome: `description`, `compactToolbar`, `allowPrinting`, `showRecordCount`, `sharing`, `aria`, `emptyState`; -- record actions: `addRecord`, `inlineEdit`, `rowActions`, `bulkActions`, `bulkActionDefs`, `exportOptions`; -- grid presentation: `rowHeight`, `pagination`, `selection`, `resizable`, `hiddenFields`, `conditionalFormatting`; -- search, filter and navigation: `searchableFields`, `filterableFields`, `userFilters`, `navigation`. - -`description`, `exportOptions` and `bulkActionDefs` had no rung before and are read off the two views only, never off the node, so the objectui#5097 host-composition exemption keeps its 27 names. A named view's `rowHeight` is read as itself; the host `views` entry still goes through the density fold. - -What moves for a host: where the active named view and the host `views` entry both carry one of these members, the named view's value now wins. A named view that carries none of them hands down exactly what it did before. The registered `object-view` renderer passes no `renderListView`, so an authored node is unaffected. diff --git a/.changeset/10765-draft-merge-deletion.md b/.changeset/10765-draft-merge-deletion.md deleted file mode 100644 index 3c73164569..0000000000 --- a/.changeset/10765-draft-merge-deletion.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the metadata editors take a served draft as-is instead of spreading it over the published layer (objectui#10765) - -The metadata-admin editor (`ResourceEditPage`) rebuilt its draft as the served draft spread -over `layered.effective` — on load, after every draft save and after publish — and the Studio -design surface did the same when it opened an app, a surface, an object or a flow, as did the -package OWD overview when it read and re-saved an object's draft. `effective` is the PUBLISHED -layer, and a spread cannot express deletion: a key the author cleared in the draft (the report -inspector's joined clear of `dataset` / `values` / `rows` / `columns` / `chart` / `order`, an OWD -model set back to unset, any key deleted from the JSON tab) was absent from the first draft PUT, -came back into the editor from the published layer on the refresh after that save, invisibly, -and the next save or publish sent it again. - -The spread existed for a partial draft overlay that never reaches these editors: the server -(`metadata-protocol`) stores a `?mode=draft` body raw and its `?state=draft` read returns that -row raw, and every draft writer sends a whole document. So each site now takes the served draft -as-is when there is one and falls back to `effective` (then `code`) only when no draft exists; -the inherited `type` the spread was protecting is already inside the draft. `config.toDraft` -still normalises whatever is taken, now on the post-publish refresh as well. This removes the -reach limit the objectui#10746 entry states — a bound published report getting its cleared -keys back after the first draft save; a report already saved `joined` with stale keys is still -not repaired on load, and the author deletes them from the JSON tab. diff --git a/.changeset/10767-value-data-source-rule-array-filter.md b/.changeset/10767-value-data-source-rule-array-filter.md deleted file mode 100644 index 69afc578ce..0000000000 --- a/.changeset/10767-value-data-source-rule-array-filter.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -'@object-ui/core': patch ---- - -fix(core): `ValueDataSource.find` reads a spec `ViewFilterRule[]` `filter`, so an inline-data map, tree, calendar or gantt renders the rows the one filter form the spec accepts selects - -The spec's converged `filter` doors accept ONLY the rule array -`[{ field, operator, value }, …]` (objectui#6206 B). `ValueDataSource.find` picked a -matcher on the SHAPE of `$filter` — an object to the `$`-dialect matcher, an array -to the AST matcher — and a rule OBJECT is none of the AST shapes, so every row was -refused with one `console.warn` ("is not a shape the matcher reads"). The four -blocks whose rows can be inline (`object-map`, `object-tree`, `object-calendar`, -`object-gantt`, the last through `resolveDataSource`) hand `schema.filter` to this -adapter unlowered, so a spec-conformant page with inline rows rendered an EMPTY -component while `os validate` was green. - -The array arm now lowers through the repo's ONE sink, `toFilterNode` -(`toFilterNodeSafely`) — the same function the grid, the list and every other -lowering caller already use — before it matches, so the spec's vocabulary -(`equals`, `greater_than`, the aliases the spec folds, a valueless `is_null`) selects -rows in memory exactly as it does on the wire. No second lowering and no second -operator table were added; the `$`-dialect arm is untouched. - -The matcher is NOT relaxed. An empty rule array is still "no filter" (as on the -object-bound arm). A genuinely unreadable node, an operator the vocabulary does not -know, and a rule the lowering itself refuses (an ARRAY on a single-valued operator, -an empty `icontains` comparand) still exclude every row and log ONCE, with the same -sentence tail — the lowering's refusal is delivered the way this adapter delivers -every refusal, excluded and logged, never thrown. - -`QueryParams.$filter` (`@object-ui/types`) already declared the array form legal for -every DataSource and named the wire adapter's `translateFilterToAST` as the accept -set; this adapter was the one face in the family that did not read the rule array, -so `resolveDataSource` handed back an adapter whose `find` read fewer filter shapes -on `provider: 'value'` than on `provider: 'object'`. That gap is what closed. diff --git a/.changeset/10770-object-chart-react-tier-node.md b/.changeset/10770-object-chart-react-tier-node.md deleted file mode 100644 index cc0dba5cad..0000000000 --- a/.changeset/10770-object-chart-react-tier-node.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`ObjectChartSchema` (and its TS twin) accepts the `object-chart` node that the react tier's `` block produces: the spec's `{ name }` series arm, with the chart family carried as `specType` (objectui#10770, ruling 5617465269 principle 1). - -The react tier's `` authors `@objectstack/spec`'s `ChartConfigSchema`: its react-blocks entry has -`schemaType: 'object-chart'` and `schema: ChartConfigSchema`, and publishes `type` and `series` among its data -props. The objectstack showcase renewals-pipeline page writes -``. -The react-page wrapper spreads those props into an `object-chart` node and parks the author's `type` as `specType`, -because `type` is the node's discriminator. Both faces refused that node: `chartType` was required, and every -series entry needed `dataKey`. - -- **`series` is two arms.** An entry is either the spec's `ChartSeriesSchema` (TS: `ChartSeries`), by reference, - which is the AUTHOR arm, or the unchanged INTERNAL `{ dataKey }` arm the relays compose. The author arm is the - spec's own closed shape, so an unknown key on it is refused by name, and the spec's `.default()`s are not written - into the parse output. An entry with neither `name` nor `dataKey` is still refused. -- **`specType` is declared**, as the spec's `ChartTypeSchema` (TS: `ChartType`), by reference. -- **`chartType` is optional.** The zod mirror requires one of `chartType` or `specType`, so a node that names no - chart family is still refused, at `chartType`. An interface cannot express "one of two", so the TS face does not - carry that floor. - -Measured before the change: no render, publish or `objectui validate` path ran `ObjectChartSchema` on the wrapper's -node, so no user met the refusal. It sat on the contract face: `objectui validate` over a hand-written copy of -that node, and a TS author typing it as `ObjectChartSchema`. - -⚠️ Shipped as `minor`. The runtime accept set only widens, but two TS types move in a way that can stop a consumer -compiling: - -- `ObjectChartSchema['chartType']` now includes `undefined`. -- An element of `ObjectChartSchema['series']` is a union, so reading `.dataKey` off it needs narrowing first, for - example `'dataKey' in entry` or `Extract<…, { dataKey: string }>`. diff --git a/.changeset/10771-dead-citation-sweep.md b/.changeset/10771-dead-citation-sweep.md deleted file mode 100644 index 5e8fb51340..0000000000 --- a/.changeset/10771-dead-citation-sweep.md +++ /dev/null @@ -1,17 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`, `@object-ui/components`, `@object-ui/core`, -`@object-ui/data-objectstack`, `@object-ui/plugin-calendar`, `@object-ui/plugin-gantt`, -`@object-ui/plugin-map`, `@object-ui/plugin-tree`, `@object-ui/react` and `@object-ui/types`: -docblocks and code comments that cited objectui issues which answer 404 now cite the commit -that landed each change, as a 9-character sha (objectui#10771). Some of these docblocks -reach the emitted `.d.ts` and `.js`; none of them moves a claim, and no code or type token -changes — the comment-stripped syntax tree of every touched file is identical before and -after. No published behaviour changes, so this declares no release. The one runtime -message the sweep touches, `assertObjectMetadataWritable`'s refusal in -`@object-ui/data-objectstack`, is declared on its own as a patch in -`10771-write-guard-message-citation.md`. - -The same repair in the pending changesets that carried these citations is prose-only, and -their frontmatter is byte-identical. diff --git a/.changeset/10771-write-guard-message-citation.md b/.changeset/10771-write-guard-message-citation.md deleted file mode 100644 index 39097dcfad..0000000000 --- a/.changeset/10771-write-guard-message-citation.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/data-objectstack': patch ---- - -fix(data-objectstack): the object-metadata write refusal no longer points at an issue that answers 404 - -`assertObjectMetadataWritable` throws when an object-metadata write carries a relationship -field with no usable target, and a host surfaces that message on screen or in a log. Its -reason ended with two issue pointers, and one of them answers 404, so a reader who followed -it found nothing. The message now cites only objectui#7714, the ruling the refusal enforces. - -Nothing else in the message moves: the door name it opens with, the field it names, the -target state it describes and the advice it closes with are unchanged, and the guard refuses -exactly the writes it refused before. diff --git a/.changeset/10772-inline-screen-visiblewhen-cell.md b/.changeset/10772-inline-screen-visiblewhen-cell.md deleted file mode 100644 index 522d5ab9ba..0000000000 --- a/.changeset/10772-inline-screen-visiblewhen-cell.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the flow inspector's inline `visibleWhen` cell for a screen field reads the screen's declared fields, as the Problems panel and the Debug run do - -**What was wrong.** A screen field's `visibleWhen` is bare CEL over the same screen's declared -fields plus `record` (spec `ScreenFieldSpec.visibleWhen`). The Problems panel and the Debug -run's screen step judge the `screen` node's `fields[].visibleWhen` column by that rule -(`screenPredicateRoots` / `screenVisibleWhenScopeError`), but the inline inspector cell for -the same column still read the flow scope. On a sibling-field predicate (`discount > 0`, the -console sample's shape) its inline note read "`discount` is not a reference in scope at this -step"; on a run variable (`needsApproval == true`) it said nothing; and its picker offered the -flow scope (`needsApproval`, `record`, `previous`). It invited an author to rewrite a correct -predicate into one the runner cannot bind. Measured with the real `FlowObjectListField`, the -`screen` node's `fields` columns and the `resolveFlowScope` groups. - -**What changed.** That one column now reads the screen's rule; every other expression column -keeps the flow scope. - -- The cell is identified by `isScreenVisibleWhenColumn`, the predicate the Problems panel - already judges the column by (now exported), from the node the inspector passes and the - list's descriptor id (`FlowObjectListField`'s new `fieldId`, set by `FlowNodeConfigField` - and never forwarded to a nested list). -- Its picker offers exactly the roots `screenPredicateRoots(node)` admits — the screen's - declared fields and `record` — under a "Screen fields" section. -- Its inline note is `screenVisibleWhenScopeError`'s: silent on a sibling-field predicate, - and "`needsApproval` is not a field on this screen" on a run variable, the sentence the - Problems panel shows for that row. A `{var}` brace is still the brace error, ahead of the - scope. - -No evaluation moved: the runner (`ScreenView`, `FlowRunner`) and the Problems panel's -verdicts are unchanged. diff --git a/.changeset/10778-dashboard-bus-readers.md b/.changeset/10778-dashboard-bus-readers.md deleted file mode 100644 index c154279d39..0000000000 --- a/.changeset/10778-dashboard-bus-readers.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -fix(plugin-dashboard): `object-pivot` and `object-data-table` re-read on the data-invalidation bus - -The fetch effects of `ObjectPivotTable` and `ObjectDataTable` now name the -`useDataInvalidation` nonce for `schema.objectName`, so a write declared on the -bus (`notifyDataChanged`, as a page action over raw HTTP does) re-reads the rows -in place. Before, both refreshed after such a write only when their host -remounted them, and `PageView` is about to stop doing that (objectui#10519). - -The pivot's element-bound spelling (`dataSource: { object }`) resolves onto the -same key. The table is also what a `dashboard` block draws for a table widget -over `{ provider: 'object' }` and what a drill-down drawer lists the underlying -records with, so those re-read too. A drill that opens a report -(`drillDown.report`) and the single-record drawer a table row opens do not -re-read. Bound rows and authored `data` rows do not subscribe. - -⚠️ **Dated note, 2026-09-27 — the report a drill opens does re-read — objectui#10853.** -The sentence above that a drill opening a report (`drillDown.report`) does not -re-read stopped holding with objectui#10814 (PR objectui#10836), pending in the -same release: the drawer's `drillDown.report` arm renders `spec-report` through -`SchemaRenderer`, and the dataset report renderer's own reader re-reads it on the -bus. `drillDownReport.invalidationRefetch-10814.test.tsx` in `apps/console` pins -that through the real drawer. The single-record drawer a table row opens still -does not re-read. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-02 — the drawer renders a `report` node — objectui#11440.** -Later in this same release the drawer's `drillDown.report` arm renders `{ type: 'report', report }` -through `SchemaRenderer`, not `spec-report`, which `@object-ui/plugin-report` retired. So "renders -`spec-report` through `SchemaRenderer`" in the 2026-09-27 note no longer holds; the report it opens -still re-reads on the bus, as that note says. `.changeset/11440-drill-drawer-report-node.md` states -what ships. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10778-tree-bus-reader.md b/.changeset/10778-tree-bus-reader.md deleted file mode 100644 index 811a14029b..0000000000 --- a/.changeset/10778-tree-bus-reader.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/plugin-tree': patch ---- - -fix(plugin-tree): `object-tree` re-reads its rows on the data-invalidation bus - -The record effect of `ObjectTree` now names the `useDataInvalidation` nonce for -the object its `object` provider queries — whether the node spells it -`objectName` or `data: { provider: 'object', object }` — so a write declared on -the bus (`notifyDataChanged`, as a page action over raw HTTP does) re-reads the -tree in place, keeping the user's expansion choices. Before, a tree that no -host handed rows to refreshed after such a write only when its host remounted -it, and `PageView` is about to stop doing that (objectui#10519). - -Inline rows (a `data` array, the `value` provider) name no object and do not -subscribe. A tree whose host hands down rows (the `list-view` tree) subscribes -too: it runs its own full query ahead of those rows, so its freshness does not -rest on the host's rows moving. diff --git a/.changeset/10783-grid-currency-scale-not-read.md b/.changeset/10783-grid-currency-scale-not-read.md deleted file mode 100644 index e72410c91b..0000000000 --- a/.changeset/10783-grid-currency-scale-not-read.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/fields': minor -'@object-ui/plugin-form': patch ---- - -fix(fields): a currency grid column's width is its currency's minor unit, never an authored `scale`; a hydrated currency column's `scale` is reported (objectui#10783) - -The line-item grid (`GridField` / `LineItemsField`) no longer reads `scale` on a -`currency` column. The currency's ISO 4217 minor unit decides both the width a -computed amount is stored at and the places the cell shows: whole yen for JPY, -two places for USD, three for KWD, whatever `scale` the column carries. -`@objectstack/spec` 17.5.0 refuses `scale` on an inline grid column that -declares `type: 'currency'` (ruling B on objectstack-ai/objectstack#19629, -ruling 乙 on objectstack-ai/objectstack#19910), and the grid now matches it. -`scale` on a `number` column is unchanged. - -A column that declares no `type` and takes `currency` from its child field, such -as `inlineColumns: [{ name: 'amount', scale: 2 }]` over a currency `amount` -field, still passes the spec, which cannot see the child field's type. The -master-detail form's column hydration now reports such a `scale` on the console, -once per column, naming the column and the child object, instead of leaving it -unread in silence. It reports a declared currency column that carries `scale` -too, because a form view's `subforms[].columns` is not judged by the spec. The -column still renders, at its currency's minor unit; delete the key. - -**Behaviour change** for a currency column with an authored `scale`: a computed -amount is stored and shown at the currency's minor unit instead of at that -`scale`. A JPY tenant's column with `scale: 2` used to show `¥1,234.57` and now -shows `¥1,235`. diff --git a/.changeset/10785-avatar-submits-file-id.md b/.changeset/10785-avatar-submits-file-id.md deleted file mode 100644 index d06382951c..0000000000 --- a/.changeset/10785-avatar-submits-file-id.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/fields': minor ---- - -fix(fields): an avatar pick uploads through the `UploadProvider` and submits its `sys_file` id, or is refused by name — never stored as a `data:` URL - -**BREAKING (`@object-ui/fields`), graded `minor` by this repo's release model** (AGENTS.md: objectui's major follows the `@objectstack` family major, so its own breaking changes ship as `minor` with the breaking semantics stated here, never `major`), the grade objectui#7699 gave the same change to the file and image widgets: - -- **Who breaks.** A host that renders `AvatarField` under an upload adapter whose result carries no id-shaped `meta.fileId`. That includes the object-URL default: `useUpload()` falls back to it when no `UploadProvider` is mounted, and `UploadProvider` uses it when given no `adapter`. It also includes any S3- or Azure-style adapter, `createS3Adapter` and `createAzureBlobAdapter` among them, because neither mints a `sys_file` row. Such a host used to get a `data:` URL in `onChange` for every accepted pick. -- **What they see now.** The pick is refused with the translated "did not complete" row `FileField` and `ImageField` render for the same pick, and the field is not changed. -- **What to do.** Mount an `UploadProvider` whose adapter returns the `sys_file` id in `meta.fileId`. `createObjectStackUploadAdapter`, the ObjectStack presigned flow, does. A host on another backend returns its own file id there (word characters and `-`, 1 to 64 long, as `isFileIdToken` requires) and has its read path return `{ id, name, url }`, because a bare id otherwise renders from ObjectStack's `/api/v1/storage/files/:id`. - -`Clause-②: yes (narrowing)` — `AvatarField`, a public export of `@object-ui/fields` and the registered `avatar` widget, now refuses a pick whose upload adapter surfaces no id-shaped `meta.fileId` where it used to hand every accepted pick to `onChange` as a `data:` URL; its props type is unchanged and no accept set widens. - -`avatar` is a member of the file-reference family, so its stored value has been the bare `sys_file` id since spec `17.0.0`. `AvatarField` read the picked file with `FileReader.readAsDataURL` and stored the resulting `data:` URL instead: the whole image inlined into the record row, as a value the engine's record validator refuses (`invalid_type`) whenever `mediaStrictEffective` answers true and otherwise admits only warn-first. It answers true when the deployment's `adr-0104-file-references` flag is recorded (by `os migrate files-to-references --apply`, or at creation for a datastore born empty) or when `OS_DATA_VALUE_SHAPE_STRICT_ENABLED=1` forces strict; `OS_ALLOW_LAX_MEDIA_VALUES=1` wins over both and keeps it lenient. - -The pick now goes through `useUpload()` and `fileValueForSubmit`, the path the file and image widgets use: the id reaches `onChange`, and the preview shows the upload's own URL until the next read expands the value. While the upload runs, the button shows the uploading state and the widget reports it through `onUploadingChange` and the ambient uploading scope, as the file and image widgets do, so the record forms' upload gate, `FormPage` (`/f/:slug`, `/forms/:name`) and `ActionParamDialog` hold their submit until it settles. Reading is unchanged for a legacy `data:` or http(s) URL already on a record, which still renders as itself, and a bare id now renders from the storage endpoint instead of as a relative `src`. diff --git a/.changeset/10785-avatar-upload-gates.md b/.changeset/10785-avatar-upload-gates.md deleted file mode 100644 index ca6dc7ed79..0000000000 --- a/.changeset/10785-avatar-upload-gates.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/console': patch ---- - -fix(app-shell, console): `ActionParamDialog` and `FormPage` hold their submit while an `avatar` upload is in flight - -`AvatarField` now uploads its pick through the ambient `UploadProvider` and hands the `sys_file` id to `onChange` only once the adapter settles, reporting the wait through `onUploadingChange` (objectui#10785). Both hosts handed that callback to `file` and `image` alone, so a Confirm or Submit pressed during an avatar upload went out without the avatar and reported success, the objectui#10167 class. `ActionParamDialog` (`@object-ui/app-shell`) and `FormPage` (`@object-ui/console`, `/f/:slug` and `/forms/:name`) now gate `avatar` too: the button is disabled and reads "Uploading…" until the upload settles. diff --git a/.changeset/10788-empty-operator-map-beside-key-refused.md b/.changeset/10788-empty-operator-map-beside-key-refused.md deleted file mode 100644 index 68448c8a84..0000000000 --- a/.changeset/10788-empty-operator-map-beside-key-refused.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/core': patch ---- - -`convertFiltersToAST` now refuses an EMPTY operator map BESIDE a key that lowers — -`{ status: 'a', created: {} }` — with a `FilterOperatorError` (`INVALID_FILTER` / 400) -whose subject is the field, instead of silently dropping it (objectui#10788). - -**Before.** `{ created: {} }` names a field and no operator, so the operator loop ran zero -times and pushed no condition for it. objectui#9164 refused that map in the general tail, -but the tail was reached only when NOTHING produced a condition. Beside a key that lowers, -the sibling's condition carried the filter and the field vanished: -`{ status: 'a', created: {} }` lowered to `['status', '=', 'a']`, and both `find()` routes -of `@object-ui/data-objectstack` sent a request byte-identical to `{ status: 'a' }`. The -result was WIDER than the author wrote, with nothing thrown. `@objectstack/spec` records -`{ field: {} }` as REJECTED in every position (objectstack#5240, on -`FilterConditionSchema`). - -**After.** The empty operator map is refused in the operator-map arm, where it is met, like -this function's bare-array and exotic-comparand refusals. One throw site now answers it -alone (objectui#9164) and beside other keys, so the two cases cannot drift apart. The -message names the field and the fix: choose an operator (`$eq`, `$in`, `$null`, …) or -remove the key. A `$and` / `$or` member is converted by the same function, so -`{ $and: [{ status: 'a', created: {} }] }` is refused too. - -**What an author sees.** The same as for this function's other refusals. A list or view -that loads through `buildEffectiveFilter` / `ObjectView` fails its load with the -`INVALID_FILTER` envelope. `ObjectGrid`, `RelatedList` and `LineItemsPanel` read -`toFilterNodeSafely` and render the "this view's filter is malformed" state naming the -field. `@object-ui/data-objectstack`'s `find()` rejects with the envelope and sends no -request. - -**Unchanged.** `{ status: 'a' }` still lowers to `['status', '=', 'a']`. A real operator -beside the key (`{ status: 'a', created: { $gte: d } }`) still lowers. A `null` / -`undefined` value is still skipped, not refused. `{}` still returns `{}`. - -**Migration.** A stored filter carrying `{ field: {} }` beside other keys used to return -more rows than it said. It is now a named refusal. Give the field an operator, or delete -the key. diff --git a/.changeset/10789-render-time-filter-refusals.md b/.changeset/10789-render-time-filter-refusals.md deleted file mode 100644 index 516a93c8d5..0000000000 --- a/.changeset/10789-render-time-filter-refusals.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/core': patch -'@object-ui/react': patch -'@object-ui/fields': patch -'@object-ui/plugin-charts': patch -'@object-ui/plugin-dashboard': patch -'@object-ui/plugin-report': patch -'@object-ui/plugin-list': patch ---- - -A filter refused as malformed (`INVALID_FILTER`) no longer throws out of render or out of a click -handler at the sites that merge filters there. That holds whether this layer's filter converter -refused it or, at the drill seam, the spec's own `parseFilterAST`. Each site now surfaces the -refusal the way its siblings already do (objectui#10789). The filter stays **refused**: nothing -that was refused is accepted, and no site falls back to "no filter". - -- **`ElementDataSourceGate` / `useElementDataSource`** (`@object-ui/react`): the gate's merge of - the component's `filter` with the composed binding, and the merge of a saved view's filter - with the binding's own, lowered through the throwing converter inside render. A refused - filter from either now makes the binding `missing` with a new optional `filterRefusal` on the - result (`error` carries its message). The gate then draws, in place of the block, the - malformed-filter notice the wrapped blocks draw: `view.malformedFilter`, naming the refused - operator or field. `element:record_picker`, which reads the same hook, shows its - configuration-error panel with the refusal. -- **`PeoplePicker` / `RecordPickerDialog`** (`@object-ui/fields`): the recents merge and the - dialog's `mergedFilter` lower through `toFilterNodeSafely`; a refusal is shown in the picker's - existing error state and no query runs without the filter. -- **Drill-downs** (`ObjectChart`, `ObjectPivotTable`, `DatasetWidget`, `DatasetReportRenderer`): - a widget or report filter refused at the drill seam made the drill click throw. The converter - refuses some (a spec `$not`, say). The spec's `parseFilterAST` refuses others, such as a scalar - on a list operator in either dialect: `[['stage', 'in', 'won']]` or `{ stage: { $in: 'won' } }`. - The drill is now not opened or emitted (never with the scope dropped), and the refusal is logged - with `console.warn`, naming the operator. `composeDrillFilter` (`@object-ui/core`) now throws - one refusal type: the spec's `INVALID_FILTER` error is re-raised as a `FilterOperatorError` with - its message and the same `INVALID_FILTER` / 400 envelope, and any other error passes through - unchanged. -- **`ListView` export** (`@object-ui/plugin-list`): the server export builds its filter inside - its `try`, so a refusal is named in the export menu instead of escaping the click. -- **`convertFiltersToAST`** (`@object-ui/core`): an `$or` member that is the TRUE identity no - longer stops the members after it from being read. `{ $or: [{}, { a: {} }] }` is now refused - like `{ $or: [{ a: {} }, {}] }` already was, instead of answering TRUE (every row); a TRUE - disjunct beside members that lower still absorbs its `$or`. diff --git a/.changeset/10790-empty-operators-accepted-shape.md b/.changeset/10790-empty-operators-accepted-shape.md deleted file mode 100644 index d00c96ef3b..0000000000 --- a/.changeset/10790-empty-operators-accepted-shape.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/fields': patch ---- - -fix(fields): "Is empty" / "Is not empty" in the filter-condition widget store a criteria the objectstack filter faces accept - -`FilterConditionField` (the `filter-condition` widget behind `relatedListFilter`, a -roll-up's `summaryOperations.filter` and `sys_sharing_rule.criteria_json`) stored -"Is empty" as `{ FIELD: { $in: [null, ''] } }` and "Is not empty" as -`{ FIELD: { $nin: [null, ''] } }`. A `null` list member is refused by -`@objectstack/spec`'s comparand-shape face (`assertListComparandShapes`, -`INVALID_FILTER` / 400) in every position, so a related list, roll-up or sharing -rule authored with either operator failed whenever it was evaluated. - -They now store the spelling that refusal prescribes, with the same meaning — no -value OR the empty string, and its complement: - -- "Is empty": `{ $or: [{ FIELD: { $in: [''] } }, { FIELD: { $null: true } }] }` -- "Is not empty": `{ FIELD: { $nin: [''], $null: false } }` - -Criteria saved in the old shape still open in the builder as the same row, and -opening one rewrites nothing; the builder writes the new shape the next time any -row of that criteria is edited. - -**Correction, 2026-10-03 (objectui#10813).** The two shapes above are not what this release -writes. Later in the same release the pair moved to the spec's one 「is empty」 operator: -"Is empty" stores `{ FIELD: { $empty: true } }` and "Is not empty" `{ FIELD: { $empty: false } }`, -whose meaning is the field's declared row of the spec's per-type table rather than "no value OR -the empty string" on every type. Criteria saved in either earlier shape still open as the same -row and are written as `$empty` on their next edit (`.changeset/10813-filter-condition-empty-operator.md`). diff --git a/.changeset/10799-calendar-default-month.md b/.changeset/10799-calendar-default-month.md deleted file mode 100644 index 8ea2e1e4c8..0000000000 --- a/.changeset/10799-calendar-default-month.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/components': patch -'@object-ui/plugin-calendar': patch -'@object-ui/plugin-dashboard': patch ---- - -fix: every `Calendar` picker opens on its selected date's month, not today's (objectui#10799) - -react-day-picker opens on `month`, else `defaultMonth`, else today, and -`selected` does not move it. Five `Calendar` mounts passed `selected` only, so -a value outside the current month opened the picker on today's month: with -the calendar on 4 March 2020 and today in September 2026, the header of -`CalendarView` read `March 2020` while the popover under it opened on -`September 2026`, with no selected day in view. - -Each mount now passes its first selected day as `defaultMonth`: - -- `CalendarView`'s header date popover (`@object-ui/plugin-calendar`) opens on - the date the header names, and follows Previous / Next between opens; -- `ui:calendar` opens on its day in `single` mode, on the first valid listed - day in `multiple` mode (an entry that is not a date is skipped) and on `from` - in `range` mode. It reads that month once, when it mounts: a value that - changes afterwards does not move the month it shows; -- the form date picker (`date-picker`) and `DatePicker` open on their value; -- the dashboard date filter's custom-range calendar - (`@object-ui/plugin-dashboard`) opens on the range's `from`. - -With no value, each still opens on today. react-day-picker throws on an -invalid `defaultMonth`, so a day that names no instant is not passed as one: an -unparseable `ui:calendar` day, a range `from` that does not parse, and an -invalid `Date` a host hands `CalendarView` each open on today, as before. The -two date pickers are unchanged in this respect: an invalid value already fails -in their trigger's label, before any calendar mounts. The `Calendar` primitive -itself is unchanged. diff --git a/.changeset/10803-dead-citation-sweep-eighth-batch.md b/.changeset/10803-dead-citation-sweep-eighth-batch.md deleted file mode 100644 index 7b0480faf6..0000000000 --- a/.changeset/10803-dead-citation-sweep-eighth-batch.md +++ /dev/null @@ -1,18 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`, `@object-ui/components`, `@object-ui/plugin-detail`, -`@object-ui/plugin-form` and `@object-ui/plugin-grid`: docblocks and code comments that cited -an `objectstack` issue or pull request by a bare number, which answers 404 in objectstack and -resolves to an unrelated issue or pull request in this repository, now cite the commit in -that repository that landed the change, written as objectstack and a 9-character sha -(objectui#10803, the eighth batch). One of them sits inside a quotation of an objectstack -source comment; there the commit stands in square brackets in place of the quoted number. -Comments that named objectstack's card for the effective operation set on detail and form -surfaces by its bare number, or qualified with this repository's name, now read -`objectstack#3546`: in this repository that number is an unrelated card. None of these -comment edits moves a claim or changes a code or type token. No published behaviour changes -through them, so this declares no release. - -The same repair in the one pending changeset that carried such a citation is prose-only, and -its frontmatter is byte-identical. diff --git a/.changeset/10803-dead-citation-sweep-fifth-batch.md b/.changeset/10803-dead-citation-sweep-fifth-batch.md deleted file mode 100644 index 066ec8b3da..0000000000 --- a/.changeset/10803-dead-citation-sweep-fifth-batch.md +++ /dev/null @@ -1,23 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`, `@object-ui/components`, `@object-ui/core`, -`@object-ui/fields`, `@object-ui/plugin-charts`, `@object-ui/plugin-chatbot`, -`@object-ui/plugin-dashboard`, `@object-ui/plugin-designer`, `@object-ui/plugin-detail`, -`@object-ui/plugin-grid`, `@object-ui/plugin-list`, `@object-ui/plugin-markdown`, -`@object-ui/plugin-timeline`, `@object-ui/react` and `@object-ui/types` (whose runtime text is -declared separately below), plus the private -`@object-ui/test-support`: docblocks and code comments that cited objectui issues or pull -requests which answer 404 now cite the commit that landed each change, as a 9-character -sha, the ruling by its date where the sentence cites a ruling, or a live pointer the -sentence already named, and where nothing answers they name the card by role -(objectui#10803, the fifth batch). Bare numbers that were sister-repo cards are now written -`objectstack#3720`, `objectstack#5506` and `objectstack#6936`. Some of these docblocks -reach the emitted `.d.ts` and `.js`; none of them moves a claim, and none of these comment -edits changes a code or type token. No published behaviour changes through them, so this -declares no release. The runtime text the sweep touches, six tombstone guidance strings, -one refusal message and one zod `.describe()` string in `@object-ui/types`, is declared on -its own as a patch in `10803-fifth-batch-runtime-strings.md`. - -The same repair in the pending changesets that carried these citations is prose-only, and -their frontmatter is byte-identical. diff --git a/.changeset/10803-dead-citation-sweep-fourth-batch.md b/.changeset/10803-dead-citation-sweep-fourth-batch.md deleted file mode 100644 index 370cdd3129..0000000000 --- a/.changeset/10803-dead-citation-sweep-fourth-batch.md +++ /dev/null @@ -1,21 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`, `@object-ui/cli`, `@object-ui/components`, -`@object-ui/core`, `@object-ui/data-objectstack`, `@object-ui/fields`, `@object-ui/i18n`, -`@object-ui/plugin-chatbot`, `@object-ui/plugin-grid`, `@object-ui/plugin-kanban`, -`@object-ui/plugin-timeline` and `@object-ui/types`, plus the private -`@object-ui/test-support`: docblocks and code comments that cited objectui issues which -answer 404 now cite the commit that landed each change, as a 9-character sha, the ruling -by its date where the sentence cites a ruling, or a live pointer the sentence already -named, and where nothing answers they name the card by role (objectui#10803, the fourth -batch). One bare number that was a sister-repo pull request is now written -`objectstack#6942`. Some of these docblocks reach the emitted `.d.ts` and `.js`; none of -them moves a claim, and none of these comment edits changes a code or type token. No -published behaviour changes through them, so this declares no release. The runtime text -the sweep touches, two tombstone guidance strings and two zod `.describe()` strings in -`@object-ui/types`, is declared on its own as a patch in -`10803-fourth-batch-runtime-strings.md`. - -The same repair in the pending changesets that carried these citations is prose-only, and -their frontmatter is byte-identical. diff --git a/.changeset/10803-dead-citation-sweep-second-batch.md b/.changeset/10803-dead-citation-sweep-second-batch.md deleted file mode 100644 index 68e47865b5..0000000000 --- a/.changeset/10803-dead-citation-sweep-second-batch.md +++ /dev/null @@ -1,20 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`, `@object-ui/components`, `@object-ui/core`, -`@object-ui/fields`, `@object-ui/plugin-calendar`, `@object-ui/plugin-chatbot`, -`@object-ui/plugin-dashboard`, `@object-ui/plugin-gantt`, `@object-ui/plugin-grid`, -`@object-ui/plugin-list`, `@object-ui/plugin-map`, `@object-ui/plugin-timeline`, -`@object-ui/plugin-tree`, `@object-ui/plugin-view`, `@object-ui/react`, -`@object-ui/sdui-parser` and `@object-ui/types`: docblocks and code comments that cited -objectui issues which answer 404 now cite the commit that landed each change, as a -9-character sha, or the ruling by its date where no single commit answers (objectui#10803, -the second batch after objectui#10771). Some of these docblocks reach the emitted `.d.ts` -and `.js`; none of them moves a claim, and none of these comment edits changes a code or -type token. No published behaviour changes through them, so this declares no release. -The one runtime text the sweep touches, eleven zod `.describe()` strings in -`@object-ui/types`, is declared on its own as a patch in -`10803-describe-string-citations.md`. - -The same repair in the pending changesets that carried these citations is prose-only, and -their frontmatter is byte-identical. diff --git a/.changeset/10803-dead-citation-sweep-seventh-batch.md b/.changeset/10803-dead-citation-sweep-seventh-batch.md deleted file mode 100644 index 8c4b7b2e10..0000000000 --- a/.changeset/10803-dead-citation-sweep-seventh-batch.md +++ /dev/null @@ -1,23 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`, `@object-ui/components`, `@object-ui/core`, -`@object-ui/data-objectstack`, `@object-ui/i18n`, `@object-ui/permissions`, -`@object-ui/plugin-calendar`, `@object-ui/plugin-designer`, `@object-ui/plugin-detail`, -`@object-ui/plugin-form`, `@object-ui/plugin-grid`, `@object-ui/plugin-kanban`, -`@object-ui/plugin-list`, `@object-ui/plugin-tree`, `@object-ui/providers`, -`@object-ui/react` and `@object-ui/types` (two console warnings in `@object-ui/app-shell` -and `@object-ui/plugin-detail` are runtime text, declared separately below): docblocks and -code comments that cited an `objectstack` issue or pull request which answers 404 now cite -the commit in that repository that landed the change, written as objectstack and a -9-character sha (objectui#10803, the seventh batch). Where the sentence already names that -change's live pull request or commit, or dates the ruling it points at, the dead number is -dropped instead, and one sentence cites this repository's own landing commit, because the -fix it names landed here. Comments that named the apiMethods whitelist card as a bare -number now read `objectstack#3391`, and the two that paired it with a second bare number -read `objectstack#3546` for it: a bare number resolves to this repository, where both -numbers are unrelated cards. None of these comment edits moves a claim or changes a code or -type token. No published behaviour changes through them, so this declares no release. - -The same repair in the pending changesets that carried these citations is prose-only, and -their frontmatter is byte-identical. diff --git a/.changeset/10803-dead-citation-sweep-sixth-batch.md b/.changeset/10803-dead-citation-sweep-sixth-batch.md deleted file mode 100644 index ba2f432eb8..0000000000 --- a/.changeset/10803-dead-citation-sweep-sixth-batch.md +++ /dev/null @@ -1,24 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`, `@object-ui/components`, `@object-ui/core`, -`@object-ui/data-objectstack`, `@object-ui/fields`, `@object-ui/layout`, -`@object-ui/plugin-dashboard`, `@object-ui/plugin-designer`, `@object-ui/plugin-detail`, -`@object-ui/plugin-form`, `@object-ui/plugin-grid`, `@object-ui/plugin-kanban`, -`@object-ui/plugin-list`, `@object-ui/plugin-view` and `@object-ui/types` (whose runtime -text is declared separately below): docblocks and code comments that cited objectui issues -which answer 404 now cite the commit that landed each change, as a 9-character sha, and -where nothing answers they name the card by role (objectui#10803, the sixth batch). Bare -numbers that were sister-repo cards or pull requests are now written `objectstack#N`, and -where the sister-repo pull request itself answers 404 the sentence cites its commit in -that repository instead. Two `@object-ui/plugin-grid` sites beside `objectstack#3720` that -named the apiMethods whitelist card bare now read `objectstack#3391`, the card they meant. -Some of these docblocks reach the -emitted `.d.ts` and `.js`; none of them moves a claim, and none of these comment edits -changes a code or type token. No published behaviour changes through them, so this -declares no release. The one runtime string the sweep touches, a zod `.describe()` string -in `@object-ui/types`, is declared on its own as a patch in -`10803-sixth-batch-runtime-strings.md`. - -The same repair in the pending changesets that carried these citations is prose-only, and -their frontmatter is byte-identical. diff --git a/.changeset/10803-dead-citation-sweep-third-batch.md b/.changeset/10803-dead-citation-sweep-third-batch.md deleted file mode 100644 index 033b46563e..0000000000 --- a/.changeset/10803-dead-citation-sweep-third-batch.md +++ /dev/null @@ -1,20 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/app-shell`, `@object-ui/components`, `@object-ui/core`, -`@object-ui/data-objectstack`, `@object-ui/i18n`, `@object-ui/layout`, -`@object-ui/plugin-charts`, `@object-ui/plugin-dashboard`, `@object-ui/plugin-detail`, -`@object-ui/react`, `@object-ui/sdui-parser` and `@object-ui/types`: docblocks and code -comments that cited objectui issues which answer 404 now cite the commit that landed each -change, as a 9-character sha, the ruling by its date where the sentence cites a ruling, or -a live successor, and where nothing answers they name the card by role (objectui#10803, -the third batch). Some of these docblocks reach the -emitted `.d.ts` and `.js`; none of them moves a claim, and none of these comment edits -changes a code or type token. No published behaviour changes through them, so this -declares no release. The runtime text the sweep touches, four tombstone guidance strings -and two zod `.describe()` strings in `@object-ui/types` and one CEL authoring advisory in -`@object-ui/app-shell`, is declared on its own as a patch in -`10803-third-batch-runtime-strings.md`. - -The same repair in the pending changesets that carried these citations is prose-only, and -their frontmatter is byte-identical. diff --git a/.changeset/10803-describe-string-citations.md b/.changeset/10803-describe-string-citations.md deleted file mode 100644 index d064ececc0..0000000000 --- a/.changeset/10803-describe-string-citations.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/types': patch ---- - -fix(types): eleven zod `.describe()` strings no longer point at an objectui issue that answers 404 - -The runtime descriptions of eleven members of the published zod mirrors ended with, or -carried, a pointer to an objectui issue that answers 404: `CheckboxSchema.wrapperClass`, -`TreeViewSchema.nodes`, `ObjectMapSchema.objectName`, `ObjectGanttSchema.objectName`, -`ObjectGanttSchema.data`, `TooltipSchema.trigger` / `content` / `children`, and -`ContextMenuSchema.triggerClassName` / `contentClassName` / `modal`. A reader of a zod -`description` has no repository to resolve a commit against, so each dead pointer is dropped -rather than replaced (objectui#10803). On `ObjectGanttSchema.data` the clause that carried it, -"undeclared on either face until" that issue, goes with it, leaving -"Data source configuration — read FIRST by resolveRecordSourceConfig": the same shape as its -`ObjectMapSchema.data` twin, which names `getDataConfig`. - -Nothing else in any string moves, and no key, path, accept set or refusal changes: every -document that parsed before parses the same way. diff --git a/.changeset/10803-fifth-batch-runtime-strings.md b/.changeset/10803-fifth-batch-runtime-strings.md deleted file mode 100644 index 44c56b1c12..0000000000 --- a/.changeset/10803-fifth-batch-runtime-strings.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/types': patch ---- - -fix(types): eight more runtime strings no longer point at objectui issues that answer 404 - -Six ADR-0049 retirement tombstones in the published zod mirrors, one refusal message and -one runtime description carried a pointer to an objectui issue that answers 404. A reader -of a parse error or a zod `description` has no repository to resolve a commit against, so -no dead pointer becomes a commit: the six tombstones keep `ADR-0049` and lose the dead -card beside it, the `actions` tombstone cites `ADR-0049` in its place, and the one -description simply drops its pointer (objectui#10803). - -- **The tombstone guidance.** `ChatbotSchema`'s `loading`, `showAvatars`, `userAvatar`, - `assistantAvatar`, `markdown` and `height` tombstones feed both the parse error an - author reads and the `.describe()` text, and each now opens `RETIRED (ADR-0049) —` where - it opened with the dead card and `ADR-0049` together. The `showAvatars` message also - ends its sentence about the fenced props spread at "was fenced." Everything else after - the dash is unchanged, so the remedy each message gives is word for word what it was. -- **The `page` node's `actions` refusal**, an ADR-0049 tombstone too, now reads "`actions` - is not a key of the `page` node and never was (ADR-0049): no renderer reads it", and the - remedy after it is unchanged. -- **One description.** `ChartDataSeriesSchema.variant` now ends "the renderer-internal - `current` spelling is not a member". - -Nothing else in any string moves, and no key, path, issue code, accept set, refusal or -severity changes: every document that parsed before parses the same way and is refused at -the same path with the same code. diff --git a/.changeset/10803-fourth-batch-runtime-strings.md b/.changeset/10803-fourth-batch-runtime-strings.md deleted file mode 100644 index 8a1cad1a5f..0000000000 --- a/.changeset/10803-fourth-batch-runtime-strings.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/types': patch ---- - -fix(types): four more runtime strings no longer point at objectui issues that answer 404 - -Two ADR-0049 retirement tombstones in the published zod mirrors and two runtime -descriptions carried a pointer to an objectui issue that answers 404. A reader of a parse -error or a zod `description` has no repository to resolve a commit against, so no dead -pointer becomes a commit: the tombstones cite `ADR-0049` in its place, and the two -description pointers are simply dropped (objectui#10803). - -- **The tombstone guidance.** The legacy `ActionSchema`'s `onSuccess` and `onFailure` - tombstones feed both the parse error an author reads and the `.describe()` text, and - each now opens `RETIRED (ADR-0049) —` in place of the dead card. Everything after the - dash is unchanged, so the remedy each message gives is word for word what it was. -- **Two descriptions.** `DataTableSchema.rowActions` now ends "mirrors the boolean the - renderer truthiness-tests", and `DataTableSchema.cellClassName` ends "so row density has - to be set on both". - -Nothing else in any string moves, and no key, path, issue code, accept set, refusal or -severity changes: every document that parsed before parses the same way and is refused at -the same path with the same code. diff --git a/.changeset/10803-seventh-batch-runtime-strings.md b/.changeset/10803-seventh-batch-runtime-strings.md deleted file mode 100644 index 0911ff1f80..0000000000 --- a/.changeset/10803-seventh-batch-runtime-strings.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/plugin-detail': patch ---- - -fix(app-shell, plugin-detail): the unmapped activity type warnings no longer point at an objectstack issue that answers 404 - -`@object-ui/app-shell` warns on the console, once per value, when a `sys_activity` row's -`type` maps to no activity item type, and `@object-ui/plugin-detail`'s `[record:activity]` -block does the same when it maps to no feed item type. Both messages said `sys_activity.type` is -author-extensible with a pointer to an objectstack issue that answers 404 beside the -ruling's date. A reader of a console warning has no repository to resolve a commit -against, so the pointer is dropped rather than replaced: both now read "author-extensible -(ruled 2026-08-24)" (objectui#10803). - -Nothing else in either message moves, and what renders, and when and how often each -warning fires, are unchanged. diff --git a/.changeset/10803-sixth-batch-runtime-strings.md b/.changeset/10803-sixth-batch-runtime-strings.md deleted file mode 100644 index 87e3800d3c..0000000000 --- a/.changeset/10803-sixth-batch-runtime-strings.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/types': patch ---- - -fix(types): `InputSchema.wrapperClass`'s description no longer points at an objectui issue that answers 404 - -The zod `.describe()` text of `InputSchema.wrapperClass` ended with a pointer to an -objectui issue that answers 404. A reader of a zod `description` has no repository to -resolve a commit against, so the pointer is dropped rather than replaced: the description -now reads "Classes on the wrapper div around the input and its label" (objectui#10803). - -Nothing else in the string moves, and no key, path, issue code, accept set, refusal or -severity changes: every document that parsed before parses the same way and is refused at -the same path with the same code. diff --git a/.changeset/10803-third-batch-runtime-strings.md b/.changeset/10803-third-batch-runtime-strings.md deleted file mode 100644 index cc3a2de328..0000000000 --- a/.changeset/10803-third-batch-runtime-strings.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/types': patch -'@object-ui/app-shell': patch ---- - -fix(types,app-shell): runtime strings no longer point at objectui issues that answer 404 - -Four ADR-0049 retirement tombstones in the published zod mirrors, two runtime descriptions -and the Studio CEL authoring advisory carried a pointer to an objectui issue that answers -404. A reader of a parse error, a zod `description` or an editor warning has no repository -to resolve a commit against, so no dead pointer becomes a commit: tombstones cite -`ADR-0049` in its place, and every other pointer is simply dropped (objectui#10803). - -- **The tombstone guidance.** Each tombstone's guidance feeds both the parse error an - author reads and the `.describe()` text, and now opens `RETIRED (ADR-0049) —` in - place of the dead card: `TreeViewSchema.data`, `TextSchema.value`, - `ChartDataSeriesSchema.data`, and `DashboardConfigSchema.aria` (its error and its - describe text, two strings). Everything after the dash is unchanged, so the remedy - each message gives is word for word what it was. -- **Two descriptions.** `TreeViewSchema.nodes` loses the pointer in two places: its - parenthesis now ends "no presence rule exists", and its history clause reads "the - `data` fallback spelling was retired". `TextSchema.content` likewise ends "its `value` - fallback spelling was retired". -- **The advisory** that tells an author a row predicate binds the row as `record` and - nothing else ends that clause at "nothing else". - -Nothing else in any string moves, and no key, path, issue code, accept set, refusal or -severity changes: every document that parsed before parses the same way and is refused -at the same path with the same code, and the advisory still fires on exactly the same -predicates. diff --git a/.changeset/10804-designer-notes-locale.md b/.changeset/10804-designer-notes-locale.md deleted file mode 100644 index 9d85b00e9e..0000000000 --- a/.changeset/10804-designer-notes-locale.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the flow designer's expression notes and the dashboard add-widget picker read the designer locale (objectui#10804, objectui#10805) - -Under zh-CN these designer words stayed English beside Chinese headings: - -- the unknown-reference note under a repeater cell (`FlowExprIssue`), although - its row had a zh translation and the sibling edge and config-field notes - already passed their locale; -- the Problems panel's expression messages — a brace or bracket error on a CEL - slot and on a screen field's `visibleWhen` — which read English where the - inline cell read the same message in Chinese; a row with no label of its own - is now prefixed by the column label the inspector shows; -- the `Screen fields` heading of a screen `visibleWhen` picker, and that cell's - note naming a root that is not a field on the screen; -- the add-widget picker's search box, empty text, category headings and type - names. - -Each new en row is the English the literal carried, so en renders unchanged. -A new widget's default `New TYPE` title is stored author data and keeps writing -the English name in every locale; the stored `type` does not move. The parse and -shape refusals shown for a screen `visibleWhen` are `@objectstack/formula`'s and -`@objectstack/spec`'s own words and still pass through as they are. diff --git a/.changeset/10813-dataset-filter-empty-operator.md b/.changeset/10813-dataset-filter-empty-operator.md deleted file mode 100644 index bdf87d553c..0000000000 --- a/.changeset/10813-dataset-filter-empty-operator.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -The Studio dataset filter builder writes "Is empty" / "Is not empty" as the spec's `{ FIELD: { $empty: true } }` / `{ FIELD: { $empty: false } }` instead of `$exists` (objectui#10813). - -`dataset.filter` and `measure.filter` stored the pair as `{ FIELD: { $exists: false } }` / `{ FIELD: { $exists: true } }`. `$exists` is the spec's has-a-value test (`!= null`), so a text value of `''` or a multi-value `[]` was never "empty" there, while the same operator in the sharing-rule widget and in a saved view meant something else. `@objectstack/spec` 17.6.0 admits `$empty` (objectstack#20446), whose meaning is the column's DECLARED row of the spec's per-type table (ruling B on objectstack#20311): null or `''` on a text-like column, null or `[]` on a multi-value one, null alone on every other type. The analytics service answers it from the field's declared type and `multiple` on its SQL and ObjectQL strategies. The spec's own face table declares one face that refuses it: the `driver-memory` analytics (cube) face, the lowest-priority fallback strategy (`MemoryAnalyticsService`), refuses a newly authored "Is empty" / "Is not empty" filter with `INVALID_FILTER` / 400, where it answered `$exists`. The bridge keeps no copy of the table. - -The `@objectstack/spec` dependency floor rises from `^17.5.0` to `^17.6.0`, because this package now writes `$empty`, which `@objectstack/spec` 17.5.0 declares staged and refuses. - -The read half reads `$empty` back as the pair, with a boolean flag only. - -**What moves for a stored filter.** A stored `$exists` no longer opens as "Is empty" / "Is not empty": it opens in the Source tab, with its bytes untouched, and keeps matching what it matched before. Opening it as the pair would let an edit to ANOTHER row rewrite it to `$empty` and move `''` / `[]` across the line, which the read-half invariant (objectui#10257) forbids, and this inspector offers no `exists` row. To move such a filter to the new meaning, remove the row and add "Is empty" again. Readable stores (this repository, objectstack, hotcrm and cloud) hold no `dataset.filter` with `$exists`. diff --git a/.changeset/10813-filter-condition-empty-operator.md b/.changeset/10813-filter-condition-empty-operator.md deleted file mode 100644 index 94ab1e3ee2..0000000000 --- a/.changeset/10813-filter-condition-empty-operator.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/fields': minor ---- - -`FilterConditionField` writes "Is empty" / "Is not empty" as the spec's one 「is empty」 operator, `{ FIELD: { $empty: true } }` / `{ FIELD: { $empty: false } }` (objectui#10813). - -The widget behind sharing-rule `criteria_json`, `relatedListFilter` and `summaryOperations.filter` used to write its own meaning of 「is empty」: `{ $or: [{ FIELD: { $in: [''] } }, { FIELD: { $null: true } }] }` and its complement `{ FIELD: { $nin: [''], $null: false } }`, i.e. "no value OR `''`" on every field type. The `''` member reached a number or date column as `IN ('')`, and a multi-value column (stored as JSON by the SQL driver) as an `$in` that driver refuses. `@objectstack/spec` 17.6.0 admits `$empty` to `FILTER_OPERATORS` (objectstack#20446), and its meaning is the field's DECLARED row of the spec's per-type table (ruling B on objectstack#20311): null or `''` on a text-like field, null or `[]` on a multi-value field, null alone on every other type. Every evaluator expands it itself (`expandEmptyOperator`), so the widget now writes the same token on every column type and keeps no copy of the table. - -The `@objectstack/spec` dependency floor rises from `^17.5.0` to `^17.6.0`, because this package now writes `$empty`, which `@objectstack/spec` 17.5.0 declares staged and refuses. - -`kvToCondition` reads `$empty` back as the pair, with a boolean flag only: any other flag stays the raw criteria it is, as every evaluator refuses it. - -**What moves for a stored rule.** Reading alone rewrites nothing: a criteria saved in either earlier shape (the objectui#10790 `$or` entry and `$nin` + `$null` pair, or the older `$in: [null, '']` / `$nin: [null, '']`) still opens as the same "Is empty" / "Is not empty" row, and an un-edited rule keeps its stored bytes and keeps matching as before. The next time the criteria is edited, those rows are written as `$empty`, which re-scopes the rule: - -- text-like column: no change (both mean null or `''`); -- every other single-valued column (number, boolean, date, datetime, time, select, a single lookup): a row holding `''` is no longer "empty" and becomes "not empty". Since objectstack#20308 the write door stores a cleared number, boolean, date, datetime or time as null, so on those types only a value written before it can hold `''`; a select or lookup can still hold one, and the spec's ruled table does not count it as empty; -- multi-value column (multiselect, checkboxes, tags, or a `multiple: true` select, lookup or user): a row holding `[]` becomes "empty" and leaves "is not empty". On the SQL driver the earlier shape was refused outright, so a rule there starts running; -- the `$in: [null, '']` shapes were refused by every objectstack filter face, so a rule still in them starts running. - -Measured on the installed 17.6.0 by-value readers (`@objectstack/formula`'s `matchesFilterCondition` and `ValueDataSource`) over null, an absent key, `''`, `[]` and set values: the `$or` entry and `$empty: true` disagree only on `[]`. Readable stores (this repository, objectstack, hotcrm and cloud) hold no criteria in either earlier shape. diff --git a/.changeset/10813-list-view-empty-operator.md b/.changeset/10813-list-view-empty-operator.md deleted file mode 100644 index a4e560fea6..0000000000 --- a/.changeset/10813-list-view-empty-operator.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/plugin-list': minor ---- - -The list view's live query sends "Is empty" / "Is not empty" as the spec's `isempty` / `isnotempty` instead of an equality to `null` (objectui#10813). `@objectstack/spec` 17.6.0 and later lower that pair to `$empty`; an earlier reader lowers it to `$null`, as it does the saved view's `is_empty`. - -`convertFilterGroupToAST` resolved the pair to `[FIELD, '=', null]` / `[FIELD, '!=', null]`, a null-only test, before `mapOperator` was consulted. The same rule saved into the view is persisted as `is_empty`, which `@objectstack/spec` 17.6.0 lowers to `$empty` (objectstack#20446): so one filter panel answered two record sets, depending on whether the view had been saved. The pair now takes the value-less path like `is_null`, and `mapOperator` gains `isempty` / `isnotempty` arms. The node is `[FIELD, 'isempty', null]`; the spec discards the third slot. - -**What moves.** Nothing is stored by this path. Against a 17.6.0 or later server, on a text-like column a row holding `''` is now "empty", and on a multi-value column a row holding `[]` is, matching the server's per-type answer for the saved view. On a `provider: 'value'` list a row with no key at all is now "empty" too: the equality to `null` did not select it there. diff --git a/.changeset/10814-report-line-items-bus-readers.md b/.changeset/10814-report-line-items-bus-readers.md deleted file mode 100644 index 0fb74130a1..0000000000 --- a/.changeset/10814-report-line-items-bus-readers.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/plugin-report': patch -'@object-ui/plugin-form': patch ---- - -fix(plugin-report,plugin-form): a dataset report and an authored-parent `record:line_items` panel re-read on the data-invalidation bus - -The one fetch every dataset report presentation runs through (the tabular and -summary table, the matrix, the embedded chart, each joined block) now names the -`useDataInvalidation` nonce for the dataset's base object, the object the -query's answer names. So a write declared on the bus (`notifyDataChanged`, as a -page action over raw HTTP does) re-reads a `report` / `spec-report` block in -place: the rows on screen stay drawn until the answer replaces them, where -before the block dropped back to "Running report…". The `spec-report` a -drill-down drawer opens for `drillDown.report` re-reads the same way. A report -whose answer names no object does not subscribe. A re-read that fails shows the -error in place of the rows and keeps listening, so the next such write re-reads -the report; a first load that fails, or a new selection, listens to nothing -until an answer names its object. - -The child-row read of `record:line_items` now names the nonce for its child -object, so a panel with an authored `parentId` / `recordId` (one a stored page -holds with no record context) re-reads its lines after such a write. A re-read -of the lines on screen keeps the grid drawn, taking no input until the answer -lands. While the panel holds unsaved edits the re-read is held, and the save's -reload carries it, as for any other re-read of this panel. - -Before, both refreshed after such a write only when their host remounted them, -and `PageView` is about to stop doing that (objectui#10519). - -⚠️ **Dated note, 2026-10-02 — `spec-report` is retired — objectui#11440.** -Later in this same release `@object-ui/plugin-report` stopped registering `spec-report`, an alias of -`report`, and the drill-down drawer renders `drillDown.report` as `{ type: 'report', report }`. So -"a `report` / `spec-report` block" above now reads a `report` block, and "The `spec-report` a -drill-down drawer opens" reads the `report` node it opens; both re-read the same way. -`.changeset/11440-retire-spec-report.md` states what ships. The rest of this entry is kept as the -reading of this change. diff --git a/.changeset/10815-dashboard-block-ambient-source.md b/.changeset/10815-dashboard-block-ambient-source.md deleted file mode 100644 index ba092f1daf..0000000000 --- a/.changeset/10815-dashboard-block-ambient-source.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -fix(plugin-dashboard): a `dashboard` block on a page loads its dataset widgets, and they re-read on the data-invalidation bus - -`DashboardRenderer` read its adapter from its `dataSource` prop only. A page -renders its blocks through `SchemaRenderer`, which passes no adapter prop, so a -`dashboard` block held on a page sent no `queryDataset` call and every -dataset-bound widget showed "This data source does not support dataset -queries." although the page had a capable adapter. The renderer now resolves -its adapter the way `object-grid`, `object-form` and `detail-view` do -(`useResolvedDataSource`): the prop first, the `SchemaRendererProvider` context -second. The widgets, the filter bar's `optionsFrom` read and the drill drawers -all get that one adapter. A host with no capable adapter anywhere still sees -the alert. - -`DatasetWidget`'s query now also names the `useDataInvalidation` nonce for the -dataset's base object (the `object` its answer names), so a write declared on -the bus (`notifyDataChanged`) re-reads the tile in place. This holds on both -dashboard surfaces. The current rows stay on screen under a refresh indicator -during the re-read, not the loading skeleton. A widget whose adapter cannot run -dataset queries subscribes to nothing. diff --git a/.changeset/10816-tree-keeps-rows-on-reread.md b/.changeset/10816-tree-keeps-rows-on-reread.md deleted file mode 100644 index 0354ca3375..0000000000 --- a/.changeset/10816-tree-keeps-rows-on-reread.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/plugin-tree': patch ---- - -fix(plugin-tree): `object-tree` keeps its rows on screen while it re-reads them - -`ObjectTree` drew its "Loading…" placeholder whenever a read was in flight, so -every re-read — each data-invalidation event for its object among them — took -the table off the screen and put it back: the rows flashed, and a scrolled tree -lost its scroll offset. - -The placeholder is now drawn only while the tree has no rows for the source it -is bound to: the first load, a switch to another object or data provider, and an -empty result being re-read. A re-read of the same source keeps the rows, the -scroll container and the user's expansion choices on screen, with the shared -`RefreshIndicator` bar across the top of the tree while the read is in flight -(named through the locale's `grid.refreshing`). The previous object's rows are -never drawn under a new object or provider. diff --git a/.changeset/10817-value-source-empty-operator-map.md b/.changeset/10817-value-source-empty-operator-map.md deleted file mode 100644 index 64579ded2c..0000000000 --- a/.changeset/10817-value-source-empty-operator-map.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -'@object-ui/core': patch ---- - -`ValueDataSource.find` now refuses an object `$filter` that carries an EMPTY operator -map — `{ created: {} }`, alone, beside other keys, or inside a `$and` / `$or` member — -instead of silently dropping that field's constraint (objectui#10817). - -**Before.** The object-dialect matcher read `{ created: {} }` as an operator map with -zero operators, so the field added no constraint. `{ status: 'a', created: {} }` -answered the same rows as `{ status: 'a' }`, and `{ created: {} }` answered every row, -with no console line. The ObjectStack path refuses the same filter: `@objectstack/spec` -ruled `{ field: {} }` REJECTED wherever it appears (objectstack#5240, recorded on -`FilterConditionSchema`), and `convertFiltersToAST` refuses it alone (objectui#9164) and -beside a key that lowers (objectui#10788). - -**After.** Before any row is matched, the object arm walks the filter's field entries -and the members of `$and` / `$or`. A field whose condition is an object with no own -keys is handed to `toFilterNodeSafely` on its own, so the converter alone decides what -an empty operator map is, in its own wording. If the converter refuses it, the whole -filter answers no rows (`data: []`, `total: 0`) and the converter's reason is logged -once — the envelope the array arm already uses for a rule its lowering refuses -(objectui#10767). `find` still never rejects. `{ $or: [{ status: 'b' }, { status: 'a', -created: {} }] }` answers no rows, not the `'b'` rows. - -**Also refused, by the same routing.** Any other object with no own keys that is not a -plain object or a `Date` — a `RegExp`, `Map`, `Set`, `URL` or a class instance with no -own fields — has no own keys either. The converter refuses it as an exotic comparand -(objectui#8567), so this face now refuses it too, with the converter's wording, instead -of dropping the constraint: `{ status: 'a', created: /x/ }` used to answer the same rows as `{ status: 'a' }`. - -**Unchanged.** `{ status: 'a' }`, a real operator beside the key, the `{}` whole filter -and a `null` condition answer as before. A `Date` comparand is not refused: the -converter lowers it, so it reaches the matcher exactly as before, where its constraint -still vanishes (objectui#10829). Every other refusal -on this face — an operator the matcher does not implement, an array comparand, `$not` — -is still excluded per node with its own sentence; when the same filter also carries a -condition the walk refuses, only that refusal is logged — `{ status: ['a'], created: {} }` -logs `created`'s refusal, where the converter names `status`. - -**Clause-②: no** — the value face now refuses, in its own exclude-and-log envelope, a -shape objectstack#5240 ruled refused, and comparands the spec's -`ACCEPTED_FILTER_COMPARAND_TYPES` rules out (objectui#8567); on this face both only -ever dropped a constraint. No declared surface moves and no export is added. - -**Migration.** A filter carrying `{ field: {} }` returned more rows than it said. It is -now a named refusal. Give the field an operator, or delete the key. - -⚠️ **Dated note, 2026-09-27 — a `Date` condition now matches the rows holding that instant — objectui#10829.** Later in this same release a `Date` condition in an object `$filter` is read as implicit equality, and two `Date`s compare their instant in both arms, so `{ status: 'a', created: someDate }` answers the status-`'a'` rows whose `created` is a `Date` of that instant, the same rows as its lowered array, rather than the rows of `{ status: 'a' }`. "where its constraint still vanishes (objectui#10829)" above is this change's reading, not the release's. The rest of this entry is kept as the reading of this change; the objectui#10829 entry states what that input now answers. diff --git a/.changeset/10824-timeline-readme-schema-node.md b/.changeset/10824-timeline-readme-schema-node.md deleted file mode 100644 index 73df17b025..0000000000 --- a/.changeset/10824-timeline-readme-schema-node.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/plugin-timeline': patch ---- - -docs(plugin-timeline): the README's "Schema-Driven Usage" example is now a document the validator accepts - -The example spelled its node `component: 'timeline'`. Every node in the protocol -is keyed by `type`, so `safeValidateSchema` — the call `objectui validate` makes — -refused the document exactly as a reader would copy it (`invalid_union` at -`type`), and rendering it painted the registry's "Unknown component type" panel -instead of a timeline. The README ships in this package's tarball, so the wrong -spelling was on the npm landing page (objectui#10824). - -The node is now `type: 'timeline'`. The rest of the example already fits the item -element objectui#6356 declared — a feed item with `time`, `title`, `description` -and `variant` — so nothing else in it moves. - -A new pin extracts that block from the README on every run and feeds it to -`safeValidateSchema` and to the strict authoring face, so the example cannot drift -from the schema again without a test going red. No source or behaviour change. diff --git a/.changeset/10825-filter-builder-value-group-only.md b/.changeset/10825-filter-builder-value-group-only.md deleted file mode 100644 index 7446155f5e..0000000000 --- a/.changeset/10825-filter-builder-value-group-only.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/types': minor ---- - -fix(types)!: a `filter-builder` `value` is a filter group only, and `defaultValue` is retired (objectui#10825) - -⚠️ **BREAKING (authoring)**, marked `minor` under this repository's version-alignment rule (a `major` in the fixed group would move all of it off the `@objectstack` major). A `filter-builder` node that authors a bare condition as its `value`, or that authors `defaultValue` at all, now FAILS to validate, and a TypeScript literal that authors `defaultValue` no longer compiles. - -**Clause-②: yes (narrowing)** — an authorable key of `FilterBuilderSchema` stops accepting a bare condition, and `defaultValue` retires on both published faces. - -- **`value` takes a group only.** The zod mirror took `union([condition, group])` while the TypeScript face declares `value?: FilterGroup`, so the validator was wider than the published type. A bare condition `{ id, field, operator, value }` validated, and `FilterBuilder` then drew an empty builder: its `isValidGroup` gate needs `logic` and `conditions`, so it fell back to its empty group with no error, and the condition was lost. The mirror now follows the published type. A value that carries a condition's own `field` or `operator` and no `conditions` is refused by name: ONE `custom` issue at `value`, whose message says to wrap it in `{ logic, conditions: [ … ] }`. That message is also the published description of `value`. Every other value is judged by `FilterGroupSchema`, as a group always was. -- **Group refusals are reported where they are.** With the condition arm gone, `value` is no longer a union, so a refusal inside a group is reported at its own path: an id-less row is `invalid_type` at `value.conditions.0.id`, where it used to be one `invalid_union` at `value`. -- **`defaultValue` is retired.** Nothing read it: the `filter-builder` registration hands `FilterBuilder` `schema.value || props.value`, and `FilterBuilder` has no `defaultValue` prop. Measured through the real `SchemaRenderer`, a group authored as `defaultValue` drew the same empty builder as a node with no filter key at all. It is a `?: never` tombstone on the TypeScript face and a `retirementTombstone()` arm on the mirror, an `invalid_type` issue at the key whose message points at `value`. It stays declared because the node is `.passthrough()`, so a deleted key would be kept in silence. - -**Migration:** wrap a bare condition in a group, `{ "logic": "and", "conditions": [ … ] }`, with the condition as its one row, and author a `defaultValue` group as `value` instead. A one-time reading on the pull request, not re-derived here: every `filter-builder` node authored in this repository's examples and docs already writes a group as `value`, and none writes `defaultValue`. Stored tenant metadata was not measured (it cannot be read from this repository); a bare-condition `value` there draws an empty builder today and is refused on its next validation. - -Pinned in `packages/types/src/__tests__/filter-builder-value-group-only-10825.test.ts`. diff --git a/.changeset/10827-app-branding-logo-one-spelling.md b/.changeset/10827-app-branding-logo-one-spelling.md deleted file mode 100644 index 6f978e16b5..0000000000 --- a/.changeset/10827-app-branding-logo-one-spelling.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/layout': patch -'@object-ui/app-shell': patch -'@object-ui/runner': patch ---- - -An app's `branding.logo` now shows in the console, and it is the only logo spelling -(objectui#10827). - -**The console renders it.** The designer (`AppCreationWizard`, `BrandingEditor`) writes an -app's `branding.logo` and previews it, but nothing mounted in the console drew it. Its only -reader was `AppSidebar`, which was never mounted and has since been removed. `UnifiedSidebar`, -the console's sidebar, now reads the active app's `branding.logo` and shows it as an image in a -header at the top of the sidebar. The image's alt text is the app's label. An app without a -logo gets no header, so its sidebar looks the same as before. The header appears only inside -an app. On Home the sidebar's fallback app is not the screen's app, so no logo is shown there. -`AppShellBranding` is unchanged: objectui#4818 removed its `logo` key, and this change does not -add it back. - -**One spelling — breaking for a top-level `logo`.** `@objectstack/spec` declares the app logo -only as `branding.logo` (a URL). Its app schema refuses a top-level `logo` and suggests -`branding`. objectui had a second spelling of its own: `AppComponentSchema.logo`, described as -"Logo URL or icon name". This change retires it: - -- `@object-ui/types`: `AppComponentSchema.logo` is now `never` on the TypeScript face, and the - zod mirror refuses a top-level `logo` by name, answering "Did you mean `logo` → `branding`?". - It is a named refusal rather than a deletion because the node is `.passthrough()`, and a - deleted key would be kept without any error. `wizardDraftToAppSchema` no longer copies the - draft's logo to the top level. The logo goes into `branding` only. -- `@object-ui/layout`: `AppSchemaRenderer`'s default sidebar header draws `branding.logo` as - an image. This includes site-relative paths and `data:` URIs, which the old read skipped - because it drew an image only for values starting with `http`. The header's icon now comes - from the app's `icon`. -- `@object-ui/runner`: `LayoutRenderer`'s sidebar brand mark does the same. It draws - `branding.logo` as an image and takes an icon name from `icon`. It no longer guesses the kind - of value from a `/` or `.`. - -Migration: move a top-level `logo` URL to `branding: { logo: '…' }`. An icon name that was -written as `logo` belongs in `icon`. The published 17.6.0 changelog entry that removed -`AppShellBranding.logo` says the top-level `logo` is "rendered directly by -`AppSchemaRenderer`'s default sidebar header". That is no longer true: the header reads -`branding.logo`. diff --git a/.changeset/10829-value-source-date-comparand.md b/.changeset/10829-value-source-date-comparand.md deleted file mode 100644 index 7466a75ee4..0000000000 --- a/.changeset/10829-value-source-date-comparand.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -'@object-ui/core': patch ---- - -`ValueDataSource.find` now answers a `Date` equality or membership test with the rows -holding that instant as a `Date`, in both filter dialects (objectui#10829). The object -dialect used to drop an implicit `Date` equality, and every explicit equality or -membership test compared a `Date` by identity. - -**Before — the object dialect.** The object-dialect matcher sent every object condition -that is not an array to its operator branch. A `Date` has no own keys, so the operator -loop ran zero times and the field added no constraint: `{ status: 'a', created: someDate }` -answered the same rows as `{ status: 'a' }`, and `{ created: someDate }` answered every -row, with no console line. `convertFiltersToAST` lowers the same filter to -`['created', '=', someDate]` (objectui#8555), because `@objectstack/spec`'s -`ACCEPTED_FILTER_COMPARAND_TYPES` includes `Date`. - -**Before — both dialects.** Every equality and membership position compared with `===`, -and membership with `includes`, so a `Date` was compared by identity. The adapter clones -the rows it is constructed with, so none of those rows held the comparand's instance: -over them `['created', '=', someDate]`, `{ created: { $eq: someDate } }` and -`$in: [someDate]` matched nothing, not even the row holding that exact instant, while -`$gte` and `$lte` both matched it, and `!=`, `$ne` and `$nin` selected every one of -them. Only a row written through `create` or `update`, which copy the record shallowly, -could hold the caller's own instance and match it by identity. - -**After.** A condition the spec's `isAcceptedFilterComparand` accepts takes the -object dialect's implicit-equality branch, the predicate the converter lowers a `Date` -through; today a `Date` is its only object-typed member. One equality helper serves -implicit equality, `$eq` / `$ne` / `$in` / `$nin` and the AST `=` / `!=` / `in` / `nin`: -when the stored value and the comparand are both `Date` instances it compares -`getTime()`, and an invalid `Date` equals nothing. So an object filter answers what its -lowered array answers, and `=`, `$gte` and `$lte` agree on one instant. - -**Unchanged.** A `Date` comparand is not coerced to another storage form: a row holding -the same instant as an ISO string or as epoch milliseconds does not equal it. -`@objectstack/spec`'s `FILTER_COMPARAND_TYPE_CASES` declines to assert a `Date` row set, -because what it matches "legitimately differs per storage form (ADR-0053)". `$gt` / -`$gte` / `$lt` / `$lte` / `$between` compare a `Date` by its number, as before. Every -other comparand keeps `===`. The one value where membership moves is the number `NaN`: -`includes` found a stored `NaN` in `[NaN]` and `===` does not, so `$in: [NaN]` and -`['x', 'in', [NaN]]` no longer match a stored `NaN`, and `$nin` / `nin` now keep that -row, agreeing with `{ x: NaN }` and `$eq`, which never matched it. - -**Clause-②: no** — the value face stops dropping a `Date` constraint that -`@objectstack/spec`'s `ACCEPTED_FILTER_COMPARAND_TYPES` accepts and the converter lowers -to equality; no declared surface moves and no export is added. diff --git a/.changeset/10835-dashboard-preview-debug-run-locale.md b/.changeset/10835-dashboard-preview-debug-run-locale.md deleted file mode 100644 index 56fa8e9deb..0000000000 --- a/.changeset/10835-dashboard-preview-debug-run-locale.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the dashboard designer's preview canvas and the flow Debug run read the designer locale (objectui#10835) - -Under zh-CN these designer words stayed English beside Chinese headings: - -- the dashboard preview canvas: the empty-canvas message, the hint under a widget - that fails to render, the loading text, and the selected-widget strip (its - "Selected" chip, the rename tooltip, the untitled fallback and the save, rename - and clear-selection buttons' accessible names); -- the flow Debug run: every note and error sentence the simulator itself writes on a step (a wait, a - screen with or without inputs, an approval and its decision, a decision branch, - an assignment's unmodelled tokens, a loop, a mocked call, an unsupported node, - the end, and the routing notes), each step's status chip, and an out-edge's - error result. A screen step that names a field whose `visibleWhen` refers to - something that is not a field on the screen now gives that reason in the same - words the flow inspector's note uses. - -Each new en row is the English the literal carried, so en renders unchanged. A -widget's stored title (a new widget's default `New TYPE` title included) is author -data and shows as written in every locale. Node labels, ids and types, branch -labels, CEL sources, a guard's `true` / `false` value, and the parse and shape -refusals that `@objectstack/formula` and `@objectstack/spec` write still pass -through as they are. The frames the Debug run's CEL evaluation puts around such a refusal — "condition failed to evaluate as CEL: ", "CEL evaluation failed: " and the "Evaluation failed." fallback, written by flow-sim-validate — and the default edge's else keyword stay English under zh-CN; they are outside this change. diff --git a/.changeset/10841-timeline-root-dom-props.md b/.changeset/10841-timeline-root-dom-props.md deleted file mode 100644 index b6e1bc9ba6..0000000000 --- a/.changeset/10841-timeline-root-dom-props.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -'@object-ui/plugin-timeline': patch ---- - -A `plugin-timeline:timeline` node no longer writes its own schema onto the -page as HTML attributes (objectui#10841). - -`TimelineRenderer` collected every prop it did not name and spread them onto -the root element of each variant. Created through `SchemaRenderer`, that bag -holds every node key left after `SchemaRenderer` strips its metadata keys, so -the rendered timeline carried `items="[object Object]"`, `variant="vertical"`, -`dateformat="long"` and, on a gantt, `scale` / `rowlabel` / `mindate` / -`maxdate`. React also logged an unknown-prop warning for each camelCase key. -The renderer reads all of those keys off `schema`, so nothing it draws -changes. - -The root now takes the same route as the converged renderers in -`@object-ui/components`: the bag goes through `toDomProps`, the SDUI widget -contract's DOM pass-through in `@object-ui/core`, and `style` is forwarded by -name. That keeps the `data-obj-id` / `data-obj-type` locator, the -`data-testid` an authored `testId` promises, the resolved `aria-*` / `role`, -`id`, `tabIndex`, and the host event handlers that contract forwards -(`dom-props.ts` declares the full set). - -Dropped, and no longer on the root: - -- every authored schema key; -- the `disabled` attribute a disabled node used to put on the `ol` / `div` - root, where it had no effect; -- `name` / `label`, which `BaseSchema` declares but which have no effect on an - `ol` / `div`; -- an authored `title`, which the timeline node does not declare. It is a - global HTML attribute, so dropping it removes the native tooltip it used to - put on the root. - -`ObjectTimeline` hands `TimelineRenderer` its schema alone, so the object-bound -timeline is unchanged. The prop type is unchanged. diff --git a/.changeset/10842-wizard-app-declared-keys.md b/.changeset/10842-wizard-app-declared-keys.md deleted file mode 100644 index 8484738ebf..0000000000 --- a/.changeset/10842-wizard-app-declared-keys.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/layout': patch -'@object-ui/plugin-designer': patch ---- - -The Studio's app wizard saves an app the platform accepts, and the app favicon has one -spelling, `branding.favicon` (objectui#10842). - -**Creating an app is no longer refused.** The console's "create app" and "edit app" pages save through -`client.meta.saveItem('app', …)`, and the platform judges that document with -`@objectstack/spec`'s strict `AppSchema`. `wizardDraftToAppSchema` wrote four top-level keys the -spec does not declare (`type`, `title`, `favicon` and `layout`), so the save was refused with -`422 INVALID_METADATA` (`unrecognized_keys`). It now writes only declared keys: the draft's -title as `label`, the logo and favicon inside `branding`, and no `type` or `layout`. The spec -has no app layout, so the wizard's layout choice is not saved. - -- `@object-ui/types` — **breaking:** `wizardDraftToAppSchema` now returns the app document - (the spec's `App` shape, with objectui's `NavigationItem[]` as `navigation`) instead of an - `AppComponentSchema` renderer node. It has no `type`, `title`, top-level `favicon` or `layout`. - Code that read `result.title` reads `result.label`. Code that fed the result to - `AppSchemaRenderer` builds the renderer node itself (`type: 'app'`, `title`). -- `@object-ui/types` — **breaking:** `AppComponentSchema.favicon` is now `never` on the - TypeScript face, and the zod mirror refuses a top-level `favicon` by name, answering "Did you - mean `favicon` → `branding`?". This is the objectui#10827 rule that retired the top-level - `logo`: the spec refuses the key, and the console reads only `branding.favicon`. -- `@object-ui/layout`: `AppSchemaRenderer` puts `branding.favicon` on the tab. It read the - top-level `favicon` before, and never `branding.favicon`. -- `@object-ui/plugin-designer`: `EditAppPage` keeps the keys the wizard does not maintain, but - only keys the spec's `AppSchema` declares, read from that schema. A row stored before the - schema closed is served with the old wizard's top-level keys, and echoing them made every - edit of such an app fail the same way. Its pre-fill no longer falls back onto a top-level - `logo`, `favicon` or `title`; it reads `branding.logo`, `branding.favicon` and `label`. - -Migration: move a top-level `favicon` URL to `branding: { favicon: '…' }`. - -⚠️ **Dated note, 2026-09-28 — the wizard has no layout choice — objectui#10867.** -Later in this same release the wizard's Layout control was removed, with `AppWizardDraft.layout`, so there is no -layout choice left to not save. The rest of this entry still holds. diff --git a/.changeset/10843-dashboard-custom-range-reopen.md b/.changeset/10843-dashboard-custom-range-reopen.md deleted file mode 100644 index 485a16a795..0000000000 --- a/.changeset/10843-dashboard-custom-range-reopen.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -The dashboard date filter's "Custom…" item now opens the range calendar, -including over a stored custom range, and the calendar stays open -(objectui#10843). - -Two defects, both measured in Chromium. With a custom range stored, the -select's value already is the "Custom…" item, and Radix Select reports a pick -only when it changes the value, so picking it again did nothing: a stored range -could not be reopened for editing. From a preset, picking "Custom…" from the -list did open the calendar, but the select then returned focus to its trigger, -and focus leaving the calendar's popover dismissed it as soon as the select -finished closing. - -Picked from the list (pointer, touch, Enter or Space), "Custom…" now opens the -calendar whether the value changes or not, and only after the list has closed, -so the calendar keeps focus. Typing its first letter on the focused, closed -select still opens the calendar when that changes the value (from a preset or -"All time"), as it did before this change. A stored range reopens on the month -of its first day. Closing the calendar with Escape returns focus to the date -select. Closing the select without picking "Custom…" (Escape, a click outside) -still opens nothing, and picking a preset commits it as before. diff --git a/.changeset/10844-date-only-zone-closure.md b/.changeset/10844-date-only-zone-closure.md deleted file mode 100644 index 03d2618e3d..0000000000 --- a/.changeset/10844-date-only-zone-closure.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch -'@object-ui/components': patch -'@object-ui/plugin-report': patch ---- - -fix(plugin-dashboard,components,plugin-report): three more read sites show the day a stored date-only value names, in every zone (objectui#10844) - -Each read below parsed a date-only `YYYY-MM-DD` string with the engine's own `Date` -parse, which reads it as UTC midnight. West of UTC that is the evening before, so -each face showed the previous day. Each now reads the value through `toDisplayDate` -(`@object-ui/core`), which rebuilds a date-only string at local midnight of the day it -names. For a real day, a viewer in UTC or east of it sees no change. - -- **Dashboard date filter, custom range.** The range calendar highlighted the day - before each stored bound and could open on the previous month: clicking 15 Sep stored - `2026-09-15` and then highlighted the 14th. It now highlights and opens on the stored - days. A bound naming a day its month does not have (`2026-02-30`) no longer rolls - into March: it selects no day, and a `from` like that opens the calendar on today, as - an unparseable `from` already did. -- **`date-picker` renderer, an ISO string `value`.** An authored or bound - `value: '2024-01-15'` was labelled "January 14th, 2024" and selected the 14th. It now - labels and selects the 15th. Only a date-only string naming a real day is read this - way: a `Date`, a date-time string and any other string reach date-fns exactly as - before. So an unparseable string still makes the trigger's `format` throw, as it did - before, and a date-only string naming a nonexistent day is still rolled forward - rather than refused, because refusing it would make `format` throw where it rendered - before. -- **Report cell date face (`formatValue`).** The `yyyy-MM-dd` face `ReportViewer` gives - an untyped ISO-looking value and an aggregated column read `2026-09-14` for a stored - `2026-09-15`. It now reads `2026-09-15`. A value naming a nonexistent day now renders - as the raw stored string, this face's existing answer for an unparseable value, - instead of a rolled-forward day. - -A date-time value (one with a time part) still renders in the viewer's zone at every -site. diff --git a/.changeset/10847-dashboard-strip-i18n-title.md b/.changeset/10847-dashboard-strip-i18n-title.md deleted file mode 100644 index 918a291f74..0000000000 --- a/.changeset/10847-dashboard-strip-i18n-title.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): selecting a dashboard widget whose title is a per-locale map no longer crashes the designer canvas - -`DashboardWidget.title` is the spec's `I18nLabel`, so it can be a string or an -inline per-locale map such as `{ 'en-US': 'Revenue', 'zh-CN': '收入' }`. The -dashboard designer's selected-widget strip rendered the stored value as a React -child. Selecting a widget with a map title threw "Objects are not valid as a -React child", and the whole preview was replaced by "Preview failed to render". - -The strip now resolves the title with the spec's `resolveI18nLabel` in the -designer locale. That is the call the preview already makes for the selection -label, and the rename draft is seeded from the same string. The inline rename -saves through `setLocalized`, the same write the widget inspector's title field -uses. For a map title it replaces the entry the designer locale resolves to -within its own language (the exact tag, else the base language, else a regional -variant of it). When the map has no entry in that language, it adds one under -the designer locale. Every other locale is kept. A plain-string title stays a -plain string. The inspector's title field edits that same entry through the same -read/write pair; editing every locale from one surface is still an open question. diff --git a/.changeset/10848-designer-preview-chrome-locale.md b/.changeset/10848-designer-preview-chrome-locale.md deleted file mode 100644 index ebdf2cce07..0000000000 --- a/.changeset/10848-designer-preview-chrome-locale.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the preview error heading, the flow screen preview and the Debug run's CEL error frames read the designer locale (objectui#10848) - -Under zh-CN these designer words stayed English beside Chinese text: - -- the heading "Preview failed to render" that every designer preview's error - boundary shows above the thrown message; -- the flow screen preview, in the flow node inspector and in the Debug run's - paused screen: its "Preview" header, the text shown while a screen has nothing - configured, the disabled "Submit" button, the note shown when an object-form - screen has no backend to preview against, and the note counting fields hidden - by their "visible when" condition; -- the frames the Debug run puts around a CEL failure on a step or an out-edge - ("condition failed to evaluate as CEL: ", "CEL evaluation failed: "), and the - "Evaluation failed." fallback when the failure carries no message. - -Each new en row is the English the literal carried, so en renders unchanged. The -text inside a CEL frame is the expression engine's own and passes through as it -is, as does the message a failing preview threw. A screen's title, description -and field labels are author data and show as written in every locale. diff --git a/.changeset/10853-master-detail-picker-bus-readers.md b/.changeset/10853-master-detail-picker-bus-readers.md deleted file mode 100644 index 731965aa32..0000000000 --- a/.changeset/10853-master-detail-picker-bus-readers.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -'@object-ui/plugin-form': patch -'@object-ui/components': patch ---- - -fix(plugin-form,components): an edit-mode `object-master-detail-form`'s detail lines and `element:record_picker`'s options re-read on the data-invalidation bus - -An `object-master-detail-form` in edit mode now reads the bus for each detail -collection's child object: a write declared there (`notifyDataChanged`, as a -page action over raw HTTP does), or an unscoped `'*'`, re-reads that -collection's lines in place, and the rows and the baseline the next save diffs -against move together. A collection only re-reads for its own child object. The -header already re-read through its own form. While a collection holds lines the -user has changed since they were last read or saved (compared the way the save -compares rows, with the link to the parent set aside), or while the row editor -("Open row") is open on it, its re-read is held. It runs once, when the row -editor is closed and either the lines have been changed back or this form's -save has landed. A line typed while a re-read is in flight, in the grid or in -the row editor, is kept, and the re-read is held behind it; an open row editor -is never reset by a re-read. A re-read that fails keeps the lines on screen. -`object-form` with `subforms`, which renders the same form, re-reads the same -way. - -`element:record_picker` now re-reads its options when the bus reports a write to -the object it queries. The re-read keeps the control enabled over the options on -screen (no "Loading…") and never touches the bound page variable. If the bound -record is no longer among the options, the variable keeps its value and the -control shows no label until a later read offers that record again. - -Before, both refreshed after such a write only when their host remounted them, -and `PageView` is about to stop doing that (objectui#10519). diff --git a/.changeset/10859-ai-node-zod-arms.md b/.changeset/10859-ai-node-zod-arms.md deleted file mode 100644 index c6fd028ac4..0000000000 --- a/.changeset/10859-ai-node-zod-arms.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`safeValidateSchema` — and so `objectui validate` — accepts the three `@object-ui/plugin-ai` node types, `ai-form-assist`, `ai-recommendations` and `nl-query` (objectui#10859, batch 1). - -**Clause-②: yes** — the accept set of `AnyComponentSchema` widens by three `type` literals, and `@object-ui/types/zod` exports eight new schemas. Nothing that parsed before is refused now. - -**What it was.** All three types are registered by `@object-ui/plugin-ai`, declared on the published TypeScript face (`AIFormAssistSchema`, `AIRecommendationsSchema`, `NLQuerySchema`) and taught by that package's README. `AnyComponentSchema` carried no arm for any of them, so every document naming one was refused with `invalid_union` at `type` — the README's own `{ "type": "ai-form-assist", "showConfidence": true, "showReasoning": true }` included, which `objectui validate` reported as "Schema validation failed". - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `AIFormAssistSchema`, `AIRecommendationsSchema`, `NLQuerySchema`, their sub-schemas `AIConfigSchema`, `AIFieldSuggestionSchema`, `AIRecommendationItemSchema` and `NLQueryResultSchema`, and the category union `AIComponentSchema`, which `AnyComponentSchema` now lists. The strict authoring face (`StrictAnyComponentSchema`) derives from `AnyComponentSchema` and accepts the same three types, closed to undeclared keys like every other arm. -- Each arm restates its TypeScript declaration member for member. The objectui#8178 retired members (`formId`, `objectName`, `fields`, `autoFill`, `maxResults`) and both content channels (objectui#9256) are refused by name, as they already were on the TypeScript face. -- ⚠️ The `on*` members are the one place the two faces differ. The TypeScript face still types `onApplySuggestion`, `onRejectSuggestion`, `onSelect`, `onDismiss` and `onSubmit` as `string`; the zod face refuses an authored value on each, by name, following objectui#6182 (the handler-expression string dialect is not an authoring form) and objectui#6124 (`onSelect` / `onDismiss` / `onSubmit` are runtime slots a React host fills; the other two have no reader). An authored string was never a working handler: `onSelect`, `onDismiss` and `onSubmit` are called only as function props a React host passes, and `onApplySuggestion` / `onRejectSuggestion` are read by nothing — delete the key from the document. The TypeScript face's `string` typing is objectui#10874's to correct. - -⚠️ **Dated note, 2026-09-28 — the TypeScript face now types the `on*` members per key, and `config` / `context` are refused — objectui#10874.** -Later in this same release the TypeScript face settles the five `on*` members by the objectui#6124 -rule, so the `string` typing described above is gone. `onSelect`, `onDismiss` and `onSubmit` are typed -as the callables their components invoke: the objectui#6124 shape, a callable twin beside the named -refusal this entry added. `onApplySuggestion` and `onRejectSuggestion` are `?: never`, so both faces -refuse those two. The same change retires `config` (all three types) and `context` (`ai-form-assist`, -`ai-recommendations`) on both faces, so `safeValidateSchema` — and `objectui validate` — refuses a -document that carries one of them, by name, where the arms this entry added accepted it. The rest of -this entry is kept as the reading of this change; the objectui#10874 entry states what ships. diff --git a/.changeset/10859-console-phase-2b-stubs.md b/.changeset/10859-console-phase-2b-stubs.md deleted file mode 100644 index cd11d110ef..0000000000 --- a/.changeset/10859-console-phase-2b-stubs.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/console': minor ---- - -chore(console)!: drop the lazy `scatter-chart` and `dashboard-grid` stubs, and stop the `metric` / `metric-card` stubs claiming the bare key (objectui#10859, batch 8 phase 2b) - -**BREAKING (authoring):** the console no longer registers lazy stubs for `scatter-chart` (`@object-ui/plugin-charts`) or `dashboard-grid` (`@object-ui/plugin-dashboard`), which those packages retired. The `metric` / `metric-card` stubs, in `register-plugins.ts` and in the dev-only preview gallery, now pass `skipFallback: true`, like the registrations they stand in for, so only `plugin-dashboard:metric` / `plugin-dashboard:metric-card` resolve before the chunk loads. - -Migration: - -- `scatter-chart` → `{ "type": "chart", "chartType": "scatter" }`; -- `dashboard-grid` → `dashboard`; -- a standalone `metric` / `metric-card` node → `plugin-dashboard:metric` / `plugin-dashboard:metric-card`. - -**Clause-②: yes**, released as `minor` with this banner. diff --git a/.changeset/10859-console-phase-2c-stubs.md b/.changeset/10859-console-phase-2c-stubs.md deleted file mode 100644 index 56641a95b9..0000000000 --- a/.changeset/10859-console-phase-2c-stubs.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/console': minor ---- - -chore(console)!: drop the lazy `pie-chart`, `donut-chart` and `radar-chart` stubs (objectui#10859, batch 8 phase 2c) - -**BREAKING (authoring):** the console no longer registers lazy stubs for `pie-chart`, `donut-chart` or `radar-chart` in `register-plugins.ts`, nor for `pie-chart` in the dev-only preview gallery. `@object-ui/plugin-charts` retired those keys. `chart`, `object-chart`, `bar-chart` and `chart:bar` stay lazily registered. - -Migration: - -- `pie-chart` / `donut-chart` / `radar-chart` → `{ "type": "chart", "chartType": "pie" | "donut" | "radar" }`. - -**Clause-②: yes**, released as `minor` with this banner. diff --git a/.changeset/10859-console-tree-stub.md b/.changeset/10859-console-tree-stub.md deleted file mode 100644 index d746cc27c0..0000000000 --- a/.changeset/10859-console-tree-stub.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/console': minor ---- - -chore(console)!: drop the lazy `tree` registration stub (objectui#10859, batch 8) - -**BREAKING (authoring):** the console no longer registers a lazy `tree` stub for `@object-ui/plugin-tree`, which retired that key. `object-tree` stays lazily registered. - -Migration: - -- `{ "type": "tree", … }` → `{ "type": "object-tree", … }`. - -**Clause-②: yes**, released as `minor` with this banner. diff --git a/.changeset/10859-dashboard-node-keys.md b/.changeset/10859-dashboard-node-keys.md deleted file mode 100644 index 762b148718..0000000000 --- a/.changeset/10859-dashboard-node-keys.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/plugin-dashboard': minor ---- - -refactor(plugin-dashboard)!: retire the `dashboard-grid` node type key, and register the `metric` / `metric-card` node keys without a bare fallback (objectui#10859, batch 8 phase 2b) - -**BREAKING (authoring):** - -- **`dashboard-grid` is unregistered** (with `plugin-dashboard:dashboard-grid`). It was builder chrome published as a node key: `objectui validate` refused it at `type`, and nothing authored or emitted it. `DashboardGridLayout` stays a named export; mount it directly. -- **`metric` and `metric-card` register with `skipFallback: true`.** Both dashboard surfaces (`DashboardRenderer`, `DashboardGridLayout`) now hand `SchemaRenderer` `plugin-dashboard:metric` / `plugin-dashboard:metric-card` through one table, `DASHBOARD_NODE_TYPES` in `widgetDispatch.ts`. That covers the static metric tile, the `metric-card` widget-slot entry and a `metric` / `metric-card` node in a widget's legacy `component` envelope. The dashboard WIDGET vocabulary is unchanged: `widgets[].type: 'metric'` and the 2026-08-14 `metric-card` slot entry author exactly as before. -- **`dashboardComponents`** drops `dashboard-grid`, and its `metric` / `metric-card` entries are keyed `plugin-dashboard:metric` / `plugin-dashboard:metric-card`, the type each now serves, so iterating the map cannot re-create the retired bare keys. -- A rendered KPI tile's `data-obj-type` reads `plugin-dashboard:metric` (or `plugin-dashboard:metric-card`) instead of the bare spelling. - -Migration: - -- `{ "type": "dashboard-grid", "widgets": [ … ] }` → `{ "type": "dashboard", "widgets": [ … ] }`, or mount `DashboardGridLayout` directly for the drag/resize editor. -- a standalone `{ "type": "metric", … }` node → `{ "type": "plugin-dashboard:metric", … }`; inside a dashboard, keep authoring the `metric` widget. -- a standalone `{ "type": "metric-card", … }` node → put it in a dashboard's `widgets[]` (the slot entry), or write `plugin-dashboard:metric-card`. -- `dashboardComponents['metric']` / `dashboardComponents['metric-card']` → `dashboardComponents['plugin-dashboard:metric']` / `dashboardComponents['plugin-dashboard:metric-card']`; `dashboardComponents['dashboard-grid']` → import `DashboardGridLayout`. -- a selector `[data-obj-type="metric"]` / `[data-obj-type="metric-card"]` → `[data-obj-type="plugin-dashboard:metric"]` / `[data-obj-type="plugin-dashboard:metric-card"]`. - -**Clause-②: yes** — registrations leave the runtime (narrowing), released as `minor` with this banner. - -⚠️ **Dated note, 2026-10-02 — `metric-card` leaves the widget vocabulary — objectui#11483.** At this change, "The dashboard WIDGET vocabulary is unchanged" held, and that vocabulary named `metric-card`. Now the widget `type` vocabulary (`DashboardWidgetTypeSchema` / `DashboardWidgetTypeName`) names no component type. The `metric-card` slot entry is still authored as before when it carries its `value`; without one it is refused. `.changeset/11483-metric-card-needs-value.md` states what ships. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10859-designer-zod-arms.md b/.changeset/10859-designer-zod-arms.md deleted file mode 100644 index c3eab27496..0000000000 --- a/.changeset/10859-designer-zod-arms.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types): the six `@object-ui/plugin-designer` node types validate; `ProcessDesignerSchema.variables` and `ReportDesignerSchema.parameters` leave the TypeScript face (objectui#10859, batch 7) - -**BREAKING (authoring):** `ProcessDesignerSchema` no longer declares `variables`, and `ReportDesignerSchema` no longer declares `parameters`. Nothing reads either key: `ProcessDesigner` and `ReportDesigner` take neither as a prop, and a node that carried one drew exactly what it drew without it. Nothing in this repository authored either one. - -Migration: delete `variables` from your `process-designer` nodes and `parameters` from your `report-designer` nodes. Neither reaches the screen, so removing it changes nothing a user sees. TypeScript code that read `schema.variables` or `schema.parameters` off one of these types now reads the `BaseSchema` index signature (`any`) instead of the old array type. The strict authoring face refuses either key as an unrecognized key on these nodes; `safeValidateSchema` passes it through, as it does any undeclared key. - -**Clause-②: yes** — `@object-ui/types/zod` accepts six registered node types it refused at `type` before (a widening), and the TypeScript face narrows by two members. Released as `minor` under the objectui narrowing rule, with this banner. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `PageDesignerSchema`, `DataModelDesignerSchema`, `ProcessDesignerSchema`, `ReportDesignerSchema`, `ObjectManagerSchema` and `FieldDesignerSchema`, each a mirror of its TypeScript declaration in `designer.ts`, and the mirrors of the record types those nodes hold (`DesignerComponentSchema`, `DesignerCanvasConfigSchema`, `BPMNNodeSchema`, `ReportDesignerSectionSchema`, `ObjectDefinitionSchema`, `DesignerFieldDefinitionSchema` and the rest). They reach `AnyComponentSchema` through `DesignerUnionSchema`, so `safeValidateSchema`, `validateSchema`, the strict authoring face and `objectui validate` now judge a designer node by its own members instead of refusing it with `invalid_union` at `type`. -- Each arm requires what its declaration requires (for example `processName`, `nodes` and `edges` on `process-designer`), and refuses `body` and `children` by name, because none of the six components reads a content channel (objectui#9256). -- Four declared members that no designer reads are NOT on the arms: `autoLayout` on `data-model-designer`, `lanes` and `version` on `process-designer`, and `previewMode` on `report-designer`. They stay declared on the TypeScript face. The strict face refuses them as unrecognized keys, and the tolerant face passes them through unjudged. - -⚠️ **Dated note, 2026-10-02 — two of the four unmirrored members, and seven members in all, are retired in this release — objectui#11434.** -Later in this same release objectui#11434 retired `autoLayout` (`data-model-designer`) and `previewMode` (`report-designer`) on both faces: each is now a `?: never` tombstone on the TypeScript face and refused BY NAME on the arms, not as an unrecognized key. The same change retired the record members `DesignerComponent.parentId`, `DataModelRelationship.onUpdate`, `BPMNNode.serviceEndpoint`, `ObjectDefinition.relationships` and `DesignerFieldDefinition.validationRules`, and removed the record mirrors `ObjectDefinitionRelationshipSchema` and `DesignerValidationRuleSchema` with their types. `lanes` and `version` on `process-designer` are still unmirrored. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-02 — `lanes` and `version` on `process-designer` are mirrored in this release — objectui#11434.** -Later still in this same release, objectui#11434 gave `ProcessDesigner` a reader for both (the toolbar draws `version` beside the process name, and each lane in `lanes` is a band around the nodes it names) and mirrored them on the arm, with a `BPMNLaneSchema` record mirror. The strict face accepts both now and judges each lane's members, so none of the four members above stays unmirrored. The rest of this entry, and the note above, are kept as the readings of their changes. diff --git a/.changeset/10859-known-types-phase-2b.md b/.changeset/10859-known-types-phase-2b.md deleted file mode 100644 index f58db79946..0000000000 --- a/.changeset/10859-known-types-phase-2b.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/cli': minor ---- - -chore(cli)!: the generated known-types list drops the twelve node type keys objectui#10859 batch 8 phase 2b retired - -**BREAKING (authoring):** `KNOWN_SCHEMA_TYPES` (regenerated from the registration calls) no longer lists `scatter-chart`, `dashboard-grid`, `form-analytics`, `import-wizard`, `shared-view-link`, `app-creation-wizard`, `branding-editor`, `dashboard-editor`, `navigation-designer` or `related-list`, nor their namespaced twins, and no longer lists the bare `metric` / `metric-card` (their `plugin-dashboard:` keys stay). `objectui check` now reports a root document of one of those types as an unknown type, and `objectui validate` keeps refusing it at `type`, as it already did. - -Migration: - -- `scatter-chart` → `chart` with `chartType: "scatter"`; -- `dashboard-grid` → `dashboard`; -- `related-list` → `record:related_list`; -- `metric` / `metric-card` as a standalone node → `plugin-dashboard:metric` / `plugin-dashboard:metric-card` (inside a dashboard, keep the widget spelling); -- `form-analytics`, `import-wizard`, `shared-view-link`, `app-creation-wizard`, `branding-editor`, `dashboard-editor`, `navigation-designer` → mount the exported React component directly. - -The registered-types ratchet (`REFUSED_AT_TYPE`) falls from 36 to 24, and its namespaced twin from 389 to 379. - -**Clause-②: yes**, released as `minor` with this banner. diff --git a/.changeset/10859-known-types-phase-2c.md b/.changeset/10859-known-types-phase-2c.md deleted file mode 100644 index f994e60f2f..0000000000 --- a/.changeset/10859-known-types-phase-2c.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/cli': minor ---- - -chore(cli)!: the generated known-types list drops the four node type keys objectui#10859 batch 8 phase 2c retired - -**BREAKING (authoring):** `KNOWN_SCHEMA_TYPES` (regenerated from the registration calls) no longer lists `pie-chart`, `donut-chart`, `radar-chart` or `page-header`, nor their namespaced twins (`plugin-charts:pie-chart`, `plugin-charts:donut-chart`, `plugin-charts:radar-chart`, `layout:page-header`, `protocol-placeholder:page-header`). `objectui check` now reports a root document of one of those types as an unknown type, and `objectui validate` keeps refusing it at `type`, as it already did. - -Migration: - -- `pie-chart` / `donut-chart` / `radar-chart` → `chart` with `chartType: "pie"` / `"donut"` / `"radar"`; -- `page-header` → `page:header`, with `title` / `subtitle` / `actions` in `properties`. - -The registered-types ratchet (`REFUSED_AT_TYPE`) falls from 24 to 20, and its namespaced twin from 379 to 374. - -**Clause-②: yes**, released as `minor` with this banner. diff --git a/.changeset/10859-known-types-phase-2d.md b/.changeset/10859-known-types-phase-2d.md deleted file mode 100644 index b592cad639..0000000000 --- a/.changeset/10859-known-types-phase-2d.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/cli': minor ---- - -chore(cli)!: the generated known-types list drops the ten `sidebar-*` node type keys objectui#10859 batch 8 phase 2d retired - -**BREAKING (authoring):** `KNOWN_SCHEMA_TYPES` (regenerated from the registration calls) no longer lists `sidebar-provider`, `sidebar-header`, `sidebar-content`, `sidebar-group`, `sidebar-menu`, `sidebar-menu-item`, `sidebar-menu-button`, `sidebar-footer`, `sidebar-inset` or `sidebar-trigger`, nor their `ui:` twins. `objectui check` now reports a root document of one of those types as an unknown type, and `objectui validate` keeps refusing it at `type`, as it already did. - -Migration: author the `sidebar` node, which now mounts its own provider when its host has none, and put the parts' content in its `children`. `@object-ui/components`' changeset for this phase lists the move per spelling. - -objectui#11441 retired its two layout keys first, so on that base this change takes the registered-types ratchet (`REFUSED_AT_TYPE`) from 18 to 8, and its namespaced twin from 372 to 362. - -**Clause-②: yes**, released as `minor` with this banner. diff --git a/.changeset/10859-known-types-retired-keys.md b/.changeset/10859-known-types-retired-keys.md deleted file mode 100644 index e46280d590..0000000000 --- a/.changeset/10859-known-types-retired-keys.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/cli': minor ---- - -chore(cli)!: the generated known-types list drops the thirty node type keys objectui#10859 batch 8 retired - -**BREAKING (authoring):** `KNOWN_SCHEMA_TYPES` (`packages/cli/src/utils/known-schema-types.ts`, regenerated from the registration calls) no longer lists the 28 bare field-widget fallbacks retired in `@object-ui/fields`, nor `tree` / `view:tree` (`@object-ui/plugin-tree`) or `view` / `plugin-view:view` (`@object-ui/plugin-view`). `objectui check` now reports a root document of one of those types as an unknown type, and `objectui validate` keeps refusing it at `type`, as it already did. - -Migration: - -- a root `type` naming one of the 28 field types → write the field inside a form's `fields[]`; the widget is `field:`; -- `tree` → `object-tree`; -- `view` → `object-view`. - -The registered-types ratchet (`REFUSED_AT_TYPE`) falls from 66 to 36, and its namespaced twin from 391 to 389. - -**Clause-②: yes**, released as `minor` with this banner. diff --git a/.changeset/10859-object-form-properties-bag.md b/.changeset/10859-object-form-properties-bag.md deleted file mode 100644 index d69299a5df..0000000000 --- a/.changeset/10859-object-form-properties-bag.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types): an authored `object-form` takes its props in the spec's `properties` bag; the flat spelling is refused by name (objectui#10859, batch 4) - -**BREAKING (authoring):** an `object-form` node that writes its props on the node itself is now refused by `safeValidateSchema`, `validateSchema` and the strict authoring face, and so by `objectui validate`. Move each prop into the node's `properties` bag: - -```json -{ "type": "object-form", "properties": { "objectName": "account", "mode": "create", "fields": ["name", "rating"] } } -``` - -Nothing changes at render time: `SchemaRenderer` hoists every `properties` key onto the node before `ObjectForm` runs, so the bag node draws what the flat one drew, and a node built in code keeps working with its flat keys. - -**Clause-②: yes** — the accept set narrows (a flat `object-form` node that parsed is refused) and widens (a spec-shaped bag node that was refused parses). Released as `minor` under the objectui narrowing rule, with this banner. - -**Why.** `@objectstack/spec`'s `ComponentPropsMap['object-form']` row is the published declaration of an authored `object-form` node's props, and the spec's own strict `PageComponentSchema` refuses a prop written on the node as mis-layered (ADR-0089 D3a). The arm here was the flat mirror of the TypeScript `ObjectFormSchema`, so the two validators disagreed both ways: the objectstack showcase's wizard page, written in the bag, was refused (`objectName` `invalid_type`, `mode` `invalid_value`), and the flat node `os validate` refuses was accepted. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `ObjectFormBlockSchema`, built the way `ObjectMetricBlockSchema` is: `BaseSchema`, the `object-form` literal, and `properties`, which is the spec row by reference, so the row's members, value types and strictness judge the bag. It declares the node's `dataSource` binding (the spec's `ElementDataSourceSchema`), refuses the five handler keys `ObjectForm` reads off the node as runtime slots (objectui#6124), and refuses `body` / `children` (objectui#9256). -- Each member of the row written flat on the node is refused on both faces, with a message that names its bag member (`Did you mean \`mode\` → \`properties.mode\`?`). The refusal set is read off the row, so it follows the spec. -- `ObjectFormBlockSchema` reaches `AnyComponentSchema` through `ObjectQLPublicBlockComponentSchema`. `ObjectFormSchema` leaves `ObjectQLComponentSchema`. -- Inside the bag the spec row decides, and it differs from the flat mirror in a few places. `objectName` and `mode` are optional (a `dataSource` binding can name the object). `layout` takes `vertical` or `horizontal` only (the spec retired `inline` and `grid`; set `columns` for several columns). `recordId` takes a string or a number. `buttons`, `defaults`, `subforms` and `groups` are form-VIEW keys, not members of the row, so the bag refuses them; `buttons`, `defaults` and `subforms` stay authorable in an `object-view`'s `form` slot. The row types `sections` entries as `unknown`, so a section's own keys are not judged inside the bag. - -**The same release's `.changeset/6152-object-form-unmirrored-members.md`** declared members on the flat mirror so that the strict face stopped refusing them on an authored node. On an authored node those members are now written in the bag, where the spec row judges them: every one of them except `buttons`, `defaults` and `subforms`, which the row does not declare. Those three stay authorable in an `object-view`'s `form` slot, which is built from the mirror, and a section there is still judged member by member. - -**What did not move.** The TypeScript `ObjectFormSchema` and its zod mirror `ObjectFormSchema` stay published and unchanged in shape. They are the node as `ObjectForm` reads it after the hoist, and as code composes it (`ObjectView`, `RecordFormPage`, `ScreenView`, a host mounting ``). The object-view `form` slot is still built from the mirror. - -**Note, 2026-10-01 (objectui#11168 slice 3, objectui#7759 group C, shipping in this same release).** `layout` is no longer one of the places the bag and the flat mirror differ. `ObjectFormSchema.layout`, on both faces, now takes the row's own `vertical | horizontal` by reference, the `object-form` registration publishes the same two, and the designer offers only those. `inline` and `grid` rendered as `vertical` before they were refused, so nothing that rendered is lost. The other differences listed above stand. diff --git a/.changeset/10859-object-gantt-properties-bag.md b/.changeset/10859-object-gantt-properties-bag.md deleted file mode 100644 index c8ee43be2a..0000000000 --- a/.changeset/10859-object-gantt-properties-bag.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types): an authored `object-gantt` takes its props in the spec's `properties` bag; the flat spelling is refused by name (objectui#10859, batch 6) - -**BREAKING (authoring):** an `object-gantt` node that writes its props on the node itself is now refused by `safeValidateSchema`, `validateSchema` and the strict authoring face, and so by `objectui validate`. Move each prop into the node's `properties` bag, and the field mapping into the bag's `gantt` block: - -```json -{ "type": "object-gantt", "properties": { "objectName": "task", "gantt": { "startDateField": "start", "endDateField": "end", "titleField": "name" } } } -``` - -Nothing changes at render time: `SchemaRenderer` hoists every `properties` key onto the node before `ObjectGantt` runs, so the bag node draws what the flat one drew, and a node built in code (`ObjectView` and `ListView` flatten a stored gantt view this way, flat field keys and the toolbar's `search` term included) keeps working with its flat keys. - -**Clause-②: yes (narrowing)** — the accept set narrows (a flat `object-gantt` node that parsed is refused) and widens (a spec-shaped bag node that was refused parses). Released as `minor` under the objectui narrowing rule, with this banner. - -**Why.** `@objectstack/spec`'s `ComponentPropsMap['object-gantt']` row is the published declaration of an authored `object-gantt` node's props, and the spec's own strict `PageComponentSchema` refuses a prop written on the node as mis-layered (ADR-0089 D3a). The arm here was the flat mirror of the TypeScript `ObjectGanttSchema`, so the two validators disagreed both ways: a document written in the bag was refused (the flat mirror found no record source on the node), and the flat node `os validate` refuses was accepted. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `ObjectGanttBlockSchema`, built the way `ObjectMapBlockSchema` is: `BaseSchema`, the `object-gantt` literal, and `properties`, which is the spec row by reference, so the row's members, value types and strictness judge the bag. It declares the node's `dataSource` binding (the spec's `ElementDataSourceSchema`) and refuses `body` / `children` (objectui#9256). The row carries spec defaults; none is written into a validated document. -- Each member of the row written flat on the node is refused on both faces, with a message that names its bag member (`Did you mean \`objectName\` → \`properties.objectName\`?`). The refusal set is read off the row, so it follows the spec. `label` is the exception: the spec's page component declares a node-level display `label` of its own, so a `label` on the node is kept. -- The flat field-mapping keys the flat mirror declared (`startDateField`, `endDateField`, `titleField`, `viewMode` and the rest of `GanttConfig`) and its `dependencyField` alias are refused the same way, pointed at the bag's `gantt` block (`properties.gantt.startDateField`; `dependencyField` at `properties.gantt.dependenciesField`). Inside the bag the spec row refuses them too, with its prescription to move them into `gantt`. -- The record-source rule stays: the node needs one of `properties.data`, `properties.staticData` or `properties.objectName`, or the node's `dataSource` binding naming its object, which the renderer lands on `objectName`. A node with none is refused at the root (`RECORD_SOURCE_REQUIRED`), as the flat node was. A bag node bound only through `dataSource` parses. -- `ObjectGanttBlockSchema` reaches `AnyComponentSchema` through `ObjectQLPublicBlockComponentSchema`. `ObjectGanttSchema` leaves `ObjectQLComponentSchema`. -- `search` and `searchableFields` are not authored keys: a list view writes them onto the node it composes, and the spec row does not declare them. Written flat on an authored node they are unjudged by the tolerant face and refused by the strict one; in the bag the spec row refuses them. - -**The same release's `.changeset/6475-gantt-block-face-declared.md`, `.changeset/6939-objectql-record-source-refinement.md`, `.changeset/9256-e3-residual-content-channels.md`, `.changeset/11070-strict-face-read-keys.md` and `.changeset/11117-datasource-objectname-waiver.md`** describe what the validators say about an `object-gantt` written flat. On an authored node those readings now happen in the bag: the `gantt` block is the row's own `gantt` member, with the same three required fields, and the record-source rule reads `properties.data`, `properties.staticData`, `properties.objectName` or the node's `dataSource`. The flat mirror they name still behaves as they say. - -**What did not move.** The TypeScript `ObjectGanttSchema` and its zod mirror `ObjectGanttSchema` stay published and unchanged in shape. They are the node as `ObjectGantt` reads it after the hoist, and as code composes it, or hands it to `` directly. diff --git a/.changeset/10859-object-map-properties-bag.md b/.changeset/10859-object-map-properties-bag.md deleted file mode 100644 index 2334ce74ab..0000000000 --- a/.changeset/10859-object-map-properties-bag.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/types': minor ---- - -feat(types): an authored `object-map` takes its props in the spec's `properties` bag; the flat spelling is refused by name (objectui#10859, batch 5) - -**BREAKING (authoring):** an `object-map` node that writes its props on the node itself is now refused by `safeValidateSchema`, `validateSchema` and the strict authoring face, and so by `objectui validate`. Move each prop into the node's `properties` bag: - -```json -{ "type": "object-map", "properties": { "objectName": "store", "map": { "latitudeField": "lat", "longitudeField": "lng" } } } -``` - -Nothing changes at render time: `SchemaRenderer` hoists every `properties` key onto the node before `ObjectMap` runs, so the bag node draws what the flat one drew, and a node built in code (`ObjectView` and `ListView` flatten a stored map view this way) keeps working with its flat keys. - -**Clause-②: yes (narrowing)** — the accept set narrows (a flat `object-map` node that parsed is refused) and widens (a spec-shaped bag node that was refused parses). Released as `minor` under the objectui narrowing rule, with this banner. - -**Why.** `@objectstack/spec`'s `ComponentPropsMap['object-map']` row is the published declaration of an authored `object-map` node's props, and the spec's own strict `PageComponentSchema` refuses a prop written on the node as mis-layered (ADR-0089 D3a). The arm here was the flat mirror of the TypeScript `ObjectMapSchema`, so the two validators disagreed both ways: a document written in the bag was refused (the flat mirror found no record source on the node), and the flat node `os validate` refuses was accepted. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `ObjectMapBlockSchema`, built the way `ObjectFormBlockSchema` is: `BaseSchema`, the `object-map` literal, and `properties`, which is the spec row by reference, so the row's members, value types and strictness judge the bag. It declares the node's `dataSource` binding (the spec's `ElementDataSourceSchema`) and refuses `body` / `children` (objectui#9256). -- Each member of the row written flat on the node is refused on both faces, with a message that names its bag member (`Did you mean \`objectName\` → \`properties.objectName\`?`). The refusal set is read off the row, so it follows the spec. The flat mirror's two compatibility keys, `locationField` and `titleField`, are refused the same way and pointed at `properties.map.locationField` / `properties.map.titleField`. -- The record-source rule stays: the node needs one of `properties.data`, `properties.staticData` or `properties.objectName`, or the node's `dataSource` binding, whose `object` the renderer lands on `objectName`. A node with none is refused at the root (`RECORD_SOURCE_REQUIRED`), as the flat node was. A node bound only through `dataSource`, which the flat arm refused, now parses. -- `ObjectMapBlockSchema` reaches `AnyComponentSchema` through `ObjectQLPublicBlockComponentSchema`. `ObjectMapSchema` leaves `ObjectQLComponentSchema`. -- Inside the bag the spec row decides. The `map` block is the row's own `map` member (the same eight keys, closed), and a `map`-config key written beside it in the bag (`properties.locationField`) is refused with the spec's prescription to move it into `map`. `filter` takes the rule-array form only, and `navigation` is not judged member by member there. - -**The same release's `.changeset/5157-object-map-config-strict.md`, `.changeset/6939-objectql-record-source-refinement.md` and `.changeset/11007-check-prints-key.md`** describe what the validators say about an `object-map` written flat. On an authored node those readings now happen in the bag: a typo in the `map` block is refused at `properties.map` (`objectui check` prints `Issue at properties → map: …` for it), and the record-source rule reads `properties.data`, `properties.staticData`, `properties.objectName` or the node's `dataSource`. The flat mirror they name still behaves as they say. - -**What did not move.** The TypeScript `ObjectMapSchema` and its zod mirror `ObjectMapSchema` stay published and unchanged in shape. They are the node as `ObjectMap` reads it after the hoist, and as code composes it, or hands it to `` directly. diff --git a/.changeset/10859-object-timeline-zod-arm.md b/.changeset/10859-object-timeline-zod-arm.md deleted file mode 100644 index ae0a888609..0000000000 --- a/.changeset/10859-object-timeline-zod-arm.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`safeValidateSchema` — and so `objectui validate` — accepts one more registered node type: `object-timeline` (objectui#10859, batch 3). - -**Clause-②: yes** — the accept set of `AnyComponentSchema` widens by one `type` literal, and `@object-ui/types/zod` exports one new schema. Nothing that parsed before is refused now: every document naming `object-timeline` was refused at `type`, at the root and at every child slot. - -**What it was.** `object-timeline` is an ADR-0080 public block registered by `@object-ui/plugin-timeline`, and since `@objectstack/spec` 17.5.0 the spec declares its props as the `ComponentPropsMap['object-timeline']` row. `AnyComponentSchema` carried no arm for it, so every document naming it was refused with `invalid_union` at `type`. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `ObjectTimelineBlockSchema`, built the way `ObjectMetricBlockSchema` is: `BaseSchema`, the `type` literal, and `properties`, which is the spec row by reference, so the spec's members, value types and strictness apply to the bag unchanged. The row's defaults (`timeline.scale`, the `navigation` members) are removed at the import boundary, so a parse writes nothing into the document (objectui#8317). -- The node also declares `dataSource`, the spec's `ElementDataSourceSchema` by reference — the per-element binding the renderer reads through `ElementDataSourceGate`, declared the same way on the other gate-wrapped arms (objectui#11070). `body` and `children` are refused by name: the renderer reads neither content channel (objectui#9256). -- `ObjectMetricBlockSchema` and `ObjectMasterDetailFormBlockSchema` declare the same `dataSource` binding, by the same construct: both registrations are gate-wrapped and read it. Both arms are new in this release (`.changeset/10859-pivot-object-block-zod-arms.md`), so this only shapes what they accept on arrival: a bound node parses on both faces, and the key is judged as the binding, so an adapter name (`dataSource: 'objectstack'`) is refused. -- `ObjectTimelineBlockSchema` reaches `AnyComponentSchema` through `ObjectQLPublicBlockComponentSchema`, beside `object-metric` and `object-master-detail-form`. The strict authoring face (`StrictAnyComponentSchema`) derives from it and accepts the same documents, closed to undeclared keys. As on those two blocks, a prop written flat on the node instead of inside `properties` is not judged against the spec row: a key `BaseSchema` does not declare passes the tolerant face unjudged and is refused by name on the strict face. - -⚠️ **Dated note, 2026-10-01 — props written flat on the node — objectui#10872 batch 10.** Later in this same release every member of the `object-timeline` row (and of the `object-metric` and `object-master-detail-form` rows) written directly on the node is refused by name on both faces, at its own path, with a message naming `properties.KEY`. So the bullet's "a prop written flat on the node instead of inside `properties` is not judged against the spec row: a key `BaseSchema` does not declare passes the tolerant face unjudged" no longer describes the release as a whole. A flat `data`, which `BaseSchema` also declares, is refused the same way. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10859-page-header-placeholder.md b/.changeset/10859-page-header-placeholder.md deleted file mode 100644 index 438f62d93d..0000000000 --- a/.changeset/10859-page-header-placeholder.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/components': minor ---- - -refactor(components)!: drop `page-header` from the opt-in protocol placeholders (objectui#10859, batch 8 phase 2c) - -**BREAKING (authoring):** `PROTOCOL_COMPONENTS` no longer lists `page-header`, so a host that calls `registerPlaceholders()` no longer registers a placeholder under `protocol-placeholder:page-header` or the bare `page-header`. The key was never a protocol page block (the spec's `PageComponentType` member is `page:header`), and `@object-ui/layout` retired its registration in the same release. `page:header` stays in the list. - -Migration: - -- `{ "type": "page-header", "title": T, "subtitle": S }` → `{ "type": "page:header", "properties": { "title": T, "subtitle": S } }`. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-pivot-object-block-zod-arms.md b/.changeset/10859-pivot-object-block-zod-arms.md deleted file mode 100644 index 390cb3e892..0000000000 --- a/.changeset/10859-pivot-object-block-zod-arms.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`safeValidateSchema` — and so `objectui validate` — accepts three more registered node types: `pivot`, `object-metric` and `object-master-detail-form` (objectui#10859, batch 2). - -**Clause-②: yes** — the accept set of `AnyComponentSchema` widens by three `type` literals, and `@object-ui/types/zod` exports four new schemas. Nothing that parsed before is refused now: every document naming one of these types was refused at `type`, at the root and at every child slot. - -**What it was.** `pivot` is registered by `@object-ui/plugin-dashboard` and declared on the published TypeScript face (`PivotTableSchema`); `object-metric` and `object-master-detail-form` are ADR-0080 public blocks, registered by `@object-ui/plugin-dashboard` and `@object-ui/plugin-form`, whose props `@objectstack/spec` declares as `ComponentPropsMap` rows. `AnyComponentSchema` carried no arm for any of them, so every document naming one was refused with `invalid_union` at `type` — the objectstack showcase's own `object-metric` KPIs and its master-detail form page included. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `PivotTableSchema`, a member for member restatement of the TypeScript `PivotTableSchema`: `rowField`, `columnField`, `valueField` and `data` are required, as they are there; `aggregation` is one of `sum`, `count`, `avg`, `min`, `max`; `drillDown` is the shared `DrillDownConfigSchema`; `body` and `children` are refused by name, as the declaration's `?: never` members refuse them (objectui#9256). `DataDisplaySchema` lists it. -- `@object-ui/types/zod` exports `ObjectMetricBlockSchema` and `ObjectMasterDetailFormBlockSchema`, built the way the objectui#10872 public-block arms are: `BaseSchema`, the `type` literal, and `properties`, which is the block's `ComponentPropsMap` row by reference, so the spec's members, value types and strictness apply to the bag unchanged. `ObjectMasterDetailFormBlockSchema` also refuses `onSuccess`, `onError` and `onCancel` by name: they are runtime slots a React host fills (objectui#6124). Both reach `AnyComponentSchema` through a new union, `ObjectQLPublicBlockComponentSchema`. -- The strict authoring face (`StrictAnyComponentSchema`) derives from `AnyComponentSchema` and accepts the same three types, closed to undeclared keys like every other arm. As on the public blocks, a prop written flat on an `object-metric` or `object-master-detail-form` node instead of inside `properties` is not judged against the spec row. A key `BaseSchema` does not declare passes the tolerant face unjudged and is refused by name on the strict face; a key it does declare (`label` and `description`, both also members of the `object-metric` row) is judged by `BaseSchema`'s own type on both faces. - -⚠️ **Dated note, 2026-09-29 — `drillDown` is retired on the `pivot` node — objectui#10932.** Later in this same release `drillDown` was retired on the `pivot` node on both faces: the TypeScript `PivotTableSchema.drillDown` is a `?: never` tombstone, and the `pivot` arm of `@object-ui/types/zod` declares `drillDown` as a `retirementTombstone()`, which refuses the key by name whatever it holds (`invalid_type` at `drillDown`, with a message naming `object-pivot`). So "`drillDown` is the shared `DrillDownConfigSchema`" above no longer holds: the arm accepts no `drillDown` at all. Nothing ever drilled a `pivot` node; a pivot whose cells open the records behind a value is authored as `object-pivot`, whose `drillDown` is typed `ObjectPivotDrillDownConfig`. The rest of the `PivotTableSchema` bullet stands, including "a member for member restatement of the TypeScript `PivotTableSchema`", because both faces retired the key together. `.changeset/10932-pivot-drilldown-retired.md` (PR objectui#10972) states what ships; the text above is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-01 — props written flat on the node — objectui#10872 batch 10.** Later in this same release every member of the `object-metric` and `object-master-detail-form` rows written directly on the node is refused by name on both faces, at its own path, with a message naming `properties.KEY`. So the strict-face bullet's "a prop written flat … is not judged against the spec row. A key `BaseSchema` does not declare passes the tolerant face unjudged", and its "a key it does declare (`label` and `description` …) is judged by `BaseSchema`'s own type on both faces", no longer describe the release as a whole: a flat `description` is refused toward `properties.description`, and only `label` stays on the node, because `@objectstack/spec`'s page component declares a node-level `label` of its own. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10859-plugin-form-readme-object-form-bag.md b/.changeset/10859-plugin-form-readme-object-form-bag.md deleted file mode 100644 index 1286951a08..0000000000 --- a/.changeset/10859-plugin-form-readme-object-form-bag.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/plugin-form': patch ---- - -docs(plugin-form): the README's authored `object-form` examples write their props in the `properties` bag (objectui#10859, batch 4) - -The multi-step and metadata-route examples now author `{ "type": "object-form", "properties": { … } }`, the spelling `@objectstack/spec`'s `ComponentPropsMap['object-form']` row declares and `objectui validate` now requires. The example that mounts `WizardForm` directly keeps the flat `schema` prop: a component mounted without `SchemaRenderer` receives the node as the renderer reads it after the hoist. No runtime change. diff --git a/.changeset/10859-plugin-gantt-properties-bag-docs.md b/.changeset/10859-plugin-gantt-properties-bag-docs.md deleted file mode 100644 index 44fd72ad5e..0000000000 --- a/.changeset/10859-plugin-gantt-properties-bag-docs.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@object-ui/plugin-gantt': patch ---- - -docs(plugin-gantt): authored `object-gantt` examples write their props in the `properties` bag (objectui#10859, batch 6) - -The README's authored `object-gantt` examples now write `{ "type": "object-gantt", "properties": { …, "gantt": { … } } }`, the spelling `@objectstack/spec`'s `ComponentPropsMap['object-gantt']` row declares and `objectui validate` now requires, with the field mapping in the bag's `gantt` block. The flat field-mapping keys are described as what they are, the handoff `ObjectView` and `ListView` write onto the node they compose. The examples that mount `ObjectGantt` directly keep the flat `schema` prop: a component mounted without `SchemaRenderer` receives the node as it reads it, and nothing hoists a bag there. Under `src/`, a new render pin holds that the bag draws what the flat spelling drew, and the catalog-plans pin reads the catalog entries' bag. No runtime change. diff --git a/.changeset/10859-plugin-map-properties-bag-docs.md b/.changeset/10859-plugin-map-properties-bag-docs.md deleted file mode 100644 index 86876d63a8..0000000000 --- a/.changeset/10859-plugin-map-properties-bag-docs.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@object-ui/plugin-map': patch ---- - -docs(plugin-map): authored `object-map` examples write their props in the `properties` bag, and the `objectName` input names the `dataSource` binding (objectui#10859, batch 5) - -- The README's authored `object-map` examples now write `{ "type": "object-map", "properties": { … } }`, the spelling `@objectstack/spec`'s `ComponentPropsMap['object-map']` row declares and `objectui validate` now requires. The example that mounts `ObjectMap` directly keeps the flat `schema` prop: a component mounted without `SchemaRenderer` receives the node as it reads it, and nothing hoists a bag there. -- The registration's `objectName` input description names the node's `dataSource` binding beside `data`, `staticData` and `objectName` as a record source, because the authored arm now counts it. No runtime change. diff --git a/.changeset/10859-record-source-tree-alias.md b/.changeset/10859-record-source-tree-alias.md deleted file mode 100644 index 58e15bc9d3..0000000000 --- a/.changeset/10859-record-source-tree-alias.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/core': minor ---- - -chore(core)!: the record-source `data` arm table drops `tree` and `view:tree` (objectui#10859, batch 8) - -**BREAKING (authoring):** `recordSourceDataArmForType('tree')` and `recordSourceDataArmForType('view:tree')` now answer `'undeclared'`, because `@object-ui/plugin-tree` no longer registers either key. The table names `object-tree` / `plugin-tree:object-tree` alone, which still answer `'view-data'`. - -Migration: - -- `tree` → `object-tree`; nothing else reads these rows. - -**Clause-②: yes**, released as `minor` with this banner. diff --git a/.changeset/10859-retire-bare-field-fallbacks.md b/.changeset/10859-retire-bare-field-fallbacks.md deleted file mode 100644 index a158a7842a..0000000000 --- a/.changeset/10859-retire-bare-field-fallbacks.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/fields': minor ---- - -refactor(fields)!: the 28 field widgets that still registered a bare node-type fallback register `field:` only (objectui#10859, batch 8) - -**BREAKING (authoring):** `registerAllFields()` no longer registers the bare keys `auto_number`, `boolean`, `checkboxes`, `color`, `currency`, `date`, `datetime`, `file`, `formula`, `geolocation`, `location`, `lookup`, `master_detail`, `multiselect`, `number`, `object`, `percent`, `phone`, `qrcode`, `radio`, `rating`, `richtext`, `signature`, `summary`, `tags`, `url`, `user` and `vector`. Every field widget is registered under its `field:` key alone — the key a form resolves, and the only one it ever resolved (ruling B of objectui#5254). Each of these bare keys was a node `type` that `objectui validate` refused at `type`, and nothing in this repository authored one as a node: every catalog entry and doc example writes these values as a FIELD type inside `fields[]` / `columns[]`, which is unaffected. A node authored with one of them now renders the "Unknown component type" panel, and `objectui check` reports the type as unknown. - -Migration, one line per retired spelling: - -- `{ "type": "auto_number" }` as a node → a field `{ "name": "…", "type": "auto_number" }` in a form's `fields[]` (rendered by `field:auto_number`). -- `{ "type": "boolean" }` as a node → a field `{ "name": "…", "type": "boolean" }` in a form's `fields[]` (rendered by `field:boolean`). -- `{ "type": "checkboxes" }` as a node → a field `{ "name": "…", "type": "checkboxes" }` in a form's `fields[]` (rendered by `field:checkboxes`). -- `{ "type": "color" }` as a node → a field `{ "name": "…", "type": "color" }` in a form's `fields[]` (rendered by `field:color`). -- `{ "type": "currency" }` as a node → a field `{ "name": "…", "type": "currency" }` in a form's `fields[]` (rendered by `field:currency`). -- `{ "type": "date" }` as a node → a field `{ "name": "…", "type": "date" }` in a form's `fields[]` (rendered by `field:date`). -- `{ "type": "datetime" }` as a node → a field `{ "name": "…", "type": "datetime" }` in a form's `fields[]` (rendered by `field:datetime`). -- `{ "type": "file" }` as a node → a field `{ "name": "…", "type": "file" }` in a form's `fields[]` (rendered by `field:file`). -- `{ "type": "formula" }` as a node → a field `{ "name": "…", "type": "formula" }` in a form's `fields[]` (rendered by `field:formula`). -- `{ "type": "geolocation" }` as a node → a field `{ "name": "…", "type": "geolocation" }` in a form's `fields[]` (rendered by `field:geolocation`). -- `{ "type": "location" }` as a node → a field `{ "name": "…", "type": "location" }` in a form's `fields[]` (rendered by `field:location`). -- `{ "type": "lookup" }` as a node → a field `{ "name": "…", "type": "lookup" }` in a form's `fields[]` (rendered by `field:lookup`). -- `{ "type": "master_detail" }` as a node → a field `{ "name": "…", "type": "master_detail" }` in a form's `fields[]` (rendered by `field:master_detail`). -- `{ "type": "multiselect" }` as a node → a field `{ "name": "…", "type": "multiselect" }` in a form's `fields[]` (rendered by `field:multiselect`). -- `{ "type": "number" }` as a node → a field `{ "name": "…", "type": "number" }` in a form's `fields[]` (rendered by `field:number`). -- `{ "type": "object" }` as a node → a field `{ "name": "…", "type": "object" }` in a form's `fields[]` (rendered by `field:object`). -- `{ "type": "percent" }` as a node → a field `{ "name": "…", "type": "percent" }` in a form's `fields[]` (rendered by `field:percent`). -- `{ "type": "phone" }` as a node → a field `{ "name": "…", "type": "phone" }` in a form's `fields[]` (rendered by `field:phone`). -- `{ "type": "qrcode" }` as a node → a field `{ "name": "…", "type": "qrcode" }` in a form's `fields[]` (rendered by `field:qrcode`). -- `{ "type": "radio" }` as a node → a field `{ "name": "…", "type": "radio" }` in a form's `fields[]` (rendered by `field:radio`). -- `{ "type": "rating" }` as a node → a field `{ "name": "…", "type": "rating" }` in a form's `fields[]` (rendered by `field:rating`). -- `{ "type": "richtext" }` as a node → a field `{ "name": "…", "type": "richtext" }` in a form's `fields[]` (rendered by `field:richtext`). -- `{ "type": "signature" }` as a node → a field `{ "name": "…", "type": "signature" }` in a form's `fields[]` (rendered by `field:signature`). -- `{ "type": "summary" }` as a node → a field `{ "name": "…", "type": "summary" }` in a form's `fields[]` (rendered by `field:summary`). -- `{ "type": "tags" }` as a node → a field `{ "name": "…", "type": "tags" }` in a form's `fields[]` (rendered by `field:tags`). -- `{ "type": "url" }` as a node → a field `{ "name": "…", "type": "url" }` in a form's `fields[]` (rendered by `field:url`). -- `{ "type": "user" }` as a node → a field `{ "name": "…", "type": "user" }` in a form's `fields[]` (rendered by `field:user`). -- `{ "type": "vector" }` as a node → a field `{ "name": "…", "type": "vector" }` in a form's `fields[]` (rendered by `field:vector`). - -A host that rendered a field widget outside a form addresses it as `field:`, or uses `getLazyFieldWidget()`, which never went through the bare key. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` under the objectui narrowing rule, with this banner. diff --git a/.changeset/10859-retire-chart-family-aliases.md b/.changeset/10859-retire-chart-family-aliases.md deleted file mode 100644 index 3f631ad5be..0000000000 --- a/.changeset/10859-retire-chart-family-aliases.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/plugin-charts': minor ---- - -refactor(plugin-charts)!: retire the `pie-chart`, `donut-chart` and `radar-chart` node type keys; the families are `chart` + `chartType` (objectui#10859, batch 8 phase 2c) - -**BREAKING (authoring):** the plugin no longer registers `pie-chart`, `donut-chart` or `radar-chart` (and with them `plugin-charts:pie-chart`, `plugin-charts:donut-chart` and `plugin-charts:radar-chart`), and their `CHART_TYPE_KEYWORD_FAMILIES` rows are gone. `objectui validate` already refused each at `type`. Their one producer, this package's `examples/chart-examples.ts`, now authors `{ type: 'chart', chartType: … }`, which `objectui validate` accepts on both faces. A node still authored with one of the three types now renders the "Unknown component type" panel. - -Migration: - -- `{ "type": "pie-chart", … }` → `{ "type": "chart", "chartType": "pie", … }`, with the same keys; -- `{ "type": "donut-chart", … }` → `{ "type": "chart", "chartType": "donut", … }`, with the same keys; -- `{ "type": "radar-chart", … }` → `{ "type": "chart", "chartType": "radar", … }`, with the same keys. - -A legacy report section whose `chart.type` says one of the three now reaches the generic `chart` renderer with no family derived from that type; give it the matching `chartType`. `chart:bar` is the one family keyword this package still registers. - -**Clause-②: yes** — registrations leave the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-retire-designer-node-keys.md b/.changeset/10859-retire-designer-node-keys.md deleted file mode 100644 index d30ba7637c..0000000000 --- a/.changeset/10859-retire-designer-node-keys.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/plugin-designer': minor ---- - -refactor(plugin-designer)!: retire four builder-chrome node type keys (objectui#10859, batch 8 phase 2b) - -**BREAKING (authoring):** the plugin no longer registers `app-creation-wizard`, `navigation-designer`, `dashboard-editor` or `branding-editor` (and with them their `plugin-designer:` keys). `objectui validate` refused each at `type`, and none appears as a node type anywhere in this repository, its examples or objectstack. A node authored with one of these types now renders the "Unknown component type" panel. `AppCreationWizard`, `NavigationDesigner`, `DashboardEditor` and `BrandingEditor` stay named exports. - -Migration: - -- `{ "type": "app-creation-wizard", … }` → mount `AppCreationWizard` directly; -- `{ "type": "navigation-designer", … }` → mount `NavigationDesigner` directly; -- `{ "type": "dashboard-editor", … }` → mount `DashboardEditor` directly; -- `{ "type": "branding-editor", … }` → mount `BrandingEditor` directly. - -**Clause-②: yes** — registrations leave the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-retire-form-analytics.md b/.changeset/10859-retire-form-analytics.md deleted file mode 100644 index 66ca253b5a..0000000000 --- a/.changeset/10859-retire-form-analytics.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/plugin-form': minor ---- - -refactor(plugin-form)!: retire the `form-analytics` node type key (objectui#10859, batch 8 phase 2b) - -**BREAKING (authoring):** the plugin no longer registers `form-analytics` (and with it `plugin-form:form-analytics`). `objectui validate` refused a `form-analytics` node at `type`, and nothing in this repository, its examples or objectstack authored it. A node authored `type: "form-analytics"` now renders the "Unknown component type" panel. `FormAnalytics` stays a named export. - -Migration: - -- `{ "type": "form-analytics", "formId": …, "formTitle": …, "metrics": … }` → mount `FormAnalytics` directly with the same three props. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-retire-import-wizard.md b/.changeset/10859-retire-import-wizard.md deleted file mode 100644 index fe1bb1ff55..0000000000 --- a/.changeset/10859-retire-import-wizard.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/plugin-grid': minor ---- - -refactor(plugin-grid)!: retire the `import-wizard` node type key; the `ImportWizard` export stays (objectui#10859, batch 8 phase 2b) - -**BREAKING (authoring):** the plugin no longer registers `import-wizard` (and with it `plugin-grid:import-wizard`). `objectui validate` refused an `import-wizard` node at `type`, and nothing in this repository, its examples or objectstack authored it. A node authored `type: "import-wizard"` now renders the "Unknown component type" panel. `ImportWizard` stays a named export, and `@object-ui/app-shell` already mounts it directly. - -Migration: - -- `{ "type": "import-wizard", "objectName": …, "fields": … }` → mount `ImportWizard` directly, passing `objectName`, `fields` and the `dataSource`. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-retire-page-header-layout.md b/.changeset/10859-retire-page-header-layout.md deleted file mode 100644 index a43c327da0..0000000000 --- a/.changeset/10859-retire-page-header-layout.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/layout': minor ---- - -refactor(layout)!: retire the `page-header` node type key; the header node is `page:header` (objectui#10859, batch 8 phase 2c) - -**BREAKING (authoring):** `registerLayout()` no longer registers `PageHeader` under `page-header` (and with it `layout:page-header`). `objectui validate` already refused a `page-header` node at `type`, and nothing in this repository authored or emitted it. objectstack's `page-header-subtitle-alias` conversion renames the key `description` → `subtitle` on both header spellings and leaves the type to objectui. A `page-header` node now renders the "Unknown component type" panel. `PageHeader` stays a named export for JSX composition. - -Migration, measured against `objectui validate` (`page:header` carries its props in `properties`): - -- `{ "type": "page-header", "title": T, "subtitle": S }` → `{ "type": "page:header", "properties": { "title": T, "subtitle": S } }`; -- `actions` (action ids) → `properties.actions`, the same id array; -- `icon` has no `page:header` spelling: the contract refuses `properties.icon` by name (an ADR-0087 D2 tombstone). Drop it, or compose `PageHeader` in JSX, which still takes `icon`; -- `children` (the right-hand slot) has no `page:header` spelling: the contract refuses a node-level `children` by name, and `properties.children` as an unrecognized key. Put the buttons in `properties.actions` as action ids, or compose `PageHeader` in JSX, which still renders its `children`. - -`registerLayout()` now registers four keys: `layout:page:card`, `responsive-grid`, `navigation-renderer` and `app-schema-renderer`. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. - -⚠️ **Dated note, 2026-10-02 — `responsive-grid` and `navigation-renderer` are retired too — objectui#11441.** -Later in this same release objectui#11441 (the maintainer's ruling, letters B / B) unregistered both, with their -`layout:` twins, so `registerLayout()` registers two keys: `layout:page:card` and `app-schema-renderer`. The rest of -this entry is kept as the reading of this change. diff --git a/.changeset/10859-retire-related-list.md b/.changeset/10859-retire-related-list.md deleted file mode 100644 index 3cf71903b7..0000000000 --- a/.changeset/10859-retire-related-list.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/plugin-detail': minor ---- - -refactor(plugin-detail)!: retire the `related-list` node type key; the related-list block is `record:related_list` (objectui#10859, batch 8 phase 2b) - -**BREAKING (authoring):** the plugin no longer registers `related-list` (and with it `plugin-detail:related-list`). `objectui validate` refused a `related-list` node at `type`, nothing in this repository, its examples or objectstack authored it, and its declared `type` input collided with the node discriminator. A node authored `type: "related-list"` now renders the "Unknown component type" panel. `RelatedList` stays a named export. - -Migration: - -- `{ "type": "related-list", … }` → `{ "type": "record:related_list", "properties": { … } }`, the armed block this plugin registers, or mount `RelatedList` directly. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-retire-scatter-chart.md b/.changeset/10859-retire-scatter-chart.md deleted file mode 100644 index 5b725b7c41..0000000000 --- a/.changeset/10859-retire-scatter-chart.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/plugin-charts': minor ---- - -refactor(plugin-charts)!: retire the `scatter-chart` node type key; scatter is `chart` + `chartType: 'scatter'` (objectui#10859, batch 8 phase 2b) - -**BREAKING (authoring):** the plugin no longer registers `scatter-chart` (and with it `plugin-charts:scatter-chart`), a second key on the generic `ChartRenderer` whose family came from its `CHART_TYPE_KEYWORD_FAMILIES` row. That row is gone too. `objectui validate` refused a `scatter-chart` node at `type`, and nothing in this repository, its examples or objectstack authored it. A node authored `type: "scatter-chart"` now renders the "Unknown component type" panel. - -Migration: - -- `{ "type": "scatter-chart", … }` → `{ "type": "chart", "chartType": "scatter", … }`, with the same keys. - -A legacy report section whose `chart.type` says `scatter-chart` now reaches the generic `chart` renderer with no family derived from that type; give it `chartType: "scatter"`. - -`pie-chart`, `donut-chart` and `radar-chart` were ruled the same way but stay registered: this package's `examples/chart-examples.ts` still authors them, so they wait on their own decision. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. - -⚠️ **Dated note, 2026-10-02 — the three chart aliases are retired too — objectui#10859.** -The decision this entry said `pie-chart`, `donut-chart` and `radar-chart` wait on is made (the seat's fork ruling on objectui#10859): later in this same release, phase 2c moved `examples/chart-examples.ts` to `{ type: 'chart', chartType: 'pie' | 'donut' | 'radar' }` and then unregistered all three keys, with their `plugin-charts:` twins and `CHART_TYPE_KEYWORD_FAMILIES` rows. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10859-retire-shared-view-link.md b/.changeset/10859-retire-shared-view-link.md deleted file mode 100644 index 4ec485ca10..0000000000 --- a/.changeset/10859-retire-shared-view-link.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/plugin-view': minor ---- - -refactor(plugin-view)!: retire the `shared-view-link` node type key (objectui#10859, batch 8 phase 2b) - -**BREAKING (authoring):** the plugin no longer registers `shared-view-link` (and with it `view:shared-view-link`). `objectui validate` refused a `shared-view-link` node at `type`, and nothing in this repository, its examples or objectstack authored it. A node authored `type: "shared-view-link"` now renders the "Unknown component type" panel. `SharedViewLink` stays a named export. - -Migration: - -- `{ "type": "shared-view-link", "objectName": …, "viewId": … }` → mount `SharedViewLink` directly with the same props. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-retire-sidebar-parts.md b/.changeset/10859-retire-sidebar-parts.md deleted file mode 100644 index 01302af671..0000000000 --- a/.changeset/10859-retire-sidebar-parts.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/components': minor ---- - -refactor(components)!: retire the ten `sidebar-*` node type keys; the `sidebar` node supplies its own provider (objectui#10859, batch 8 phase 2d) - -**BREAKING (authoring):** `@object-ui/components` no longer registers `sidebar-provider`, `sidebar-header`, `sidebar-content`, `sidebar-group`, `sidebar-menu`, `sidebar-menu-item`, `sidebar-menu-button`, `sidebar-footer`, `sidebar-inset` or `sidebar-trigger`, nor their `ui:` twins. `objectui validate` already refused each of them at `type`. Nothing in this repository or in objectstack authored or emitted them except the four `components-basic-sidebar` catalog documents, which now author the `sidebar` node. A node of one of these types now renders the "Unknown component type" panel. The shadcn components behind them (`SidebarProvider`, `SidebarHeader`, `SidebarMenuButton`, `SidebarTrigger` and the rest) stay exported for JSX composition. - -Migration, measured against `objectui validate`. The `sidebar` node is the one sidebar region; it renders its `children` in order and passes `className` to the sidebar element: - -- `sidebar-provider` → drop it. The `sidebar` node uses the provider its host already mounts, such as the app shell's, and mounts its own when the host has none. A `sidebar-provider` wrapping a `sidebar` becomes that `sidebar` node alone; -- `sidebar-header`, `sidebar-content`, `sidebar-footer`, `sidebar-group`, `sidebar-menu` and `sidebar-menu-item` → drop the wrapper and move its `children` up into the `sidebar` node's `children`. Group headings are `text` nodes, and a `separator` node divides groups; -- `sidebar-group`'s `label` → a `text` node with that `content`, placed before the group's items; -- `sidebar-menu-button` → a `button` node with `label` and `variant: "ghost"`, or a `flex` row (`properties.children`) holding a `text` node and a `badge` node for an item with a count; -- `sidebar-inset` → no node spelling. Place the main content beside the `sidebar` node in your page layout, or compose `SidebarInset` in JSX; -- `sidebar-trigger` → no node spelling. A host that mounts the provider renders `SidebarTrigger` itself, as the app shell does. - -**Clause-②: yes** — ten registrations leave the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-retire-tree-alias.md b/.changeset/10859-retire-tree-alias.md deleted file mode 100644 index 6110bcdade..0000000000 --- a/.changeset/10859-retire-tree-alias.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/plugin-tree': minor ---- - -refactor(plugin-tree)!: retire the bare `tree` node type key; `object-tree` is the one spelling (objectui#10859, batch 8) - -**BREAKING (authoring):** the plugin no longer registers `tree` (and with it `view:tree`), the second key it registered on the `object-tree` renderer with the same inputs. `objectui validate` refused a `tree` node at `type`, because only `object-tree` has a declaration (`@objectstack/spec`'s `ComponentPropsMap` row), and nothing in this repository authored the alias. A node authored `type: "tree"` now renders the "Unknown component type" panel. - -Migration: - -- `{ "type": "tree", … }` → `{ "type": "object-tree", … }`, with the same keys. - -The host-composition VIEW type `tree` and the FIELD type `tree` are different layers and are unchanged: `ObjectView` and `ListView` already compose a stored tree view into an `object-tree` node. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-retire-view-alias.md b/.changeset/10859-retire-view-alias.md deleted file mode 100644 index 5331a9e9b9..0000000000 --- a/.changeset/10859-retire-view-alias.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/plugin-view': minor ---- - -refactor(plugin-view)!: retire the bare `view` node type key; `object-view` is the one spelling (objectui#10859, batch 8) - -**BREAKING (authoring):** the plugin no longer registers `view` (and with it `plugin-view:view`), an alias of the `object-view` renderer that declared no inputs. `objectui validate` refused a `view` node at `type` while it accepts `object-view`, and nothing in this repository authored the alias. A node authored `type: "view"` now renders the "Unknown component type" panel. The README's and the plugin page's registration tables lost the row. - -Migration: - -- `{ "type": "view", … }` → `{ "type": "object-view", … }`, with the same keys. - -The `view` METADATA namespace (saved views, `client.meta.getItems('view')`) is a different layer and is unchanged. - -**Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner. diff --git a/.changeset/10859-sidebar-node-provider-collapsible.md b/.changeset/10859-sidebar-node-provider-collapsible.md deleted file mode 100644 index d72ca6b372..0000000000 --- a/.changeset/10859-sidebar-node-provider-collapsible.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/components': minor ---- - -feat(components): the `sidebar` node mounts a `SidebarProvider` only when none is above it, and honours the boolean `collapsible` (objectui#10859, batch 8 phase 2d) - -- **Provider.** shadcn's `Sidebar` throws outside a `SidebarProvider`, so a `sidebar` node used to render the error panel in any host that did not mount one. Now the node reads the provider context without throwing. In a host that already mounts a provider (the app shell, through `@object-ui/layout`'s `AppShell`), the node uses that one: the tree keeps exactly one provider, and the host's open state drives the node. In a host without one, the node mounts its own around itself. -- **`collapsible`.** The spec types `SidebarSchema.collapsible` as a boolean, but the node forwarded it into shadcn's `'offcanvas' | 'icon' | 'none'` prop, so `true` and `false` reached the DOM as `data-collapsible="true"` / `"false"`, which no rule matches. Now `false` draws shadcn's in-flow, fixed-width form, which ignores the open state. `true`, or leaving the key out, keeps the default the node applied before (`offcanvas`). Any other value is forwarded unchanged, as before; `objectui validate` refuses it at `collapsible`. The registration's `collapsible` input is now declared as a boolean, and its `defaultProps` no longer name `collapsible`: that `'icon'` was never read at render. -- **`useOptionalSidebar()`.** A new export next to `useSidebar()`, added to the Shadcn primitive as a declared local patch (`scripts/shadcn-local-patches.mjs`). It returns the sidebar context, or `null` where `useSidebar()` would throw. diff --git a/.changeset/10862-designer-admin-previews-locale.md b/.changeset/10862-designer-admin-previews-locale.md deleted file mode 100644 index cf1b732d8e..0000000000 --- a/.changeset/10862-designer-admin-previews-locale.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the admin previews and the CEL lint advisories read the designer locale (objectui#10862, slice 2) - -Under zh-CN these designer surfaces rendered their own words in English beside -Chinese text: - -- the app, book, datasource, email template, permission set, position and - translation previews: their empty prompts, section and column headings, - pills, badges, legends, notes, toolbar links and their tooltips, the - permission set's sanity-check warnings, the email template's envelope - labels and variable placeholders, and the translation bundle's category - names; -- the two advisories the CEL lint writes itself beneath the CEL editors: the - wrong-layer `data.*` root on a record-scope expression, and an RLS `USING` - read filter that cannot be pushed down to the query. - -Each new en row is the English the literal carried, so en renders unchanged. -Author data (labels, names, doc names, config keys and values, variable -names, a translation bundle's own locale), identifiers (navigation kinds, tab -visibility values, access-scope tokens, the C / R / U / D column letters, -"SSL"), the expression engine's own messages and `@objectstack/lint`'s -field-rule message show as written in every locale. - -This is slice 2 of objectui#10862 (the admin previews). The object / data -previews and the preview error-boundary hints remain for slice 3. diff --git a/.changeset/10862-designer-automation-previews-locale.md b/.changeset/10862-designer-automation-previews-locale.md deleted file mode 100644 index 8f80aef519..0000000000 --- a/.changeset/10862-designer-automation-previews-locale.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the action, agent, skill, tool and job previews and the CEL try-it dialog read the designer locale (objectui#10862, slice 1) - -Under zh-CN these designer surfaces rendered their own words in English beside -Chinese text: - -- the action preview: its pills ("AI: opted out", "AI: exposed", "refresh - after" and the type / object / variant labels), the "Visible when" and - "Disabled when" lines, the "On click" sentence for every action type, the - "Where it appears" frames and their capability note, the input and result - dialog mocks, and the test-request panel; -- the agent, skill, tool and job previews: their empty prompts, section - headings, pills, table headers, notes, the "Try in chat" and "Open in API - Console" links and their tooltips, and the job's next-run list; -- the RLS policy editor's CEL try-it dialog: the result for an empty - predicate, the "Evaluation failed." fallback when the engine gives no - message, and the "expected a JSON object." refusal for a sample. - -Each new en row is the English the literal carried, so en renders unchanged. -Author data (labels, names, instructions, condition sources, handler keys), -identifiers (enum tokens, location keys, object and capability names, -JSON-Schema types, compact durations such as `5m`, the name "Cron") and the -expression engine's own messages show as written in every locale. - -This is slice 1 of objectui#10862 (the flow / automation previews). The -object / data previews and the admin previews remain for the later slices. diff --git a/.changeset/10862-designer-federation-flow-stub-locale.md b/.changeset/10862-designer-federation-flow-stub-locale.md deleted file mode 100644 index 3fa58b7953..0000000000 --- a/.changeset/10862-designer-federation-flow-stub-locale.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell,i18n): the designer's flow, federated-panel and field-stub chrome speak the user's language (objectui#10862, slice 4) - -Under zh-CN these designer surfaces rendered their own words in English beside -Chinese text: - -- the federated datasource panel's tables tab: the filter box, refresh button, - loading, empty and no-match notes, table headers, import buttons and the - federation-unavailable message; -- its validation tab: the intro, run button, match and divergence summaries, - per-object diff counts, the ten diff-kind badges, the expected / actual line - and its federation-unavailable message; -- the import dialog: its title, intro, draft progress, object name, review - count, generated-source heading, import / cancel / close buttons, the - imported confirmation and the federation-unavailable message; -- the flow canvas: an edge's hover title for an un-declared cycle and for a - back-edge, and a node card's branch count, approver count and `code` summary; -- the flow preview's variable `in` / `out` tags, and an expanded run's - `run …` / `trigger …` line in the run history; -- the address field stub's placeholder in the form designer; -- the "not found" reason the view, report and dashboard widget inspectors - show when the bound object or dataset is missing. - -Each new en row is the English the literal carried, so en renders unchanged. -Remote table, column and object names, a diff's expected and actual values, a -draft's review notes and generated source, node ids, run ids and trigger types, -and a server's own error message show as written in every locale. - -This is slice 4 of objectui#10862. diff --git a/.changeset/10862-designer-object-data-previews-locale.md b/.changeset/10862-designer-object-data-previews-locale.md deleted file mode 100644 index e269a902aa..0000000000 --- a/.changeset/10862-designer-object-data-previews-locale.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the object / data previews and the federated datasource panel read the designer locale (objectui#10862, slice 3) - -Under zh-CN these designer surfaces rendered their own words in English beside -Chinese text: - -- the object, dataset, view, report, page and validation previews: their - empty states and notes, the dataset preview's run button, counts and - ratio-axis note, the page preview's sample-record picker, the validation - rule's pills, section headings and redirect sentences for the removed rule - types, and the hint beneath every preview's error box; -- the page block canvas: its region and container labels, its empty states (no regions, an empty region, an inherited slot, an empty container group), the add-region and add-block buttons, drop target, rename tooltip, select labels, each block's render-failure hint and the add-block picker's search box, category headings and block names; -- the page source editor's label and error hint; -- the view column manager's heading, empty note, remove controls and - positional column label; -- the federated datasource panel inside the datasource preview: the save - prompt, header, write badge, snapshot line, refresh button, tab labels and - the federation-unavailable message. - -Each new en row is the English the literal carried, so en renders unchanged. -Author data (names, labels, messages, tags, rule and block types, region and -slot names, field names, CEL and regex sources), the error a renderer threw and -the name "JSON Schema" show as written in every locale. - -This is slice 3 of objectui#10862 (the object / data previews). diff --git a/.changeset/10864-app-shell-spec-floor.md b/.changeset/10864-app-shell-spec-floor.md deleted file mode 100644 index cd377b9ef0..0000000000 --- a/.changeset/10864-app-shell-spec-floor.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -Raise `@object-ui/app-shell`'s declared `@objectstack/spec` floor from -`^17.3.0` to `^17.4.0` (objectui#10864) — the old range admitted a spec that -lacks four symbols this package's own shipped artifact imports. - -`packages/app-shell/src/views/metadata-admin/previews/screen-spec.ts` imports -`predicateSlotRefusal` from `@objectstack/spec/automation`; -`packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-validate.ts` -imports `structuralConditionRefusal` from the same subpath plus -`EVALUATED_EXPRESSION_SOURCE_REQUIRED` and `EvaluatedExpressionSchema` from -`@objectstack/spec/shared`. `@objectstack/spec` was declared as `^17.3.0`, so -any resolution landing on 17.3.0 (which the range allows) gets a module that -names exports its own declared spec dependency does not have. - -Measured against the published `@objectstack/spec` tarballs (`npm pack`): -`predicateSlotRefusal`, `structuralConditionRefusal`, -`EVALUATED_EXPRESSION_SOURCE_REQUIRED` and `EvaluatedExpressionSchema` are -absent from every file under 17.3.0's `dist/`, and present under 17.4.0's -`dist/automation` and `dist/shared`. `@object-ui/types` already declares -`^17.4.0`. - -In this repository nothing moves at runtime: the lockfile already resolved -`@objectstack/spec` 17.4.0 for this specifier, so only the declared -`specifier:` range was stale. For a consumer, the range now refuses -`@objectstack/spec` 17.3.0, which the old range admitted and under which the -metadata-admin preview modules named four exports the installed spec does not -have. - -`pnpm check:spec-floors` was red before this change (4 `floor-too-low` -findings, all in `@object-ui/app-shell`) and green after, over a full -workspace build. diff --git a/.changeset/10866-calendar-dst-day-moves.md b/.changeset/10866-calendar-dst-day-moves.md deleted file mode 100644 index 7c1d46ca1e..0000000000 --- a/.changeset/10866-calendar-dst-day-moves.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch -'@object-ui/plugin-gantt': patch -'@object-ui/types': patch -'@object-ui/core': patch ---- - -fix(plugin-calendar): a day event moved across a DST change writes the days it was dropped on (objectui#10866, slice 4) - -- **plugin-calendar.** At this change the month grid moved each date of an event by the milliseconds between two local midnights, the grabbed cell's and the drop cell's, and a date-only value is read at local midnight of its day. So when a DST change lay between one of an event's dates and where it landed, but not between the two cells (or the other way round), that date came back an hour off local midnight; at 23:00 of the day before, the write took the day before. Under `America/Los_Angeles` a span of `date` fields moved across November 1st or March 8th could be written a day short at its start or its end. A move of an event whose start, and end when it has one, are both stored calendar days now writes each `date` field as its stored day moved by the whole days the grid moved it. Every other write is unchanged: a `datetime` field still writes the instant the grid hands back, and at this change the grid's own arithmetic does not change. - - ⚠️ **Dated note, 2026-09-29 — the month grid now moves by calendar days — objectui#11005.** Later in this same release the month grid moves a value by the calendar days between the grabbed cell and the drop cell and keeps its time of day, for a move and for a drag of a span's end, so a 10:00 `datetime` stays at 10:00 across a DST change. A `date` value read at local midnight of its day then comes back at local midnight of the day it was dropped on, so the repair described above is removed and a moved `date` field is written as that local day, which is the same day the repair wrote. The rest of this entry is kept as the reading of this change; the objectui#11005 entry states what ships. -- **plugin-gantt, types.** The business `timeZone` prose (`GanttConfig.timeZone`, `GanttViewProps.timeZone` and `makeTzShift`) said persisted data stays real instants. A `date` field under a zoned chart has been written as a calendar day since this card's first slice; at this change the prose says so, and says that near a DST change of the chart's zone or the viewer's the shim can place a day's midnight an hour early, onto the day before. Documentation only. - - ⚠️ **Dated note, 2026-09-29 — a zoned chart reads and writes a day exactly on a DST change — objectui#10866, slice 5.** Later in this same release `ObjectGantt` inverts the shim exactly for a date-only day, so a stored day is drawn from its own midnight and a drop writes the day it was dropped on, on a DST change of the chart's zone or the viewer's too. The `GanttConfig.timeZone` and `GanttViewProps.timeZone` prose no longer says a day can land on the day before, and `makeTzShift`'s says a day does not take the shim's round trip. The rest of this entry is kept as the reading of this change; the slice-5 entry states what ships. -- **core.** The `DATEADD` / `DATEDIFF` / `DATEFORMAT` docblock names how a mixed `DATEDIFF`, one day and one instant, reads each argument when it counts months or years. Comment only. diff --git a/.changeset/10866-calendar-gantt-date-only-days.md b/.changeset/10866-calendar-gantt-date-only-days.md deleted file mode 100644 index 6eb59d3b98..0000000000 --- a/.changeset/10866-calendar-gantt-date-only-days.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch -'@object-ui/plugin-gantt': patch -'@object-ui/types': patch ---- - -fix(plugin-calendar,plugin-gantt): a stored date-only day shows on that day in every viewer zone, and a `date` field is written back as a calendar day (objectui#10866, slice 1) - -The calendar and the gantt read a record's `YYYY-MM-DD` value with the engine's own `Date` parse, which reads it as UTC midnight. West of UTC a task due on the 5th therefore showed on the 4th, in both views. Moving it then wrote `toISOString()` into the field: a UTC instant stored in a `Field.date`. - -- **Reads.** Every date-only read in the two plugins now goes through `toDisplayDate` from `@object-ui/core`, which reads the value at local midnight of the day it names. In the calendar these are the object calendar's event start and end, and the `calendar-view` node's events and its authored `currentDate`. In the gantt they are the task start, end and baselines, a marker authored as a day, and the day typed into the inline editor. A value with a time keeps its instant. -- **Writes.** A calendar drop, a calendar quick-create and a gantt drag now write a field declared `date` as the local calendar day, `yyyy-MM-dd`. A `datetime` field keeps its instant. When no object schema is available to say which type a field is, the stored value's own shape decides, which is the same split the read makes; a calendar quick-create has no stored value, so there it still writes the instant. -- **Gantt `timeZone`.** A chart with a business `timeZone` re-bases every instant into that zone. A date-only day is not re-based: its bar and its marker stand on that day of the chart's calendar for every viewer, and a drop writes the day of the chart's calendar that the bar was dropped on. -- **Gantt working calendar.** `skipWeekends` / `holidays` now count the chart's own calendar days (local midnight, the same keys the day columns already folded by) rather than UTC days. The UTC floor put a rescheduled successor on the previous day in every zone except UTC once date-only values read as local days. `@object-ui/types` updates the `holidays` description to match. - -The timeline, charts, formula date functions and i18n helpers are later slices of objectui#10866. diff --git a/.changeset/10866-gantt-axis-formula-day-arithmetic.md b/.changeset/10866-gantt-axis-formula-day-arithmetic.md deleted file mode 100644 index 8126f27d66..0000000000 --- a/.changeset/10866-gantt-axis-formula-day-arithmetic.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/plugin-timeline': patch -'@object-ui/core': patch ---- - -fix(plugin-timeline,core): the timeline's gantt axis draws a stored date-only day on that day in every viewer zone, and the formula date functions do their day arithmetic on the UTC calendar, as the server does (objectui#10866, slice 3) - -- **Timeline, gantt variant.** Every date string the gantt branch reads now goes through `toDisplayDate` from `@object-ui/core`, the step its bar tooltip already takes: in the axis headers, the extent computed from the rows, the bar positions, the validity check and the check that the start is not after the end. A date-only value is local midnight of the day it names, and a value with a time part keeps its instant, which the axis places at its local hour in the viewer's day. A number or a `Date` is an instant and is read as before. West of UTC the headers no longer read the day before: a day axis over October 5th to 7th reads Oct 5, Oct 6, Oct 7, and the schema catalog's `gantt-style-timeline.json` reads Jan 2024 to Apr 2024, where it read Dec 2023, Jan 2024, Mar 2024, Apr 2024 in Los Angeles. So the axis now agrees with the bar tooltip. The computed extent is printed as the viewer's calendar day. An empty plan's one-day axis is the viewer's today, where it was the UTC day. A bar date naming a day its month does not have, such as `2026-02-30`, is now refused by the render-time "not a valid date" message, where it was rolled into March and drawn there. `generateTimeScaleHeaders`, which the package exports, reads a date-only `minDate` / `maxDate` the same way. -- **Formula date functions.** `DATEADD`, `DATEDIFF` and `DATEFORMAT` in `@object-ui/core` now do a calendar day's arithmetic on the UTC calendar. A date-only value naming a day its month has is read as UTC midnight of that day, as before, and is now moved and read with UTC setters and getters, so what the three answer for a day no longer depends on the viewer's zone. `DATEADD` hands such a day moved by days, months or years back as `YYYY-MM-DD`, where it gave an instant string. Its months clamp to the target month's last day, as the server's `addMonths` does: `DATEADD('2026-01-31', 1, 'month')` is `2026-02-28`, where it was `2026-03-03T00:00:00.000Z` in every zone, and a year from February 29th is February 28th. West of UTC, `DATEFORMAT('2026-09-01', 'YYYY-MM-DD')` no longer prints `2026-08-31`, `DATEDIFF` in months or years counts between the stored days rather than the days before them (`DATEDIFF('2026-08-31', '2026-09-01', 'month')` read 0), and a day added across a DST change no longer lands an hour off midnight. A value with a time part is unchanged: it is still moved and read in the viewer's zone and comes back as an instant, so `DATEFORMAT` still prints an instant's clock in the viewer's zone. So is a date-only value naming a day its month does not have, which the engine rolls forward as before. `TODAY()` is unchanged. diff --git a/.changeset/10866-gantt-move-end-days.md b/.changeset/10866-gantt-move-end-days.md deleted file mode 100644 index 099a5f6234..0000000000 --- a/.changeset/10866-gantt-move-end-days.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/plugin-gantt': patch ---- - -fix(plugin-gantt): a gantt move shifts a task's end by the calendar days it shifts the start, keeping each value's time of day across a DST change (objectui#10866, slice 6) - -On the day, week, month, quarter and year scales a drag snaps to whole days. The start moved by calendar days, but the end followed it by the elapsed milliseconds of the start's move, and a summary's group move carried every task beneath it by that same span. Across a DST change of the viewer's zone that span is a whole number of days plus or minus an hour. Under `America/Los_Angeles`, a `date` task from October 29th to October 31st moved three days wrote `end_date` `2026-11-02` where the drop reads November 3rd; a `datetime` end that crossed the change when its start did not moved its wall-clock time by an hour; a task under a moved summary could start on the day before the one it was dropped on. An edge drag past the other edge stopped 24 hours from it, which on a DST day is 23:00 of the day before, or 01:00. - -- **Move.** A drag now counts the calendar days its snapped start moved and moves the start and the end by that many days on the local calendar. Each keeps its hours, minutes, seconds and milliseconds, as objectui#11005 ruled for the calendar's month grid, so a `date` task keeps its length in days and a 10:00 start stays at 10:00. This deliberately changes the instant a drag writes into a `datetime` end across a DST change; what a `datetime` field stores and how it is read are unchanged. -- **Edge drags.** The end handle already moved the end by calendar days, keeping its time of day. An edge dragged past the other edge now stops one calendar day from it. -- **Group move.** Dragging a summary moves the summary and every unlocked task beneath it by the same calendar days, and the live preview draws what the drop writes. -- **Unchanged.** In a zone without DST every day is 24 hours, so a drag writes what it wrote before. The shift-band scale (`timeSegments` in day view) moves by bands on an elapsed-time axis and is unchanged. diff --git a/.changeset/10866-gantt-zoned-dst-days.md b/.changeset/10866-gantt-zoned-dst-days.md deleted file mode 100644 index dc419dc012..0000000000 --- a/.changeset/10866-gantt-zoned-dst-days.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@object-ui/plugin-gantt': patch -'@object-ui/types': patch ---- - -fix(plugin-gantt): a zoned chart reads and writes a stored day as that day on a DST change (objectui#10866, slice 5) - -A gantt with a business `timeZone` draws every date through a shim that re-bases it into that zone, and hands every dropped date back through the shim's inverse. Since this card's first slice, earlier in this same release, `ObjectGantt` has handed a date-only day in as the shim's inverse of the day's local midnight, and read a dropped `date` field back through the shim. Each direction reads the two zones' offsets at the instant it is handed, so on a DST day of one zone and not the other the round trip missed by an hour. An `America/Los_Angeles` viewer of an `America/New_York` chart saw a stored `2026-03-08` drawn from 23:00 on March 7th, and a drop onto March 8th wrote `2026-03-07`; `2026-11-01` was drawn from 01:00. A `Europe/Berlin` viewer of the same chart saw `2026-03-29` drawn from 23:00 on March 28th, and a drop onto it wrote `2026-03-28`. - -- **plugin-gantt.** `ObjectGantt` now inverts the shim exactly for a day: it hands the view the instant the shim maps onto the day's local midnight, and writes the day of the display date the dropped instant was translated from. A stored day is drawn from its own midnight and a drop writes the day it was dropped on, on a DST change of the chart's zone or the viewer's too. Where the shim draws no instant at that midnight, as when the chart's zone changes its clocks at 00:00, the day is drawn from the first instant after it, on that day. A `datetime` value goes through the shim unchanged, and a chart with no `timeZone` is unchanged. -- **types.** The `GanttConfig.timeZone` description said that near a DST change a day could be drawn, and a drop written, as the day before. It now says the day holds on a DST change too. diff --git a/.changeset/10866-timeline-charts-i18n-date-only.md b/.changeset/10866-timeline-charts-i18n-date-only.md deleted file mode 100644 index bbc5085eba..0000000000 --- a/.changeset/10866-timeline-charts-i18n-date-only.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/plugin-timeline': patch -'@object-ui/plugin-charts': patch -'@object-ui/i18n': patch ---- - -fix(plugin-timeline,plugin-charts,i18n): a stored date-only day reads as that day in every viewer zone on the timeline, on a chart's date axis and in the published date helpers (objectui#10866, slice 2) - -These readers parsed a `YYYY-MM-DD` value with the engine's own `Date` parse, which reads it as UTC midnight, so every viewer west of UTC saw the day before. Each now reads the value through `toDisplayDate` from `@object-ui/core`, which rebuilds a date-only value at local midnight of the day it names. A value with a time part keeps its instant. - -- **Timeline.** The object timeline's date bucket, its sort and the item date the renderer prints read the value that way. West of UTC an item due today no longer sits under "Overdue", one due tomorrow no longer sits under "Today", and the `short` and `long` item faces print the stored day. The `iso` face prints a date-only value's day from local getters, and an instant's UTC day as before. A day its month does not have, such as `2026-02-30`, is no longer rolled into March: the item sits under "No date", sorts with the dateless items, and its `short` and `long` faces are the ones an unparsable value already had. An unparsable value now sorts with the dateless items too, and the `iso` face prints such a value as written where it used to throw. The gantt variant's axis headers, extent and bar positions are not changed here, so west of UTC its bar tooltip, which prints through the same item-date function, now names the stored day while the axis above it still reads the day before, until a later slice of objectui#10866. -- **Charts.** A date-only category on the x axis reads `Sep 1` for `2026-09-01`, and `Sep 2026` on a month-grained axis, in every zone. When the display locale is a tag `Intl` refuses, the tick still prints the stored day: it reads the local-midnight value with local getters, because its `toISOString()` would name the day before east of UTC. An instant's fallback keeps its UTC day. A date-only category naming a day its month does not have falls back to the raw category, the face any other non-date category gets, instead of the rolled day. -- **i18n helpers.** `formatDate`, `formatDateTime`, `formatRelativeTime` and `formatDateSpec` read a date-only string as the day it names: `formatDateTime` shows midnight of that day, and `formatRelativeTime` counts to the start of it. `formatDateSpec` applies its `timeZone` to an instant only, and formats a date-only value in the local zone, where the shared step's local midnight reads back as its day; a `timeZone` west of UTC no longer turns `2026-09-01` into August 31st for every viewer. All four return a day its month does not have as the raw string. `formatRelativeTime` now returns an unparsable value as its string, the face the other three already gave one, where it used to throw a `RangeError`. diff --git a/.changeset/10867-app-wizard-saves-spec-app.md b/.changeset/10867-app-wizard-saves-spec-app.md deleted file mode 100644 index 0d0e81edb1..0000000000 --- a/.changeset/10867-app-wizard-saves-spec-app.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-designer': patch -'@object-ui/i18n': minor -'@object-ui/layout': patch -'@object-ui/app-shell': patch ---- - -fix(types,plugin-designer)!: the Studio app wizard saves a document the platform accepts, and an edit keeps the stored `accentColor` (objectui#10867) - -⚠️ **BREAKING (authoring)**, marked `minor` under this repository's version-alignment rule (a `major` in the fixed group would move all of it off the `@objectstack` major). Two published `@object-ui/types` members narrow: a navigation separator no longer takes a `label`, and `AppWizardDraft.layout` is removed. A TypeScript literal that writes either no longer compiles. `NavigationItem` is now a union type alias, not an interface. So code that reads `label` off an unnarrowed `NavigationItem` into a `string` slot (its type is now `string | undefined`; objectui#11299, in the same release, widens it to the spec's `I18nLabel` or `undefined`, see `.changeset/11299-types-nav-label-locale-map.md`) also stops compiling, as does code that spreads an entry-only key onto one, and an `interface` that `extends NavigationItem` or augments it (extend `NavigationEntryItem` instead). `objectui validate` now refuses a separator `label` too: the zod mirror's `NavigationItemSchema` refuses every key on a separator that the spec's separator does not declare. The four `appDesigner` layout keys also leave the published `@object-ui/i18n` packs and `DESIGNER_DEFAULT_TRANSLATIONS`, so an application that calls `t()` with one of them now renders the raw key (unless the call passes a `defaultValue`). - -**Clause-②: yes (narrowing)** — the separator arm of `NavigationItem` loses `label`, and `AppWizardDraft` loses `layout`. - -- **A separator carries only `type`, `id` and `order`.** `@objectstack/spec`'s separator branch declares exactly those keys, and its `AppSchema` refuses anything else. `NavigationItem` required a `label` on every item, so the wizard's "Add separator" wrote `{ id, type: 'separator', label: '' }`, and the console's create-app and edit-app saves were refused with `422 INVALID_METADATA` (`unrecognized_keys` `['label']` at `navigation.N`). `NavigationItem` is now a union of two arms, discriminated by `type`. `NavigationEntryItem` holds every other nav type and keeps its required `label`. `NavigationSeparatorItem` admits `type`, `id` and `order`, and every other entry key is `?: never` on it. Both arms are exported. Reading an entry-only key off an unnarrowed item still compiles, but its type now includes `undefined` (a `label` is `string | undefined`; objectui#11299, in the same release, makes it the spec's `I18nLabel` or `undefined`, see `.changeset/11299-types-nav-label-locale-map.md`), so passing it where a `string` is required does not. Narrow on `item.type === 'separator'` before relying on `label`. `menuItemToNavigationItem` maps a legacy separator to `{ id, type: 'separator' }` and drops its label. `spec-derived-unions.test.ts` no longer pins the separator `label` as a blocker. It asserts, at both spec tiers, that the separator arm admits the spec separator's keys and no others. -- **`@object-ui/plugin-designer`: the wizard and `NavigationDesigner` write a separator as `{ id, type }`.** `NavigationDesigner` no longer writes a `label` onto a new separator, and its label, icon and visibility patchers skip one. -- **`@object-ui/layout` narrows on the separator arm; nothing it renders changes.** `resolveNavItemLabel` answers `''` for every separator. A stored separator carrying a non-empty `label`, which `menuItemToNavigationItem` produced before this change, used to resolve to that label. No renderer asks it for a separator's label. The mobile bottom nav's leaf list, which already skipped separators, is now typed as entries. -- **`@object-ui/app-shell` narrows the same way; nothing it renders changes.** `useNavPins` registers a favorite only for an entry and leaves a separator as it is, and the Studio sidebar's navigation walk passes a separator through unchanged. -- **`@object-ui/plugin-designer`: `EditAppPage` keeps the stored branding.** The wizard maintains the logo, primary colour and favicon, and its `branding` replaced the stored block, so a stored `accentColor` was dropped on every edit. The console reads that key. The save now keeps every stored `branding` key the spec's `AppBrandingSchema` declares, read from that schema. The wizard's values win for the keys it maintains. A stored key the spec does not declare is still left out. -- **The wizard's Layout control is removed, with `AppWizardDraft.layout`.** The spec declares no app `layout`, no console surface reads one, and since objectui#10842 the save wrote none. The control persisted nothing. `EditAppPage` no longer reads a stored `layout` into the draft. The Basic Info step's description now reads "Name, title, and icon". -- **`@object-ui/i18n`:** the four `appDesigner` layout keys (`layout`, `layoutSidebar`, `layoutHeader` and `layoutEmpty`) are removed from all ten packs, and `appDesigner.stepBasicDesc` no longer names a layout. - -**Migration:** write a separator as `{ id, type: 'separator' }`, with an optional `order`. Remove `layout` from any `AppWizardDraft` you build. Code that spreads an entry-only key (`label`, `visible`, `requiredPermissions` and the rest) onto a value typed `NavigationItem` narrows it first (`item.type !== 'separator'`) or types it `NavigationEntryItem`: the separator arm refuses those keys. `AppComponentSchema.layout`, the renderer node's own layout strategy, is a different member and is unchanged. - -Pinned in `packages/types/src/__tests__/app-wizard-separator-layout-10867.test.ts` and `packages/plugin-designer/src/__tests__/AppWizard.specDocument-10867.test.tsx`. diff --git a/.changeset/10868-list-view-leftovers.md b/.changeset/10868-list-view-leftovers.md deleted file mode 100644 index 7944c08ab0..0000000000 --- a/.changeset/10868-list-view-leftovers.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/core': patch -'@object-ui/types': patch ---- - -fix(core): `normalizeListViewSchema`'s density fold tests an own key, not `in` (objectui#10868) - -The fold turned a legacy `densityMode` into `rowHeight` when the value was `in` -`DENSITY_MODE_TO_ROW_HEIGHT`, and `in` walks the prototype chain. So -`densityMode: 'toString'` came back with `rowHeight` set to -`Object.prototype.toString`, a function, and the key was dropped. The fold now -uses the same own-key test that `rowHeightToDensityMode` uses in the read -direction. An inherited key such as `'toString'` or `'constructor'` is now -treated like any other unrecognized density, such as `'cozy'`: nothing is -folded, `rowHeight` stays unset, and `densityMode` is kept. The three densities -`compact`, `comfortable` and `spacious` fold exactly as before. - -Such a value reaches the fold only on a render path that does not validate. -`@object-ui/types`' zod schemas already refuse it: the `list-view` node declares -`densityMode` as a three-value enum, and a named view refuses `densityMode` by -name. - -docs(types): `NamedListView`'s docblock no longer says the type is used in -`ObjectViewSchema.listViews`. Since objectui#7928 that member has been the -protocol's `ObjectListViewSchema`, by reference. The docblock now says what the -type is: exported, and the type of no member of the contract. The type itself is -unchanged. diff --git a/.changeset/10872-container-children-channel.md b/.changeset/10872-container-children-channel.md deleted file mode 100644 index be89409283..0000000000 --- a/.changeset/10872-container-children-channel.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/types': minor ---- - -The four `page:` containers take their child list in `properties.children`, the member their `@objectstack/spec` row declares, and refuse a node-level `children` by name: `page:card`, `page:section`, `page:footer` and `page:sidebar` (objectui#10872, batch 6). - -**Clause-②: yes (narrowing).** On each of the four zod arms, `children` and `body` are declared as by-name refusals, each kept a member of the arm. Both carry one message per block, which names `properties.children`. - -**What it was.** Each arm took `BaseSchema`'s node-level `children` as it was, so `{ "type": "page:section", "children": [ … ] }` parsed green on both faces (`safeValidateSchema`, and so `objectui validate`, and `StrictAnyComponentSchema`). `@objectstack/spec`'s own `PageComponentSchema` refuses that node: a page component has no node-level `children`, and the key is refused as unrecognized (ADR-0089 D3a). So `objectui validate` accepted a page that `os validate` refuses. A flat `body` was already refused, by `BaseSchema` (objectui#6771), but its message sent the author to the node-level `children`. - -**What changed, in observable terms.** - -- A node-level `children` on any of the four is refused with `invalid_type` at its own path, on both faces and nested in a page. -- `body` is refused as before, at the same path with the same code. The message no longer says "Did you mean `body` → `children`". -- The message's first sentence names `properties.children` and the row that declares it (`PageCardProps`, or `PageContainerProps` for the other three), with the node to write: `{ "type": "page:section", "properties": { "children": [ … ] } }`. -- `properties.children` parses on both faces, as it did. The spec row declares it on all four, and the spec's `PageComponentSchema` passes it. - -**Nothing renders differently.** The renderers are not touched and keep reading the node-level `children` and `body` for stored documents. `SchemaRenderer` hoists every `properties` key onto the node before the renderer runs, so a container authored with `properties.children` renders the same child list. The page designer's canvas addresses `properties.children` on these blocks, and the default page synthesizer emits none of them; where the node-level spelling still appears in a tree, `pnpm census:body-dialect --keys page:card,page:section,page:footer,page:sidebar` lists it. - -**Why `minor`, and why this breaks no published document.** `minor` follows the objectui#9256 narrowing precedent. This repo's version policy forbids `major` in any changeset (one `fixed` group), and records a narrowing as `minor` with an explicit note like this one. But the narrowing is not breaking against the last release. In `@object-ui/types` 17.6.0 no arm claims these four types, so every document naming one is refused with `invalid_union`: their arms (objectui#10872 batch 1) are unreleased, and ship in the same release as this entry. So no published version ever accepted a node-level `children` on these nodes: across the release, the accept set only widens. - -Also in this change, with no behaviour change: `objectql.zod.ts`'s two public-block arms (`object-metric`, `object-master-detail-form`) build their `properties` member with the same `propsBag` helper as the other public-block arms, instead of a byte copy of it. The member's description text is unchanged. - -Migration: move the child list into the bag. `{ "type": "page:section", "children": [ … ] }` becomes `{ "type": "page:section", "properties": { "children": [ … ] } }`. diff --git a/.changeset/10872-container-children-runtime-pin.md b/.changeset/10872-container-children-runtime-pin.md deleted file mode 100644 index 4777cf3699..0000000000 --- a/.changeset/10872-container-children-runtime-pin.md +++ /dev/null @@ -1,13 +0,0 @@ ---- ---- - -Tests only, no package released (objectui#10872, batch 7). A new pin in `@object-ui/components`, -`page-container-bag-children-10872.test.tsx`, mounts `page:card`, `page:section`, `page:footer` and -`page:sidebar` through the real `SchemaRenderer` and registry with two distinct children in -`properties.children`. It asserts that both render inside the container's own element, in the order -written. The controls are the same containers with no children and with an empty -`properties.children`: each renders its empty element and no child content. - -Batch 6 made `properties.children` the only child-list spelling the zod faces accept on these four -containers. It measured the runtime half once, with a probe it did not commit. This file is that -probe, committed. No renderer, schema or published file changes. diff --git a/.changeset/10872-element-number-arm.md b/.changeset/10872-element-number-arm.md deleted file mode 100644 index 30fae5e40c..0000000000 --- a/.changeset/10872-element-number-arm.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`safeValidateSchema` — and so `objectui validate` — accepts `element:number`, the ADR-0080 public block held back from batch 1, in both of the binding forms `@objectstack/spec` accepts (objectui#10872, batch 2). - -**Clause-②: yes** — the accept set of `AnyComponentSchema` widens by one `type` literal, and `@object-ui/types/zod` exports one new schema, `ElementNumberBlockSchema`. Nothing that parsed before is refused now. - -**What it was.** `element:number` is registered, curated as platform contract by ADR-0080 and declared by the spec (`ComponentPropsMap['element:number']`), while `AnyComponentSchema` carried no arm for it — so every `element:number` document was refused with `invalid_union` at `type`, and `objectui validate` reported "Schema validation failed" for any page that placed one. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `ElementNumberBlockSchema`, a member of `PublicBlockComponentSchema`; the strict authoring face (`StrictAnyComponentSchema`) accepts the same documents, closed to undeclared keys like every other arm. -- The props live where the spec puts them: `properties`, read by reference from the block's `ComponentPropsMap` row — its members, value types, retired-key refusals and strictness. `{ "type": "element:number", "properties": { "object": "order", "aggregate": "count" } }` is accepted; a `format` outside `number` / `currency` / `percent`, or a record-form `filter` (the spec's migration `element-number-filter-rule-array`), is refused at that member, and an undeclared prop is refused by name (`unrecognized_keys` on `properties`). -- The spec's one waiver is mirrored: the row requires `object`, and a bag may omit it when the node's `dataSource.object` is a non-empty object name, as the spec's props gate (`validateComponentProps` in `@objectstack/lint`) waives it. `{ "type": "element:number", "dataSource": { "object": "order" }, "properties": { "aggregate": "sum", "field": "total" } }` is accepted. -- A bag that names its object nowhere is refused at `properties.object`, with a message naming both fixes (set `properties.object`, or bind `dataSource.object`). An empty or non-string `dataSource.object` supplies nothing. The waiver covers an omitted `object` only: a wrong one (`"object": 7`) is refused even beside a binding. -- `dataSource` is declared on the node as the spec's `ElementDataSourceSchema`, by reference — the schema `PageComponentSchema.dataSource` is — so its members and its alias refusals (`objectName` → `object`) are the spec's, and the strict face judges a `dataSource` rather than refusing it as undeclared. -- A node with no `properties` bag is not judged against the row, as for every other public block and as the spec's props gate does. diff --git a/.changeset/10872-envelope-responsive-styles.md b/.changeset/10872-envelope-responsive-styles.md deleted file mode 100644 index 274fa2222e..0000000000 --- a/.changeset/10872-envelope-responsive-styles.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/types': minor ---- - -Every ADR-0080 public-block arm accepts the node-level `responsiveStyles` that `@objectstack/spec`'s `PageComponentSchema` declares, and judges it as the spec does (objectui#10872, batch 8). - -**Clause-②: yes (widening)** — the strict authoring face (`StrictAnyComponentSchema`) now accepts a node-level `responsiveStyles` on the 30 public-block arms (`PublicBlockComponentSchema` and `ObjectQLPublicBlockComponentSchema`), where it refused the key by name. On the tolerant face (`safeValidateSchema`) the key was already accepted, unjudged; it is now judged, so a value the spec refuses is refused there too. - -**What it was.** `responsiveStyles` is the ADR-0065 per-breakpoint style map that `SchemaRenderer` compiles to CSS scoped to the node. The spec declares it on every page component, the objectstack showcase writes it on public-block nodes (`element:text`, `element:button`, `object-metric`, `page:card`) and objectstack's UI skill teaches it. No arm here declared it, so a spec-valid node failed the strict face with `unrecognized_keys`, and the tolerant face kept any value it was given: `responsiveStyles: 7`, or a breakpoint the spec does not have (`md`), parsed clean and styled nothing. - -**What changed, in observable terms.** - -- Each public-block arm declares `responsiveStyles` as the spec's `ResponsiveStylesSchema`, by reference, so its breakpoints (`large`, `medium`, `small`, `xsmall`), its strictness and its own unknown-breakpoint message come from the spec. All 30 arms share one declaration. -- A node such as `{ "type": "page:section", "responsiveStyles": { "large": { "padding": "var(--space-6)" }, "small": { "padding": "var(--space-4)" } } }` parses on both faces, and the map comes back unchanged. -- A value the spec refuses (a `md` breakpoint, a number instead of a map, a style value that is neither a string nor a number) is refused on both faces at `responsiveStyles`, with the same issue the spec reports. On the tolerant face this is a narrowing: such a value used to pass unjudged, and `SchemaRenderer` would not have applied it. -- Nothing else widens. `BaseSchema` does not declare `responsiveStyles`, so the strict face still refuses it on the other arms. The other node-level keys the spec declares (`events`, `aria`, `visibility`, `responsive`, and `dataSource` outside the arms that already read it) stay undeclared and are still refused by name on the strict face. diff --git a/.changeset/10872-flat-arm-responsive-styles.md b/.changeset/10872-flat-arm-responsive-styles.md deleted file mode 100644 index 5fc1b5eba5..0000000000 --- a/.changeset/10872-flat-arm-responsive-styles.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`flex`, `object-grid` and `object-chart` accept the node-level `responsiveStyles` that `@objectstack/spec`'s `PageComponentSchema` declares on every page component, and judge it as the spec does (objectui#10872, batch 9). - -**Clause-②: yes (widening)**: the strict authoring face (`StrictAnyComponentSchema`) now accepts a node-level `responsiveStyles` on `FlexSchema`, `ObjectGridSchema` and `ObjectChartSchema`, where it refused the key by name. Batch 8 declared the same key on the 30 public-block arms; these are the three arms outside that set whose nodes the objectstack showcase and UI skill write it on. - -**What changed, in observable terms.** - -- The three arms declare `responsiveStyles` from the same shared declaration as the public-block arms: the spec's `ResponsiveStylesSchema`, by reference. Its breakpoints (`large`, `medium`, `small`, `xsmall`), its strictness and its unknown-breakpoint message come from the spec. -- A node such as `{ "type": "flex", "direction": "col", "responsiveStyles": { "large": { "display": "block", "minWidth": "0" }, "small": { "padding": "12px" } } }` parses on both faces, and the map comes back unchanged. The same holds for `object-grid` and `object-chart` nodes. -- The published TypeScript interfaces `FlexSchema`, `ObjectGridSchema` and `ObjectChartSchema` declare `responsiveStyles?: ResponsiveStyles`, the spec's type. Before, the key was typed `any` through `BaseSchema`'s index signature. -- Nothing else widens. `BaseSchema` still does not declare `responsiveStyles`, and neither does any other arm (`stack`, `grid` and `container` included), so the strict face still refuses it there by name. The other node-level keys the spec declares (`events`, `aria`, `visibility`, `responsive`, and `dataSource` on `flex` and `object-chart`) stay undeclared. - -**Narrowing, on already-published arms.** Unlike the public-block arms, these three were published before this change, and two things now refuse what used to pass: - -- The tolerant face (`safeValidateSchema`, the face `objectui validate` runs) used to keep any node-level `responsiveStyles` value on these arms unjudged. It now refuses a value the spec refuses, at `responsiveStyles`, with the spec's own issue: a breakpoint the spec does not have (`md`), a number instead of a map, or a style value that is neither a string nor a number. `SchemaRenderer` applied nothing for a number or for a map with no spec breakpoint. It emitted a non-CSS value inside a valid breakpoint verbatim, where the browser dropped it, and it applied the valid breakpoints of a mixed map. -- In TypeScript, a `responsiveStyles` value that is not the spec's `ResponsiveStyles` no longer type-checks on these three interfaces. -- An `object-view`'s `table` slot, which takes `ObjectGridSchema`'s members, does not gain the key. `ObjectView` draws its grid as a component, not as a schema node, so nothing compiles a `responsiveStyles` map written in `table`. The slot therefore refuses `table.responsiveStyles` by name, with that reason, on both faces, as it refuses the other node-level keys (objectui#10976). The tolerant face used to keep it unjudged, and the TypeScript slot never declared it. - -⚠️ **Dated note, 2026-10-01 — `object-chart` declares `dataSource` — objectui#11070.** "`dataSource` on `flex` and `object-chart`" in the list of node-level keys that stay undeclared held when this change landed. Later in this same release objectui#11070 (round 7) declared `dataSource` on `object-chart`, as the spec's `ElementDataSourceSchema` by reference; `flex` is unchanged. `.changeset/11070-grid-columns-chart-binding-round7.md` states what ships; the text above is kept as the reading of this change. diff --git a/.changeset/10872-flat-props-refusal.md b/.changeset/10872-flat-props-refusal.md deleted file mode 100644 index 8e2664e64c..0000000000 --- a/.changeset/10872-flat-props-refusal.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/types': minor ---- - -A public block's prop written directly on the node, instead of inside its `properties` bag, is refused by name on both faces, with a message naming `properties.KEY` (objectui#10872, batch 10). - -**Clause-②: no.** The change only refuses: no document that was refused now parses, and nothing joins the public surface. The new helper is internal to the zod modules and not re-exported from `@object-ui/types/zod`. - -**What it was.** Each public-block arm declares `properties` as the block's `@objectstack/spec` `ComponentPropsMap` row. The same member written on the node itself was not judged against that row. A key the node base (`BaseSchema`) does not declare, such as `{ "type": "record:details", "columns": "2" }`, passed `safeValidateSchema`, and so `objectui validate`, unjudged, and the strict authoring face refused it only as an unnamed `unrecognized_keys`. A key the base does declare (`visible`, `disabled`, `name`, `description`, `data`) passed both faces against the base's own type. `@objectstack/spec`'s own page component refuses every one of them as mis-layered (ADR-0089 D3a), so `objectui validate` accepted documents `os validate` refuses. - -**What changed, in observable terms.** - -- On the 26 public-block arms whose row declares a member, and on `object-metric`, `object-master-detail-form` and `object-timeline`, each member of the row written on the node is refused by `safeValidateSchema` and by `StrictAnyComponentSchema`, with `invalid_type` at that key's own path. The message reads "Did you mean `KEY` → `properties.KEY`?" and shows the bag spelling. This applies at every depth the faces judge, so a flat key on a child node is refused at the child's path. -- Write the block's props in the bag instead, as `AGENTS.md` #4 teaches: `{ "type": "action:button", "properties": { "label": "Open details", "actionType": "url", "target": "/users/ada" } }`. -- Two kinds of row member are left as they were. A member `@objectstack/spec`'s page component also declares on the node itself, such as `label` or `aria`, keeps its node-level meaning. A member the row itself retires (`page:header`'s `icon`, `page:card`'s `actions`, `record:details`' `layout`) keeps the row's own retirement message when written flat, instead of pointing at a bag member that is refused too. -- An arm's own refusal of a row key keeps its message: `record:alert`'s flat `body`, the `onSuccess` of `action:button` and `action:icon`, and the content-channel refusals. -- A key that is in neither the row nor `BaseSchema` stays as before: unjudged by the tolerant face, refused by the strict face. - -**What does not change.** Nothing at render time. `SchemaRenderer` still reads both spellings: it hoists each `properties` key onto the node before the renderer runs. So stored documents keep rendering, and so do nodes built in code, such as an action bar's menu, a dashboard's metric tile and a form's master-detail node, none of which passes through these faces. The `element:*` renderers read only the bag, so a flat key there never reached the block; the refusal now says so when the document is written instead of rendering nothing. - -**Across the release.** None of these arms has shipped yet: `@object-ui/types` 17.6.0 has no public-block arm, and its `safeValidateSchema` refuses all of these types at `type`. So for a published consumer the accept set only widens; this narrows what earlier entries of this same release accept. - -**Docs.** The two teaching sites left in the flat spelling after objectui#11183 now write the bag: the `record:related_list` actions example in the slotted-pages guide, and the two `action:button` route examples in `@object-ui/app-shell`'s README. diff --git a/.changeset/10872-held-block-content-channels.md b/.changeset/10872-held-block-content-channels.md deleted file mode 100644 index f83f2d7a3c..0000000000 --- a/.changeset/10872-held-block-content-channels.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/types': minor ---- - -The six public blocks that objectui#10872 batch 4 armed now refuse an authored `children`, and name the right remedy for a flat `body`: `action:button`, `action:icon`, `action:group`, `action:menu`, `element:definition-list` and `element:repeater` (objectui#10872, batch 5, by the objectui#9256 method). - -**Clause-②: yes (narrowing).** On each of the six zod arms, `children` and `body` are declared as by-name refusals, each kept a member of the arm. Both refusals carry one message per block, from the same helpers the objectui#9256 arms use. - -**What it was.** Batch 4 gave these blocks their arms, and each took `BaseSchema`'s channels as they were. So a node-level `children` on any of them parsed green on both faces (`safeValidateSchema`, and so `objectui validate`, and `StrictAnyComponentSchema`). None of their renderers reads the node's `children` or `body`, and `SchemaRenderer` strips both out of the props it spreads. So the child list rendered nothing, with no render-time error or warning and no element; only the parser tier's `not-a-container` warning (objectui#9910) noticed it. A flat `body` was already refused, by `BaseSchema` (objectui#6771), but its message pointed the author at `children`, the key that did nothing. - -**What changed, in observable terms.** - -- `children` on any of the six is refused with `invalid_type` at its own path, on both faces and nested in a page. -- `body` is refused as before, at the same path with the same code. The message no longer says "Did you mean `body` → `children`". -- The message names what the block renders instead, and so where the content goes: - - `action:group` and `action:menu`: `properties.actions`; - - `element:definition-list`: `properties.items`; - - `action:button` and `action:icon`: the button's `properties.label` and `properties.icon`, which are its whole content. -- `element:repeater` has no content channel: each row prints fields of the queried record. Its message says so, rather than naming a key that would do nothing either. -- `@objectstack/spec`'s own `PageComponentSchema` refuses a node-level `children` on all six as an unrecognized key. This refusal brings objectui's face into line with the spec; it is not a second rule. - -**Why `minor`, and why this breaks no published document.** `minor` follows the objectui#9256 narrowing precedent: this repo's version policy forbids `major` in any changeset (one `fixed` group), and records `minor` with an explicit note as the spelling of a narrowing. But this narrowing is not breaking against the last release. In `@object-ui/types` 17.6.0, every document naming one of these six types is refused with `invalid_union` at `type`, because the batch-4 arms are unreleased. They ship in the same release as this entry. So no published version ever accepted a `children` on these nodes: across the release, the accept set only widens. - -No render behaviour changes. Nothing read these keys, which is why they can be refused. - -Migration: put the content where the message says. A member action goes in `properties.actions`, and a term / description pair goes in `properties.items`. Anything else goes beside the node, in a container that reads `children` (`page:section`, `page:card`), or is dropped. diff --git a/.changeset/10872-held-public-block-arms.md b/.changeset/10872-held-public-block-arms.md deleted file mode 100644 index f74d883707..0000000000 --- a/.changeset/10872-held-public-block-arms.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`safeValidateSchema`, and so `objectui validate`, accepts the six ADR-0080 public blocks held back until `@objectstack/spec` carried a `ComponentPropsMap` row for each: `action:button`, `action:icon`, `action:group`, `action:menu`, `element:definition-list` and `element:repeater` (objectui#10872, batch 4). Their rows arrived in `@objectstack/spec` 17.5.0, measured at the renderers' read points (objectstack-ai/objectstack#20371). - -**Clause-②: yes.** The accept set of `AnyComponentSchema` widens by six `type` literals, and `@object-ui/types/zod` exports six new schemas. Nothing that parsed before is refused now. - -**What it was.** Each of these types is registered and curated as platform contract by ADR-0080, and `AnyComponentSchema` carried no arm for any of them. So every document naming one was refused with `invalid_union` at `type`. That included `action:button`, the node the validator's own handler-key refusals tell an author to write instead of an `onClick`. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `ActionButtonBlockSchema`, `ActionIconBlockSchema`, `ActionGroupBlockSchema`, `ActionMenuBlockSchema`, `ElementDefinitionListBlockSchema` and `ElementRepeaterBlockSchema`, each a member of `PublicBlockComponentSchema`. The strict authoring face (`StrictAnyComponentSchema`) accepts the same documents, closed to undeclared keys like every other arm. -- Each arm's `properties` bag is the block's spec row, read by reference: its members, value types and strictness are the spec's. The rows were measured at what the renderers read, not at what the registrations publish, so the validator refuses what no renderer reads: - - a group-level `name` on `action:group`, with the spec's own prescription; - - `size: "md"` on `action:group` and `action:menu`, whose renderers hand it to the Button primitive unmapped; - - the strings `"1"` / `"2"` for `element:definition-list`'s `columns`, where the renderer compares the number `2`: write `columns: 2`; - - a `label` on an `element:repeater` `fields` entry, which the list never prints. -- `element:repeater` requires `properties.object`: its renderer never queries without one, and it does not read the node's `dataSource`. -- `action:button` and `action:icon` also refuse two keys their renderers read off the node, each by name: - - an authored `onClick`, a runtime slot for a host-supplied function (objectui#6124), as `ButtonSchema.onClick` is; - - a flat `onSuccess`, with a message naming `properties.onSuccess`, where the spec row declares the post-success `{ navigate, openIn }` block. The spec's own page component refuses the flat spelling too. -- A prop written directly on the node rather than in `properties` is treated as on every other public block. The tolerant face passes a key `BaseSchema` does not declare, unjudged; the strict face refuses it. So the taught `{ "type": "action:button", "label": "Open details", "actionType": "url", "target": "/users/ada" }` validates through `objectui validate` as it runs today, while `StrictAnyComponentSchema` refuses its flat `actionType` and `target`, as `@objectstack/spec`'s `PageComponentSchema` does. The same node with its props in `properties` passes both faces. -- `record:line_items` is still refused at `type`: the spec has no row for it yet. - -⚠️ **Dated note, 2026-10-01 — props written flat on the node — objectui#10872 batch 10.** Later in this same release every member of a public block's row written directly on the node is refused by name on both faces, at its own path, with a message naming `properties.KEY`. So the bullet that says the tolerant face passes such a key unjudged, and that the flat `{ "type": "action:button", "label": "Open details", "actionType": "url", "target": "/users/ada" }` "validates through `objectui validate`", no longer describes the release as a whole: `objectui validate` refuses its `actionType` and `target` by name, as the strict face and `@objectstack/spec`'s page component do, and keeps the node-level `label`, which the spec's page component also declares. The bag spelling still passes both faces. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-03 — `record:line_items` armed — objectui#10872.** Later in this same release `@objectstack/spec` 17.6.0 carries a `ComponentPropsMap` row for `record:line_items`, and the block is armed from that row (`.changeset/10872-record-line-items-arm.md`). So the bullet "`record:line_items` is still refused at `type`: the spec has no row for it yet" no longer describes the release as a whole. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10872-public-block-zod-arms.md b/.changeset/10872-public-block-zod-arms.md deleted file mode 100644 index 51a388981c..0000000000 --- a/.changeset/10872-public-block-zod-arms.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`safeValidateSchema` — and so `objectui validate` — accepts twenty of the ADR-0080 public blocks, the ones whose props `@objectstack/spec` declares as a `ComponentPropsMap` row less `element:number` (below): `page:header`, `page:tabs`, `page:card`, `page:accordion`, `page:section`, `page:footer`, `page:sidebar`, `record:details`, `record:highlights`, `record:related_list`, `record:path`, `record:activity`, `record:discussion`, `record:history`, `record:quick_actions`, `record:reference_rail`, `record:alert`, `element:text`, `element:button` and `element:divider` (objectui#10872, batch 1). - -**Clause-②: yes** — the accept set of `AnyComponentSchema` widens by twenty `type` literals, and `@object-ui/types/zod` exports twenty-one new schemas. Nothing that parsed before is refused now. - -**What it was.** Every one of these types is registered, curated as platform contract by ADR-0080 (`PUBLIC_BLOCKS` in `@object-ui/core`) and declared by the spec, while `AnyComponentSchema` carried no arm for any of them — so every document naming one was refused with `invalid_union` at `type`, and `objectui validate` reported "Schema validation failed" for any page built from the public vocabulary, down to `{ "type": "record:details" }`. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports one arm per block — `PageHeaderBlockSchema`, `PageTabsBlockSchema`, `PageCardBlockSchema`, `PageAccordionBlockSchema`, `PageSectionBlockSchema`, `PageFooterBlockSchema`, `PageSidebarBlockSchema`, `RecordDetailsBlockSchema`, `RecordHighlightsBlockSchema`, `RecordRelatedListBlockSchema`, `RecordPathBlockSchema`, `RecordActivityBlockSchema`, `RecordDiscussionBlockSchema`, `RecordHistoryBlockSchema`, `RecordQuickActionsBlockSchema`, `RecordReferenceRailBlockSchema`, `RecordAlertBlockSchema`, `ElementTextBlockSchema`, `ElementButtonBlockSchema`, `ElementDividerBlockSchema` — and the category union `PublicBlockComponentSchema`, which `AnyComponentSchema` now lists. The strict authoring face (`StrictAnyComponentSchema`) derives from `AnyComponentSchema` and accepts the same blocks, closed to undeclared keys like every other arm. -- Each arm declares the block's props where the spec puts them: `properties`, whose value is the block's `ComponentPropsMap` row, read by reference. A bag is judged only when present, as the spec's own props gate judges it, and it is judged by the spec's row — its members, value types, retired-key refusals and strictness — so `{ "type": "page:header", "properties": { "title": "Account", "inventedProp": true } }` is refused, naming `inventedProp`, on both faces. `element:divider` is the one row restated rather than read, because the spec exports it under no name; it declares no prop, as the row does. -- A prop written directly on the node rather than inside `properties` is not judged against the block's row. A key the shared node base (`BaseSchema`) does not declare, such as `{ "type": "record:details", "columns": "2" }`, passes the tolerant face and is refused by the strict face. A key the base does declare is judged by the base instead. `children` (`page:card`, `page:section`, `page:footer`, `page:sidebar`), `label` and `disabled` (`element:button`) and `visible` (`record:alert`) are judged against the base's own types. `body` (`page:card`, `record:alert`) is refused on both faces by the base's objectui#6771 retirement: write a `record:alert` banner's `body` inside `properties`. -- `page:tabs` also refuses an authored `onTabChange`, by name: it is the callback `@object-ui/app-shell` injects onto the node to write `?tab=` back, a runtime slot a React host fills (objectui#6124), and a JSON value there was never a working handler — delete the key. -- Not armed in this release, and still refused at `type`: `element:number` (its row's required `object` is waived by the spec when the node binds through `dataSource`, which the row alone would refuse), `record:line_items` (the spec has no row for it yet), `element:definition-list` and `element:repeater` (the spec's `element:` vocabulary does not declare them), and `action:button`, `action:group`, `action:menu` and `action:icon` (no spec row yet; one is being measured from the renderers' read points upstream, objectstack-ai/objectstack#20371). - -⚠️ **Dated note, 2026-09-28 — `element:number` armed — objectui#10872 batch 2.** Later in this same release `element:number` is armed as well (`ElementNumberBlockSchema`, with the spec's `dataSource` waiver on its required `object`), so the lead sentence's "less `element:number`" and the first item of the "Not armed in this release" bullet no longer describe the release as a whole; the other held blocks are still refused at `type`. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-09-29 — `record:alert`'s flat `body` — objectui#10872 batch 3.** Later in this same release `record:alert`'s arm restates `body` with its own refusal, which names `properties.body`. So the bullet on a prop written directly on the node, where it says "`body` (`page:card`, `record:alert`) is refused on both faces by the base's objectui#6771 retirement", no longer describes the release as a whole: that holds for `page:card` only, and a flat `body` on `record:alert` is still refused on both faces, by the arm's own refusal instead. The bullet's advice, to write a `record:alert` banner's `body` inside `properties`, is what that refusal now says. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-09-30 — the six held blocks armed — objectui#10872 batch 4.** Later in this same release `@objectstack/spec` 17.5.0 carries a `ComponentPropsMap` row for `element:definition-list`, `element:repeater`, `action:button`, `action:group`, `action:menu` and `action:icon`, and each is armed from its row (`.changeset/10872-held-public-block-arms.md`). So the last two blocks of the "Not armed in this release" bullet no longer describe the release as a whole: of the held blocks, only `record:line_items` is still refused at `type`. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-09-30 — the four `page:` containers' child list — objectui#10872 batch 6.** Later in this same release the arms of `page:card`, `page:section`, `page:footer` and `page:sidebar` refuse a node-level `children` and restate `body`, both with a message that names `properties.children`, the member their spec row declares (`.changeset/10872-container-children-channel.md`). So the bullet on a prop written directly on the node, where it says `children` (`page:card`, `page:section`, `page:footer`, `page:sidebar`) is judged against the base's own type and `body` (`page:card`) is refused by the base's objectui#6771 retirement, no longer describes the release as a whole: on those four, both keys are refused by the arm's own refusal. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-01 — props written flat on the node — objectui#10872 batch 10.** Later in this same release every member of a public block's row written directly on the node is refused by name on both faces, at its own path, with a message naming `properties.KEY`. So the bullet on a prop written directly on the node, where it says such a key "is not judged against the block's row", that `{ "type": "record:details", "columns": "2" }` "passes the tolerant face", and that `disabled` (`element:button`) and `visible` (`record:alert`) are judged against the base's own types, no longer describes the release as a whole: all of those are refused, on both faces, and the message names the bag member. `label` (`element:button`) is the exception, because `@objectstack/spec`'s page component declares a node-level `label` of its own. The rest of this entry is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-03 — `record:line_items` armed — objectui#10872.** Later in this same release `@objectstack/spec` 17.6.0 carries a `ComponentPropsMap` row for `record:line_items`, and the block is armed from that row (`.changeset/10872-record-line-items-arm.md`). So the "Not armed in this release" bullet's `record:line_items` item ("the spec has no row for it yet"), and the 2026-09-30 note's "only `record:line_items` is still refused at `type`", no longer describe the release as a whole: none of the held public blocks is still refused at `type`. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/10872-record-alert-body-remedy.md b/.changeset/10872-record-alert-body-remedy.md deleted file mode 100644 index 8bbcfe04c6..0000000000 --- a/.changeset/10872-record-alert-body-remedy.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/types': patch ---- - -`record:alert`: a `body` written directly on the node, rather than inside `properties`, is now refused with a pointer to `properties.body`, where the banner's message text lives (objectui#10872, batch 3). The refusal used to be `BaseSchema`'s objectui#6771 message, which sent the author to `children`: a key this block renders nothing from, and which its arm refuses (objectui#9256). - -- Before: `{ "type": "record:alert", "body": "Verify your email" }` was refused at `body` with "Did you mean `body` → `children`?". -- After: the same document is refused at `body` with "Did you mean `body` → `properties.body`?", and the message spells the document to write: `{ "type": "record:alert", "properties": { "body": "…" } }`. - -**What does not change: which documents parse.** A flat `body` on `record:alert` was refused before and is refused now, with the same issue code (`invalid_type`) at the same path, by `safeValidateSchema` (and so by `objectui validate`) and by the strict authoring face. `properties.body` parsed before and parses now. Every other node keeps its `body` refusal as it was. - -Migration: if you followed the old message and moved an alert's text into `children`, move it to `properties.body`. A `children` on `record:alert` is refused, and nothing renders it. diff --git a/.changeset/10872-record-line-items-arm.md b/.changeset/10872-record-line-items-arm.md deleted file mode 100644 index e478f88ef8..0000000000 --- a/.changeset/10872-record-line-items-arm.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`safeValidateSchema`, and so `objectui validate`, accepts `record:line_items`, the last ADR-0080 public block it refused at `type` (objectui#10872). `@objectstack/spec` 17.6.0 carries the block's `ComponentPropsMap` row, measured at the reads of `LineItemsPanel`, and the arm reads that row by reference. - -**Clause-②: yes.** The accept set of `AnyComponentSchema` widens by one `type` literal, and `@object-ui/types/zod` exports one new schema, `RecordLineItemsBlockSchema`. Nothing that parsed before is refused now: every document naming `record:line_items` was refused before. - -**What it was.** `record:line_items` is registered by `@object-ui/plugin-form` and curated as platform contract by ADR-0080, and `AnyComponentSchema` carried no arm for it. Every document naming it was refused with `invalid_union` at `type`, whatever the rest of the node said. The arm was held until the spec carried a row for the block. - -**What changed, in observable terms.** - -- `@object-ui/types/zod` exports `RecordLineItemsBlockSchema`, a member of `PublicBlockComponentSchema`. The strict authoring face (`StrictAnyComponentSchema`) accepts the same documents and is closed to undeclared keys, as on every other arm. -- The block's props live in `properties`, and the bag is the spec row: its members, value types and strictness are the spec's. `relationshipField` and `columns` are required there, and `childObject` is optional. A key the row does not declare is refused inside the bag, by name. -- A row member written on the node instead of in `properties` is refused by name on both faces, at its own path, with a message naming `properties.KEY`, as on every other public block. -- The node's `dataSource` binding is declared as the spec's `ElementDataSourceSchema`, read by reference. The block's registration wraps `ElementDataSourceGate`, which puts `dataSource.object` into `childObject`, so a bound node without `childObject` passes both faces. A binding that the spec refuses is refused at `dataSource`. -- A node-level `children` or `body` is refused by name on both faces. The block renders the grid of child records and reads neither key, and `@objectstack/spec`'s page component refuses a node-level `children` on it too. diff --git a/.changeset/10874-ai-node-faces-agree.md b/.changeset/10874-ai-node-faces-agree.md deleted file mode 100644 index 72c498e6fa..0000000000 --- a/.changeset/10874-ai-node-faces-agree.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -'@object-ui/types': minor ---- - -**BREAKING (authoring)** — the three `@object-ui/plugin-ai` node declarations stop offering members that no runtime honours, and type the handler slots their components call (objectui#10874, ADR-0049, the objectui#6124 per-key rule). - -**Clause-②: yes** — authorable members of published `@object-ui/types` declarations narrow. Three members become callable: `string` to a function type (`onSelect`, `onDismiss`, `onSubmit`). `config` and `context` become `never` on both faces, five members across the three declarations. `onApplySuggestion` and `onRejectSuggestion` become `never` on the TypeScript face, and the zod face already refused them. Scored `minor`, not `major`: this repository scores its own breaking changes `minor` and spells the breaking semantics out in the body (`check:changeset-no-major`). - -**What changes, on which face.** - -| Member | Was on | TypeScript face | zod face | -|---|---|---|---| -| `onSelect`, `onDismiss` | `AIRecommendationsSchema` | CALLABLE: `(item: AIRecommendationItem) => void` (was `string`) | refused by name, unchanged | -| `onSubmit` | `NLQuerySchema` | CALLABLE: `(query: string) => void` (was `string`) | refused by name, unchanged | -| `onApplySuggestion`, `onRejectSuggestion` | `AIFormAssistSchema` | `?: never` (was `string`) | refused by name, unchanged | -| `config` | `AIFormAssistSchema`, `AIRecommendationsSchema`, `NLQuerySchema` | `?: never` (was `AIConfig`) | refused by name (was accepted) | -| `context` | `AIFormAssistSchema`, `AIRecommendationsSchema` | `?: never` (was a string-keyed record) | refused by name (was accepted) | - -**Why.** - -- `onSelect`, `onDismiss` and `onSubmit` are RUNTIME SLOTS. Each node type is registered to its raw component, `SchemaRenderer` spreads the node's own keys onto the component's props, and `AIRecommendations` and `NLQueryInput` call these keys as functions. So a function on the node was always called, and a string there was called as a function and threw at click. The TypeScript face now declares the callable the component invokes, as objectui#6124 rules for a key a runtime consumer calls. The zod face keeps refusing an authored value, because JSON has no function value. -- `onApplySuggestion` and `onRejectSuggestion` were read by nothing: `AIFormAssist` takes `onApply` and `onRefresh`, so a string there did nothing. -- `config` and `context` were read by nothing in `@object-ui/plugin-ai`. The three components are presentation only and call no model, so a `provider`, `model`, `systemPrompt` or context written on the node did nothing and changed nothing on screen. -- Before this change the zod face refused all five `on*` strings (objectui#10859) while the TypeScript face offered them, so `onSelect: 'x'` passed `tsc` and was then refused by the validator. Now `tsc` refuses the string too. - -**Migration.** - -- `onSelect`, `onDismiss`, `onSubmit`: pass a function, never a string — either as the component prop of the same name, or on a node you build in TypeScript. `AIRecommendations` and `NLQueryInput` take the same signatures as props, unchanged. -- `onApplySuggestion`: delete it, and use the `onApply` prop of the `AIFormAssist` component. `onRejectSuggestion`: delete it; the component has no reject callback. -- `config`: delete it. Configure the model in your host's own AI service (ObjectUI has no AI-provider API; these components call no model), and hand its output to the node as `suggestions`, `recommendations` or `result`. -- `context`: delete it, and pass the context to your host's own AI service when you ask it for suggestions or recommendations. - -```tsx -// before: compiled; `config` did nothing, and the string was called as a function and threw at click -const picks: AIRecommendationsSchema = { - type: 'ai-recommendations', - recommendations, - config: { model: 'gpt-4' }, - onSelect: 'openItem', -}; - -// after -const picks: AIRecommendationsSchema = { - type: 'ai-recommendations', - recommendations, - onSelect: (item) => openItem(item), -}; -``` - -**What does not change.** The renderers are untouched, so a stored document renders exactly as it did: `config` and `context` were ignored and still are, and a function reaching `onSelect`, `onDismiss` or `onSubmit` is still called. What moves is the verdict. `tsc` refuses the four retired keys, on all seven member slots that carried them, and a string on the three slots. The validator refuses `config` and `context` by name, where the arms objectui#10859 added in this same release accepted them. The exported `AIConfig` type and `AIConfigSchema` stay; no node member takes them any more. - -⚠️ **The census behind "read by nothing" is the in-repo half.** Every package, app, example, doc and skill in this repository was searched: none reads `config` or `context` off an AI node, and none authors a changed member. Customer applications and published documents outside it were not enumerated. A TypeScript consumer that authored one of these keys gets a compile error naming it. diff --git a/.changeset/10881-grouping-needs-header-query.md b/.changeset/10881-grouping-needs-header-query.md deleted file mode 100644 index 64b16e69cb..0000000000 --- a/.changeset/10881-grouping-needs-header-query.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -'@object-ui/plugin-grid': minor -'@object-ui/plugin-list': minor -'@object-ui/i18n': minor ---- - -A grouped grid over a data source that declares no `queryGroupHeaders` now -**refuses grouping** instead of grouping a page of rows (objectui#10881, -maintainer ruling F). Grouping is a property of the query (ruling A on -objectui#7189): a data source that cannot answer the group header query cannot -group, so the grid names the member it is missing rather than drawing counts it -cannot know. - -- **`@object-ui/plugin-grid`** — a grouped `object-grid` that fetches its own - rows over such a source renders an error panel naming `queryGroupHeaders` - and issues no row query. It used to fetch one window and group it in the - browser, so every group count was a page slice and a group whose rows all - fell past the window was missing. Rows handed in WHOLE — a - `data: { provider: 'value', items }` block, or a `data` prop from a parent - view that declares no larger `rowCount` — are still grouped in the browser, - exactly. A host that hands rows in while declaring them one page of more - (the external-pagination props: `manualPagination`, `onPageChange` and a - `rowCount` above the rows it handed) is now refused as well, with a sentence - of its own: grouping needs every record. It used to have that page grouped as - if it were whole. -- **`@object-ui/plugin-list`** — `ListView` makes the same refusal, with the - same sentence, in place of a grouped grid over such a source, and fetches no - window for it. It used to fetch one window and hand it to the grid as - `data`, which the grid grouped as if the rows were whole. Rows handed to - `ListView` in whole are still handed to the grid. -- **`@object-ui/i18n`** — two new keys, `grid.grouping.needsHeaderQuery` and - `grid.grouping.needsWholeRows`, in all ten locale packs. - -The `Partial` marker described by the pending -`7189-grouped-grid-partial-disclosure` entry is retired everywhere before any -release carried it: its three `grid.grouping.partial*` strings, `GroupRow`'s -`partialLabel` / `partialTitle` props and the notice above the group list are -gone. - -**Breaking semantics (declared `minor` per this repo's version policy):** a -grouped grid that fetches its own rows over a data source without -`queryGroupHeaders` — `ApiDataSource`, `ValueDataSource`, or a host adapter — -grouped the page it fetched in the last release, and now renders an error panel -instead. So does a grouped grid view in `ListView` over such a source. So does -a grouped grid handed rows by a host that declares them one page of more -(`manualPagination`, `onPageChange` and a `rowCount` above the rows handed), -whatever its data source. To keep grouping, either: - -- implement `queryGroupHeaders` on the data source (the ObjectStack adapter - does), and let the grid fetch its own rows, or -- hand the rows in whole (`data: { provider: 'value', items }`, or a `data` - prop with no `rowCount` above it). - -Not changed here: while a toolbar search is active, `ListView` over a data -source that answers the header query still hands a grouped grid its window, -whose group counts are the window's, because the header query carries no -search (objectstack#20358). diff --git a/.changeset/10885-object-view-route2-named-grid.md b/.changeset/10885-object-view-route2-named-grid.md deleted file mode 100644 index 27e3f4e017..0000000000 --- a/.changeset/10885-object-view-route2-named-grid.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -The registered `object-view` renderer reads a named grid view's own grid members off the named view (objectui#10885). - -`object-view` is registered without a `renderListView`, so an authored node, and the Studio's view preview (which renders a stored view through `SchemaRenderer`), draws a grid view as the `object-grid` node `ObjectView` builds for `ObjectGrid`. That node read `columns`, `filter`, `sort`, `grouping` and `rowColor` off the active named view and nothing else, so a stored or authored grid view's `rowHeight`, `pagination` and the rest were accepted and not shown. - -It now also reads, off the active named view first, ten members the protocol declares under the same name on both a named view and `object-grid` and that `ObjectGrid` reads: `pagination`, `selection`, `rowHeight`, `resizable`, `searchableFields`, `conditionalFormatting`, `rowActions`, `bulkActions`, `bulkActionDefs` and `exportOptions`. `pagination` and `selection` still fall back to the node's `table` when the named view omits them; at this change the others have no node fallback on this path, as before. Three other members declared on both, `label`, `data` and `navigation`, are still not read off the named view on this path. - -A named view's `hiddenFields` is applied the way the protocol composes it: the hidden fields are removed from the column projection the grid receives. Only a declared projection is narrowed; with no `columns` anywhere the grid still derives its own. - -What moves: only a grid view that authors one of these members. A named view that carries none of them renders exactly as before, and the host `renderListView` delegation is unchanged. - -`Clause-②: no` — no declared type, accepted key or published export moves. A renderer starts honouring members the spec already declares on a named view and the grid already reads. - -⚠️ **Dated note, 2026-09-28 — `navigation` has since been read off the named view — objectui#10885.** Later in this same release, the row click on this path follows the active named view's `navigation`, which replaces the node's `navigation` as a whole, and so do the surface and width of the forms it opens. The host `renderListView` delegation's row click follows it too, because both paths hand down the same click handler. A host `onRowClick` passed to `ObjectView` still wins on both paths. The same change applies a named view's `fieldOrder` to the projected columns, after `hiddenFields`, and hands the grid its `inlineEdit`, which `ObjectGrid` still gates on the object's inline-edit grant. `label` and `data` are not handed to the grid on this path, by ruling: `label` is already the tab's text, and `data` waits on objectui#10971. The rest of this entry is kept as the reading of this change; the objectui#10885 member 4 entry states what the path reads now. - -⚠️ **Dated note, 2026-09-29 — every one of these members now falls back to `table` — objectui#10976.** Later in this same release the node's `table` is the fallback of each of the ten members above, and of `inlineEdit` as `table.editable`, on this path; the named view still wins where it declares the member. The other grid keys the `table` slot relays reach the grid on this path too, `label` among them: a `label` written on `table` is now the grid's caption and export view label on this path, which supersedes, for `table.label`, the 2026-09-28 note's sentence that `label` is not handed to the grid; the named view's `label` is still not read, and `table.data` is withheld by the slot and refused by name. The rest of this entry is kept as the reading of this change; the objectui#10976 entry states what ships. diff --git a/.changeset/10885-object-view-route2-named-view-rest.md b/.changeset/10885-object-view-route2-named-view-rest.md deleted file mode 100644 index d64a47e9e1..0000000000 --- a/.changeset/10885-object-view-route2-named-view-rest.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -A named view's `navigation`, `fieldOrder` and `inlineEdit` now reach the registered `object-view` renderer's grid (objectui#10885, member 4). - -`object-view` is registered without a `renderListView`, so an authored node, and the Studio's view preview, draws a grid named view as the `object-grid` node `ObjectView` builds for `ObjectGrid`. That path now reads three more members off the active named view: - -- `navigation` replaces the node's `navigation` as a whole while the named view is active. Everything `ObjectView` derives from it follows: the row click, the surface the record, create and edit forms open on, and that surface's width. Under a named `split` or `popover`, as under the node's own, the New button opens no form, because those two surfaces open only beside a selected record. The host `renderListView` delegation's row click follows it too: both paths hand down the same click handler, and until now that handler read the node's `navigation` only, so a named view's `navigation` was overruled there as well. A host `onRowClick` passed to `ObjectView` still wins on both paths. -- `fieldOrder` orders the projected columns, after `hiddenFields` has removed its fields, the same way `ListView` orders them on the delegation. Columns `fieldOrder` does not name keep their order after the named ones. A name the projection does not carry orders nothing, and with no projection nothing is added. -- `inlineEdit` is handed to the grid as `editable`. `ObjectGrid` still turns in-cell editing on only where the object grants inline edit and the user may update the record. - -At this change `label` and `data`, also declared on both a named view and `object-grid`, are not handed to the grid on this path, by ruling. The named view's `label` is already the tab's text, and handing it to the grid would paint a second caption the delegation never paints. `data` is held back because `ListView` and `ObjectGrid` pick different objects when `data.object` differs from the node's `objectName` (objectui#10971). - -What moves: only a named view that authors one of these three members. The objectui#5097 host-composition relay is unchanged. - -`Clause-②: no` — no declared type, accepted key or published export moves. A renderer starts honouring members the spec already declares on a named view. - -⚠️ **Dated note, 2026-09-28 — the New button now opens a create form under `split` and `popover` — objectui#10975.** -Later in this same release, under a `split` or `popover` navigation, the node's own or the active named view's, the New button's create form opens on the surface the node uses with no `navigation`: the modal for `layout: 'modal'`, the drawer otherwise. A record opened to view or edit still opens beside the list. The sentence above that says the New button opens no form is kept as the reading of this change; the objectui#10975 entry states what ships. - -⚠️ **Dated note, 2026-09-29 — a `label` written on `table` now reaches the grid on this path — objectui#10976.** -Later in this same release the registered renderer hands the grid on this path a `label` written on the node's `table`, and the grid draws it as its caption and uses it as its export view label, as it already did with `table.title`; the host `renderListView` delegation does not take it. The named view's `label` is still not read on this path. `data` is not handed to the grid on this path either way: the `table` slot withholds `data` and the validator refuses `table.data` by name, and the named view's `data` still waits on objectui#10971. The sentence above about `label` and `data` is kept as the reading of this change; the objectui#10976 entry states what ships. diff --git a/.changeset/10887-dashboard-filter-options-bus-reader.md b/.changeset/10887-dashboard-filter-options-bus-reader.md deleted file mode 100644 index eeeb3fd42e..0000000000 --- a/.changeset/10887-dashboard-filter-options-bus-reader.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -fix(plugin-dashboard): a dashboard filter's `optionsFrom` options re-read on the data-invalidation bus - -A `select` or `lookup` entry in a dashboard's `globalFilters` that reads its -options through `optionsFrom` now re-reads them when the bus reports a change to -`optionsFrom.object` (`notifyDataChanged`, as a page action over raw HTTP -does), or an unscoped `'*'`, on either read: the server-side dataset GROUP BY -and the client-side `find` fallback. A change to another object does not -re-read. The options on screen stay until the re-read answers, and the value the -user selected is kept: it is the dashboard variable's, and the read never writes -it. Before, the options refreshed after such a write only when the host -remounted the dashboard, and `PageView` is about to stop doing that -(objectui#10519). - -A filter with authored `options` and no `optionsFrom` reads nothing and does not -subscribe. - -**Clause-②: no** — no exported symbol, prop or authored key is added, removed, -renamed or retyped, and no accept set moves. What changes is when an existing -read runs. diff --git a/.changeset/10887-object-view-non-grid-bus-reader.md b/.changeset/10887-object-view-non-grid-bus-reader.md deleted file mode 100644 index 6d8490b2ee..0000000000 --- a/.changeset/10887-object-view-non-grid-bus-reader.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -fix(plugin-view): an `object-view` in a non-grid view re-reads its rows on the data-invalidation bus - -For the non-grid views (kanban, calendar, gallery, timeline, map, gantt), -`ObjectView` fetches the rows itself and hands them to the inner view as -`data`, which switches off that view's own bus reader. A gantt handed zero rows -is the one exception: it still queries for itself and keeps its own bus reader -beside this one (objectui#7333), so both re-read, and both answers are correct. -`ObjectView`'s fetch now names the `useDataInvalidation` nonce for -`schema.objectName`, so a write declared on the bus (`notifyDataChanged`, as a -page action over raw HTTP does), or an unscoped `'*'`, re-reads the rows in -place: the inner view is not remounted. A change to another object does not -re-read. Before, such a write reached these views only when their host -remounted them, and `PageView` is about to stop doing that (objectui#10519). - -The subscription follows the rows the view draws: a host `renderListView` (its -`ListView` reads the bus itself) and the grid (`ObjectGrid` does too) do not -subscribe here, and neither does a view with no object or no data source. Nor -do the host-only `tree` and `chart` views: their renderers query for themselves -and read the bus themselves, so a re-read here would only add reads beside -theirs. - -**Clause-②: no** — no exported symbol, prop or authored key is added, removed, -renamed or retyped, and no accept set moves. What changes is when an existing -read runs. diff --git a/.changeset/10887-react-page-data-invalidation.md b/.changeset/10887-react-page-data-invalidation.md deleted file mode 100644 index 1624351a61..0000000000 --- a/.changeset/10887-react-page-data-invalidation.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/components': minor ---- - -feat(components): a `kind: 'react'` page's author scope injects `useDataInvalidation` - -A react page reads data through the injected `useAdapter`, in an effect it -writes itself. The scope gave that effect no data-invalidation reader to name, -so the read the react-pages guide taught, keyed on `[adapter]`, re-ran only -when the page was remounted (as `PageView` did after a page action) or its -adapter changed. - -The scope now injects `useDataInvalidation` from `@object-ui/react` beside -`useAdapter`: the same hook `ListView` reads to refresh its rows. -`useDataInvalidation('showcase_project')` returns a number that moves when the -data-invalidation bus reports a write to that object, or an unscoped `'*'`. -Named in the dependency list of the effect that reads through `useAdapter`, it -re-runs that read in place: the page is not remounted and keeps its own state. -A write to another object does not re-run it, and a page that does not name the -hook behaves as before. The hook is a module-level function, so the scope's -identity is as stable as it was and injecting it recompiles no page. - -The react-pages guide (`content/docs/guide/react-pages.md`) lists it in the -scope table, and its Live data example names the nonce in the effect's -dependencies. - -**Clause-②: yes** — one identifier joins the published author scope of -`kind: 'react'` pages, so the set of names a page's source can resolve widens. -Nothing is removed or renamed. The one source this can break is a page that -declares its own top-level `const` or `let` named `useDataInvalidation`: the -scope's names are the parameters of the function the source is evaluated in, -so that declaration is now a `SyntaxError`, shown in the page's error panel. -Renaming the page's own identifier resolves it. diff --git a/.changeset/10893-signup-carries-verification-callback.md b/.changeset/10893-signup-carries-verification-callback.md deleted file mode 100644 index 7d5f76b138..0000000000 --- a/.changeset/10893-signup-carries-verification-callback.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@object-ui/auth': minor -'@object-ui/console': patch ---- - -fix(auth, console): a registration started from an invitation link comes back to the invitation after email verification - -better-auth builds the verification mail's link server-side from the -`/sign-up/email` request's `callbackURL`, defaulting it to `/`. The console kept -`?redirect=/accept-invitation/ID` from the login page through `/register` to the -"check your inbox" screen, but `createAuthClient().signUp` never sent a -`callbackURL`, so the mail read `callbackURL=/` and the invitee verified onto the -workspace picker ("Create workspace") instead of the invitation. - -`@object-ui/auth` (additive): - -- `SignUpData.callbackURL` is forwarded verbatim to `/sign-up/email`. Absent, the - key stays off the wire and the server default is untouched. -- `useAuth().signUp(name, email, password, callbackURL?)` takes it as an optional - fourth argument. -- `RegisterForm` gains a `verificationCallbackURL` prop, forwarded to `signUp`. - -`@object-ui/console`: - -- `RegisterPage` passes a safe `?redirect=` as the verification callback, and the - verify-email prompt's "Resend" sends the same value. Before, Resend sent the - bare router path, which the server redirects to at the ORIGIN root, outside - the `/_console` mount. -- Both resolve the route through the new `withConsoleBaseRootRelative`. The server - never sees ``, and better-auth refuses a document-relative `./…` - callback — what `withConsoleBase` answers in the embedded build — with - `403 INVALID_CALLBACK_URL`, failing the whole sign-up. diff --git a/.changeset/10894-app-edit-keeps-navigation.md b/.changeset/10894-app-edit-keeps-navigation.md deleted file mode 100644 index cd8f1fb39e..0000000000 --- a/.changeset/10894-app-edit-keeps-navigation.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/plugin-designer': patch ---- - -fix(plugin-designer): editing an app keeps its stored navigation (objectui#10894) - -**Clause-②: no** — an edit stops destroying stored navigation. No declared type, accepted key or published surface moves. - -The console's "edit app" page (`EditAppPage`) loads the stored app into `AppCreationWizard`. Leaving the wizard's Objects step replaced the draft's `navigation` with one generated object entry per selected object, and every edit passes through that step. So any edit, even a title change, saved a stored `[object, separator, group, url]` tree as `[object]`. It dropped every separator, group (with its children) and `url` / `dashboard` / `page` / `report` / `component` / `action` entry, and each object entry's own label, icon and order, with no warning. - -- **Leaving the Objects step no longer replaces the navigation.** An empty navigation (the create path) is still filled with one object entry per selected object. A non-empty one is merged: - - a newly selected object gets an object entry, appended at the end; - - the object entries of a deselected object are dropped, at the top level or inside a group. The group keeps its place and its other children, even when that leaves it with none; - - every other entry is kept as stored, in its position. That includes each object entry's label, icon and order, and an object entry for an object the Objects step does not list. -- **`EditAppPage` counts an object as selected when the stored navigation has an object entry for it at the top level or inside a group, at any depth.** It counted only top-level entries, so a grouped object showed as unselected. -- The same merge applies on the create path once the author has shaped the navigation. Going back to the Objects step and forward again keeps the added separators, groups and links, and the order. - -Pinned in `packages/plugin-designer/src/__tests__/EditAppPage.keepsNavigation-10894.test.tsx`. diff --git a/.changeset/10895-plugin-detail-relatedlist-client-sort-gate.md b/.changeset/10895-plugin-detail-relatedlist-client-sort-gate.md deleted file mode 100644 index b934ceaed3..0000000000 --- a/.changeset/10895-plugin-detail-relatedlist-client-sort-gate.md +++ /dev/null @@ -1,9 +0,0 @@ ---- ---- - -Test-only, no package released: `RelatedList.unmaterializedSort.test.tsx`'s case "keeps that button in -client mode" now awaits the object schema before it reads the `Total` sort button. Since -objectui#10728 the sort-button row reads the masked stamp, which covers every column until -`getObjectSchema` resolves, and the case gated only on the view type, which client mode reaches on the -first commit. So whether the button existed when it was read depended on scheduling; on one merge-queue -build it did not (objectui#10895). No source file changes. diff --git a/.changeset/10899-assistant-fab-yields-to-open-dock.md b/.changeset/10899-assistant-fab-yields-to-open-dock.md deleted file mode 100644 index 80bbe9b8fa..0000000000 --- a/.changeset/10899-assistant-fab-yields-to-open-dock.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the assistant FAB is hidden while the chat dock is open (objectui#10899) - -The console's round assistant button is the chat dock's collapsed affordance -(ADR-0057), but `ConsoleLayout` rendered it whether the dock was collapsed or -open. With the right rail open inside an app, the `fixed bottom-6 right-6` -button sat on top of the rail composer's send button, so only the Enter key -could send. - -The FAB now renders only while the dock is collapsed — the same rule the Studio -dock's `ChatDockLauncher` already follows. The open rail and the mobile sheet -keep their own collapse and close controls. diff --git a/.changeset/10899-chat-step-turns-no-empty-blocks.md b/.changeset/10899-chat-step-turns-no-empty-blocks.md deleted file mode 100644 index 04ed345480..0000000000 --- a/.changeset/10899-chat-step-turns-no-empty-blocks.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/plugin-chatbot': patch ---- - -fix(plugin-chatbot): a reloaded multi-step build no longer shows an empty 「执行过程」 block under every step (objectui#10899) - -The conversation store persists each step of an agent turn as its own assistant -row whose only text is a `(called …)` placeholder, so a reloaded build (the -in-app dock, the Studio copilot) hydrates into one message per step. Each one -rendered its tool row, then the italic 执行过程 note, then the message action -bar — invisible until hover but full height — so every step read as an empty -block with a large gap. - -- The 执行过程 note is now only the fallback for a placeholder turn that shows - nothing else. A turn whose tool row, build panel or design panel is on screen - does not repeat it. -- The copy / regenerate bar renders only for a turn with visible prose. A - prose-less step has nothing to copy, and Copy used to copy the internal - placeholder. diff --git a/.changeset/10899-dataset-tile-read-refusal-no-access.md b/.changeset/10899-dataset-tile-read-refusal-no-access.md deleted file mode 100644 index 9626f655fc..0000000000 --- a/.changeset/10899-dataset-tile-read-refusal-no-access.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/data-objectstack': patch -'@object-ui/plugin-dashboard': patch -'@object-ui/i18n': patch ---- - -fix(data-objectstack, plugin-dashboard): a dataset tile the viewer may not read shows a localized "no access" state (objectui#10899) - -When the analytics read admission refused a dashboard dataset query — `403` -with ADR-0112 `PERMISSION_DENIED` — `queryDataset` had no branch for that code, -so it threw the generic `Dataset query failed: 403 Forbidden — [Analytics] -Access denied: …` string, and `DatasetWidget` printed it verbatim in a red -alert. The list view over the same object already says 「无权访问」. - -- `queryDataset` now throws a typed `AnalyticsForbiddenError` for that code, - carrying `httpStatus: 403` and `code: 'PERMISSION_DENIED'` (plus the server's - code and message for diagnostics). A code-less 403 — no ObjectStack route - wrote it — keeps the generic error. -- `DatasetWidget` classifies a failed query with the shared `classifyLoadError` - and, for `forbidden`, renders a localized no-access state - (`dashboard.widgetForbiddenTitle` / `dashboard.widgetForbiddenMessage`, new in - all ten packs) instead of the exception text. Every other failure keeps the - detailed alert. diff --git a/.changeset/10899-failed-comment-never-shown-as-sent.md b/.changeset/10899-failed-comment-never-shown-as-sent.md deleted file mode 100644 index 6bad7535b7..0000000000 --- a/.changeset/10899-failed-comment-never-shown-as-sent.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/plugin-detail': patch -'@object-ui/i18n': patch ---- - -fix(app-shell, plugin-detail): a record comment whose write fails is never shown as sent (objectui#10899) - -The record page's discussion writers appended the new comment (or reply) to the -panel first and then fired the `sys_comment` create, swallowing its rejection. -On a tenant with no `sys_comment` the write answered 404 while the panel showed -the comment and a bumped count, with no error — and the comment was gone after a -reload. - -`RecordDetailView` now appends a comment or reply only after its write resolves. -A failed write raises a localized error toast (`detail.commentFailed`, new in all -ten packs) and rejects back to the composer. The composers — the activity -timeline's comment box, the threaded reply input, and `RecordComments` — now -treat a rejected `onAddComment` / `onAddReply` explicitly as "not written": they -keep the draft for a retry instead of letting the rejection escape unhandled. diff --git a/.changeset/10899-failed-reaction-write-reverts.md b/.changeset/10899-failed-reaction-write-reverts.md deleted file mode 100644 index 276f743234..0000000000 --- a/.changeset/10899-failed-reaction-write-reverts.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/i18n': patch ---- - -fix(app-shell): a failed reaction write takes the reaction back and says so, instead of staying shown as applied (objectui#10899) - -A reaction click on the record page's discussion shows at once and is stored in -the background with a `sys_comment` update. That update was issued from inside -the React state updater and its rejection was discarded, so a refused write -left the reaction on screen as applied, with no message, until a reload. In a -StrictMode development build the updater also ran twice, so one click sent two -updates. - -`RecordDetailView` now computes the toggle and issues the write from the click -handler, one write per click. When a write is refused, the row shows the newest -reaction set a write stored or can still store, and a localized error toast -(`detail.reactionFailed`, new in all ten packs) says the reaction was not -saved. A refused click that a later click's write also carries is kept, because -each write stores the row's whole reaction set. The stored -`{ emoji: userIds[] }` shape is unchanged. diff --git a/.changeset/10899-marketplace-update-is-higher-version.md b/.changeset/10899-marketplace-update-is-higher-version.md deleted file mode 100644 index 0c4d3924dc..0000000000 --- a/.changeset/10899-marketplace-update-is-higher-version.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the marketplace offers an "update" only for a HIGHER version (objectui#10899) - -The environment marketplace detail page decided "update available" — the amber -`Update available → vX` badge, the primary button's `Update` label, and the -install dialog's per-environment `Update → vX` hint — by comparing the installed -version with the latest approved one using `!==`. An environment holding a newer -version than the latest approved one (a draft installed ahead of review) was -therefore told `Installed v1.1.0 · Update available → v1.0.0`, and the button -offered to "update" it to the older version. - -Both call sites now ask `isNewerVersion`, which orders the two by SemVer 2.0.0 -precedence — the grammar the package manifest contract declares for `version`. -Only a version of higher precedence is an update; an equal, older or -non-SemVer pair offers none, so the page never guesses an order the contract did -not give it. diff --git a/.changeset/10899-studio-bridges-need-authoring-capability.md b/.changeset/10899-studio-bridges-need-authoring-capability.md deleted file mode 100644 index ce88510c94..0000000000 --- a/.changeset/10899-studio-bridges-need-authoring-capability.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): the Studio edit/design affordances follow the server's authoring capability (objectui#10899) - -A page's "Edit in Studio" pencil and the top bar's "Design in Studio" hammer -were gated on the workspace-admin ROLE alone. An organization owner is a -workspace admin, but framework's `organization_admin` permission set -deliberately withholds `manage_metadata` (ADR-0066), and -`GET /api/v1/auth/me/permissions` reports that. So on the cloud control plane a -freshly signed-up customer was offered the platform's own page metadata editor. - -Both affordances now also require `manage_metadata` through -`useCanAuthorMetadata` — the server's answer, the same one HomePage's builder -CTAs already consume. A server that reports no `systemPermissions` at all -(predating ADR-0066) keeps today's admin-only behaviour, since an unknown answer -fails open; the server refuses the write either way. diff --git a/.changeset/10900-zh-cn-leftovers.md b/.changeset/10900-zh-cn-leftovers.md deleted file mode 100644 index f8e0b0299b..0000000000 --- a/.changeset/10900-zh-cn-leftovers.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/auth': minor -'@object-ui/react': patch -'@object-ui/i18n': patch -'@object-ui/app-shell': patch -'@object-ui/console': patch ---- - -Four Console surfaces that read English under a zh-CN session now read the session's -language (objectui#10900). English stays the default. - -- **The generic action success toast.** When an action declares no `successMessage`, the - runner falls back to "Action completed successfully". - That fallback now goes through a translator: `ActionRunner.setTranslator(translate)` is - new in `@object-ui/core`, and `` and `useActionRunner` in - `@object-ui/react` install the session's `t` on the runner they build. The pack key is - `actions.completedSuccessfully`. An author's `successMessage` still reaches the toast - untranslated, and a runner with no translator installed still toasts the English sentence. -- **The social sign-in buttons on the login and sign-up pages.** `SocialSignInButtons` - takes a new `buttonText` prop, a template whose `{provider}` is replaced with the - provider's display name; unset, the buttons keep "Continue with {provider}" and - "Sign up with {provider}". `LoginForm` and `RegisterForm` take a new `socialButton` - label and pass it, with their existing `orText` label, to the buttons. `orText` was - documented as the divider label but rendered nowhere; it now sets the divider under the - buttons, and its documented default is corrected from "or" to "or continue with email", - the text that divider has always shown. The console's login and sign-up pages and - `@object-ui/app-shell`'s `DefaultLoginPage` / `DefaultRegisterPage` pass the new - `auth.login.*` and `auth.register.*` `socialButton` / `orText` keys. The provider's display - name is inserted as-is: the component's own label for the branded providers it knows, - otherwise the name the server reports. -- **Build Doctor.** The build conversation's Build Doctor button (its accessible name and - both tooltips) and the title of the drawer it opens read `console.ai.buildDoctor`, - `console.ai.buildDoctorTitle` and `console.ai.buildDoctorDisabledTitle`. -- **Setup → marketplace.** On `system/marketplace` and the pages under it, the breadcrumb - segment after System reads `console.breadcrumb.marketplace` instead of the humanized URL - slug; other `system/*` segments are unchanged. The zh marketplace search placeholder - reads 「按名称或标识搜索应用…」 instead of 「按名称或 manifest ID 搜索应用…」. The search - itself is unchanged: it matches the display name, the identifier and the description. - -All ten locale packs carry the nine new keys; no existing `en` value changes. - -**Clause-②: yes** — besides the nine pack keys, the public surface widens by four optional -members: `ActionRunner.setTranslator`, `SocialSignInButtonsProps.buttonText`, -`LoginFormLabels.socialButton` and `RegisterFormLabels.socialButton`. Nothing is removed, -renamed or narrowed, no accept set changes, and `@object-ui/react` exports nothing new. diff --git a/.changeset/10903-today-reference-day-rule.md b/.changeset/10903-today-reference-day-rule.md deleted file mode 100644 index 5f016153ef..0000000000 --- a/.changeset/10903-today-reference-day-rule.md +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -Comment-only in `@object-ui/core`: the built-in `TODAY()` formula function now carries a docblock stating which calendar day it names, as ruled on objectui#10903 (option A). A client-evaluated `TODAY()` names the same reference day the server resolves for that user, on the compute-tz axis of objectstack ADR-0053, and the UTC day while no reference timezone reaches the client. The implementation reads no timezone, so it answers the UTC day, which is the ruled fallback; nothing it returns changes. - -Declared as releasing nothing because the emit was measured rather than assumed: the docblock sits inside the private `registerDateFunctions` body, so it cannot reach the emitted `FormulaFunctions.d.ts`, and the comment-stripped emit of `FormulaFunctions.ts` is byte-identical to the base. No published behaviour changes (objectui#10903). diff --git a/.changeset/10905-types-stale-docblocks.md b/.changeset/10905-types-stale-docblocks.md deleted file mode 100644 index 78d41c8e27..0000000000 --- a/.changeset/10905-types-stale-docblocks.md +++ /dev/null @@ -1,20 +0,0 @@ ---- ---- - -Comment-only correction in `@object-ui/types`; releases nothing (objectui#10905). - -Two source docblocks still described shapes that objectui#10770 and objectui#7928 -changed earlier in this same unreleased batch. The `ObjectChartSchema.series` -docblock said a `type` written on the `{ dataKey }` arm is an excess property on -a literal typed by the interface; since the `{ name }` arm is the spec's -`ChartSeries`, which declares `type`, that literal compiles, and only the zod -mirror still strips the key. The zod route overview headed "WHERE THIS ARM IS -INSTALLED" said a named view's `listViews` is unmirrored and named a `custom` -issue under `options.kanban` there; `listViews` is the protocol's strict record -by reference, which refuses a named view's `options` bag whole, and the named-view -check reports at `listViews.KEY.kanban.groupBy` only. - -No behaviour, type, accept set or `.describe()` string moves. Both docblocks reach -the build output only as comment text (the `series` one in the emitted `.d.ts`, -the route overview in the zod module's JavaScript), so there is nothing for a -consumer to act on. diff --git a/.changeset/10909-element-number-datasource.md b/.changeset/10909-element-number-datasource.md deleted file mode 100644 index 600b5bdf24..0000000000 --- a/.changeset/10909-element-number-datasource.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/components': minor ---- - -`element:number` reads its object from the node-level `dataSource` binding, as the spec declares it (objectui#10909). - -`PageComponentSchema.dataSource` is the spec's per-element data binding, and the spec lint gate waives a missing `properties.object` when `dataSource.object` names one. `ElementNumberRenderer` read its object only from `properties.object`, so a metric written `{ type: 'element:number', dataSource: { object: 'contact' }, properties: { aggregate: 'count' } }` — which the spec lint gate accepts, as `objectui validate` will once objectui#10908 arms the type — issued no query and painted the empty dash, with nothing to tell the author why. - -The renderer now resolves the binding the way `element:record_picker` does: - -- `object` is `dataSource.object ?? properties.object`, resolved once and used for the fetch guard, the `aggregate` / `find` call and the data-invalidation bus key. The binding wins when both are set. -- A named `view` is honoured: its filter scopes the aggregate. A view that cannot be resolved renders the shared "data source could not be resolved" panel and aggregates nothing, rather than counting every record of the object. -- `properties.filter` is AND-combined with the binding's `filter` and with its view's, the rule every block behind `ElementDataSourceGate` applies: neither is dropped, so a validated `properties.filter` can never be discarded and widen the count. A filter the converter refuses while combining them renders the same configuration-error panel, naming the refused rule, and aggregates nothing. -- The binding's `sort` and `limit` are not read: an aggregate has no ordering, and a capped count would be a wrong number. - -A metric with no `dataSource` behaves exactly as before. - -**The registration's declared inputs move.** `element:number` is now registered through `elementDataSourceBlock`, so its registration and the published manifest declare the `dataSource` input (the one injected declaration every reader of the binding carries), and the html tier no longer reports `has no prop "dataSource"` on the node. `object` is no longer `required`, because the binding can supply it; its description, and a new `filter` description, say how each combines with the binding. - -**Clause-②: yes (widening)** — no export moves, but the published `element:number` entry in `sdui.manifest.json` widens: it declares `dataSource`, and `object` is no longer `required`. The html tier, and the objectstack CLI's JSX gate that reads this manifest, therefore accept a node bound through `dataSource` alone — and also one that names neither `object` nor a binding, which no longer draws `missing-required-prop` and paints the empty dash. diff --git a/.changeset/10916-joined-report-block-pin-two-specs.md b/.changeset/10916-joined-report-block-pin-two-specs.md deleted file mode 100644 index f9148dead9..0000000000 --- a/.changeset/10916-joined-report-block-pin-two-specs.md +++ /dev/null @@ -1,9 +0,0 @@ ---- ---- - -Rewrite the `JoinedReportBlock` pin in `report-chart-query-spec-parity.test.ts` -(objectui#10916) so it compiles against both the installed `@objectstack/spec` -17.4.0, which still erases the block type to `unknown`, and spec `main`, which -objectstack#20369 typed. A test-time tripwire now fails at the first spec bump -past 17.4.0, which is when the burn-down it records becomes possible. Test and -ledger text only; no package is released by this change. diff --git a/.changeset/10918-console-action-ctx-org.md b/.changeset/10918-console-action-ctx-org.md deleted file mode 100644 index 421f5cd518..0000000000 --- a/.changeset/10918-console-action-ctx-org.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): console actions supply the spec-declared `${ctx.org.*}` scope (objectui#10918) - -`@objectstack/spec` declares `${ctx.org.id}` in an action's `target`, and lists the -interpolation scope as `ctx.user.*`, `ctx.org.*`, `ctx.recordId` and `ctx.selection`. -The console's action contexts never carried `org`, so the `org` the action runner -interpolates from was empty. A target such as -`/apps/cloud_control/sys_organization/record/${ctx.org.id}` navigated to -`/apps/cloud_control/sys_organization/record/` with the id blanked out. - -Two providers were missing it: - -- `useConsoleActionRuntime`, the shared runtime behind the console's root action - provider, object views, SDUI pages and declared action bars. It published the active - organization only under the undeclared key `activeOrganization`. -- The record page's own action provider in `RecordDetailView`, which carried only - `record`, `objectName` and `user`. - -Both now publish the active organization under `org`, with the fields `id`, `slug` and -`name`, through one shared projection. `${ctx.org.id}` in a console action target -resolves to the active organization's id. With no active organization it still resolves -to an empty string. The existing `activeOrganization` key on the shared runtime is -unchanged, and the record page gains no key besides `org`. diff --git a/.changeset/10919-cloud-plan-status.md b/.changeset/10919-cloud-plan-status.md deleted file mode 100644 index 7c35e41098..0000000000 --- a/.changeset/10919-cloud-plan-status.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/app-shell': minor -'@object-ui/types': minor -'@object-ui/i18n': patch -'@object-ui/cli': patch ---- - -New SDUI widget `cloud:plan-status`: a "Current plan" badge for one plan card on the Cloud pricing page, shown when that card's plan is the organization's plan (objectui#10919). - -**Clause-②: yes** — the accept set of `AnyComponentSchema`, and so of `safeValidateSchema` and `objectui validate`, widens by one `type` literal, `cloud:plan-status`, and `@object-ui/types/zod` exports one new schema, `CloudPlanStatusSchema`. Nothing that parsed before is refused now. - -**Why.** The pricing page is static metadata, and nothing in a page's expression scope carries the organization's plan, so the page could not tell which of its cards the organization is already on. The plan is available only from the org-scoped `GET /cloud/environment-entitlements` summary. - -**What changed, in observable terms.** - -- `@object-ui/app-shell` registers `cloud:plan-status`. A page places one node on each plan card and names that card's plan code in `properties.plan`: `{ "type": "cloud:plan-status", "properties": { "plan": "free" } }`. The widget reads the summary through the hook the environment list already uses, and renders the badge when the summary's `plan` equals `properties.plan`. The comparison is exact, so `Free` does not match `free`. -- The widget renders nothing on every other card, while the summary loads, when the request fails, and when the body is not the `{ success, data }` envelope. It never guesses a plan. -- The node's `className` and `responsiveStyles` reach the badge. Each node reads the summary itself, so a page with three cards makes three requests. -- The widget is registered under one key, `cloud:plan-status`. There is no bare `plan-status` fallback and no `app-shell:`-prefixed twin. -- `@object-ui/types/zod` exports `CloudPlanStatusSchema`, a member of `AnyComponentSchema`. `properties` is required and must be exactly `{ plan }`, with `plan` a non-empty string. A missing bag, a missing or empty `plan`, and any other key in the bag are each refused at that path. -- `body` and `children` are refused by name on this node, because the widget reads neither. -- `plan` is not an enum: the plan catalog belongs to the control plane, and ObjectUI does not list its codes. -- `@object-ui/i18n` adds `cloudPlanStatus.current` ("Current plan") to all ten locale packs. -- `@object-ui/cli`: `objectui check` knows `cloud:plan-status` as a registered type. diff --git a/.changeset/10925-plan-card-wait-stream.md b/.changeset/10925-plan-card-wait-stream.md deleted file mode 100644 index a25e16a360..0000000000 --- a/.changeset/10925-plan-card-wait-stream.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-chatbot': patch ---- - -fix(plugin-chatbot): the proposed-plan card's actions wait until no turn is in flight - -The proposed-plan card renders as soon as `propose_blueprint` returns, but the -turn that proposed it keeps streaming after that, and the server stores each of -its remaining steps as it goes. Build it, Adjust and the one-click answer chips -were live the whole time. In a cloud E2E run the user clicked Build it inside -that window. The next turn was sent while the previous one was still being -stored, and the stored history interleaved the two turns. - -These actions are now disabled while `isLoading` is true, on the structured plan -card and on the fallback confirm card alike. `isLoading` is the signal that -already turns the composer's send into a stop button. The actions come back once -the response stream has been read to its end, and the buttons carry the native -`disabled` attribute while they wait. The gate also covers two windows that a -message's own `streaming` flag misses: a request that is out but has no reply -yet, and a newer turn streaming below an older plan card. - -Ordering replayed history by turn in the conversation store is a separate -server-side fix. diff --git a/.changeset/10926-dock-binds-build-thread-to-app.md b/.changeset/10926-dock-binds-build-thread-to-app.md deleted file mode 100644 index c9012ae43b..0000000000 --- a/.changeset/10926-dock-binds-build-thread-to-app.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -The console's assistant dock binds its build conversation to the app you are in -(objectui#10926). - -Inside an app whose package is not a `com.objectstack.*` platform built-in, a dock -whose agent resolves to `build` now keys its conversation `app:PKG:build` — the key -the Studio copilot and `/ai/build?package=PKG` already use — so the three show one -thread. The dock's header chip and empty state name the app instead of reading -"New app", and each build request carries the app's package as `context.packageId`, -so the agent no longer has to infer which app to edit. The dock's "Open full page" -button opens `/ai/build?package=PKG` for such a thread. - -Unchanged: an `ask` dock keeps its app-less thread; inside a `com.objectstack.*` -app, or with no current app, a build dock keeps the product-only thread; and bare -`/ai/build` still resolves that product-only thread. The product-only thread is -never cleared — it stays listed in the `/ai` sidebar, and a dock entering an app -adopts it only when its own history is bound to that app (the same check the -`?package=` entry already applies). diff --git a/.changeset/10928-content-channel-parser-tier-clause.md b/.changeset/10928-content-channel-parser-tier-clause.md deleted file mode 100644 index fda89c0964..0000000000 --- a/.changeset/10928-content-channel-parser-tier-clause.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@object-ui/types': patch ---- - -Correct a false clause in the content-channel refusal messages (objectui#10928). - -The family-D / E3 refusals on the nodes whose renderer reads neither content channel (objectui#9256) explain why `body` and `children` are refused by name: an authored value rendered nothing. They went on to say it drew "no error, no warning, no element". The render path is as described, but the parser tier is not: `validateTree` warns `not-a-container` for a child list under a registration that declares no `children` input (objectui#9910), and it answers a `body` child list with the same code. So each of these refusals now says "no render-time error or warning and no element; only the parser tier's `not-a-container` warning (objectui#9910) noticed it". - -The change reaches the zod mirror's refusal messages and their `.describe()` text (on both members, whether the string is a literal or is built by `neitherContentChannelGuidance`), and the matching `body?: never` / `children?: never` docblocks in the emitted `.d.ts`. Every other word of each message is unchanged. - -Message and documentation text only: every document is accepted or refused exactly as before, with the same issue code at the same path. diff --git a/.changeset/10929-action-aria-retired.md b/.changeset/10929-action-aria-retired.md deleted file mode 100644 index aaac4c38a1..0000000000 --- a/.changeset/10929-action-aria-retired.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/core': minor ---- - -fix(core): `ActionDef` no longer declares `aria`, which `@objectstack/spec` 17.5.0 retired on an action - -`@objectstack/spec` 17.5.0 retired `action.aria` as a `retiredKey()` tombstone: -authoring it is a parse rejection, because no action surface ever applied it. -The accessible name an action gets is its `label`. To name the region that -places the actions, use the `aria` block of the placing node. - -`ActionDef` (`@object-ui/core`) mirrored the key as `aria?: SpecActionInput['aria']`. -After the 17.5.0 bump that type resolved to `undefined`, so the field mirrored -nothing. It is removed, and so is its entry in the exported `ACTION_DEF_KEYS` -inventory. `aria` stays in `SPEC_ACTION_KEYS`, because the spec still declares -the tombstone, so the dev-mode unknown-key warning does not change for an action -that still carries it. - -**Breaking, at the type level only.** Two names on the package root narrow: - -- the `ActionDef` interface loses its `aria` member; -- the exported `ACTION_DEF_KEYS` constant loses its `'aria'` element, both in - the runtime array and in its `as const` element union. - -Code that compiled before and does not now: - -- an explicit `aria: undefined` in an `ActionDef` object literal (an - excess-property error); -- a read of `.aria` on an `ActionDef`; -- `'aria'` used as a `keyof ActionDef`, or as a `typeof ACTION_DEF_KEYS[number]`. - -Every other `aria` value in an `ActionDef` literal was already a compile error, -because the member's type was `undefined`. The runtime accept set does not move: -nothing validates an `ActionDef` at runtime, and `KNOWN_ACTION_KEYS` still holds -`aria` through `SPEC_ACTION_KEYS`. Measured reach: this repository had no reader -of an action's `aria`, and CI `Type Check`, which compiles every workspace -consumer of `@object-ui/core`, is green with the member removed. The level is -`minor`, which is how this repository ships its own breaking changes. - -The Studio action editor did not need a change: the served `action` schema from -17.5.0 on does not carry `aria`, so its "More fields" form offers no `aria` -control. A test in `@object-ui/app-shell` now pins that. diff --git a/.changeset/10932-pivot-drilldown-retired.md b/.changeset/10932-pivot-drilldown-retired.md deleted file mode 100644 index 06b940ef62..0000000000 --- a/.changeset/10932-pivot-drilldown-retired.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-dashboard': minor ---- - -`drillDown` is retired on the bare `pivot` node: author `object-pivot` to drill (objectui#10932) - -**Breaking for authored metadata, graded `minor` by this repo's convention (AGENTS.md: a -breaking change here is `minor`, never `major`):** a `pivot` node no longer accepts -`drillDown` on either published face. The TypeScript `PivotTableSchema.drillDown` is a -`?: never` tombstone, and the `pivot` arm of the zod mirror, the door `objectui validate` / -`safeValidateSchema` run, refuses the key by name with `invalid_type` at `drillDown`. The -refusal names the remedy. Migration: delete the key, or, for a pivot whose cells open the -records behind a value, author an `object-pivot` (`objectName` plus the same `rowField` / -`columnField` / `valueField`) and put the `drillDown` there. Every other `pivot` member is -accepted exactly as before. - -Nothing ever honoured the key on this node. `PivotTable` fired a drill only when its host -passed an `onDrillDown` handler. The one host that does is `ObjectPivotTable`, which renders -`object-pivot`, and the `pivot` registration passes none. So an authored `drillDown` -validated and clicking a cell did nothing, with no signal. A pivot over inline `data` also -names no object to list the drilled records from. No shipped or example document authors -the key on a `pivot` node. - -This supersedes what three pending entries say about the `pivot` arm's `drillDown`: the -objectui#10859 (batch 2) entry ("`drillDown` is the shared `DrillDownConfigSchema`"), and the -dated notes on the objectui#7352 and objectui#10685 entries, which read that key as the shared -mirror (a third referencing declaration, and `mode` accepted there). As of this change the -arm refuses the key. - -- `@object-ui/types`: `PivotTableSchema.drillDown` is `?: never`, and the zod `pivot` arm's - `drillDown` is a `retirementTombstone()`. The content-channel refusal on `body` / `children` - no longer lists `drillDown` among what a `pivot` renders. -- `@object-ui/plugin-dashboard`: `PivotTable` reads nothing off `schema` for its drill. - **Behaviour change for React callers:** its `onDrillDown` prop is now the only switch. A - caller that passes a handler gets interactive cells, headers and totals, and a - `schema.drillDown` no longer gates them (the type refuses that key anyway). A caller that - wants no drill passes no handler. `ObjectPivotTable` already passed its handler only when - its own `drillDown` was enabled, so `object-pivot` behaves exactly as before, and its - `schema.drillDown` keeps the `ObjectPivotDrillDownConfig` type. diff --git a/.changeset/10935-master-detail-i18n-labels.md b/.changeset/10935-master-detail-i18n-labels.md deleted file mode 100644 index 461907e22b..0000000000 --- a/.changeset/10935-master-detail-i18n-labels.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/plugin-form': minor ---- - -A master-detail form whose `title`, `submitText` or `cancelText` is a per-locale map now shows the viewer's language instead of crashing or toasting "[object Object] saved" (objectui#10935). - -**What it was.** `@objectstack/spec` types these three members of `object-master-detail-form` as `I18nLabel`, a plain string or an inline per-locale map such as `{ en: 'Purchase order', 'zh-CN': '采购单' }`, and objectui's validator accepts such a map in the node's `properties` (objectui#10927). `MasterDetailForm` read all three raw. `submitText` and `cancelText` are Button children, so a map threw "Objects are not valid as a React child" and took the form down. A map `title` went into the built-in edit-save toast as "[object Object] saved". - -**What changed, in observable terms.** - -- Each of the three is resolved with `pickLocalized` against the active UI language (`useObjectTranslation().language`), the source `ObjectMetricWidget` resolves its own `I18nLabel` members against. A map shows the entry for the viewer's language, then falls back the way `pickLocalized` does. -- A plain string renders exactly as authored. -- With nothing authored, this change leaves the defaults as they were: 'Create' or 'Save' on the Save button, 'Cancel' on the Cancel button, and 'Created' or 'Saved' in the built-in save toast. objectui#11039 moves those defaults, and the " saved" the toast puts after an authored `title`, into the locale packs, so they follow the session language. -- On the two buttons, an authored empty string, or a map with no string entry, now shows the default. An authored empty string used to render an empty button; a map with no string entry used to throw as a React child. -- The parent `ObjectForm` is handed the resolved `title` string, the `string` its `ObjectFormSchema.title` declares. -- The block's registration declares both arms for the three keys, `type: ['string', 'object']`, with descriptions that teach the per-locale map. The manifest built from `ComponentRegistry.getPublicConfigs()` therefore no longer makes `validateTree` report `type-mismatch` on a locale map for these keys. A value that matches neither arm, such as a number, is still reported. - -**Types.** `MasterDetailFormSchema.title`, `.submitText` and `.cancelText` widen from `string` to `I18nLabel` (from `@object-ui/types`), matching the spec row. Code that writes these members compiles unchanged. Code that reads one of them and uses it as a `string` no longer compiles: resolve it first, for example with `pickLocalized` from `@object-ui/i18n`. - -**Clause-②: yes** — three members of `MasterDetailFormSchema`, which the package entry exports, widen from `string` to `I18nLabel`, and the registration's `inputs` for the same three keys widen from `'string'` to `['string', 'object']`. Nothing that was accepted before is refused now. diff --git a/.changeset/10940-joined-report-block-from-spec.md b/.changeset/10940-joined-report-block-from-spec.md deleted file mode 100644 index 24062d1385..0000000000 --- a/.changeset/10940-joined-report-block-from-spec.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`JoinedReportBlock` is now the spec's own type, derived from the installed `@objectstack/spec` instead of hand-written (objectui#10940). It is `JoinedReportBlock` from `@objectstack/spec/ui`, the input shape of `JoinedReportBlockSchema`. `JoinedSpecReport.blocks` is now the spec's own `Report.blocks`, made required. It is on the parsed tier, like `SpecReport` itself, so each element is the spec's parsed block, which can be assigned to `JoinedReportBlock`. - -Through `@objectstack/spec` 17.4.0 the spec erased this block to `unknown`, so objectui published its own interface. That interface described the legacy inline-query block. Spec 17.5.0, installed since objectui#11073, types the block as the ADR-0021 dataset-bound block in a closed schema. The spec refuses every key that is only in the old interface. The published type follows the spec, member by member: - -- **Removed (narrowing):** `objectName`, `groupingsDown`, `groupingsAcross`, `filter` and `chart`. The spec's schema refuses all five, and refuses `chart` by name (objectstack#20161). The `[k: string]: unknown` index signature is gone too, so a literal typed `JoinedReportBlock` no longer accepts an undeclared key. -- **Changed concept:** `columns` was a required array of column objects (`{ field, label?, aggregate? }`). It is now an optional array of dimension names (`string[]`) for the across axis of a matrix block. -- **Narrowed:** `label` and `description` still accept a plain string. Their object form is now the spec's inline locale map, where every value is a string. The legacy `{ default, translations }` object is no longer accepted. -- **Added (widening):** `dataset`, `rows`, `values`, `runtimeFilter` (a `FilterCondition`) and `order` (`{ by, direction? }[]`). -- **Unchanged:** `name` (a required string) and `type` (optional `'tabular' | 'summary' | 'matrix'`, defaulting to `tabular`). - -⚠️ This is breaking for TypeScript code that builds or reads legacy inline-query blocks. It is marked `minor` under this repository's version-alignment rule. Nothing changes at runtime: `isJoinedSpecReport` is untouched, and when this change was made no renderer in this repository typed its blocks with either type (the dataset-bound renderer uses its own local shape). diff --git a/.changeset/10946-expression-wire-slots-by-reference.md b/.changeset/10946-expression-wire-slots-by-reference.md deleted file mode 100644 index bc24c0156c..0000000000 --- a/.changeset/10946-expression-wire-slots-by-reference.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -'@object-ui/types': minor ---- - -A spec-shape conditional-formatting rule's `condition` and a bulk action's `visible` now declare the named view's own expression slots, read by reference from `@objectstack/spec` (objectui#10946). - -- `SpecConditionalFormattingRule.condition` was `string`. It is now `string` or the protocol's `ObjectListViewSchema.conditionalFormatting[].condition` slot, which adds the `{ dialect, source }` envelope that `objectstack build` emits. The widening reaches every type built on the rule: `ConditionalFormattingRule`, `KanbanConditionalFormattingRule`, and the `conditionalFormatting` members of `ObjectGridSchema`, `ListViewSchema`, `ObjectKanbanSchema` and `NamedListView`. -- `BulkActionDef.visible` keeps its arm `ExpressionWire` (a string or `{ dialect?, source }`), which it now names instead of spelling inline. It gains the protocol's `bulkActionDefs[].visible` slot as a second arm. On the installed spec that envelope makes `source` optional and may carry `ast` and `meta`. -- The zod mirror moves with the type. The list view's and the kanban board's rule unions share one `condition` schema. `z.string()` is its first arm, so a string condition parses exactly as before: it is not canonicalized into an envelope, and `''` is still accepted. The spec's own slot schema is the second arm, taken by reference, so `safeValidateSchema` (what `os validate` and `os check` run) now accepts an envelope condition on `list-view` and `object-kanban` nodes and refuses one the protocol refuses. - -Why: both members were narrower than the protocol declares and than the grid's evaluator reads. `resolveConditionalFormatting` and the bulk-eligibility fold both accept the envelope. So every relay of a named view into a grid needed a type assertion. `@object-ui/plugin-view`'s route-2 `ObjectView` loses its two. Nothing changes at runtime: no evaluator, renderer or relay changed behaviour. The compiled output of the removed assertions is unchanged. - -The two spec lines differ, and these members follow the installed one. The published slot is `ExpressionInputSchema` (`source` or `ast`). Spec `main` narrows it to `EvaluatedExpressionInputSchema`, which requires a non-blank `source`. No engine evaluates `ast` today. So an `ast`-only envelope, which the installed slot admits, is evaluated as a fault: the formatting rule does not match, the bulk def qualifies no record, and the fault is warned. - -**Breaking for TypeScript readers of these members, released as `minor`** under this repo's version-alignment rule (the fixed group's major follows `@objectstack`). Code that reads `rule.condition` as a `string`, or reads `def.visible.source` as a `string`, stops compiling. Narrow on `typeof` first, as the shared evaluator does. Code that writes these members compiles unchanged. - -Pins: `spec-expression-wire-slots-10946.test.ts` in `@object-ui/types` covers the relays with no assertion, the zod twin's input equalling the TS member, envelope acceptance with string and empty-string controls, and the reference identity of the spec arm. `specExpressionWire-10946.test.tsx` in `@object-ui/plugin-grid` covers the real grid painting an envelope-matched row, the bulk fold reading `source` beside `ast`, and the `ast`-only fault on both. - -**Note, 2026-10-01 (objectui#11322, shipping in this same release).** -The `ast`-only reading above changed for the bulk def after this entry was -written. The grid's selection bar now asks the action family's one "is a gate -declared?" definition (`hasDeclaredVisibilityGate`) before the bulk fold, as -the row menu and the toolbars already did, and that definition reads an -envelope with no `source` as no gate. -- An `ast`-only bulk `visible` is no gate: the button shows and every selected - record qualifies, with no warning. The formatting rule's `ast`-only - `condition` is unchanged: it does not match, and the fault is warned. -- `specExpressionWire-10946.test.tsx` pins the formatting fault and, for the - bulk def, the no-gate answer. - -So the sentences above that say the bulk def qualifies no record, and that the -test file pins the `ast`-only fault "on both", describe the tree at -objectui#10946, not the code in this release. See objectui#11322's changesets -for `@object-ui/plugin-grid` and `@object-ui/types`. - -⚠️ **Dated note, 2026-10-03 — the kanban rule is no longer a union — objectui#11522.** -At this change the kanban board's rule was a union of two dialects (the native -`{ field, operator, value }` comparison and `{ condition, style }`), and the -sentence above that says "the list view's and the kanban board's rule unions -share one `condition` schema" describes that union. Now the kanban rule is ONE -object, the spec list view's `{ condition, style }` rule by reference, and the -native and flat-colour dialects are refused by name on `object-kanban`. It still -reads the same `condition` schema, so everything this entry says about the -condition (the `z.string()` first arm, the envelope, the `''` control, the -reference identity of the spec arm) still holds on `object-kanban`, and -`spec-expression-wire-slots-10946.test.ts` still pins it there, now reading -`condition` straight off the rule's shape. The rest of this entry is kept as -the reading of this change. - -⚠️ **Dated note, 2026-10-03 — the list view's (and the grid's) rule is no longer a union either — objectui#11533.** -At this change the list view's rule, which `ObjectGridSchema` shares, was also a -union of two dialects (the native `{ field, operator, value, … }` comparison and -`{ condition, style }`), so the sentence above about "the list view's and the -kanban board's rule unions" described two unions. Now neither is one: the grid's -and the list view's rule is ONE object, the spec list view's `{ condition, style }` -rule by reference, with the native rule, its `expression` and a top-level colour -refused by name. It reads the same `condition` schema, so everything this entry says -about the condition (the `z.string()` first arm, the envelope, the `''` control, -the reference identity of the spec arm) still holds on `list-view` and -`object-grid`, and `spec-expression-wire-slots-10946.test.ts` now reads -`condition` straight off the list view's rule as well. `ConditionalFormattingRule` -is still built on `SpecConditionalFormattingRule`, so the widening this entry -describes still reaches it. The rest of this entry is kept as the reading of this -change. diff --git a/.changeset/10948-flow-inspector-required-keys.md b/.changeset/10948-flow-inspector-required-keys.md deleted file mode 100644 index 5073e52a0e..0000000000 --- a/.changeset/10948-flow-inspector-required-keys.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/app-shell': minor ---- - -feat(app-shell): the flow node inspector marks the config keys the installed spec refuses the node -without (objectui#10948). - -`@objectstack/spec` 17.5.0 refuses, at authoring, a flow node whose executor could not run it: a key -its config contract requires left out (a CRUD node's `objectName`, an `http` node's `url`, a -`notify` node's `title` while it has no `template`, a `script` node's `function`, a `subflow` or -`map` node's `flowName`, …), a decision branch with no `label` or `expression`, a screen field with -no `name`, and a `connector_action` whose `connectorConfig` names no connector or action. The -designer's live flow check already reports each one at the node's config path; the inspector now -marks the same keys before the author reaches that error, with the metadata form's own required -marker — the `*` in the field label, the row label of a branch or screen-field row, and -`aria-required` on the control where the inspector owns it. - -The inspector keeps no list of required keys. Each marker is the installed spec's own verdict, asked -of the node as it stands: the key is removed from a copy of the node and handed to the judges the -flow parse runs (`flowNodeConfigRefusals`, the predicate-slot walk, and `FlowNodeSchema`), so a -requirement that depends on the configuration — `notify`'s `title` without a `template`, a `loop`'s -`collection` once it has a body, a refused `end`'s `message` — is marked only while it applies. diff --git a/.changeset/10951-element-number-no-object-state.md b/.changeset/10951-element-number-no-object-state.md deleted file mode 100644 index 966623f638..0000000000 --- a/.changeset/10951-element-number-no-object-state.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/components': patch -'@object-ui/i18n': patch ---- - -fix(components): an `element:number` that asks for an aggregate and names no object says so instead of painting a silent dash - -Since `element:number` accepts its object from the node-level `dataSource` -binding (objectui#10909), `object` is no longer a required input, and the -manifest has no way to say "one of `object` and `dataSource.object`". A node -that authors an `aggregate` with neither therefore passes the html tier with no -diagnostic, and the renderer used to paint "—", which reads like a real empty -value. - -The renderer now draws a short muted notice in that case: "No object named: set -object or dataSource.object." It is renderer chrome, so it reads the locale -packs (`element.number.noObject`, added to all ten packs) and speaks the session -language. It does not throw and it queries nothing. - -Only authored absence draws it. A binding that names an object keeps its own -panels while its `view` is resolving or after it failed to resolve, and a node -with no `aggregate` still paints the dash exactly as before. diff --git a/.changeset/10959-unknown-prop-parser-tier-clause.md b/.changeset/10959-unknown-prop-parser-tier-clause.md deleted file mode 100644 index c17049658d..0000000000 --- a/.changeset/10959-unknown-prop-parser-tier-clause.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/types': patch ---- - -Correct a false clause in the `header-bar` refusal messages and in nine `body?: never` docblocks (objectui#10959). - -The `HeaderBarSchema` refusals for `title`, `logo`, `nav`, `left`, `center`, `right`, `sticky`, `height` (objectui#10387) and `variant` (objectui#10286) said an authored value drew "no error, no warning". So did the `body?: never` docblocks on `box`, `span`, `container`, `flex`, `stack`, `grid`, `scroll-area`, `toggle` and `form` (objectui#8284), which ship in the emitted `.d.ts`. The render path is as described, but the parser tier is not: `validateTree` answers each of those keys with an `unknown-prop` warning. So the refusals now say "no render-time error or warning and no element; only the parser tier's `unknown-prop` warning noticed it" (`variant` keeps "no class" where the others say "no element"), and the docblocks say the `body` "rendered an EMPTY element with no render-time error or warning; only the parser tier's `unknown-prop` warning noticed it". - -Message, `.describe()` and documentation text only: every document is accepted or refused exactly as before, with the same issue code at the same path. Every other word of each message and docblock is unchanged. diff --git a/.changeset/10963-codewidget-expression-envelope.md b/.changeset/10963-codewidget-expression-envelope.md deleted file mode 100644 index 27fd90c090..0000000000 --- a/.changeset/10963-codewidget-expression-envelope.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -The metadata form's code editor reads and writes an expression slot through -the ADR-0089 envelope (objectui#10963). - -A form row `{ type: 'code', language: 'expression' }` sits over a spec slot -that persists as the `{ dialect, source, … }` envelope: a field's -`visibleWhen` / `readonlyWhen` / `requiredWhen` and a formula field's -`expression`. `CodeWidget` read the value with `String(value)`. The editor -therefore showed the literal text `[object Object]`, and the first edit wrote a -bare string over the envelope and dropped its `meta`. - -For the `expression` language, `CodeWidget` now reads the editor text through -`expressionSource` and writes each edit through `writeExpressionSource`. This -is the pair `ConditionWidget` already uses, with the same write rule: - -- an edit over an envelope keeps its `dialect` and `meta`, replaces `source` - and drops the stale `ast`; -- an edit over a bare-string or empty value writes the bare string, which the - spec normalises to `{ dialect: 'cel', source }`; -- **a cleared expression now writes `undefined`, where `CodeWidget` used to - write `''`**. This matches `ConditionWidget`, so a cleared predicate removes - the key instead of storing an empty expression. - -The switch is the row's declared language and nothing else. Every other -language (`javascript`, `html`, `jsx`, `json`, …) keeps the string path -exactly as before, and a stored value's shape is never used to pick the path. -A row that holds an expression but declares another language is fixed in the -form that declares it. The hook form's `condition` row is one such row: it -declares `javascript` today, and objectstack-ai/objectstack#20439 carries its -fix. diff --git a/.changeset/10964-matrix-report-chart.md b/.changeset/10964-matrix-report-chart.md deleted file mode 100644 index 9c207b4859..0000000000 --- a/.changeset/10964-matrix-report-chart.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/plugin-report': patch ---- - -A `matrix` report that declares `columns` now draws its declared `chart` below the cross-tab -(objectui#10964). `ReportSchema` has always accepted a matrix report carrying both `columns` and -a `chart`, but the renderer's cross-tab branch returned before the chart was read, so the chart -parsed and was never drawn. It binds the way the summary report's chart does: `chart.xAxis` names -a dataset dimension (a `rows` or a `columns` dimension of the matrix) and `chart.yAxis` a dataset -measure, plotted from the chart's own dataset query. Summary, tabular and matrix-without-`columns` -reports keep the chart above their table, as before. - -The notice an out-of-spec chart type shows no longer says the table is "below" it, since on a -matrix report the table sits above the notice. diff --git a/.changeset/10965-changes-card-wait-stream.md b/.changeset/10965-changes-card-wait-stream.md deleted file mode 100644 index 3a03306af0..0000000000 --- a/.changeset/10965-changes-card-wait-stream.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-chatbot': patch ---- - -fix(plugin-chatbot): the confirm-changes card's actions wait until no turn is in flight - -The confirm-changes card renders as soon as a tool such as `update_metadata` -returns `changes_proposed`, but the turn that proposed the change keeps -streaming after that. Confirm and Adjust were live the whole time, and Confirm -sends its confirmation straight away, so a click in that window sent the next -turn while the previous one was still in flight. The proposed-plan card's -actions were fixed for the same overlap. - -Confirm and Adjust are now disabled while `isLoading` is true, the signal the -proposed-plan card's actions already wait on. They carry the native `disabled` -attribute while they wait and come back once no turn is in flight. Because the -signal is not tied to the card's own message, the gate also holds an older card -while a newer turn is in flight below it, including a request that is out with -no reply yet. - -Only those two buttons change. The card's other states render as before: the -Applying badge, the blocked state after an AI quota refusal, the Confirmed -badge, and the reply hint shown when the host passes no `onSendMessage`. diff --git a/.changeset/10969-console-zh-leftovers.md b/.changeset/10969-console-zh-leftovers.md deleted file mode 100644 index 24d4a4024f..0000000000 --- a/.changeset/10969-console-zh-leftovers.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/core': patch -'@object-ui/app-shell': patch -'@object-ui/i18n': patch ---- - -The console strings objectui#10900 left English under zh-CN now read the session's language (objectui#10969). - -- **The action runner's other own text.** `ActionRunner` asks the translator installed through `setTranslator` (objectui#10900) for three more strings it writes itself: the error toast when the error that reached it carries no readable message (`actions.failed`), a parallel chain's error when no failed action reported one (`actions.parallelFailed`), and the label of an undoable success toast's Undo button (`actions.undo`). An author's `errorMessage` / `successMessage` and an action's own error stay untranslated. With no translator the text stays English. -- **The Undo label now arrives from the runner.** For an undoable result the runner hands the toast handler `undo: { label }` where it used to hand `undo: {}`; `ToastHandler`'s type is unchanged (`label` was already optional). A handler that renders `options.undo.label` shows the translated label; one that ignores it keeps its own. -- **The console app's `system/*` breadcrumbs.** In `AppHeader`, the segment after `System` for `settings`, `apps`, `profile`, `approvals`, `ai-approvals` and `audit-log` reads `console.breadcrumb.*` (as `marketplace` has since objectui#10900). In English, `ai-approvals` now reads `AI Approvals` instead of the humanized slug `Ai Approvals`; the other five read as before. A segment the header does not know keeps its humanized slug. -- **The Build Doctor drawer's body.** Its description, loading and not-found states, summary line, verdict, and each section's title and hint read `console.ai.buildDoctorDrawer.*`. The report's own data (tool, artifact and status names, timeline text) stays verbatim. -- **"manifest ID" leaves the marketplace search placeholder in every pack.** `en` now reads `Search apps by name or app ID…`, and the eight packs that translated the jargon literally follow. zh already read 「按名称或标识搜索应用…」 and is unchanged. - -The new keys are in all ten packs. diff --git a/.changeset/10975-split-popover-create-surface.md b/.changeset/10975-split-popover-create-surface.md deleted file mode 100644 index cd4be55ab9..0000000000 --- a/.changeset/10975-split-popover-create-surface.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -Under a `split` or `popover` navigation, `ObjectView`'s New button now opens a create form (objectui#10975). - -Both surfaces draw a form only beside a selected record, and New clears the selected record, so until now the button did nothing under either mode. That held for the node's own `navigation` and, since objectui#10885, for the active named view's. The create form now opens on the surface the node uses with no `navigation`: the modal for `layout: 'modal'`, the drawer otherwise. A `layout: 'page'` node with an `onNavigate` handler still hands New to the router, as before. A record opened to view or edit still opens beside the list under `split`, and in the popover under `popover`. - -`Clause-②: no` — no declared type, accepted key or published export moves. diff --git a/.changeset/10976-table-slot-relay.md b/.changeset/10976-table-slot-relay.md deleted file mode 100644 index f1be59d2f4..0000000000 --- a/.changeset/10976-table-slot-relay.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -'@object-ui/plugin-view': patch -'@object-ui/types': minor ---- - -An `object-view`'s `table` now hands the grid it draws every grid key it types, and stops -typing the grid keys that had nothing to act on there (objectui#10976). - -**What was wrong.** `ObjectViewSchema.table` declared every `ObjectGridSchema` member except -`type` and `objectName`, while the grid node `ObjectView` builds copied a fixed handful of -them. So `table: { editable: true }`, and `frozenColumns`, `rowHeight`, `rowActions` and the -rest, type-checked, passed the validator, and did nothing. - -**`@object-ui/plugin-view` (fix).** The registered `object-view` renderer now relays these -`table` keys to its grid as written, each one a key `ObjectGrid` reads: `editable`, -`singleClickEdit`, `frozenColumns`, `rowHeight`, `resizable`, `reorderableColumns`, -`searchableFields`, `showSearch`, `showPagination`, `showColumnTypeIcons`, -`conditionalFormatting`, `rowActions`, `bulkActions`, `bulkActionDefs`, `exportOptions`, -`grouping`, `aggregations`, `rowColor` and `label`. A key is copied only when you write it, so -a view that writes none of them renders as before. Where the active named view declares the -same member, the named view still wins and `table` is the fallback. `ObjectGrid` still gates -`editable` on the object's inline-edit grant. A host that supplies `renderListView` still takes -only `columns`, `fields`, `filter` and `sort` from `table`. - -**`@object-ui/types` (breaking for a writer of a withheld key, hence `minor`).** The `table` -slot no longer declares the grid keys the view's grid does not honour: - -- no read in `ObjectGrid`: `showFilters`, `keyboardNavigation`, `rowSpecActions`, - `bulkSpecActions`, `name`, `placeholder` (the last four retired from `object-grid` itself by - objectui#11068); -- not handed on by the view: `emptyState`, `description` (`ObjectGrid` honours both on an - `object-grid` node since objectui#11068; write them there); -- owned by the view: `data`, `staticData`, `bind` (the view lists its own `objectName`), - `navigation`, `onNavigate` (write them on the `object-view` node), `id`; -- node-level keys, which no renderer applies to a grid the view draws as a component: `style`, - `testId`, `ariaLabel`, `hidden`, `hiddenOn`, `visible`, `visibleOn`, `visibleWhen`, - `disabled`, `disabledOn`; -- legacy aliases of a relayed key: `batchActions` (write `bulkActions`) and `resizableColumns` - (write `resizable`). - -**Who breaks.** TypeScript code that writes one of those keys inside an `object-view`'s -`table` now fails to compile (excess property), and a document that carries one fails -`safeValidateSchema` / `objectui validate` with a message that names the key and says why it -reached nothing. None of them ever reached the grid, so no rendered view changes. Remove the key, -or move `navigation` / `onNavigate` / `description` to the `object-view` node. No example, -doc or builder in this repository writes one. - -The slot's key list and the withheld set are pinned against drift by -`packages/types/src/__tests__/object-view-slot-key-lists.test.ts`, which also requires the -validator to refuse every withheld key by name, so the two faces refuse the same keys. - -**Correction, 2026-10-03 (objectui#11068).** `keyboardNavigation` moved from the first group to -the second: `ObjectGrid` honours it on an `object-grid` node since objectui#11068's build, and -the view still does not hand it on, so the slot still refuses it, now with that reason -(`.changeset/11068-keyboard-navigation.md`). diff --git a/.changeset/10981-silence-clause-parser-tier-closure.md b/.changeset/10981-silence-clause-parser-tier-closure.md deleted file mode 100644 index 0e4a036c76..0000000000 --- a/.changeset/10981-silence-clause-parser-tier-closure.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/types': patch ---- - -Correct the last four published "no error, no warning" clauses that the parser tier contradicts (objectui#10981, closing the family of objectui#10928 and objectui#10959). - -- The `FormSchema.mode` refusal (objectui#10286) said every spelling "rendered the same form — no error, no warning". `validateTree` answers `mode` on a `form` node with an `unknown-prop` warning, so it now says "no render-time error or warning; only the parser tier's `unknown-prop` warning noticed it". -- The `TimelineSchema.events` docblock (objectui#6170), which ships in the emitted `.d.ts`, said a timeline authored with `events` "drew an EMPTY rail, with no error and no warning". It gets the same clause: the parser tier answers `events` with `unknown-prop`. -- The `BaseSchema.bind` docblock said a `bind` on `data-table` renders its header over an empty body "with no error and no warning". Neither half was true: `data-table` logs a console warning for an authored `bind` (objectui#6575), and the parser tier answers it with `unknown-prop`. It now says "with no render-time error; nothing on the page says why, but a render-time console warning (`[ObjectUI] DataTable bind:`, objectui#6575) and the parser tier's `unknown-prop` warning both name it". -- The note on the `object-grid` `exportOptions` refusal (objectui#7762) said a bare format array lost to the default with "no error, no warning, no console line". The registration declares `exportOptions` as an object, so the parser tier answers an array with `type-mismatch`, not `unknown-prop`, and the note now says "no render-time error, warning or console line (only the parser tier's `type-mismatch` warning noticed it)". - -Message, `.describe()` and documentation text only: every document is accepted or refused exactly as before, with the same issue code at the same path. Every other word of each message and docblock is unchanged. diff --git a/.changeset/10982-objectview-reread.md b/.changeset/10982-objectview-reread.md deleted file mode 100644 index 0b034a87ba..0000000000 --- a/.changeset/10982-objectview-reread.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -fix(plugin-view): `ObjectView` fetches only for views that draw the rows, and a re-read keeps them on screen - -`ObjectView` fetches the rows for its non-grid views itself and hands them to the -inner view as `data`. Two things were wrong with that fetch. - -- **It ran for views that never draw the rows.** The gate was a deny-list (`grid`, - `tree`, `chart`), so every other view type was read on mount and re-read on every - data-invalidation event. That included `gantt`, whose registered renderer hands - its chart the schema alone and queries for itself, and every view type with no - renderer case (`page`, `list`, `detail`), which falls through to the grid. The - gate is now an allow-list of the view types whose renderer draws the rows: - `kanban`, `calendar`, `gallery`, `timeline` and `map`. The others keep reading - and refreshing through their own query, as they already did, without a second - request beside it. A tree no longer runs its own query twice when the view's - rows arrive. -- **A re-read flashed the loading placeholder.** Every run set `loading`, bus - re-reads included, and a calendar handed rows swaps them for "Loading calendar…" - while that is true, so each bus event flashed the calendar. A run that issues the - same request as the rows on screen answer is now a re-read: the rows stay until - the new ones arrive. The first load for a request still shows the placeholder, and - a failed re-read is still logged the way a failed first load is. diff --git a/.changeset/10987-retire-list-view-tabs-fixture.md b/.changeset/10987-retire-list-view-tabs-fixture.md deleted file mode 100644 index 6b249ceee3..0000000000 --- a/.changeset/10987-retire-list-view-tabs-fixture.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Test-only change in `@object-ui/types`; no published behaviour changes. objectstack#20357 retired the list view's own `tabs` as a tombstone whose input type is `never`, so the `p1-spec-alignment` fixture "should accept tabs configuration" stopped compiling on the Spec Main Shape Gate. The fixture is retired, and a fixture for the protocol's prescription takes its place: each tab becomes a named `listViews` entry, and `defaultListView` names the one `isDefault` picked. It compiles against both the installed `@objectstack/spec` 17.4.0 and spec `main` (objectui#10987). diff --git a/.changeset/10993-batch2-i18nlabel-reads.md b/.changeset/10993-batch2-i18nlabel-reads.md deleted file mode 100644 index 05d09ceb14..0000000000 --- a/.changeset/10993-batch2-i18nlabel-reads.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-detail': minor -'@object-ui/plugin-dashboard': minor -'@object-ui/plugin-grid': minor ---- - -A `record:path` whose stage labels are per-locale maps now shows the viewer's language instead of failing to render, and five label inputs on `object-metric`, `object-grid` and `record:related_list` now accept the per-locale map their renderers already resolve (objectui#10993, batch 2). - -**`record:path`, `stages[].label`.** `@objectstack/spec` types each stage's `label` as `I18nLabel`: a plain string or an inline per-locale map such as `{ en: 'Draft', 'zh-CN': '草稿' }`. `RecordPathRenderer` read it raw, as the stage's visible text and inside the stage's accessible name, so a map threw "Objects are not valid as a React child" and the node rendered `Component "record:path" failed to render` instead of the path. It now resolves each map with `pickLocalized` against the active UI language (`useObjectTranslation().language`) before the stages are translated, classified or drawn: - -- Both rows (desktop and mobile) paint the entry for the viewer's language, and each stage's accessible name carries the same text beside its state words, in one language. -- A stage with no `terminal` is still classified from its label: a lost stage whose label is a map (for example `{ en: 'Closed Lost', 'zh-CN': '丢单' }`) still reads as lost. -- A plain string renders exactly as authored. A picklist translation of the status field still outranks the authored label, as it did for a string. - -**The registry inputs.** These inputs declared `type: 'string'` only, while their renderers already resolve a per-locale map, so the manifest built from `ComponentRegistry.getPublicConfigs()` made `validateTree` report `type-mismatch` on a map the spec accepts. Each now declares both arms, `type: ['string', 'object']`, with a description that teaches the map: - -- `@object-ui/plugin-dashboard`: `object-metric`'s `label` (the tile heading), `description` (the sub-caption under the value) and `title` (the drill-down panel heading), resolved against the active UI language. -- `@object-ui/plugin-grid`: `object-grid`'s `label` (the table caption, the export title and the record-detail overlay heading), resolved against the display locale: the workspace's regional default when one is configured, otherwise the active UI language. `view:grid` registers the same inputs, so its declared `label` carries the same two arms. -- `@object-ui/plugin-detail`: `record:related_list`'s `title` (the list heading), resolved against the active UI language. - -A value that matches neither arm, such as a number, is still reported. No renderer changes for these five: each already resolved the map. - -**Clause-②: yes** — five published registry inputs widen from `'string'` to `['string', 'object']`, so `validateTree` accepts a locale map on them (and `view:grid`'s `label`, which shares `object-grid`'s inputs, declares the same arms). Nothing that was accepted before is refused now. diff --git a/.changeset/10993-batch3-grid-title.md b/.changeset/10993-batch3-grid-title.md deleted file mode 100644 index f887a517f9..0000000000 --- a/.changeset/10993-batch3-grid-title.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/plugin-grid': patch ---- - -An `object-grid` whose deprecated `title` is a per-locale map now shows the viewer's language in the table caption and the export file name, instead of failing to render (objectui#10993, batch 3). - -**What it was.** `title` is the legacy spelling of `label`, read only when `label` resolves to nothing. `@objectstack/spec` types it as `I18nLabel`: a plain string or an inline per-locale map such as `{ en: 'Accounts', 'zh-CN': '客户' }`. `ObjectGrid` resolved `label` against the display locale at its two reads, the data-table caption and the export file name, but handed `title` on raw. A map therefore reached the caption as an object, the data-table threw "Objects are not valid as a React child", and the node rendered `Component "data-table" failed to render` instead of the grid; in the export file name the same map would have read `[object Object]`. - -**What changed, in observable terms.** - -- The caption and the view label in the export file name take the `title` entry for the display locale, the same channel `label` uses: the workspace's regional default when one is configured, otherwise the active UI language. -- `label` still wins whenever it resolves to something, and a plain-string `title` renders exactly as authored. - -No registry input changes: `title` stays one of the block's unregistered deprecated spellings, so `validateTree` reads it as before. diff --git a/.changeset/10993-batch4-ts-face.md b/.changeset/10993-batch4-ts-face.md deleted file mode 100644 index 5473ca96e3..0000000000 --- a/.changeset/10993-batch4-ts-face.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-detail': patch ---- - -Five label positions that `@objectstack/spec` types as `I18nLabel` now accept the per-locale map in `@object-ui/types` too, where they were typed `string` (objectui#10993, batch 4). - -**What it was.** `I18nLabel` is a plain string or an inline per-locale map such as `{ en: 'Overview', 'zh-CN': '概览' }`. At these five positions the spec accepts the map and the renderer resolves it to the viewer's language, but `@object-ui/types` declared `string`, so a TypeScript author who wrote the spec's map got a compile error, and for `object-grid`'s `title` the published zod validator (`safeValidateSchema`) refused the map with `invalid_type` as well. - -**What changed, in observable terms.** - -- `RecordDetailsComponentProps.sections[].label`, `RecordRelatedListComponentProps.title`, `RecordRelatedListComponentProps.add.label` and `RecordPathComponentProps.stages[].label` are typed `I18nLabel`, the spec's own type, so the map compiles. A number is still a type error. -- `ObjectGridSchema.title`, the deprecated fallback for `label`, is `I18nLabel` on the TypeScript interface and in the zod mirror, which takes the spec's `I18nLabelSchema` by reference. The validator now accepts the map; a number, or a map entry that is not a string, is still refused at `title`. `label` still wins whenever it resolves to something. -- An `object-view`'s `table` slot takes `ObjectGridSchema`'s keys, so `table.title` accepts the map on both faces too. `ObjectView` hands it to the grid it draws, which shows the entry for the display locale. -- Rendering at these five positions does not change: each renderer already resolved the map. A plain string is accepted and rendered exactly as before. - -**`record:related_list`, `columns[].label` (`@object-ui/plugin-detail`).** Since `@objectstack/spec` 17.5.0 a related list's `columns` may be column objects (`{ field, label, … }`, the saved-view shape), and a column's `label` is an `I18nLabel` too. A string label became the column header, but a per-locale map drew a blank header. `record:related_list` now resolves the map against the active UI language before it draws the list, so the header shows the viewer's entry; a string label, and a plain field-name column, render exactly as before. - -**Clause-②: yes** — published `@object-ui/types` props types and one zod mirror member widen from `string` to the spec's `I18nLabel`, so the accepted set grows by the per-locale map at these positions. Nothing that was accepted before is refused now. diff --git a/.changeset/10993-object-form-i18nlabel.md b/.changeset/10993-object-form-i18nlabel.md deleted file mode 100644 index 05ce5c9cf6..0000000000 --- a/.changeset/10993-object-form-i18nlabel.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-form': patch -'@object-ui/plugin-view': patch -'@object-ui/types': minor ---- - -An `object-form` whose `title`, `description`, `submitText`, `cancelText`, `nextText`, `prevText` or `successMessage` is a per-locale map now shows the viewer's language instead of failing to render (objectui#10993). - -**What it was.** `@objectstack/spec` types these seven members of `object-form` as `I18nLabel`: a plain string or an inline per-locale map such as `{ en: 'Save order', 'zh-CN': '保存订单' }`. `ObjectForm` handed all seven raw to the presentation its `formType` picked, and every presentation that displays one renders it as a React child. A map therefore threw "Objects are not valid as a React child", and the node rendered `Component "form" failed to render` instead of a form. - -**What changed, in observable terms.** - -- `ObjectForm` resolves the seven with `pickLocalized` against the active UI language (`useObjectTranslation().language`), once, before it picks a presentation. So the simple, tabbed, split and wizard forms, the drawer and modal presentations, and the master-detail route all receive the entry for the viewer's language, with the fallback chain `pickLocalized` applies. -- A plain string renders exactly as authored. With nothing authored, every presentation shows the default label it showed before. -- A map with no string entry resolves to nothing, so the presentation's default label shows. -- `object-view`'s `form` slot takes `ObjectFormSchema`'s keys, so its `form.title` and `form.description` are `I18nLabel` too. `ObjectView` draws its own drawer and modal header around the form, and it now resolves both the same way, against the same UI language, where it used to read them raw. -- The `object-form` registration declares both arms for the seven keys, `type: ['string', 'object']`, with descriptions that teach the per-locale map. The manifest built from `ComponentRegistry.getPublicConfigs()` therefore no longer makes `validateTree` report `type-mismatch` on a locale map for these keys. A value that matches neither arm, such as a number, is still reported. - -**Types.** In `@object-ui/types`, `ObjectFormSchema.title`, `.description`, `.submitText`, `.cancelText`, `.nextText`, `.prevText` and `.successMessage` widen from `string` to `I18nLabel`, matching the spec row. The zod mirror's `title`, `description`, `submitText`, `cancelText` and `successMessage` widen from `z.string()` to the spec's `I18nLabelSchema`, by reference, so `safeValidateSchema` accepts a locale map on them; a number is still refused at the member. `nextText` and `prevText` stay unmirrored, as before. Code that writes these members compiles unchanged. Code that reads one of them off an `ObjectFormSchema` and uses it as a `string` no longer compiles: resolve it first, for example with `pickLocalized` from `@object-ui/i18n`. - -**Clause-②: yes** — seven members of the exported `ObjectFormSchema` type, and five members of its zod mirror, widen from a string to `I18nLabel`, and the registration's `inputs` for the seven keys widen from `'string'` to `['string', 'object']`. Nothing that was accepted before is refused now. - -**Correction, 2026-09-30 (objectui#6152).** The **Types** paragraph above says `nextText` and `prevText` stay unmirrored. That was true when this change was written, and it no longer is: objectui#6152 (PR #11125) mirrors both, by the same reference to the spec's `I18nLabelSchema`, so `safeValidateSchema` now judges them as it judges the other five: a locale map is accepted, and a number is refused at the member. diff --git a/.changeset/10998-register-refusal-codes.md b/.changeset/10998-register-refusal-codes.md deleted file mode 100644 index 379ccc09fa..0000000000 --- a/.changeset/10998-register-refusal-codes.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/console': patch -'@object-ui/i18n': patch ---- - -fix(console): a sign-up refused by the server's audience gate reads in the session's language (objectui#10998) - -When an environment admits new accounts by invitation only (the server's default) -or only from allowlisted email domains, the server refuses `/sign-up/email` with -`403 SELF_REGISTRATION_CLOSED` or `403 EMAIL_DOMAIN_NOT_ALLOWED`. The console's -register page mapped only the user-exists codes to pack text, so either refusal -showed the server's English message in every language, and the invitation-only -refusal also named the internal setting behind it. - -- `@object-ui/console`: `RegisterPage` maps both codes to localized text. A code it - does not map still shows the server's own message. -- `@object-ui/i18n`: all ten locale packs carry the two new keys, - `auth.register.errors.selfRegistrationClosed` and - `auth.register.errors.emailDomainNotAllowed`. No existing value changes. diff --git a/.changeset/10999-wizard-form-chrome-i18n.md b/.changeset/10999-wizard-form-chrome-i18n.md deleted file mode 100644 index 8fd6090aa5..0000000000 --- a/.changeset/10999-wizard-form-chrome-i18n.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@object-ui/plugin-form': patch -'@object-ui/i18n': patch ---- - -`WizardForm`'s own chrome now reads the locale packs (objectui#10999). The -default Cancel, Back, Next, Submitting, Create and Update labels, the -"Step x of y" counter, the step indicator's label for a step that declares no -`label`, the indicator's accessible name, and the notice on a step with no -fields were English literals, so a wizard in a zh session showed `Cancel`, -`Step 1 of 3` and `Next` beside a Chinese UI. They now resolve through the -wizard's existing `createSafeTranslation` hook, the way the rest of -plugin-form's chrome does. - -An authored `cancelText`, `prevText`, `nextText` or `submitText` still renders -exactly as authored, in every locale: only the defaults are localized, and the -four keys stay plain strings. - -Five of the strings reuse keys the packs already carried: `common.cancel`, -`common.next`, `form.create`, `form.update`, and `form.stepOf`, a key that -`pnpm check:i18n-dead-keys` listed as read by nothing until now. Five are new -under `wizard.` in all ten packs: `back`, `submitting`, `stepFallback`, -`progressLabel` and `emptyStep`. The wizard gets its own `back` rather than -`common.back` because zh words a wizard's step back ("previous step", the term -`grid.import.back` and `grid.bulk.back` already use) differently from a page's -back ("return"). - -The zh value of `form.stepOf` gains the spaces around its numbers that the zh -pack's other position counters, such as `table.pageInfo` and -`detail.recordOf`, already carry. - -**One rendered English string changes**: the final button's in-flight label was -typed with three ASCII full stops and is now `Submitting…` with the typographic -ellipsis, because it is a pack value now and `ellipsis-glyph-3878.test.ts` -holds every pack value to U+2026. Every other English default renders the same -text as before. diff --git a/.changeset/11000-closed-affordance-notice.md b/.changeset/11000-closed-affordance-notice.md deleted file mode 100644 index 3dde5312a5..0000000000 --- a/.changeset/11000-closed-affordance-notice.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/plugin-form': patch -'@object-ui/i18n': patch ---- - -A record form whose fields are all locked because the user may not create (or -edit) records of its object now says so (objectui#11000). The ADR-0092 D4 lock -disables every field when the object's affordance for the form's mode is -closed: the object's `managedBy` bucket keeps it closed, or the server's -effective API operation set for the user lacks `create` (or `update` on an edit -form). Until now nothing on the form said why, and a wizard's Next stayed -enabled. - -- Every form layout that draws the lock (the default form, `drawer`, `modal`, - `tabbed`, `split` and `wizard`) renders one notice above the fields, such as - "You don't have permission to create Project records. The fields are - read-only." It names the object by its label, translated when the app's - locale bundle translates it, and names `create` on a create form or `edit` on - an edit form. It is announced as a status (`role="status"`). -- The notice reads the same verdict the lock does, so it appears exactly when - every field is locked for that reason. A field locked on its own (one the - user may read but not edit, or one declared `readonly`) shows no notice. -- A wizard does not walk a user who cannot submit through its steps: while the - lock holds, Next and the final submit button are disabled, and the step - indicator does not jump forward even with `allowSkip`. Cancel and Back stay - usable, and every step is still shown. A user whose affordance is open sees - no change. -- Two keys are new in the `form` namespace of all ten packs: - `noPermissionToCreate` and `noPermissionToEdit`, each with an `{{object}}` - placeholder. - -The lock itself is unchanged, and so is the Save button of the non-wizard -layouts. diff --git a/.changeset/11001-record-delete-confirm.md b/.changeset/11001-record-delete-confirm.md deleted file mode 100644 index 3ad63f1661..0000000000 --- a/.changeset/11001-record-delete-confirm.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): a record page's delete asks through the console's own confirm dialog (objectui#11001) - -On a record page, More actions then Delete asked through the browser's native -`window.confirm` box, while the list view's delete (and every other destructive -action in the console) asks through the in-app confirm dialog. The native box -cannot be themed, and headless automation dismisses it, so the button read as -dead in tests. - -`RecordDetailView`'s header Delete now awaits the page's own confirm handler, -the one it already hands the action runner, which opens `ActionConfirmDialog` -with the same question as before (`detail.deleteConfirmation`) and the dialog's -default title and buttons, as on the list view. Confirm runs the existing delete -unchanged; Cancel leaves the record and the page as they are. No pack key is -added. diff --git a/.changeset/11004-autorefresh-handler-ref.md b/.changeset/11004-autorefresh-handler-ref.md deleted file mode 100644 index 9b85bdd6b0..0000000000 --- a/.changeset/11004-autorefresh-handler-ref.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@object-ui/plugin-dashboard': patch ---- - -fix(plugin-dashboard): the auto-refresh interval reads its handler through a ref, not a memoised identity - -`useDashboardAutoRefresh`, the one timer behind `DashboardGridLayout` and -`DashboardRenderer`, armed its interval in an effect keyed on -`[seconds, onRefresh, handleRefresh]`, and `handleRefresh` is a `useCallback` -result. AGENTS.md #10 bans exactly that: React may throw a memo away and hand -back a new function while nothing it depends on changed, and every such -identity change cleared the interval and set it again, restarting its phase. A -host that passed a new `onRefresh` identity at the same period restarted it the -same way. - -The interval is now keyed on the two values it reads, the period and whether a -handler is wired. The handler is read through a ref when a run happens, so the -run still calls the CURRENT `onRefresh`, and a new handler identity, from the -host or from a discarded memo, leaves the phase where it was. The manual -"Refresh All" button reads the same ref. - -The existing timer pin keeps every case green, the equal-period phase case and -the handler-swap case among them, and adds one case per surface that forces a -memo discard mid-period and then swaps the host handler mid-period, asserting -both times that the run still lands on the original schedule. diff --git a/.changeset/11005-month-grid-calendar-days.md b/.changeset/11005-month-grid-calendar-days.md deleted file mode 100644 index 3e00760fc5..0000000000 --- a/.changeset/11005-month-grid-calendar-days.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch ---- - -fix(plugin-calendar): a month-grid move keeps the wall-clock time across a DST change (objectui#11005) - -The month grid moved an event by the milliseconds between the grabbed cell's local midnight and the drop cell's. Across a DST change that span is 23 or 25 hours. Under `America/Los_Angeles`, a 10:00 event moved onto or off November 1st or March 8th landed at 09:00 or 11:00. A span starting at local midnight, grabbed on a later day and moved, started at 23:00 of the day before the one it was dropped on. The calendar's own month-view quick-create writes such local-midnight instants. - -- **Move.** The grid now counts the calendar days between the grabbed cell and the drop cell and moves the start and the end by that many days on the local calendar. Each keeps its hours, minutes, seconds and milliseconds, so a 10:00 event stays at 10:00 on the day it is dropped on, whatever DST change lies between. This deliberately changes the instant a drag writes into a `datetime` field; what a `datetime` field stores and how it is read are unchanged. In a zone without DST every day is 24 hours, so a move writes what it wrote before. -- **Drag of a span's end.** The right-edge handle moves the end by calendar days the same way. It already kept the end's hours, minutes and seconds; it now keeps its milliseconds too. -- **`date` fields.** A `date` value is read at local midnight of its day, so it now comes back at local midnight of the day it was dropped on, and `ObjectCalendar` writes that local day. The `ObjectCalendar` repair from objectui#10866, which moved a day event's stored day by the whole days the grid moved it, is removed: every day move it pinned writes the same day without it. -- The week and day views are unchanged. Their time grid places a moved event at its snapped time on the drop day's own clock, not by a day delta. diff --git a/.changeset/11007-check-prints-key.md b/.changeset/11007-check-prints-key.md deleted file mode 100644 index ea1506a76e..0000000000 --- a/.changeset/11007-check-prints-key.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/cli': patch ---- - -`objectui check` prints the key and path a file was refused for, and no longer ends with 「✓ All checks passed」 over files it never validated (objectui#11007). - -`check` recognises a JSON file in one of two ways: by a structural root key (`children`, -`className`, …), which admits the file without parsing it, or by the whole document -validating. - -- **A file that did not validate now carries its reason.** Each entry in the "did not validate" - list gets one indented line: the validator's first issue, its path spelled the way - `objectui validate` prints it, and its message, with the issue count when there is more than - one. A root `object-map` whose `map` block carries the typo `latitudeFieId` was listed by file - and type only. It now reads `Issue at map: Unrecognized key: "latitudeFieId"`. The issue comes - from the parse `check` already ran to recognise the file. Skipped files, which are foreign, - still get no diagnosis. -- **The closing line is a tally, not a pass.** A run with no parse errors used to end on - 「✓ All checks passed」, including over a page whose nested node carries a refused key: that - page is admitted on `children` and never parsed. The line now counts the recognised files - that validated, those recognised by a structural key and not validated, and those that did - not validate, and points to `objectui validate ` for a verdict. - -`check` still does not parse a file its structural key admits. The verdict on a document stays -`objectui validate`'s, and `check` still exits non-zero on unreadable JSON only, so no exit code -changes. `objectui validate`'s output is unchanged: its path spelling moved into a helper both -commands share. diff --git a/.changeset/11008-bind-base-prop.md b/.changeset/11008-bind-base-prop.md deleted file mode 100644 index 810abd18a9..0000000000 --- a/.changeset/11008-bind-base-prop.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@object-ui/sdui-parser': patch -'@object-ui/types': patch ---- - -`validateTree` no longer calls a declared `bind` or `hidden` unknown (objectui#11008). - -`BaseSchema` declares `bind` and `hidden` for every node, and no registration declares either as an input. `validateTree`'s base-prop set held neither, so its undeclared-key branch answered every authored one with an `unknown-prop` warning (`has no prop "bind"`), including on the nodes that honour it: `list`, `tree-view` and the `object-*` widgets read `bind` through `useDataScope`, and `SchemaRenderer` reads `hidden` for every node. Both are now base props of the parser tier, so neither draws a diagnostic on any node. A near-miss spelling such as `bindTo` still draws `unknown-prop`. - -The cost is named rather than hidden. `data-table` does not read `bind` (objectui#6575), and a `bind` on it now draws nothing at the parser tier either. Its render-time console warning (`[ObjectUI] DataTable bind:`) is the one signal left. The `BaseSchema.bind` docblock, which ships in the emitted `.d.ts`, said that the console warning and the parser tier's `unknown-prop` both named such a `bind`. It now names the console warning as the one signal and says the parser tier is silent. That supersedes the wording the objectui#10981 entry describes for the same docblock: the parser half it names held until this change. - -At this change, `placeholder` is also a `BaseSchema` member that `validateTree` does not count as a base prop, and it is left as it was. Some registrations declare it as a typed input, and a base prop skipped the declared-input lookup, so adding it would have silenced their `type-mismatch`. - -⚠️ **Dated note, 2026-09-29 — `placeholder` has since become a base prop where a type does not declare it — objectui#11044.** Later in this same release, `placeholder`, `name`, `label`, `description`, `data` and `ariaLabel` join the base props as `where-undeclared` members: each is a base prop only on a type that declares no input of that name. Where a type declares one, the declared input wins and keeps its `type-mismatch`, so no declared type check is silenced. The paragraph above is kept as the reading of this change; the objectui#11044 entry states what ships. diff --git a/.changeset/11009-protocol-readers-only-bind-warning.md b/.changeset/11009-protocol-readers-only-bind-warning.md deleted file mode 100644 index 11a8b1a00a..0000000000 --- a/.changeset/11009-protocol-readers-only-bind-warning.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Docs-only: the "Readers only." paragraph of `skills/objectui/rules/protocol.md` said that a `bind` on `data-table` renders its header over an empty body "— no error, no warning" (objectui#11009). The render tier is not silent: `data-table` logs one `[ObjectUI] DataTable bind:` console warning per such node (objectui#6575). The parser tier is: since objectui#11008 `validateTree` counts `bind` among the base props every node may carry, so it draws no `unknown-prop` there. The clause now says both. Every other sentence of the paragraph, and every example, is unchanged; no published package source moves. diff --git a/.changeset/11011-project-setup-objectview-mount.md b/.changeset/11011-project-setup-objectview-mount.md deleted file mode 100644 index cc08cfe602..0000000000 --- a/.changeset/11011-project-setup-objectview-mount.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Docs only, no package released: the published objectui skill's project-setup guide (`skills/objectui/guides/project-setup.md`, the `@object-ui/app-shell` section) no longer mounts `ObjectView` as a bare element carrying an `objectName` prop — a prop the component never had (it reads the route's `:objectName` and resolves it against `objects`), a mount that threw on first render, and one that `ConsoleObjectViewProps` now refuses at compile time. The guide points at the `ObjectView` section of `packages/app-shell/README.md`, the one copy `pnpm check:doc-snippets` compiles, and says the shell runs under React Router (`react-router-dom` is its peer dependency) in place of the sentence that called it router-agnostic (objectui#11011). diff --git a/.changeset/11013-view-row-declared-spellings.md b/.changeset/11013-view-row-declared-spellings.md deleted file mode 100644 index 61672646fd..0000000000 --- a/.changeset/11013-view-row-declared-spellings.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/data-objectstack': patch -'@object-ui/app-shell': patch -'@object-ui/plugin-view': patch ---- - -**The console reads a saved view by the spellings `@objectstack/spec` declares, and stops reading the keys nothing writes (objectui#11013).** This is the console end of the ruling on objectstack#20051: the spec now declares the keys the console writes onto a stored view and reads back (`VIEW_CONSOLE_ROUND_TRIP_KEYS`), and the console reads a stored view under those spellings. - -**A saved view keeps its switcher state across a reload.** A view saved as a record (the "+" tab's create, or "Edit view config → Save") used to come back from `listViews()` with only its configuration, name, label and default flag. It now also comes back with its pin (`isPinned`), its position among saved views (`sortOrder`), its switcher group (`visibility`), its column layout (`columnState`) and its bound `object`. Visible effect: a saved view you dragged to a new position keeps that position after a reload, including in a browser that never saw the drag. The carried keys are read off the spec's record, not hand-listed. - -**Keys a saved view no longer steers.** No console surface writes any of these onto a view, no view in this repository authors one, and the spec's view schema refuses each by name. A stored view that still carries one now behaves as if it did not: - -| key on the stored view | what changes for the user | -| --- | --- | -| `allowExport` | A view carrying `allowExport: false` no longer hides the list's export control or drops its `exportOptions`. Whether a list offers export is the page's setting (the `list-view` / `object-view` node's `allowExport`); which formats it offers is the view's `exportOptions.formats`. | -| `wrapHeaders` | Column-header wrapping follows the page's setting, not the view's. | -| `editRecordsInline` | On the object page this was read as a second spelling of `inlineEdit`. A view carrying only it no longer turns inline editing on; write `inlineEdit`. | -| `clickIntoRecordDetails`, `addRecordViaForm`, `addDeleteRecordsInline`, `collapseAllByDefault`, `fieldTextColor`, `prefixField` | Relayed into the list, which drew nothing from them. No visible change. | - -The same keys authored on the `object-view` node itself are unchanged: that node's own values still reach the list. - -**The toolbar policy is read as `userActions`.** The `object-view` node the object page builds, and `@object-ui/plugin-view`'s own kanban / calendar / gallery / timeline / gantt / map route (a host that renders the `object-view` node without `renderListView`), read a view's search, sort and filter toggles from `userActions.search`, `.sort` and `.filter`, where they used to read the bare `showSearch`, `showSort` and `showFilters` flags. On that plugin route, a view that declared `userActions: { search: false }` now hides the search control; the object page's list already honoured it. A stored view that still carries a bare flag keeps its answer: `normalizeListViewSchema` folds it onto `userActions`. - -**A stored view is bound and identified by its declared keys only.** A view row is matched to its object by `object` (or its configuration's `data.object`), and no longer by `objectName`; it is identified by `name`, and no longer by a top-level `id` or `_id`. This holds in the view switcher (`listViews()` / `listViewOverrides()`), in Studio's view picker for `interfaceConfig.sourceView`, and in Studio's view preview. Every console write stamps both `object` and `name`, and the metadata door refuses a view record or overlay row bound by `objectName` alone, so a row the console wrote is unaffected. The console also no longer stamps an undeclared `objectName` onto the rows it reads, which a saved view's toolbar save used to write back into the stored row. - -**BREAKING (TypeScript only) — `NamedListView.allowExport` is retired.** It is now a `?: never` tombstone, like the seventeen members objectui#7924 retired: a TypeScript author who writes it gets a compile error there. Ruling A on objectui#7924 had kept it declared only because both relays read it off a view, and those reads are gone. diff --git a/.changeset/11015-page-surface-fallback.md b/.changeset/11015-page-surface-fallback.md deleted file mode 100644 index 331107c4a3..0000000000 --- a/.changeset/11015-page-surface-fallback.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@object-ui/plugin-view': patch ---- - -With a `page` record surface and no `onNavigate` handler, `ObjectView`'s New button, a row click and Edit now open the record form on the drawer (objectui#11015). - -With no authored `layout`, the record surface is derived: `page` on a mobile viewport and on an object with at least `RECORD_SURFACE_PAGE_THRESHOLD` authorable fields. A page hands the record to `onNavigate`, and the registered `object-view` renderer has none, because a JSON schema cannot carry a function. New, a row click and Edit therefore opened nothing there. They now open on the drawer, the surface a page already took for New under a `split` or `popover` navigation (objectui#10975). An explicit `layout: 'page'` without `onNavigate` takes the same fallback. A `page` with an `onNavigate` handler still hands create, edit and view to the router, as before. The README and the plugin-view docs page now also say that under a `drawer` or `modal` navigation, the create form opens on that navigation's surface. - -`Clause-②: no` — no declared type, accepted key or published export moves. diff --git a/.changeset/11016-cross-repo-bare-citations.md b/.changeset/11016-cross-repo-bare-citations.md deleted file mode 100644 index 828095e1e9..0000000000 --- a/.changeset/11016-cross-repo-bare-citations.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@object-ui/core': patch -'@object-ui/app-shell': patch ---- - -Citations of objectstack cards now name their repository (objectui#11016). - -A bare `#N` in this repository resolves to an objectui item. Where the sentence -meant an objectstack card, a reader who followed the number landed on an -unrelated objectui card or pull request, and nothing flagged it: both -repositories answer for the number, so an earlier sweep that looked for dead -numbers could not see this class. - -Two of those citations are runtime text, and they now name the card they mean: - -- `@object-ui/core`: the dev warning for an action that still carries the - retired `execute` key (`RETIRED_ACTION_KEYS.execute`) points at - objectstack-ai/objectstack#3855, the card that retired the alias. The rest of - the message, including "rename the key to `target`", is unchanged. -- `@object-ui/app-shell`: the Studio skill form's help text for - `triggerConditions` points at objectstack-ai/objectstack#1878 and - objectstack-ai/objectstack#1895. - -The other sites are code comments and doc comments in the non-test sources, -requalified the same way: a bare number whose sentence meant -an objectstack card now reads `objectstack-ai/objectstack#N`. Numbers that mean -an objectui card stay bare. Where a comment quotes objectstack's own text, the -quote keeps its words and the card name sits in square brackets, the editorial -mark for a substituted word. - -Pending entries in this release that carry such a number get a dated note -naming the card, and their frontmatter is unchanged. - -Nothing else moves: no key, accept set, refusal decision or code path. diff --git a/.changeset/11019-reaction-keep-ids.md b/.changeset/11019-reaction-keep-ids.md deleted file mode 100644 index 6fd056c6df..0000000000 --- a/.changeset/11019-reaction-keep-ids.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -A reaction click on a record page's discussion keeps every other user's stored reaction - -`sys_comment.reactions` stores `{ emoji: userIds[] }`, and a reaction click -writes the comment's whole reaction set back. The panel used to keep only a -count and an own-mark per emoji, so the write rebuilt each emoji's list from -them: the clicker's id when they had reacted, padded with a literal -`'__other__'` up to the count. The first click by anyone replaced the id of -every other user on every emoji of that comment, and their own reactions -stopped reading as theirs: their next click added a second reaction instead of -taking theirs back. - -The read now keeps each emoji's stored ids on the reaction (`Reaction.userIds`), -and a click adds or removes only the clicker's own id in the clicked emoji. An -emoji left with no ids is dropped from the write, the same way the read shows an -emoji the stored map does not carry. Every other id, on every emoji, is written -back as it was read. - -Rows an earlier build already wrote keep their `'__other__'` entries: they are -stored data, still counted as someone else's reaction, and never read as the -clicker's. The ids they replaced are not recovered. - -Two people reacting at the same moment still means the later write wins. diff --git a/.changeset/11021-grouped-grid-search-both-queries.md b/.changeset/11021-grouped-grid-search-both-queries.md deleted file mode 100644 index 4f3ff34ca1..0000000000 --- a/.changeset/11021-grouped-grid-search-both-queries.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@object-ui/plugin-grid': patch ---- - -fix(plugin-grid): a search reaches the grouped grid's header query and every group's row query, so the groups are the searched ones - -A grid that groups on the server asks two queries: the group header query (the -set of groups and every count) and one row query per open group. Each group's -row query stripped `$search` / `$searchFields`, and the header query was asked -with `where` only, because the header query had no search keys. So a grid -carrying a search term drew the UNSEARCHED groups, with no word that the term -had been dropped. - -`@objectstack/spec` 17.5.0 declares ADR-0061 `search` / `searchFields` on -`EngineAggregateOptions` beside `where` (objectstack#20487), and the platform's -grouped branch honours them. The grid now sends the term on both queries, as -one pair read off the row query each group's page is asked with -(`groupSearchOf`). A searched grouped grid shows only the groups that hold -matching rows, each header counts its matching rows, the rows under it are -those rows, and clearing the term restores the unsearched groups. The -ObjectStack adapter already posts the header query verbatim, so it needs no -change. diff --git a/.changeset/11021-listview-grouped-search.md b/.changeset/11021-listview-grouped-search.md deleted file mode 100644 index f8409905f6..0000000000 --- a/.changeset/11021-listview-grouped-search.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@object-ui/plugin-list': patch -'@object-ui/plugin-grid': patch ---- - -fix(plugin-list,plugin-grid): a grouped list view under a toolbar search groups on the server, and each group counts all its matching rows - -A grouped list view whose data source answers the group header query hands -the grid its own fetch, so the groups and their counts come from the server. -A toolbar search used to take that back: the list view fetched one page of -searched rows and the grid grouped that page in the browser, so once the -matches outnumbered the page a group's count was the page's slice of it, and -a group whose matches all fell past the page was missing. - -The list view now hands the grid its toolbar term (the grid's `search` prop) -and the view's `searchableFields`, and the grid sends them on the group header -query and on every group's row query. A searched grouped list view shows only -the groups that hold matching rows, each counting all its matches, and -clearing the search restores the unsearched groups. - -`ObjectGrid` now reads a host's `search` whenever one is passed, not only -under host-driven paging: the host then owns the term, and the grid's own -queries carry it. Turning grouping back on no longer asks for, or briefly -shows, the groups of the query the grid held when it last grouped (a cleared -search, or an old filter or sort). `@object-ui/plugin-grid` now declares -`@objectstack/spec` `^17.5.0`, the release whose group header query takes a -search. diff --git a/.changeset/11022-strict-widget-slot-registered-inputs.md b/.changeset/11022-strict-widget-slot-registered-inputs.md deleted file mode 100644 index 5be1b87a9e..0000000000 --- a/.changeset/11022-strict-widget-slot-registered-inputs.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/types': minor ---- - -The strict authoring face accepts a correctly authored `metric-card` in a dashboard's widget slot (objectui#11022). This widens a published accept set; nothing that parsed before is refused now. - -`StrictAnyComponentSchema` refused every `metric-card` widget that carried `value`, its required input, and `icon`, `trend` and `trendValue` with it: each came back as `unrecognized_keys` from both arms of the widget slot's union. The widget slot holds `metric-card` as a component node whose props are its registration's `inputs`. The tolerant face admits them through `BaseSchema`'s passthrough, and the strict face closes that passthrough, so it refused them as undeclared. - -- **What changed.** The slot's component-node arm now records the input names the `metric-card` registration declares (`title`, `value`, `icon`, `trend`, `trendValue`, `description`). `deriveStrictAuthoringSchema` admits those names on that node before closing it. Each one is judged the way the tolerant face judges it: the passthrough admits any value, so the strict face checks which KEYS appear and judges no value the tolerant face does not. A name the node already declares, like `description`, keeps its declared type. -- **What still refuses.** A key no registration declares is still refused by name, as `unrecognized_keys` (`{ type: 'metric-card', bogus: 1 }`). `children` and `body` on `metric-card` are still refused with the objectui#9256 message. -- **What does not move.** The tolerant face (`AnyComponentSchema`, `DashboardComponentSchema` and every other mirror): its accept set, output and inferred types are unchanged, and the slot arm's shape and catchall are what they were. The legacy `{ id, component, layout }` widget envelope is untouched, and its `component` is still judged as a plain `BaseSchema` node on both faces. `metric-card` is still not a root-level arm of `AnyComponentSchema`, so a root `{ type: 'metric-card' }` document is refused at `type` on both faces, as before. - -No migration: a document that parsed on either face still parses there. - -⚠️ **Dated note, 2026-10-01 — the slot arm declares `layout` — objectui#11070.** "the slot arm's shape and catchall are what they were" and "a document that parsed on either face still parses there" above held when this change landed. Later in this same release, round 11 of objectui#11070 added `layout` to the slot arm's shape, by reference to the spec's widget `layout`. So the tolerant face now refuses a malformed `layout` on a `metric-card` in the widget slot. `.changeset/11070-dashboard-keys-round11.md` states what ships; the text above is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-02 — the slot arm declares `metric-card`'s registered inputs — objectui#11467.** Three readings above held when this change landed. Later in this same release, objectui#11467 made all three false. "The slot's component-node arm now records the input names the `metric-card` registration declares" and "`deriveStrictAuthoringSchema` admits those names on that node before closing it": the arm now declares `title`, `value`, `icon`, `trend` and `trendValue` as members on both faces. The recorded names and the walker step that admitted them are retired, so both faces judge each value by its member. "its `component` is still judged as a plain `BaseSchema` node on both faces": that slot now takes the arm first, then `BaseSchema`. "No migration: a document that parsed on either face still parses there": both faces now refuse a `metric-card` in the widget slot whose `trend`, `title`, `icon`, `trendValue` or `value` falls outside its member, or that carries `icon`, `trend` or `trendValue` without `value`. `.changeset/11467-metric-card-arm-inputs.md` states what ships; the text above is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-02 — the tolerant face's arm moves too — objectui#11467.** "The tolerant face (`AnyComponentSchema`, `DashboardComponentSchema` and every other mirror): its accept set, output and inferred types are unchanged" above held when this change landed. objectui#11467 changed the slot arm's accept set and inferred type on the tolerant face, as the note above states for what it now refuses. `.changeset/11467-metric-card-arm-inputs.md` states what ships; the text above is kept as the reading of this change. diff --git a/.changeset/11024-spec-gate-canonical-operator-fixtures.md b/.changeset/11024-spec-gate-canonical-operator-fixtures.md deleted file mode 100644 index 4b0381bcd9..0000000000 --- a/.changeset/11024-spec-gate-canonical-operator-fixtures.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Test-only change to `@object-ui/types`; no published behaviour changes. objectstack#20503 typed a view filter rule's input `operator` as the canonical `ViewFilterOperator`, so the two `z.input`-typed fixtures in `p2-spec-exports.test.ts` now author `'equals'` instead of the legacy alias `'eq'`, and the comment that called `'eq'` a valid input says what is true upstream: only the type narrowed, and the runtime fold of a stored or plain-JS alias is unchanged (objectui#11024). diff --git a/.changeset/11026-number-use-grouping.md b/.changeset/11026-number-use-grouping.md deleted file mode 100644 index 485c54b913..0000000000 --- a/.changeset/11026-number-use-grouping.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -'@object-ui/core': minor -'@object-ui/types': minor -'@object-ui/fields': patch -'@object-ui/plugin-grid': patch -'@object-ui/plugin-detail': patch -'@object-ui/plugin-list': patch ---- - -A number field's authored `useGrouping` now decides whether its value renders with thousands -separators (objectui#11026). This is the renderer half of `FieldSchema.useGrouping`, the -digit-grouping hint `@objectstack/spec` declares on a field. - -**What an author now controls.** Write `useGrouping` on a `number` field: - -- `useGrouping: false` renders the value with no separators, whatever its `scale`: a - `scale: 2` code field reads `12345.50`, not `12,345.50`. -- `useGrouping: true` groups it, even at `scale: 0`: a scale-0 headcount reads `2,026`, not - `2026`. An authored `true` reaches `Intl.NumberFormat` as `useGrouping: true`, which means - "always". So in a locale that leaves a four-digit number alone by default (es-ES, pl-PL), - `1234` renders `1.234` / `1 234`. -- Leave it out and nothing changes: a declared `scale: 0` still reads as an ordinal and renders - ungrouped (a year reads `2026`), and any other number is grouped the locale's way. - -Before this change nothing in the console read the key, so the only way to drop the separators -was `scale: 0`, and there was no way to keep them on a scale-0 count. - -**Where it applies.** List and grid cells, record detail sections and highlights, the record -quick-look panel, related-record tables and gallery cards. Each of these builds a cell's field -from the object's field definition key by key, and each now copies `useGrouping` next to -`scale`. Kanban cards and the grid's auto-generated columns hand the cell the whole field -definition, so they follow it too. The form's number input and the dashboard's record table -read neither `scale` nor `useGrouping` for grouping, and are unchanged. - -**API (additive).** - -- `@object-ui/core`: `DisplayNumberFormatOptions` gains `useGrouping?: boolean`, and - `shouldGroupDisplayNumber` takes it as an optional third parameter. An authored boolean - answers first; with it unset, the existing `scale`/`currency` rules decide as before. - `@object-ui/i18n` re-exports both names, so the same options reach it too. -- `@object-ui/types`: `NumberFieldMetadata` declares `useGrouping`, typed from the spec's - `FieldSchema.useGrouping`. diff --git a/.changeset/11027-preview-display-keys.md b/.changeset/11027-preview-display-keys.md deleted file mode 100644 index 7e5cea467b..0000000000 --- a/.changeset/11027-preview-display-keys.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -feat(app-shell): Studio's app, permission and view previews show the authored area descriptions, RLS policy labels and view label - -Four display keys that `@objectstack/spec` parses and publishes reached no human anywhere in Studio. The designer previews now render each one where it was authored: - -- **`app.areas[].description`** — the app preview lists the app's navigation areas: each area's `label` and `id`, with its `description` beneath it. Both `label` and `description` are the spec's `I18nLabel`, so a per-locale map resolves in the designer locale through the spec's own `resolveI18nLabel` rather than printing `[object Object]`. -- **`permission.rowLevelSecurity[].label`** and **`permission.rowLevelSecurity[].description`** — the permission preview lists each row-level security policy by its `name`, with its `label` beside it and its `description` beneath it, under the existing "Row-Level Security" heading. The header pill still counts them. A permission set whose only grants are policies now shows those policies instead of the "grant at least one permission" empty state. -- **the `view` container `label`** — the view preview draws the view's own `label` as its heading, on the list route, the form route and the no-object state alike. Before, the label was relayed only into the one named list view the preview injects, and `object-view` draws its named-view tab strip for two or more entries, so it never reached the screen. The fix is a heading, not a one-entry tab strip. - -A key the author did not write renders nothing: no invented stand-in text. The one new piece of chrome, the areas heading (`engine.appPreview.areas`), is a designer table row in `en` and `zh` like its siblings; the policy list reuses the existing `perm.rls.title` row. diff --git a/.changeset/11028-connector-action-desc-refs.md b/.changeset/11028-connector-action-desc-refs.md deleted file mode 100644 index 5d3420ef9e..0000000000 --- a/.changeset/11028-connector-action-desc-refs.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -feat(app-shell): the flow designer shows a connector action's description and offers its output references - -A `connector_action` node's action picker now shows each action's `description` -beside its label, the way the runtime connector registry -(`GET /api/v1/automation/connectors`) has always served it; an action that -authors no description shows its label alone. - -Nodes and edges downstream of a `connector_action` node now offer that node's -output in the variable picker: one `nodeId.key` reference for each top-level -`properties` key of the chosen action's `outputSchema`, which is how the engine -stores the action's result. The node and edge inspectors hand the registry -they read to the scope, so the "not in scope" note stops flagging those -references. An action with no `outputSchema`, or one whose schema has no -top-level `properties` object, offers no references: keys are never guessed. diff --git a/.changeset/11030-register-refusal-map.md b/.changeset/11030-register-refusal-map.md deleted file mode 100644 index bd1326ae7d..0000000000 --- a/.changeset/11030-register-refusal-map.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/app-shell': minor -'@object-ui/console': patch ---- - -fix(app-shell): the exported register page says why a sign-up is refused, in the reader's language (objectui#11030) - -`DefaultRegisterPage` (mounted at `/register` by `examples/console-starter`) -passed no `errorMessages` to `RegisterForm`, so every refused sign-up showed the -server's English message in every language. For `SELF_REGISTRATION_CLOSED` that -message also names the internal setting behind the refusal. - -- `@object-ui/app-shell`: new export `signUpRefusalMessages(t)`, the one map from - a sign-up refusal code to pack text (`auth.register.errors.userExists`, - `.selfRegistrationClosed`, `.emailDomainNotAllowed`). `DefaultRegisterPage` - passes it. A code the map does not name still shows the server's own message; - `AUTH_CONFIG_ERROR` stays unmapped on purpose, because its message is written - for the operator. -- `@object-ui/console`: `RegisterPage` passes the same map instead of its own - hand-written copy. What it shows does not change. diff --git a/.changeset/11035-reactions-comment-rows-only.md b/.changeset/11035-reactions-comment-rows-only.md deleted file mode 100644 index d750085211..0000000000 --- a/.changeset/11035-reactions-comment-rows-only.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/plugin-detail': patch -'@object-ui/app-shell': patch ---- - -The Add reaction button renders only on a comment row of a record's discussion feed - -A reaction is stored on the comment (`sys_comment.reactions`). The same feed -also shows activity rows read from `sys_activity`, such as a field change, a -completed task or a system event, and `RecordActivityTimeline` rendered the Add -reaction button on those rows too. Picking an emoji on an activity row handed -the host the activity's id, and the record page sent a `sys_comment` update -keyed by that activity id. - -`RecordActivityTimeline` now offers reactions only on a `comment` row, the one -feed kind built from `sys_comment` rows. Any other row renders no Add reaction -button, and reactions a host hands on such a row show as chips that cannot be -clicked. A comment row keeps its Add reaction button and its clickable chips. - -The record page's reaction handler (`RecordDetailView` in app-shell) also -refuses an id whose feed row is not a comment, without writing anything. diff --git a/.changeset/11037-time-grid-move-keeps-event-length.md b/.changeset/11037-time-grid-move-keeps-event-length.md deleted file mode 100644 index 7dc8386b55..0000000000 --- a/.changeset/11037-time-grid-move-keeps-event-length.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch ---- - -fix(plugin-calendar): a week or day view move keeps the event's own length and grab point (objectui#11037) - -The week and day views draw an event that crosses midnight as one piece per day, clipped at midnight, and a short event as a piece at least 15 minutes tall. A move took its length and its grab offset from the grabbed piece. So a 22:00 to 02:00 event dragged by its first piece to 10:00 was handed to `onEventDrop` as 10:00 to 12:00, and `ObjectCalendar`'s default drop handler writes what it is handed. Grabbed by its second piece, the event's start went where its midnight had been grabbed. A 5-minute event came back 15 minutes long. - -- **Length.** A move now keeps the event's own `end - start`, as elapsed time, so a `datetime` event keeps its real length. On the night a DST change falls in, the wall clock shows that length an hour longer or shorter: a 4-hour event placed at 22:00 on the night the clocks fall back reads 22:00 to 01:00. -- **Grab point.** The grabbed point's offset is measured from the event's own start, so the point under the pointer stays under the pointer. A 22:00 to 02:00 event grabbed at its own 00:00 and dropped at 10:00 is written 08:00 to 12:00. -- **Crossing midnight.** An event that crosses midnight is placed where it is dropped, so it can stay overnight; before, it was held to end by midnight of the drop day. An event drawn wholly inside one day is still held inside the drop day, as before. -- The drag preview is labelled with the whole event's times and drawn over the part of it that falls on the drop day. -- An event with no end is still handed an end one hour after its new start. All-day and date-only events sit in the all-day row, which has no drag, so nothing about them changes. The month grid and the resize handles are unchanged. diff --git a/.changeset/11039-form-chrome-i18n.md b/.changeset/11039-form-chrome-i18n.md deleted file mode 100644 index 0303c42b90..0000000000 --- a/.changeset/11039-form-chrome-i18n.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/plugin-form': patch -'@object-ui/i18n': patch -'@object-ui/console': patch ---- - -The form family's own feedback chrome now reads the locale packs (objectui#11039). The default success toast, the thank-you heading, the loading line, the load-failure heading and the default submit and cancel labels were English literals, so a zh session saw `Created`, `Thanks!`, `Loading form...` and `Error loading form` beside a Chinese UI. They now resolve through the i18n catalogue, the way `WizardForm`'s footer has since objectui#10999. - -**What moved.** - -- `@object-ui/plugin-form`, across the presentations `object-form` routes to: - - The success toast when no `successMessage` is authored: `form.created` after a create, `form.saved` after an edit (the default arm and `WizardForm`), and `MasterDetailForm`'s built-in save toast, whose "… saved" after an authored `title` is `form.savedNamed`. - - The note that rides that toast when a declared `navigateOnSuccess` was refused: `form.navigateRefused`. The submitter reads it, as the toast's description. - - The thank-you heading when a `thank-you` submit behaviour declares no `title` (the default arm and `WizardForm`): `publicForm.thankYouTitle`. - - The loading line of the default arm, `TabbedForm`, `SplitForm`, `WizardForm` and `DrawerForm`: `publicForm.loading`. - - The heading of the load-failure panel in those five and `ModalForm`: `form.errorLoading`. - - The default submit label, `form.create` or `form.update`, in the default arm, `TabbedForm`, `SplitForm`, `DrawerForm` and `ModalForm`; the default Cancel of `DrawerForm` and `ModalForm`, `common.cancel`; and `MasterDetailForm`'s default Save, Create and Cancel, `common.save`, `form.create` and `common.cancel`. -- `@object-ui/console`: the form page (`/f/:slug` and `/forms/:name`) reads its loading line from `common.loading`, its success toast from `form.submitted`, and its default thank-you heading and message from `publicForm.thankYouTitle` and `publicForm.thankYouMessage`, through the `I18nProvider` that `main.tsx` mounts above every console route. -- `@object-ui/i18n`: six keys are new under `form.` in all ten packs: `created`, `saved`, `savedNamed` (`{{title}}`), `submitted`, `errorLoading` and `navigateRefused`. The three `publicForm.` keys were already in all ten packs with nothing reading them (`pnpm check:i18n-dead-keys` listed them as confirmed dead), and say the same thing. The zh value of `publicForm.thankYouTitle` ends with a full-width exclamation mark instead of an ASCII one. - -**Authored values still win.** An authored `successMessage`, `submitText` or `cancelText`, a plain string or a per-locale map, and a `thank-you` behaviour's own `title` and `message`, render as authored in every locale. Only the defaults are localized. No schema key is added, renamed or retyped. - -**Three English strings change their rendered text**, because each is now the value of a key whose English differs from the old literal: - -- the loading line, `Loading form...` with three ASCII full stops, is now `Loading form…` with the typographic ellipsis; -- the thank-you heading, `Thanks!`, is now `Thank you!`, in the default arm, `WizardForm` and the form page; -- the form page's default thank-you message, `Your submission has been received.`, is now `Your submission has been received successfully.` - -Every other English default renders the same text as before. With no i18n provider mounted, plugin-form's forms still render English from their defaults tables, which `pnpm check:i18n-keys` holds byte-identical to the `en` pack. diff --git a/.changeset/11040-comment-mask-tracked-files.md b/.changeset/11040-comment-mask-tracked-files.md deleted file mode 100644 index 3c83de759f..0000000000 --- a/.changeset/11040-comment-mask-tracked-files.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Tooling and tests only, no package released: the two comment-mask sweeps in `scripts/` now read the files git tracks instead of walking the working tree. `check-hand-rolled-comment-mask` failed a Test shard with ENOENT on a pull request that touched neither file: `cli-bin.test.ts` builds with tsup, which writes a temporary `tsup.config.bundled_*.mjs` and deletes it, and the walk listed that file before the sweep read it. `collectSources` in `check-comment-mask-corpus.mjs`, which both sweeps share, now enumerates `git ls-files`, as the repository's other censuses do, so untracked build output is out of both sweeps as a class. A path that is listed and then gone before its read is read as absent rather than thrown on; any other read error still throws. No retry, timeout or quarantine was added (objectui#11040). diff --git a/.changeset/11044-base-props-one-list.md b/.changeset/11044-base-props-one-list.md deleted file mode 100644 index ab92bbe5b0..0000000000 --- a/.changeset/11044-base-props-one-list.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@object-ui/sdui-parser': minor ---- - -The base-prop list is declared once, and the renderer's `visibleWhen`, `hiddenOn` and `testId` join it (objectui#11044). - -`validateTree` and `generateDts` each kept their own hand-written list of the base props: the `BaseSchema` keys a node may carry without its registration declaring them. The two lists had drifted. After objectui#11008 the validator accepted `bind` and `hidden` on every node, while the generated JSX types (`SduiBaseProps` in `sdui-intrinsics.d.ts`) still refused both (`TS2322 … Property 'bind' does not exist`). Both now read one exported list, `SDUI_BASE_PROPS`, and the generated `SduiBaseProps` interface is emitted from it. - -Three changes to what is accepted come with it: - -- **`visibleWhen`, `hiddenOn` and `testId` are base props of every node.** `BaseSchema` declares all three, no registration declares any of them, and `SchemaRenderer` reads them for every node. It evaluates `visibleWhen` and `hiddenOn` in its hide chain, and it re-emits `testId` as `data-testid`. `validateTree` answered each with an `unknown-prop` warning on every registered type. Now none of them draws a diagnostic, and the generated JSX types accept them, along with `bind` and `hidden`. The canonical ADR-0089 predicate, `visibleWhen`, used to warn while the deprecated `visibleOn` was silent. A near-miss spelling such as `testid` still draws `unknown-prop`. -- **`name`, `label`, `description`, `placeholder`, `data` and `ariaLabel` are base props where a type does not declare them.** Some registrations declare each of these `BaseSchema` members as a typed input. On those types the declared input wins, and a wrong-typed value still draws `type-mismatch`. On every other type the key no longer draws `unknown-prop`. In the generated JSX types, an interface that declares one of these keys extends `Omit` for it, so its declared type is the one an author compiles against. -- **The cost is named.** On a type that does not declare one of the six keys, the parser tier no longer reports it, whether or not the renderer reads it. For example, `description` on `page-header` is the retired alias of `subtitle` (objectui#3226), and it used to draw `unknown-prop`. It now draws nothing. - -`SDUI_BASE_PROPS` and its `SduiBaseProp` / `SduiBasePropScope` types are new exports. Each entry names a `BaseSchema` member, the scope it is a base prop in (`'every-node'` or `'where-undeclared'`), and its type in the generated JSX surface. - -⚠️ **Dated note, 2026-10-02 — the `page-header` example no longer applies — objectui#10859.** -Later in this same release objectui#10859 batch 8 (phase 2c) unregistered `page-header`, so a -`page-header` node now draws `unknown-component` before any prop check runs. The cost this entry names -is unchanged for every type that is still registered. The rest of this entry is kept as the reading of -this change. diff --git a/.changeset/11051-inline-aria-reader.md b/.changeset/11051-inline-aria-reader.md deleted file mode 100644 index dee9da342d..0000000000 --- a/.changeset/11051-inline-aria-reader.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/react': minor -'@object-ui/components': patch ---- - -`element:text`, `element:button`, `element:image` and `element:number` now render the accessible name an author declares in their `aria` prop (objectui#11051). - -**What an author sees change.** These four elements declare the spec's `AriaPropsSchema` as their `aria` prop. The renderer used to put `aria-` in front of each key as written, so `aria: { ariaLabel: 'Order total' }` reached the DOM as `aria-arialabel="Order total"`. No assistive technology reads that attribute, so the element had no accessible name. A locale map (`{ en: 'Order total', 'zh-CN': '订单合计' }`) was written as `[object Object]`. Now: - -- `ariaLabel` renders `aria-label`. A locale map gives the entry for the display locale (`useDisplayLocale()`), resolved by the spec's own `resolveI18nLabel`. -- `ariaDescribedBy` renders `aria-describedby` (it rendered `aria-ariadescribedby`). -- `role` renders `role`, as before. - -**New export: `resolveInlineAriaProps(aria, locale)` from `@object-ui/react`.** A pure function, not a hook: it maps the spec's nested `aria` bag to those three attributes, and returns only the ones that have a value. It is exported so the renderers in `@object-ui/components` share one mapping. `SchemaRenderer`'s own reader for the FLAT node keys (`ariaLabel` in the keyed `{ key, defaultValue }` form) is unchanged: objectui#4580 Q2-B keeps the two vocabularies apart, and each resolver returns nothing useful for the other's shape. - -**What is no longer read.** The old helper also passed any raw `aria-*` key straight through, and turned any other key into `aria-KEY`. So an `aria: { label: 'x' }` rendered `aria-label="x"` by accident. The spec refuses both shapes when it parses the document (`unrecognized_keys`), and these four elements now ignore them. When this change was made, a `git grep` found no example app, doc or skill in this repository or in the ObjectStack framework that puts an `aria` bag on these four elements, so no shipped document depended on those shapes. If you wrote one, use `aria: { ariaLabel: 'x' }`. diff --git a/.changeset/11054-flow-start-api-trigger.md b/.changeset/11054-flow-start-api-trigger.md deleted file mode 100644 index 3e2e77fd34..0000000000 --- a/.changeset/11054-flow-start-api-trigger.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): Studio's flow start node writes the `api` trigger the engine routes, and can set its secret - -The flow designer's start-node inspector offered a 「Webhook / API」 trigger that -wrote `triggerType: 'webhook'`. `resolveFlowTriggerKind` (`@objectstack/spec`) -answers no trigger kind for that token, so a flow authored this way bound no -trigger and never received a post. The option now writes `api`, the token the -engine routes to the inbound hook. - -The start node also gains the inbound hook's per-flow `config.secret` field, -shown when the flow's trigger kind is `api` — by the start node's trigger, or by -a flow-level `type: 'api'`. The engine refuses an `api` flow whose start node -carries no secret. The field is write-only: - -- a value already on the node is never put back into the control; -- leaving it blank writes no key, so a save that never touched it keeps the - stored secret; -- while the flow is `api`-kind and no secret is entered, a notice says the flow - is refused without one. A server that withholds the secret from definition - reads serves the node without it, so the notice also says that a secret - already saved is kept. diff --git a/.changeset/11056-undo-confirmation-toast-i18n.md b/.changeset/11056-undo-confirmation-toast-i18n.md deleted file mode 100644 index e4fb81442f..0000000000 --- a/.changeset/11056-undo-confirmation-toast-i18n.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@object-ui/app-shell': patch -'@object-ui/i18n': patch ---- - -The console's undo confirmation toast reads the session's language (objectui#11056). - -- **The toast after Undo.** Pressing the Undo button on an undoable success toast used to raise a hard-coded English "Change undone", even where the button itself was already translated (objectui#10969). Both console undo handlers, in `useConsoleActionRuntime` and in `RecordDetailView`, now read the new `actions.undone` key through the translator each already holds. Under zh-CN the toast reads 「已撤销更改」. -- **English is unchanged.** The `en` value is `Change undone`, the same text as before. -- **The new key is in all ten packs.** de, es, fr, ja, ko, pt and ru word it as their own `navigationSync.undone` without the word for navigation; ar does the same and gives the noun its article. zh reads 「已撤销更改」, with the 撤销 of `actions.undo` and the 更改 of the pack's 「保存更改」. - -`AppContent`'s own Ctrl+Z handler, which toasts `Undo: ` or `Redo: ` followed by the operation's description, is not changed here. diff --git a/.changeset/11058-signin-refusal-map.md b/.changeset/11058-signin-refusal-map.md deleted file mode 100644 index 9cf61b0c86..0000000000 --- a/.changeset/11058-signin-refusal-map.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/app-shell': minor -'@object-ui/console': patch ---- - -fix(app-shell): the exported sign-in page says why a sign-in is refused, in the reader's language (objectui#11058) - -`DefaultLoginPage` (mounted at `/login` by `examples/console-starter`) passed no -`errorMessages` to `LoginForm`, so a wrong password or an unverified email showed -the server's English message in every language. - -- `@object-ui/app-shell`: new export `signInRefusalMessages(t)`, the one map from - a sign-in refusal code to pack text (`INVALID_EMAIL_OR_PASSWORD` to - `auth.login.errors.invalidCredentials`, `EMAIL_NOT_VERIFIED` to - `auth.login.errors.emailNotVerified`). `DefaultLoginPage` passes it. A code the - map does not name still shows the server's own message. -- `@object-ui/console`: `LoginPage` passes the same map instead of its own - hand-written copy. What it shows does not change; its redirect to the - verify-email prompt on `EMAIL_NOT_VERIFIED` stays as it was. diff --git a/.changeset/11060-overnight-resize-true-edge.md b/.changeset/11060-overnight-resize-true-edge.md deleted file mode 100644 index d519870280..0000000000 --- a/.changeset/11060-overnight-resize-true-edge.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/plugin-calendar': patch ---- - -fix(plugin-calendar): a week or day resize of an overnight event keeps its other edge (objectui#11060) - -The week and day views draw an event that crosses midnight as one piece per -day, clipped at midnight, and a short event as a piece at least 15 minutes -tall. The top resize handle sits on the event's first piece and the bottom -handle on its last. A resize rebuilt both edges on the grabbed piece's day, -the untouched one from that piece's clipped bound. So a 22:00 to 02:00 event -resized by its top handle to 21:00 was written 21:00 to 00:00, losing the two -hours past midnight, and resized by its bottom handle to 03:00 was written -00:00 to 03:00, its start moved to midnight. A press and release on the top -handle without moving cut the end to midnight too, and a 5-minute event resized -by its top handle came back ending 15 minutes after its old start. - -The top handle now changes only the start and the bottom handle only the end. -The other edge is the event's own instant, handed to `onEventDrop` unchanged. -The dragged edge is placed as before, at the pointer's row on the grabbed -piece's day, snapped, and held one slot away from the kept edge wherever that -edge falls. The preview while dragging is labelled with the whole event's -times. A same-day event resizes exactly as before. diff --git a/.changeset/11061-modal-close-button.md b/.changeset/11061-modal-close-button.md deleted file mode 100644 index 5078eaa0e6..0000000000 --- a/.changeset/11061-modal-close-button.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/components': minor -'@object-ui/plugin-form': patch ---- - -fix(plugin-form): `object-form`'s `modalCloseButton: false` hides the modal's close button - -An author can now hide the close (X) button of a modal form. `modalCloseButton` -was declared on `ObjectFormSchema` and on the `object-form` registration, and -`ObjectForm`'s modal route forwarded it, but `ModalForm` never read it: `false` -still drew the X, with no effect and no error. `ModalForm` now honours it on both -of its dialog arms (the flat form and the `subforms` master-detail form). Only an -explicit `false` hides the button; unset and `true` keep it. With the X hidden the -modal still closes on Escape, and on the Cancel action when that is shown. - -`@object-ui/components`: `MobileDialogContent` gains an optional `showCloseButton` -prop, default `true`, named after upstream Shadcn's `DialogContent` prop of the -same purpose. `false` leaves the close button out of the DOM. Existing callers are -unchanged. The component's exported props type gains this one optional member, -which is why this package takes a minor bump. diff --git a/.changeset/11062-console-dashboard-auto-refresh.md b/.changeset/11062-console-dashboard-auto-refresh.md deleted file mode 100644 index 76c45377fd..0000000000 --- a/.changeset/11062-console-dashboard-auto-refresh.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -The console now honours a dashboard's authored `refreshIntervalSeconds` (objectui#11062). `DashboardView` used to render `DashboardRenderer` with no `onRefresh`, and the renderer's auto-refresh timer only runs when its host wires one, so a period set in Studio did nothing. - -`DashboardView` now passes a refresh handler. It declares an unscoped change on the data-invalidation bus (`notifyDataChanged({ objectName: '*' })`), and every widget that already listens on the bus re-reads its data in place, so nothing is remounted. The timer is still the renderer's own: with a period of 60, those widgets re-read once every 60 seconds; `0`, a negative value or no value means no timer, and leaving the dashboard stops it. - -Not every widget listens yet. A dataset-bound widget subscribes on the base object its query's answer names, and the answer to a query with no dimensions names none, so a dataset-bound KPI tile does not refresh, on the timer or on the button. - -Wiring the handler also turns on the renderer's manual refresh button on every console dashboard, whether or not it sets a period. It is a small outlined "Refresh All" button with a refresh icon, right-aligned in its own full-width row of the widget grid, below any header actions and the filter bar, so the widgets start one grid row lower than before. A click runs one refresh. For 600 ms after each refresh, manual or timed, it reads "Refreshing…", its icon spins and it is disabled. Its labels are not localized yet. diff --git a/.changeset/11067-drop-platform-event-trigger.md b/.changeset/11067-drop-platform-event-trigger.md deleted file mode 100644 index 96cb21f423..0000000000 --- a/.changeset/11067-drop-platform-event-trigger.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@object-ui/app-shell': patch ---- - -fix(app-shell): Studio's flow start node stops offering 「Platform event」, a trigger no engine routes - -The flow designer's start-node inspector offered a 「Platform event」 trigger -that wrote `triggerType: 'event'`. `resolveFlowTriggerKind` (`@objectstack/spec`) -answers no trigger kind for that token and no engine trigger binds it, so a -flow authored this way never fired, and nothing said so. The option is gone -from the trigger select, and the Object and Entry condition fields no longer -appear for that token alone. - -A start node that already stores `triggerType: 'event'` is not rewritten. The -select shows the value flagged as one it no longer offers, and saving the flow -keeps it as stored. Pick a trigger the list offers to make the flow fire. diff --git a/.changeset/11068-grid-declared-keys.md b/.changeset/11068-grid-declared-keys.md deleted file mode 100644 index c374fa26e5..0000000000 --- a/.changeset/11068-grid-declared-keys.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -'@object-ui/plugin-grid': minor -'@object-ui/types': minor ---- - -An `object-grid` now honours `description` and `emptyState`, and four keys it declared but -never read are retired (objectui#11068). - -**What was wrong.** `ObjectGridSchema` declared eight keys the grid never read. An author who -wrote `description`, `emptyState`, `name`, `placeholder`, `rowSpecActions` or `bulkSpecActions` -on an `object-grid` got no type error, no validator refusal and no effect. The reference -example in `schema-reference.md` taught `description` and `showFilters` as if they worked. It -now authors only keys the grid reads. - -**`@object-ui/plugin-grid` (feature).** - -- `description` draws one line of help text above the grid, in the muted style `list-view` - uses for a view's description. A per-locale map resolves against the display locale, as - `label` does. A map with no usable entry draws nothing. -- `emptyState: { title?, message?, icon? }` draws in place of an empty table, through the same - empty-state component and icon resolver `list-view` uses. A member you leave out keeps the - grid's default: the shared empty-state glyph, the table's "No results found" heading, and no - message. It is not drawn when a term typed into the grid's own server-side search box emptied - it: the table and its search box stay, so the term can be cleared. A grid without the key - draws the table's own empty row, as before. - -**`@object-ui/types` (breaking for a writer of a retired key, hence `minor`).** - -- `rowSpecActions` and `bulkSpecActions` are retired. They were second spellings of - `rowActions` and `bulkActions`, which the grid reads. Rename the key. -- `name` and `placeholder` are retired on `object-grid`. A grid is not a form field or an - input, and the grid never read either key. Write `id` for the node's identity, `label` for - its caption, and `emptyState: { message }` for the text shown when it has no rows. -- Each retired key is `?: never` on the interface and a named refusal on the Zod twin, so - TypeScript code that writes one fails to compile, and a document that carries one fails - validation with a message that names the key and its replacement. -- The Zod twin now also validates `emptyState`: three optional strings, with an unknown member - refused by name. - -**Unchanged.** An `object-view`'s `table` slot still withholds `description` and `emptyState`. -Write them on the `object-grid` node itself. `keyboardNavigation` is still declared and still -not read. - -**Correction, 2026-10-03 (objectui#11227).** The Zod twin's `emptyState` is no longer three -optional strings. It is the spec's `EmptyStateSchema` by reference, which `@objectstack/spec` -17.6.0 declares on its `object-grid` row: `title` and `message` are `string | I18nLabel` (a -plain string or an inline locale map, which the grid resolves against the display locale), and -an unknown member is still refused by name (`.changeset/11227-object-grid-17-6-keys.md`). - -**Correction, 2026-10-03 (objectui#11068, the `keyboardNavigation` build).** `keyboardNavigation` -is no longer unread. The grid honours it, with arrow-key cell navigation that is on by default -when the grid renders editable, and it is in the grid's declared inputs -(`.changeset/11068-keyboard-navigation.md`). diff --git a/.changeset/11068-keyboard-navigation.md b/.changeset/11068-keyboard-navigation.md deleted file mode 100644 index 17c43a888a..0000000000 --- a/.changeset/11068-keyboard-navigation.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -'@object-ui/components': minor -'@object-ui/plugin-grid': minor -'@object-ui/types': minor ---- - -An `object-grid` honours `keyboardNavigation`: arrow-key cell navigation on the WAI-ARIA grid -pattern (objectui#11068). `@objectstack/spec` 17.6.0 declares the key on its `object-grid` row -(objectstack#20694), and the grid now reads it. - -**`@object-ui/plugin-grid` (feature).** - -- With the key on, the grid's data cells take one place in the Tab order instead of one each: - Tab reaches them once, on the cell that last held focus (the first cell to begin with), and - the next Tab moves past them. The arrow keys move focus one cell, Home / End go to the first / - last cell of the row, and Ctrl+Home / Ctrl+End to the first / last cell of the page. On an - editable grid, Enter still opens the focused cell, and an edit ended with Enter or Escape - hands focus back to its cell. A widget a cell renders (the record link, a row's action menu, - a selection checkbox) keeps its own Tab stop. -- The default is on when the grid renders editable: the authored `editable` and the viewer's - permission to update the object, the value inline editing itself obeys. A read-only grid - keeps every cell its own Tab stop unless `keyboardNavigation: true` is written, and - `keyboardNavigation: false` turns it off on an editable grid. **An editable grid changes - without an edit to its document:** its cells become one Tab stop, and the arrow keys move - between them. -- `keyboardNavigation` is in the grid's declared inputs, so the designer panel, the component - manifest and the generated `sdui-intrinsics.d.ts` offer it, and the SDUI parser no longer - reports it as `unknown-prop`. This supersedes the line in objectui#11227's entry that says - the key is not published and nothing reads it. - -**`@object-ui/components` (feature).** `data-table` takes a `keyboardNavigation` flag that does -the above: the table is exposed to assistive technology as a `grid`, its data cells are one -roving Tab stop, and the keys move it. Off, which stays the default, the table is unchanged: -every data cell is its own Tab stop and the table carries no grid role. `ObjectGrid` sets the -flag in code; it is not an authoring key on a `data-table` node. - -**`@object-ui/types` (feature).** `DataTableSchema` declares `keyboardNavigation?: boolean`, the -flag above, set in code by a host as `editable` is. `ObjectGridSchema.keyboardNavigation`'s -documentation describes the behaviour and the default. An `object-view`'s `table` slot still -refuses `keyboardNavigation`; its message now says the grid honours the key on an -`object-grid` node and the view does not hand it on. diff --git a/.changeset/11068-object-grid-show-filters.md b/.changeset/11068-object-grid-show-filters.md deleted file mode 100644 index 14ffe4a0dc..0000000000 --- a/.changeset/11068-object-grid-show-filters.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'@object-ui/types': minor ---- - -`showFilters` is retired on `object-grid` (objectui#11068). - -**BREAKING (authoring).** An `object-grid` that carries `showFilters` now fails validation, -and TypeScript code that writes it on an `ObjectGridSchema` no longer compiles. Delete the key. - -**What was wrong.** `ObjectGridSchema` declared `showFilters`, but an `object-grid` has no filter -UI and never read the key. An author who wrote `showFilters: true` on a grid got no type error, -no validator refusal and no filter. - -**Where filtering lives.** The filter builder is the `list-view` toolbar's. Author a `list-view` -and switch the builder with its `userActions.filter`. To narrow the rows a grid fetches, write -`filter` on the grid. - -**How it is refused.** The key is `?: never` on the `ObjectGridSchema` interface and a named -refusal on its Zod twin. On both authoring faces, the node face and the strict authoring face, -the message names the key and `userActions.filter`. This matches the upstream protocol, whose -`object-grid` row does not declare the key either. - -**Unchanged.** An `object-view`'s own `showFilters` and a `list-view`'s are different keys, and -both are still accepted. `ObjectView` reads its own, and `ListView` folds its own onto -`userActions.filter`. An `object-view`'s `table` slot already refused `showFilters` and still -does. diff --git a/.changeset/11068-row1-booking-17-6.md b/.changeset/11068-row1-booking-17-6.md deleted file mode 100644 index 9e800d4e90..0000000000 --- a/.changeset/11068-row1-booking-17-6.md +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -Test-only change in `@object-ui/console`; no published behaviour changes. Under objectui#11438 ruling A″, row 1 of the `@objectstack/spec` 17.6.0 bump, `object-grid.keyboardNavigation`, is booked as owed to objectui#11068 in `registry-inputs-spec-parity.test.ts`, with an expiry (2026-11-02, or when objectui#11068's build lands). The entry joins the file's objectui#11111 ledger, whose `unpublishedKeys` cap rises by exactly this one entry. The GA-block split row admits this one id by name and refuses every other exemption on the four GA blocks as before. The file sits under `apps/console/src/__tests__/`, which nothing outside `__tests__/` imports, so neither the console bundle nor `plugin.*` carries it. - -**Correction, 2026-10-03 (objectui#11068, the `keyboardNavigation` build).** The booking is struck. objectui#11068's build publishes `keyboardNavigation` in the grid's declared inputs together with its reader, so the entry went stale; the build removes it, lowers the `unpublishedKeys` cap by the same one entry, and leaves the GA-block split row admitting no booked id (`.changeset/11068-keyboard-navigation.md`). diff --git a/.changeset/11070-dashboard-formula-round6.md b/.changeset/11070-dashboard-formula-round6.md deleted file mode 100644 index 6b02c8532b..0000000000 --- a/.changeset/11070-dashboard-formula-round6.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-form': minor -'@object-ui/plugin-charts': minor -'@object-ui/app-shell': minor ---- - -`FormulaFieldMetadata` declares `@objectstack/spec`'s `expression` in place of `formula`, and three readers of a lookup's display pointer read the spec's `displayField` alone (objectui#11070, round 6). Both retired spellings go at once, with no alias. - -- **Types.** `FormulaFieldMetadata.formula` is removed. `FormulaFieldMetadata.expression` is `FieldSchema`'s `expression` by reference: a CEL source string, or the spec's `{ dialect, source, … }` envelope. Nothing in ObjectUI read the removed member through the type. `FieldSchema` refuses `formula` by name on every field type, with a rename hint to `expression`. -- **Form payloads.** `sanitizeFormData` (`@object-ui/plugin-form`) no longer treats a `formula` key as a "computed" flag. Every `type: 'formula'` field is still dropped from the payload by its type, as before. Only a field of some other type that carries `formula` changes: its value is now sent like any writable field's. The spec refuses such a definition at publish, so a served one cannot carry it. -- **Display pointer.** `deriveColumns` and `hydrateColumns` (`@object-ui/plugin-form`, the master-detail grid columns), `ObjectChart`'s group-by labels (`@object-ui/plugin-charts`) and the action-param resolver (`@object-ui/app-shell`) read `displayField`, then `reference_field`. None of them reads `display_field` any more. -- **A fix for spec-spelled lookups in master-detail grids.** `deriveColumns` and `hydrateColumns` read `display_field || reference_field` before, with no `displayField` leg. A lookup that declared only `displayField`, which is the spec's spelling, got no display pointer on its grid column. It now gets one. - -A definition served through `ObjectStackAdapter.getObjectSchema` or `MetadataProvider` loses nothing: the ingestion pass (objectui#7650) stamps a stored `display_field` onto `displayField` before any of these readers sees it. Measured with a lookup carrying `display_field: 'title'` served through `ObjectStackAdapter.getObjectSchema`: the master-detail column (`deriveColumns` and `hydrateColumns`), the chart's axis label and the action param all resolve the `title` column before and after this change. - -## ⚠️ BREAKING, priced as minor under the fixed group's version policy - -TypeScript that writes `formula` on a `FormulaFieldMetadata` no longer compiles (an excess-property error naming the key). Rename it to `expression` and write the formula in CEL against the record, for example `record.quantity * record.unit_price`. - -At runtime, a lookup whose display pointer is spelled only `display_field` loses it wherever the ingestion pass does not run first. Measured before and after this change, on a lookup with `display_field: 'title'` handed to the readers directly: - -- **`deriveColumns` / `hydrateColumns` with a `childSchema` that did not come through the ingestion pass** (an external caller, or a master-detail form whose `DataSource` is not `ObjectStackAdapter`): the column's `displayField` was `title`. It is now absent. -- **`ObjectChart` on a `DataSource` other than `ObjectStackAdapter`**, grouped by that lookup: the axis label came from the `title` column. It now comes from the `name` column, the generic fallback. -- **The action-param resolver, when a host passes its own unfolded `objects`** (for example through `RecordDetailView`'s `objects` prop): the lookup param's `displayField` was `title`. It is now absent. - -The same lookups spelled `displayField` resolve the `title` column in all three after this change. Before it, the chart and the action param already did, and the master-detail columns did not (the fix above). - -**Fix:** spell the pointer `displayField`, or serve the definition through `ObjectStackAdapter`. diff --git a/.changeset/11070-dashboard-keys-round11.md b/.changeset/11070-dashboard-keys-round11.md deleted file mode 100644 index 0458130b8e..0000000000 --- a/.changeset/11070-dashboard-keys-round11.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/types': minor ---- - -The strict authoring face accepts the `layout` that the editable dashboard grid's Save Layout writes onto a `metric-card` in a dashboard's widget slot (objectui#11070, round 11). This widens a published accept set, and it narrows the tolerant face on one corner, stated below. - -`DashboardGridLayout`'s Save Layout (`mergeLayoutIntoSchema`) writes `layout: { x, y, w, h }` onto every entry of `widgets[]`, a `metric-card` component node included, and the grid places each entry by it. The widget slot's component-node arm declared no `layout`. The tolerant face kept it through `BaseSchema`'s passthrough, and `StrictAnyComponentSchema` refused it as `unrecognized_keys: ['layout']`, so a dashboard the grid had saved failed on the strict face. - -- **What changed.** `DashboardWidgetSlotComponentSchema` declares `layout` on both faces, by reference to `@objectstack/spec`'s widget `layout`, the member the widget arm already carries: the four numbers `x`, `y`, `w` and `h`, and no other key. On the TypeScript face the member is typed `SpecDashboardWidget['layout']`, where it used to be the index signature's `any`. -- **What now refuses that did not.** A malformed `layout` on a component node in the widget slot (a coordinate that is not a number, a missing coordinate, or a key besides the four) was kept unjudged by the tolerant face (`AnyComponentSchema`, `DashboardComponentSchema`). It is now refused there, as it already was on the widget arm. On the TypeScript face such a literal is a compile error. `scripts/measure-strict-authoring-face.mjs`, run over the schema catalog, the docs fences and the apps' authored documents at this change's base and on this change, found no document that writes `layout` on a component node, so no corpus verdict moved. -- **What does not move.** The widget arm, the component node's other keys and the registered-input record objectui#11022 added. - -**Fix:** write `layout` as the four numbers Save Layout writes, or leave it out. - -`options.description` is not changed by this release. `@objectstack/spec` does not declare it on the widget's `options`, so the strict face keeps refusing an authored one (objectui#11228 ruling C), and its status is an open decision on objectui#11070. Comments in `@object-ui/plugin-dashboard` that called it declared now say so; that package's runtime behaviour is unchanged. - -⚠️ **Dated note, 2026-10-02 — the slot arm declares `metric-card`'s registered inputs — objectui#11467.** "The widget arm, the component node's other keys and the registered-input record objectui#11022 added", under "What does not move" above, held when this change landed. Later in this same release, objectui#11467 moved all three. The widget arm's `component` member now takes the slot's component arm first, then `BaseSchema`. The component node declares `title`, `value`, `icon`, `trend` and `trendValue` as members on both faces, so each value is judged by its member. The registered-input record and the strict walker's step that admitted it are retired. `.changeset/11467-metric-card-arm-inputs.md` states what ships; the text above is kept as the reading of this change. - -⚠️ **Dated note, 2026-10-02 — the widget arm's `type` vocabulary moves — objectui#11483.** At this change, "What does not move" above held for the widget arm, whose `type` vocabulary named `metric-card`; now that vocabulary names no component type, and the slot reads a `metric-card` through its component arm alone. `.changeset/11483-metric-card-needs-value.md` states what ships. The rest of this entry is kept as the reading of this change. diff --git a/.changeset/11070-field-metadata-spec-spellings.md b/.changeset/11070-field-metadata-spec-spellings.md deleted file mode 100644 index ee0b67ca25..0000000000 --- a/.changeset/11070-field-metadata-spec-spellings.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/fields': minor ---- - -The formula and summary field widgets read `@objectstack/spec`'s own spellings, `returnType` and `summaryOperations`, and the snake_case spellings they used to read are retired at once (objectui#11070). - -**Visible change.** Object metadata carries the spec spellings: the platform's example apps write `returnType` on a formula field and `summaryOperations: { object, field, function }` on a roll-up, and the metadata admin stamps `returnType` from the inferred formula type. The widgets read only `return_type` and `summary_type`, so on an object-bound form a formula or summary field rendered without its type formatting: a number formula showed `3` instead of `3.00`, a boolean formula `true` instead of `Yes`, a date formula the raw `2026-07-04` instead of the shared date face, and a `sum` roll-up `15750.5` instead of `15750.50`. They now format by what the definition declares. - -- **`@object-ui/fields`:** `FormulaField` reads `returnType` (`number` to two decimals, `boolean` as Yes/No, `date` through the shared date face, anything else as text). `SummaryField` reads `summaryOperations.function` (`count` as it arrives, `sum` / `avg` / `min` / `max` to two decimals). Neither reads a snake_case spelling any more. `FormulaField` also no longer formats a `currency` return type, which the spec does not list. -- **`@object-ui/types`, the form-field face:** `FormField` and its zod mirror `FormFieldSchema` declare `returnType` and `summaryOperations`, each the spec's `FieldSchema` member by reference, with the spec's own value rules. The strict authoring face (`StrictAnyComponentSchema`) accepts them on a hand-authored form's field, and judges them: a `returnType` of `datetime`, a `summaryOperations` with no `function`, a `function` of `first`, or an unknown member inside `summaryOperations` is refused on both faces. The tolerant face (`AnyComponentSchema`) used to strip both keys from a form field unjudged, so those values were accepted silently before this change: that half is a narrowing. -- **`@object-ui/types`, the field metadata types:** `FormulaFieldMetadata.returnType` replaces `return_type`; `SummaryFieldMetadata.summaryOperations` replaces `summary_object`, `summary_field`, `summary_type` and `summary_filter`; `PasswordFieldMetadata.minLength` / `maxLength` replace `min_length` / `max_length`. Each is the spec member by reference. - -**Breaking, priced as minor under the fixed group's version policy.** A literal annotated as `FormulaFieldMetadata`, `SummaryFieldMetadata` or `PasswordFieldMetadata` that still writes a retired member no longer compiles (an excess-property error naming the key), and at runtime a formula or summary field that carries only `return_type` or `summary_type` renders its value unformatted. `@objectstack/spec`'s `FieldSchema` refuses every retired spelling by name, so no spec-compliant producer writes them. The fix is the spec spelling: `returnType`, and `summaryOperations: { object, field, function }` (with `filter` for the former `summary_filter`). - -**Not in this change.** `LookupFieldMetadata.reference_to` and the lookup readers' `reference_to` read stay: in-repo producers still write `reference_to` onto the field definitions those readers are handed, so retiring the spelling is a separate decision on objectui#11070. The strict face keeps refusing `return_type`, `summary_type`, `summary_object` and `summary_field` on a hand-authored form's field, as before. - -⚠️ **Dated note, 2026-09-30 — the `reference_to` decision was taken in this same release — objectui#11070.** "Not in this change" above is still true of this change. Round 4 of objectui#11070, later in this same release, retired `LookupFieldMetadata.reference_to` and the lookup readers' `reference_to` read, and moved the in-repo producers to `reference`. `.changeset/11070-reference-to-round4.md` states what ships; the text above is kept as the reading of this change. diff --git a/.changeset/11070-grid-columns-chart-binding-round7.md b/.changeset/11070-grid-columns-chart-binding-round7.md deleted file mode 100644 index 447c47f1c1..0000000000 --- a/.changeset/11070-grid-columns-chart-binding-round7.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/fields': minor ---- - -The grid field's `columns` is `@objectstack/spec`'s inline grid column list, by reference, and `object-chart` declares the per-element `dataSource` binding like the other gate-wrapped blocks (objectui#11070, round 7). - -- **Grid columns (`@object-ui/types`).** `GridFieldMetadata.columns` and the form-field face's `FormField.columns` (TypeScript and the zod mirror `FormFieldSchema`) are `FieldSchema.inlineColumns` by reference: an array of the spec's strict, `name`-keyed inline grid column (`InlineGridColumn`), which the spec declares as the mirror of the `grid` widget's column. The key stays `columns`: a `grid` field is objectui's own field type, and the spec spells the same list `inlineColumns` on a `master_detail` field. -- **`GridColumnDefinition` is retired (`@object-ui/types`).** Nothing read it, and it was not the shape the widget read: it required a free-form `type` and declared `defaultValue` and `validate`, which no reader consumed. Use `InlineGridColumn` from `@objectstack/spec/data`, or `NonNullable[number]`. -- **`GridColumn` (`@object-ui/fields`)** is `InlineGridColumn` by reference instead of a hand-written copy. `GridField` already read each column by exactly the spec's keys (twenty, with no second spelling), so nothing changes at render time. -- **`object-chart` · `dataSource` (`@object-ui/types`).** `ObjectChartSchema` (TypeScript and the zod mirror) and the authored arm `ObjectChartBlockSchema` declare `dataSource` as the spec's `ElementDataSourceSchema`, by reference, at node level beside the `properties` bag, as `ObjectFormBlockSchema` and `ObjectMapBlockSchema` do. The registration is gate-wrapped, so `ElementDataSourceGate` reads the binding off the node and lands its `object` on `objectName`; the react-page wrapper no longer writes the host adapter under that key (objectui#11070, round 2). - -**Clause-②: yes (narrowing).** The strict face's accept set widens: a grid field's `columns` and an `object-chart` node's `dataSource` binding used to be refused by name there and now parse. The tolerant face narrows, because both keys are now judged by their declared type on both faces: - -- a grid column the spec refuses is refused: the retired `field` spelling, a `title`, a per-column `defaultValue`, a `type` outside the nine cell controls (`text`, `number`, `currency`, `date`, `datetime`, `time`, `select`, `lookup`, `file`), or a `scale` on a column declaring `type: 'currency'`. `FormFieldSchema` strips an undeclared key, so before this change such a column list was dropped from the parsed field in silence; -- an `object-chart` node whose `dataSource` is not a binding is refused, `null` or an adapter object included. The authored arm is `.passthrough()`, so before this change that value was kept unjudged. - -## ⚠️ BREAKING, priced as minor under the fixed group's version policy - -- **TypeScript.** `import type { GridColumnDefinition } from '@object-ui/types'` no longer resolves. A grid column literal typed `GridFieldMetadata['columns']`, `FormField['columns']` or `GridColumn` that carries a key the spec column does not declare, or a `type` outside the nine, is a compile error. A `readonlyWhen` / `requiredWhen` written as an object must name its `dialect`, as the spec's expression envelope does. An `ObjectChartSchema` literal whose `dataSource` holds an adapter is a compile error; pass the adapter as the component's `dataSource` prop, or through `SchemaRendererProvider`. -- **Validation.** The documents above that the tolerant face (`safeValidateSchema`, and so `objectui validate`) accepted are refused. Fix: write the spec's column keys (`name`, `label`, `type`, …), or drop a key the column does not have; write a binding (`{ "object": "…" }`) or no `dataSource` on an `object-chart` node. - -Rendering does not change: `GridField` reads the same keys as before, and `ElementDataSourceGate` ignores a value that is not a binding. diff --git a/.changeset/11070-grid-field-keys-round8.md b/.changeset/11070-grid-field-keys-round8.md deleted file mode 100644 index f307b76a7b..0000000000 --- a/.changeset/11070-grid-field-keys-round8.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/fields': minor -'@object-ui/plugin-form': patch ---- - -The grid field reads each field-level key under the one spelling `GridFieldMetadata` declares (objectui#11070, round 8). - -`GridFieldMetadata` declared `allow_reorder` and the docs taught it, while `GridField` read `reorderable`, so `allow_reorder: false` still drew a drag handle on every row. The widget also read its footer total under three spellings, and read four keys that no face declared. Each key now has one spelling, and that spelling is declared and read: - -- **Reorder (`@object-ui/fields`).** `GridField` reads `allow_reorder`. `allow_reorder: false` removes the drag handles. The undeclared `reorderable` is no longer read; this round's census found no writer of it in either repository. -- **Total (`@object-ui/types`, `@object-ui/fields`).** `GridFieldMetadata` declares `total_field`, the one spelling the grid reads. It names the CHILD column summed into the footer, which is the spec's `amountField` (`inlineAmountField` on a `master_detail` field, `subforms[].amountField` on a form view). It is not the spec's `totalField`, the parent field a master-detail save writes the sum to. The `amount_field` and `amountField` reads beside it are retired: the same census found nothing writing either into the grid's config. -- **`add_label` (`@object-ui/types`).** Declared. `MasterDetailForm` writes it from a detail's `addLabel`, and it labels the grid's Add button. -- **`allow_duplicate` and `show_line_numbers` (`@object-ui/fields`)** are retired under ADR-0049. No face declared either, and the census found no producer of either. The behaviour their defaults gave stays: each row offers a duplicate action whenever rows can be added, and the line-number column always shows. -- **`sort_field` is unchanged.** `MasterDetailForm` still writes it from a detail's `sortField`, which is derived from the child object when not authored. The spec declares no inline sort-field key, so it stays read and undeclared, named in one place in `GridField`. -- **`record:line_items` total (`@object-ui/plugin-form`).** The panel shows its grid's footer total whenever `amountField` names the column to sum, the way `MasterDetailForm` already did. It used to show it only when `totalField` was also set. - -`GridField` now types its config reads as `GridFieldMetadata`, so a read of a key the type does not declare fails to compile. - -**Clause-②: yes (narrowing).** The published `GridFieldMetadata` face widens by two optional members, `total_field` and `add_label`. What the grid honours narrows: five keys it used to read are no longer read. - -## ⚠️ BREAKING, priced as minor under the fixed group's version policy - -- **Rendering.** A grid field written with `reorderable`, `amount_field`, `amountField`, `allow_duplicate` or `show_line_numbers` renders as if that key were absent. Fix: write `allow_reorder: false` to turn off drag reordering, and `total_field` to name the summed column. To turn off the duplicate action, turn off adding with `allow_add: false`; there is no switch for the line-number column. -- **Behaviour.** `allow_reorder: false` now removes the drag handles; before, it was ignored. A `record:line_items` panel with `amountField` and no `totalField` now shows the footer total of that column. -- **TypeScript.** A `GridFieldMetadata` literal carrying any of the five retired keys was already a compile error, and still is. - -**Note, 2026-10-01 (objectui#11070 round 9, shipping in this same release).** -The `sort_field` bullet above no longer holds. `GridFieldMetadata` now declares -`sort_field`, so `GridField` reads no undeclared key, and a detail's `sortField` -is no longer authored: `MasterDetailDetailConfig` has no such member, and -`MasterDetailForm` hands the grid the sort field it derives from the child -object. See `11070-grid-sort-field-round9`. diff --git a/.changeset/11070-grid-form-face-round10.md b/.changeset/11070-grid-form-face-round10.md deleted file mode 100644 index c109cc7ba3..0000000000 --- a/.changeset/11070-grid-form-face-round10.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@object-ui/types': minor ---- - -A form field of `type: 'grid'` declares the grid widget's field-level keys (objectui#11070, round 10). - -A `form`'s `fields[]` entry of `type: 'grid'` is the authored path to the `grid` widget, which reads its field-level keys off that entry. `GridFieldMetadata` declares them and the grid docs teach them, but the form-field face declared none of them, so the strict authoring face (`StrictAnyComponentSchema`) refused each one by name on a form field while the widget read it. - -- **`FormField` (TypeScript)** declares `min_rows`, `max_rows`, `allow_add`, `allow_delete`, `allow_reorder`, `total_field`, `add_label` and `sort_field`, each as `GridFieldMetadata`'s own member by reference (`GridFieldMetadata['min_rows']`, and so on), so the two faces cannot drift. Before, each one resolved to the interface's `[key: string]: any` index signature. -- **`FormFieldSchema` (the zod mirror)** declares the same eight keys with the same value types: numbers for the two row limits, booleans for the three switches, and strings for the total column, the Add label and the sort field. Each `.describe()` says that only the `grid` widget reads it. -- On any other field type the keys are accepted and read by nothing, as `columns` already was. - -**Clause-②: yes (widening).** `FormFieldSchema`, a published accept set, accepts eight more keys on a form field, so the strict authoring face now accepts a grid entry that writes them. The tolerant face narrows on their values: `FormFieldSchema` strips an undeclared key, so before this change a wrong-typed value (for example `allow_add: "false"` or `min_rows: "1"`) was dropped from the parsed field in silence, and now it is refused. - -## ⚠️ BREAKING, priced as minor under the fixed group's version policy - -- **Validation.** A form field whose grid key holds a value of the wrong type, which the tolerant face (`safeValidateSchema`, and so `objectui validate`) accepted by stripping the key, is refused. Fix: write the key with its declared type (`allow_add: false`, `min_rows: 1`). -- **TypeScript.** A `FormField` literal that writes one of the eight keys with the wrong type is a compile error; before, the index signature accepted any value. - -Rendering does not change: the `grid` widget reads the same keys as before. diff --git a/.changeset/11070-grid-sort-field-round9.md b/.changeset/11070-grid-sort-field-round9.md deleted file mode 100644 index 85042632c6..0000000000 --- a/.changeset/11070-grid-sort-field-round9.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/plugin-form': minor -'@object-ui/fields': patch ---- - -The grid field's `sort_field` is declared, and a master-detail detail's sort field is derived only (objectui#11070, round 9). - -`GridField` stamps each row with its index in the field `sort_field` names, on every change, so the order a drag-reorder leaves is saved with the rows. It read that key while no face declared it. Its one producer is `MasterDetailForm`, which hands the grid the sort field `deriveDetail` picks from the child object: the first of its fields named `position`, `sort_order`, `sequence`, `line_no`, `line_number` or `sort`. A detail could also override that pick with an authored `sortField`, which nothing wrote in either repository and no spec key carries. - -- **`sort_field` is declared (`@object-ui/types`).** `GridFieldMetadata` declares `sort_field?: string`, documented as the CHILD field stamped with each row's index. `GridField` now reads its config as `GridFieldMetadata` alone, so every key it reads is declared there (`@object-ui/fields`; no runtime change). -- **The authored override is retired (`@object-ui/plugin-form`).** `MasterDetailDetailConfig` no longer has a `sortField` member, and `MasterDetailForm` no longer reads one. The sort field the grid receives is the derived one, carried on the form's internal per-detail state. - -**Clause-②: yes (narrowing).** The published `GridFieldMetadata` face widens by one optional member. The published `MasterDetailDetailConfig` face narrows by one member, and what `MasterDetailForm` honours narrows with it. - -## ⚠️ BREAKING, priced as minor under the fixed group's version policy - -- **TypeScript.** A `MasterDetailDetailConfig` literal that writes `sortField` is a compile error. Fix: delete it. The sort field comes from the child object; name the child's position field `position` (or another of the names above) so the derivation finds it. -- **Rendering.** A detail written with `sortField` (through a cast, or in a document the compiler never saw) renders as if the key were absent. On a detail the form derives, the grid stamps the child's sort-named field; on a fully configured detail (relationship field set and every column typed), which loads no child schema, the grid stamps none. diff --git a/.changeset/11070-react-page-no-adapter-on-node.md b/.changeset/11070-react-page-no-adapter-on-node.md deleted file mode 100644 index e11eae7ef2..0000000000 --- a/.changeset/11070-react-page-no-adapter-on-node.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@object-ui/components': patch ---- - -fix(components): a `kind:'react'` page no longer writes the host adapter under each block's `dataSource` - -The react-page wrapper built every injected block's node (and every `` -node) as `{ dataSource, ...props, type }`, with the host's data-source ADAPTER, -or `null` before one connects, under `dataSource`. On a node that key is -`@objectstack/spec`'s per-element BINDING (`PageComponentSchema.dataSource`, -`{ object, view, filter, sort, limit }`), so the wrapper wrote an adapter into -an authored key. Such an in-memory node was refused by `safeValidateSchema` on -every block that declares the binding. That also kept `object-chart` from -declaring it. - -The node now carries only what the author wrote. The adapter still reaches every -block through the `SchemaRendererProvider` the page is wrapped in, the channel -each registered block already resolves it from. `SchemaRenderer` never spread -the node's `dataSource` as a React prop, and the gate ignores a value that is not -a binding. The one widget family that looked for an adapter on its own node -(the `lookup` / `user` field widgets, reached through ``) falls through -to that same provider. An author's `dataSource={{ object: 'x' }}` arrives on the -node as written, as before. - -Who notices: a host-registered component, rendered inside a react page, that -read the adapter off `schema.dataSource`. It gets the node's authored binding, -or nothing, and should read the adapter from the schema renderer context -(`SchemaRendererContext`), as it must everywhere outside react pages. diff --git a/.changeset/11070-reference-to-round4.md b/.changeset/11070-reference-to-round4.md deleted file mode 100644 index 3967cc30e1..0000000000 --- a/.changeset/11070-reference-to-round4.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -'@object-ui/types': minor -'@object-ui/core': minor -'@object-ui/fields': minor -'@object-ui/app-shell': minor -'@object-ui/plugin-detail': minor -'@object-ui/plugin-form': minor -'@object-ui/plugin-grid': minor -'@object-ui/plugin-list': patch -'@object-ui/plugin-dashboard': patch -'@object-ui/data-objectstack': patch ---- - -`reference` is now the only spelling ObjectUI writes or reads for a relational field's target object (objectui#11070, round 4, under the objectui#6837 ruling: 「objectui不是前端的项目吗?后端的元数据只要对,前端按协议执行就行了呀」). - -- **Types.** `LookupFieldMetadata`, `MasterDetailFieldMetadata` and `DetailViewField` (with its zod mirror `DetailViewFieldSchema`) declare `reference` and no longer declare `reference_to`. On the two field metadata types the member is typed by reference to `@objectstack/spec`'s `FieldSchema.reference`. `@object-ui/plugin-form`'s `FieldDefaultsSchemaLike` drops its `reference_to` member the same way. -- **Readers.** `LookupField`, `UserField`, `LookupCellRenderer`, `UserCellRenderer`, the inline editor's reference fallback, the form's `current_user` seeding and the inline-subform parent lookup read `reference` alone. -- **Emitters.** Every in-repo producer that builds a field definition or a widget `field` prop writes `reference`: the action-param dialog (`paramToField`), the bulk-action dialog, the record detail page, drawer, footer, related list and synthesised page, the gallery card, the form's section-field override and the flow designer's reference picker. The grid's and the dashboard's relational copy sets carry `reference` and no longer copy `reference_to`. -- **Ingestion.** `normalizeFieldReferenceKeys` (behind `ObjectStackAdapter.getObjectSchema` and `MetadataProvider`) still folds a legacy `reference_to` / `referenceTo` onto `reference` when `reference` is absent, and still warns in dev. It no longer stamps `reference_to` onto every relational definition, and it still never drops or overwrites a key. - -`@objectstack/spec`'s `FieldSchema` refuses `reference_to` by name, and objectstack#13847 rewrites stored ones on the serve path and in `os migrate meta`, so a definition served by an ObjectStack backend is unaffected. - -## ⚠️ BREAKING for a host that hands `reference_to` to the widgets directly - -The type change is a compile error for TypeScript that writes `reference_to` on `LookupFieldMetadata`, `MasterDetailFieldMetadata` or `DetailViewField`: rename it to `reference`. - -At runtime the break reaches exactly one kind of host: one that serves object definitions spelling the target only as `reference_to` through a `DataSource` other than `ObjectStackAdapter`, or that passes such a definition straight into `LookupField`, `UserField` or a cell renderer. Those definitions never pass the ingestion fold. Measured with an object-bound lookup field on `ObjectForm` and a lookup column on `ObjectGrid`, both fed by a hand-written `DataSource` whose `getObjectSchema` returns `{ type: 'lookup', reference_to: 'account' }`: - -- before this change, opening the picker queried `account` and the cell resolved the record's name; -- after it, the picker has no object to query (no `find` call is made) and the cell shows the raw id beside the unresolved-reference marker. - -The same definition served through `ObjectStackAdapter.getObjectSchema` still works, before and after: the fold adds `reference`, the picker queries `account`, the cell resolves the name, and the dev warning names the field. **Fix:** spell the target `reference` in the definition your `DataSource` serves. - -⚠️ **Dated note, 2026-09-30 — the break reaches more than the paragraph above states — objectui#11070.** Two corrections from the contract review of this change, appended rather than edited in; neither changes what ships. - -- "The break reaches exactly one kind of host" above is too narrow. Host code that read `reference_to` off a definition after ingestion — from `ObjectStackAdapter.getObjectSchema()` or `useMetadata().objects` — also loses that key, because the ingestion pass no longer stamps it (the **Ingestion** bullet above states the fact, and `reference_to` was never a declared member of those definitions). **Fix:** read `reference`. -- The measured break above is a `lookup` field's. A `user` field handed a `reference_to`-only definition directly does not end at "no query": `UserField` falls back to `sys_user`, so its picker queries `sys_user` rather than the object `reference_to` named. **Fix:** spell the target `reference` there too. - -The text above is kept as the reading of this change. diff --git a/.changeset/11070-strict-face-read-keys.md b/.changeset/11070-strict-face-read-keys.md deleted file mode 100644 index fbf99d9f41..0000000000 --- a/.changeset/11070-strict-face-read-keys.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@object-ui/types': minor ---- - -The strict authoring face accepts keys a registered renderer reads, which it used to refuse as undeclared (objectui#11070). Each key below is now declared on the TypeScript face and on its zod mirror, so `StrictAnyComponentSchema` accepts it and `objectui validate` on that face no longer tells an author to delete a key that works. - -- **`form.showSubmit`** (`FormSchema`, a boolean, default `true`). The `form` renderer draws its submit button only while it holds, so `false` renders the fields with no submit button. -- **`form.fields[]`** (`FormField` / `FormFieldSchema`): `multiple`, `rows`, `accept`, `dimensions`, `reference`, `min`, `max`, `minLength`, `maxLength` and `pattern`. A hand-authored form has no object schema behind it, so the renderer hands each field widget the field entry itself as its metadata carrier, and the built-in `input` / `textarea` branches spread the entry onto the native control. These are the keys that path reads: `multiple` (the `file`, `image`, `lookup` and `user` widgets), `rows` (the `