Skip to content

fix(core,docs): bare citations that meant an objectstack card name its repository; the RETIRED_ACTION_KEYS.execute pointer among them (objectui#11016) - #11041

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-11016-cross-repo-bare-citations
Sep 29, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-11016-cross-repo-bare-citations

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #11016
Clause-②: no

Dispatched implementation of the domain:ui seat 2 claim (comment 5882822760) on objectui#11016, triage direction 5876435318, session https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec. Citations only: a bare number whose sentence means an objectstack card now names its repository as objectstack-ai/objectstack#N, as triage direction 2 spells it. No key, accept set, refusal decision or code path moves.

In this body a census number is written in a code span, so GitHub links it to nothing.

What changed, by class (one commit each)

  1. Runtime strings (2 sites, patch).
    • @object-ui/core RETIRED_ACTION_KEYS.execute, the dev warning for an action still carrying the retired execute key, now reads "execute was removed in @objectstack/spec 17 ([P3] Retire the three deprecated aliases — via the ADR-0087 D2 conversion layer, not by deleting the keys objectstack#3855) — rename the key to target. …". The card is live, so the pointer is qualified rather than dropped (triage item 1; ruling 5860244997 Q1 = A covers dead cards only). The rest of the message is byte-identical, and the one test that pins its text (actionKeys.pin.test.ts, "rename the key to target") still reads it.
    • @object-ui/app-shell metadata-admin default-schemas.ts, the Studio skill form's triggerConditions help text: its two bare numbers mean objectstack cards 1878 and 1895 and now name them.
  2. Source comments. Every other in-class site is a //, /* */, JSX or doc comment in non-test packages/*/src: 350 bare numbers on 337 lines in 143 files across 24 packages, requalified in place. One more is held (Held below).
  3. Pending changesets. The 10 in-class sites in 9 pending entries get a dated note each, in the form objectui#10877 used (⚠️ **Dated note, 2026-09-29 — … — objectui#11016.**, what the number means, then "The text above is kept as the reading of this change."). The note names the card and never repeats the bare token. The frontmatter block is md5-identical at the branch point and this head in all nine.
  4. Patch round 1: the qualified form of the same defect (claim amendment 5883408510, bounded in-place fix, commit ba91ecf76). Two PackageFormDialog.tsx comments (the readEnvelopeUserMessage docblock and the objectui#8051 catch-arm comment) wrote objectui#3821 for the generic-substitution card and now write objectstack-ai/objectstack#3821. The pending .changeset/violet-donkeys-brake.md, which would publish that spelling at the next release, gets a dated note in the form of the other nine: it names fix(sharing): 共享规则新建页 — 自定义 widget 未国际化,且「接收方」永远无可选项 objectstack#3821, the sharing-rule dialog card. Its frontmatter md5 is 4e8ce550 at both 29d0e9ae2 and ba91ecf76. The test file's doc comment is untouched, because tests are outside the class. Evidence on ba91ecf76: the comment-stripping print of PackageFormDialog.tsx is identical to 29d0e9ae2, with 0 parse diagnostics; pnpm exec vitest run over the five PackageFormDialog.*.test.tsx files gives Test Files 5 passed (5), Tests 67 passed (67); pnpm exec eslint on the file gives 0 errors; check:changeset-claims, check:pending-changeset-literals, check:control-bytes and check:new-line-citations all exit 0; trial merges are unchanged.

Plus .changeset/11016-cross-repo-bare-citations.md: patch for @object-ui/core and @object-ui/app-shell, the two packages whose shipped runtime text moves; the comment-only packages need no entry of their own, as in the objectui#10803 batches: every package here versions as one group.

Census (read before editing)

Population. The instrument is the one objectui#10803's batches used. Its primary form is below; the blind-spot form swaps the lookbehind for (?<=[/.\-]):

git grep -nP '(?:^|(?<=[^\w#&/.\-]))#\d+(?![0-9A-Za-z_])' REF -- '.changeset/*.md' 'packages/*/src/**' ':!**/__tests__/**' ':!**/*.test.*' ':!**/*.spec.*' ':!**/test/**' ':!**/tests/**'

At the branch point e327c8998 it finds 3880 bare occurrences: 3694 in the primary form and 186 after /, . or -, with 1005 distinct values. A number written after an already-qualified one (objectui#9469/#8649, framework#1878/#1891) inherits that qualifier and is out of the bare class.

Titles. Both repositories' full issue and pull-request title lists were read over REST: issues?state=all, cursor pagination. objectui gives 10653 items (max 11037); objectstack gives 18394 (max 20567). A number absent from a list answers 404 there.

Reading.

  • Every distinct number between 100 and 25000 (952 of them, hex colours excluded) was read with both titles beside every sentence that cites it, grouped by number.
  • Where a title did not settle it, the card or the landing commit was read. For example, objectstack 1890's comment 4708800480 carries the form-layout note two ObjectView/ModalForm comments cite. objectui PR 2078, not objectstack's same-numbered release PR, is the spec 11.2.0 bump a clientValidation comment cites.
  • The 668 occurrences below 100 were read too: commandment numbers, decision-batch numbers, React error codes and colours, none of them a card. Above 25000 there are only hex colours.

Verdicts.

  • objectstack: 105 numbers, 364 occurrences, 350 lines, 153 files (144 source files, 9 pending changesets). The table below lists them.
  • objectui: every other card citation, left bare. That includes the sentences in mixed numbers that mean the objectui card: for 2212, only the six pagination lines mean objectstack's findData card, and the visibleOn lines stay.
  • neither repository: 10 numbers (Acceptance notes 2).
  • not a card: decision batches, React errors, and one changeset's GitHub Actions run numbers.

Lit controls.

  • The review's floor is found in full: all 10 numbers on its 18 lines, plus a third 8955 site the review did not list (plugin-detail buildDefaultPageSchema.ts).
  • The known hit actionKeys.ts 3855 is found.
  • The negative control holds: 2078 sits beside "spec 11.2.0" and means objectui's bump PR, and it stays bare.

After, reconciled at this head. Re-running the instrument, every (file, number) count dropped by exactly the number of sites edited in that file (0 mismatches), and no new bare occurrence appeared anywhere in the classes (0 added). Of the 364, 11 remain: the 10 changeset sites, now carrying their notes, and the 1 held site. The census verdicts come from reading, and nothing re-derives them mechanically; the instrument above re-derives the population.

Special cases

  • Quotations of objectstack's own text keep their words, and the card name sits in square brackets, objectui#10803's editorial mark for a substituted word. There are five:
    • apiErrorEnvelope.ts, the (#3821) in the quoted envelope-writer sentence.
    • widget.ts, a quoted RETIRED_DEFS_BY_MAJOR entry.
    • data-protocol.ts, a quoted spec comment.
    • ValueDataSource.ts and filter-converter.ts, a quoted refusal message each.
  • The quoted (#3821) is named, and triage's premise about it did not hold. Triage item 4 says neither 3821 is the card. Measured: objectstack 3821 is the sharing-rule dialog card, and the objectui change that repaired it, objectui#2920 (53642d4fe), is the change that first replaced a refused write's raw server text with localized copy, the generic substitution the sentence names. The comment now says that. The three sibling "… holds by construction" comments in form.tsx, ObjectCalendar.tsx and ObjectKanban.tsx mean the same card and are qualified the same way.
  • The paraphrased spec tag @deprecated [#2578 -> size] (calendar, gantt, kanban) is corrected inside its code span, with no extra brackets: the tag's own syntax already uses them.
  • Words folded into the name. "framework #N" (objectstack's former name), "ObjectStack #N", "ObjectStack framework #N" and "objectstack #N" become the one qualified name. "issue", "PR", "pre-" and "upstream" stay.

Held (serial rule)

The census hit in plugin-grid ObjectGrid.tsx, the server-side pagination comment ending "reachable at all (framework 2212).", is not edited. Open draft objectui#10278 inserts lines directly beneath it. Qualifying it here added a conflict hunk: 3 conflict markers in that file against objectui#10278's head, versus 2 without this change. With it held, the count is 2 either way. The line waits for objectui#10278 to land or close.

Proof of prose-only (C4), against current main 2eaf5be27

  • Each of the 144 touched .ts/.tsx files was parsed on both sides with TypeScript's createSourceFile and re-printed by createPrinter({ removeComments: true }). 142 prints are identical and 2 differ, exactly the two runtime-string files (actionKeys.ts, default-schemas.ts), with 0 parse diagnostics.
  • Lit controls on the same instrument: re-spacing a comment in actionKeys.ts leaves the print unchanged, and editing its string literal moves it. Both anchors were confirmed on disk, one each.
  • Both changed literals are values in string-keyed Record types whose values are typed string and unknown, so no type moves.

Serial and trial merges

main was merged in before opening (29d0e9ae2). objectui#11038, #11036, #11034 and #11032 had landed in the meantime; the auto-merges in RecordDetailView.tsx, en.ts, ObjectCalendar.tsx and plugin-view ObjectView.tsx were clean. Re-reading the instrument on the merged tree finds nothing new.

git merge-tree --write-tree of this head with each open pull request's head, fetched into named refs:

  • objectui#11033 (it holds ActionRunner.ts and en.ts, both of which carry census edits here): clean.
  • objectui#10930 (dashboard-filters.ts): clean.
  • objectui#10278: conflicts in plugin-grid.mdx, plugin-grid README.md and ObjectGrid.tsx, the same three files as against main alone, with the same 2 conflict markers in ObjectGrid.tsx (see Held).
  • objectui#5400 (release): it deletes the pending changesets it consumes, so the 9 noted entries show modify/delete conflicts, as every edit of a pending entry does. It regenerates, and it is not a hold. If it lands first, those notes have no file to land in.

Gates and tests

Each line gives the gate's own verdict and its exit code, captured by redirect-then-$?. On this head 29d0e9ae2:

  • node scripts/check-changeset-presence.mjs --base 2eaf5be27, exit 0: "143 source file(s) of 23 released package(s) changed, and this change declares 1 changeset(s): .changeset/11016-cross-repo-bare-citations.md."
  • pnpm changeset:check, exit 0: fixed group complete; "No changeset declares a major bump."
  • pnpm check:changeset-claims (report-only), exit 0. Its standing notice lists pending entries that name a touched file. A pending entry quoting a replaced spelling would carry a bare number the census sees, and the census found exactly the nine entries noted here.
  • pnpm check:pending-changeset-literals, exit 0: "No test source names a pending changeset."
  • pnpm check:control-bytes, exit 0: "OK (scanned 9331 tracked text file(s); skipped 85 binary)."
  • pnpm check:new-line-citations, exit 0: "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0".
  • pnpm check:spec-symbols, exit 0. pnpm check:action-forward-parity, exit 0; it reads RETIRED_ACTION_KEYS off actionKeys.ts. node scripts/check-doc-links.mjs, exit 0: "Links are valid across 17 scan roots."
  • pnpm exec vitest run packages/core/ through the shared verify lock: Test Files 184 passed (184), Tests 3658 passed | 27 skipped (3685), VERDICT command-exit 0.
  • @object-ui/core type-check, after building its dependency closure (@object-ui/types): exit 0.

On 5d8eefd71, the pre-merge head with the same diff over the older base:

  • pnpm exec vitest run scripts/__tests__/, the whole-tree scanner suite: Test Files 177 passed | 2 skipped (179), Tests 5350 passed | 2 skipped (5352), VERDICT command-exit 0.
  • pnpm exec eslint on the 144 touched source files: 0 errors. The config enables no type-aware linting and no rule reads comments, and C4 shows no code token moved, so no untouched file's verdict can move either.
  • pnpm check:installed-pin-claims "OK". pnpm check:comment-mask-corpus exit 0 (1 disagreeing file, within objectui#7882's ceiling). node scripts/check-hand-rolled-comment-mask.mjs "OK every carrier is a DEBT entry". pnpm check:handler-key-reads exit 0.
  • node scripts/check-governed-queue-guard.mjs --test over the 154 paths: "NOT GOVERNED".

Declared narrowing.

  • Type-check ran for @object-ui/core only. The other 23 packages change comments only, and @object-ui/app-shell changes one string value typed unknown (C4). Their type-check is CI's.
  • Package test suites ran for packages/core/ only. No test pins the app-shell help text: a search of tests, e2e and apps for its wording finds nothing. The rest is CI's.

Census table

sites counts this change's in-class occurrences of the number. "(k stay objectui)" counts sentences citing the same number that mean the objectui card, left bare. Titles are trimmed.

number objectstack title (what the sentence means) objectui title (what the bare number resolved to) sites files
1319 [P2] i18n: zh-CN ↔ English switch occasionally garbled — requires page… chore: release packages 4 app-shell/console/ConsoleShell.tsx, auth/createAuthenticatedFetch.ts, data-objectstack/index.ts, i18n/provider.tsx
1479 Implement structured control-flow constructs (ADR-0031): loop containe… feat(auth): standalone shell-less /set-password page fo… 1 app-shell/views/metadata-admin/previews/FlowRunsPanel.tsx
1505 Surface per-iteration / per-region step logs in run observability (ADR… refactor: unify runtime dashboard editor onto studio's … 5 app-shell/views/metadata-admin/previews/FlowRunsPanel.tsx
1604 Cross-object atomic batch write (master-detail parent+children in one … chore(deps): upgrade @objectstack/spec from ^7.8.0 to ^… 3 core/adapters/batchTransaction.ts, data-objectstack/index.ts, types/data.ts
1752 Report drill-down: date-granularity dimensions need a range filter, no… chore(deps): bump @sentry/react from 10.56.0 to 10.57.0 13 changeset 9137-dataset-drill-conjoin-widget-filter.md, app-shell/views/drillUrlFilters.ts, app-shell/views/ObjectDataPage.tsx, app-shell/views/useOpenRecordList.ts, +4 more · changeset note
1753 Matrix reports: server-side totals row/column (subtotals + grand total… chore(deps): bump lucide-react from 1.17.0 to 1.18.0 1 plugin-dashboard/DatasetWidget.tsx
1874 [P2] Provide a declarative time-relative trigger (avoid fragile date-e… chore(home): remove redundant "Make this home yours" em… 1 app-shell/views/metadata-admin/inspectors/flow-node-config.ts
1878 [P0] Metadata property liveness audit: ~half of all spec properties ar… fix(console-ai): actually render the "Proposed plan" ca… 1 app-shell/views/metadata-admin/default-schemas.ts · runtime string
1885 [P0][security] Action disabled (CEL form) silently ignored Add a tree / tree-grid object view type for self-refere… 7 app-shell/views/DeclaredActionsBar.tsx, components/renderers/action/action-button.tsx, components/renderers/action/action-group.tsx, components/renderers/action/action-icon.tsx, +2 more
1890 [P1] Finish ADR-0021 analytics migration (chart view / dashboard+Studi… feat(app-shell): testability ratchet — ban synthetic-ev… 14 app-shell/console/AppContent.tsx, app-shell/views/ObjectView.tsx, app-shell/views/RecordFormPage.tsx, plugin-charts/ObjectChart.tsx, +5 more
1895 [P2] Designer authoring gaps (live prop, no Studio editor) chore(deps): bump the patch-updates group with 32 updat… 1 (1 stay objectui) app-shell/views/metadata-admin/default-schemas.ts · runtime string
2169 fix(showcase): register Mark Done action handler via inline body feat(studio): Data rail search + inline new-object (dra… 4 app-shell/views/metadata-admin/anchors.ts, core/actions/actionKeys.ts, core/actions/ActionRunner.ts
2183 fix(showcase): hide Mark Done once the task is complete fix(app-shell): don't show recovery-password reminder o… 2 components/renderers/layout/containers.tsx, core/actions/ActionEngine.ts
2212 findData 列表分页失效:total 永远等于本页条数、hasMore 恒为 false Form-view FormField.visibleOn (CEL) is never evaluated … 6 (12 stay objectui) data-objectstack/index.ts, plugin-grid/ObjectGrid.tsx, plugin-list/ListView.tsx · 1 held
2552 objectql: write pipeline accepts scalar values for multi-value fields … fix(spec-bridge/form): stop dropping spec FormViewSchem… 1 plugin-grid/hooks/multiValueFields.ts
2555 Runtime view overlay drops viewKind/object — one grid sort permanently… Studio package-create UX dogfood follow-ups (2026-07 br… 1 (2 stay objectui) data-objectstack/index.ts
2578 字段多的对象:自适应呈现表面 + 语义 field span(auto/full)+ 表单布局防呆 lint(AI-authored,ADR… Dashboard-level filters follow-ups: showcase, more exam… 20 (3 stay objectui) changeset gantt-navconfig-comment-once.md, changeset kanban-calendar-nav-width-converge.md, app-shell/views/ObjectView.tsx, plugin-calendar/ObjectCalendar.tsx, +10 more · changeset note
2604 Design: record create/edit/subtable surface + return-flow model (follo… feat(detail+fields+components+app-shell): record inline… 15 app-shell/console/AppContent.tsx, app-shell/urlParams.ts, app-shell/utils/recordFormNavigation.ts, app-shell/views/RelatedRecordActionsBridge.tsx, +2 more
2611 defineMapping artifacts are registered but never consumed — wire named… fix(actions): defuse the three action-visibility traps … 7 data-objectstack/index.ts, plugin-grid/ImportWizard.tsx, plugin-grid/savedMapping.ts, types/data.ts
2670 记录页头审批决策按钮(Approve/Reject)被 app 动作挤进溢出菜单;建议审批动作可优先渲染 + Action 增加显式排序 Flow designer: render loop / parallel / try_catch as ne… 1 (23 stay objectui) components/renderers/action/action-bar.tsx
2675 flow notify 节点无法给通知附带点击跳转目标(source_object/source_id)——inbox 通知点不进对应记录 feat(studio): visualize loop/parallel/try_catch nested … 1 app-shell/views/metadata-admin/inspectors/flow-node-config.ts
2707 [spec/cli] 对象 enable.files/trackHistory/activities/feeds 为 dead proper… fix(app-shell): guard ActionParamDialog submit during f… 4 app-shell/utils/pageSchemaIntrospect.ts, app-shell/views/RecordDetailView.tsx
2727 [objectui/framework] enable.files: generic Attachments related-list (S… fix(plugin-charts): draw dashboard bars on first paint … 5 (3 stay objectui) app-shell/views/RecordAttachmentsPanel.tsx, app-shell/views/RecordDetailView.tsx, plugin-detail/synth/buildDefaultPageSchema.ts
2755 [attachments] v1 follow-ups: sys_file orphan lifecycle + non-admin per… feat(data-objectstack): gate non-atomic batch fallback … 3 app-shell/views/RecordAttachmentsPanel.tsx
2782 feat(console/auth): 复用 objectui ImportWizard 接入 sys_user 身份导入(替代原 acti… fix(app-shell): map raw sys_activity rows in the inbox … 1 auth/types.ts
2926 app-showcase 权限模型复测清单(07-15 对照 main 重评):1 项回归级重大缺陷(N 锚点写护栏被 A4 词表打穿)+ … feat(setup): the datasource list shows the real connect… 5 fields/index.tsx, permissions/MePermissionsProvider.tsx
2948 security: 服务端 readonly 字段在 UPDATE 时未强制(可被用户上下文覆盖) feat(views): the list toolbar speaks one vocabulary — u… 1 data-objectstack/userState.ts
2970 [attachments] v2 tracking: parent-visibility inheritance, authed downl… fix(app-shell)!: the server-action URL identifies an ac… 3 app-shell/views/RecordAttachmentsPanel.tsx
2998 spec: structured form button/defaults config on FormViewSchema + enrol… fix(plugin-form): block page unload while a modal/drawe… 6 app-shell/views/RecordFormPage.tsx, plugin-form/ObjectForm.tsx, plugin-view/ObjectView.tsx, types/objectql.ts
3165 enhancement: state_machine 校验规则在 INSERT 上是 no-op —— 无法强制记录的初始状态(declar… record:activity 的 feed 结构上不可能有内容——11 个声明的输入全是空 feed 上的过… 1 (3 stay objectui) core/validation/validators/object-validation-engine.ts
3266 [P1] approvals: quorum (M-of-N) + grouped per-group sign-off (会签) + de… console preview-samples: 除 tool 外还有 11 个样例过不了对应的 spec s… 1 app-shell/views/metadata-admin/inspectors/flow-node-config.ts
3271 feat(client): 类型化 data.batchTransaction() —— master-detail 保存统一走原子跨对象批… fix(components): translate the built-in select branch's… 2 data-objectstack/index.ts
3298 discovery 广播「跨对象原子 batch」能力位(让客户端声明式协商,取代 404/405/501 运行时探测) fix(components): deliver aria-required to field control… 9 (1 stay objectui) data-objectstack/index.ts
3371 Console command palette (⌘K) doesn't surface record search hits though… fix(app-shell): flow 设计器不再给 wait 种子写入 spec 17 已退役的 wait… 5 app-shell/chrome/CommandPalette.tsx, app-shell/views/SearchResultsPage.tsx, data-objectstack/index.ts, react/hooks/useRecordSearch.ts
3405 动作参数弹窗:内联 lookup 参数无法声明引用目标(配置被静默剥离 + 文案谎报「即将上线」) fix(fields): 注册路径的全屏长文本对话框接上 i18n(N) 10 app-shell/utils/paramToField.ts, app-shell/utils/resolveActionParams.ts, app-shell/views/ActionParamDialog.tsx, app-shell/views/metadata-admin/previews/ActionPreview.tsx, +1 more
3407 service-automation: update_record reports success when written fields … record:highlights block 的 inputs 声明 readonly,使其进入 sdui.… 3 app-shell/views/metadata-admin/previews/FlowRunsPanel.tsx
3424 Approval routed to an empty position permanently locks the record (no … [i18n] @object-ui/collaboration 整包接入 i18n:CommentThread… 3 app-shell/hooks/useRecordApprovals.ts, app-shell/views/DeclaredActionsBar.tsx, react/hooks/useExpression.ts
3427 record_change flow start node binds to a single lifecycle event — no c… fix(app-shell): 把 Save as view 的 URL 下钻条件折成 spec ViewFi… 1 app-shell/views/metadata-admin/inspectors/flow-scope.ts
3431 rest: PATCH /data 对被静默剥离的写入字段无任何回传 — onFieldsDropped 通道未接线(follow-up N… [finding] 已保存视图的 ViewFilterRule[] 被原样当 FilterNode 送进 $f… 9 (1 stay objectui) app-shell/providers/AdapterProvider.tsx, app-shell/providers/writeWarningToast.ts, data-objectstack/index.ts, data-objectstack/metadata-client.ts, +1 more
3447 审批流无法在「运行中」动态确定审批人——审批人在提交时即被 $trigger 快照锁定(动态路由 / 动态会签受阻) [finding] PresenceAvatars 的状态圆点对联合类型外的 status 无颜色兜底(sta… 13 app-shell/hooks/useConsoleActionRuntime.tsx, app-shell/views/DeclaredActionsBar.tsx, app-shell/views/metadata-admin/inspectors/flow-node-config.ts, app-shell/views/metadata-admin/inspectors/flow-scope.ts, +3 more
3455 rest/protocol: 把 droppedFields 写路径观测扩展到 bulk / GraphQL / client SDK(N … fix(components,i18n): Sheet/Dialog 关闭按钮接入 common.close,… 8 app-shell/providers/AdapterProvider.tsx, app-shell/providers/writeWarningToast.ts, data-objectstack/index.ts, data-objectstack/metadata-client.ts
3479 data import: mid-lifecycle rows rejected by state_machine.initialState… content/docs 有 16 个失效的相对链接,且 check-doc-links.mjs 对相对链接一… 2 plugin-grid/ImportWizard.tsx, types/data.ts
3493 data import: a "historical" import can't preserve original timestamps … feat(app-shell,plugin-detail): read-gated Approvals tab… 1 types/data.ts
3494 [P2] Aspirational-config disposition: reconcile-or-prune the still-dea… [ci] scripts/ 在零 tsconfig 覆盖内:turbo type-check 从不检查 scr… 1 react/context/ThemeContext.tsx
3508 审批节点「处理人 Value」应改为记录 lookup(现查 metadata 端点→只能手填);附 approver value 语义核实… docs(ci): live-e2e allowlist 改为指向 package.json,不再手抄 spe… 18 app-shell/views/metadata-admin/inspectors/flow-node-config.ts, app-shell/views/metadata-admin/inspectors/FlowReferenceField.tsx, app-shell/views/metadata-admin/inspectors/json-schema-to-fields.ts, fields/widgets/LookupField.tsx, +1 more
3528 Console: screen-flow Submit never calls the resume endpoint — every sc… console-starter 的 vite 别名表漏了 5 个源码实际 import 的工作区包,未先构建就… 3 app-shell/views/FlowRunner.tsx, app-shell/views/ScreenView.tsx
3574 Dashboard widget filters do not interpolate {current_user_id} — user-s… fix(tsconfig): 根 tsconfig.node.json 加 noEmit,堵住全仓排放 12 app-shell/console/AppContent.tsx, app-shell/views/ObjectDataPage.tsx, app-shell/views/ObjectView.tsx, app-shell/views/useOpenRecordList.ts, +6 more
3689 service-storage success bodies are three shapes, none carrying success… 站点文档 content/docs/utilities/cli.mdx 的兼容表有两行失真:@objectst… 1 app-shell/views/metadata-admin/MetadataTypeActions.tsx
3697 ADR-0105 D8: the scope-bounded issuance path has no caller — every pri… 观察记录:文档散文里的版本宣称无门禁可守 —— N + N 把它清到零之后,没有任何东西阻止下一个作者写回去… 2 app-shell/console/organizations/manage/InviteMemberDialog.tsx, app-shell/console/organizations/manage/MembersPage.tsx
3713 [P2] action execute vs target: spec and objectui resolve the precedenc… docs(skills): console-development.md 指路的 7 个 console 页面… 2 core/actions/ActionRunner.ts, types/ui-action.ts
3723 sys_member.role app-role channel reverses ADR-0057 D4 ("never as the a… ci.yml's Build Docs path gate fails CLOSED: a failed gi… 1 app-shell/console/organizations/orgRoleLabel.ts
3794 审批场景下记录可写性的反馈全线失真:能改的显示「已锁定」,改不了的提示「更新成功」 ADR-0056 的 Consequences 自相矛盾:「Capabilities 在 Setup 里作者化… 3 app-shell/providers/writeWarningToast.ts, data-objectstack/index.ts, data-objectstack/userState.ts
3821 fix(sharing): 共享规则新建页 — 自定义 widget 未国际化,且「接收方」永远无可选项 fix(scripts): check-i18n-en-drift 的显式 base 提为权威,解析不出即失败… 4 app-shell/utils/apiErrorEnvelope.ts, components/renderers/form/form.tsx, plugin-calendar/ObjectCalendar.tsx, plugin-kanban/ObjectKanban.tsx
3842 The dispatcher puts the HTTP status in error.code and parks the real c… 动作 disabled 的「已声明」判定用 != null,disabled: '' 把按钮永久置灰(N 同族… 1 (4 stay objectui) app-shell/preview/commitHistory.ts
3843 Envelope drift is not just service-storage: four more route modules em… fix(app-shell,components): 服务端声明动作的 visible 门按「已声明」判定,v… 2 app-shell/views/metadata-admin/datasource/DatasourceResourcePage.tsx, app-shell/views/metadata-admin/MetadataTypeActions.tsx
3855 [P3] Retire the three deprecated aliases — via the ADR-0087 D2 convers… content/docs/guide/plugins.md 的示例 package.json 里 vite ^… 7 app-shell/views/metadata-admin/previews/ActionPreview.tsx, core/actions/actionKeys.ts, core/actions/ActionRunner.ts, test-support/spec-tombstones.ts, +1 more · runtime string
3856 [P3] objectui ActionRunner: the execute target fallback is dead cod… docs(skills): console-development.md 顶部注记的搬家归因改成 04-21→…
3896 POST /data/sharing/rules 绕过 SharingRuleSchema:criteria 缺失或拼错静默变成"共享该对象… AiChatPage 发给 agent 的四条确认文本仍按 UI 语言取值:zh 控制台 + 英文会话把「确认… 7 (1 stay objectui) changeset dashboard-aria-member-retired-5830.md, app-shell/views/metadata-admin/previews/AgentPreview.tsx, app-shell/views/metadata-admin/previews/ToolPreview.tsx, fields/widgets/FilterConditionField.tsx, +3 more · changeset note
3903 [P2] The spec contract stops at authored source — stored metadata is r… apps/site: Schema Catalog 索引页把每个缩略图包在 button 里,85 个含 bu… 4 (1 stay objectui) core/actions/ActionRunner.ts
3916 [17.0.0-rc.0] Matrix report date columns are unordered — no server-sid… fix(core): ActionRunner 的 condition 门改问「有没有声明」,conditio… 2 plugin-report/DatasetReportRenderer.tsx
3923 Action.requiredPermissions 在 Console 端形同虚设:会话不下发 systemPermissions + 客… fix(app-shell): SchemaForm 读取归一化后的 visibleWhen,让 metada… 1 plugin-grid/components/RowActionMenu.tsx
3948 A filter with an operator outside VALID_AST_OPERATORS is silently drop… fix(plugin-list): UserFilters buttons declare type="but… 1 fields/widgets/RecordPickerDialog.tsx
3959 A type: 'modal' action's server-side handler is unreachable: objectui … fix(fields): BooleanField 使用 host 下发的控件 id,可见 label 不再悬… 2 (1 stay objectui) app-shell/hooks/useActionModal.tsx, app-shell/views/RecordDetailView.tsx
3962 [17.0.0-rc] /actions reports business failures as HTTP 200 inside a do… [app-shell] ActionParamDialog 的 boolean 分支不下发 id,于是同一个控… 3 app-shell/utils/flowResponse.ts, core/actions/actionResponse.ts
4001 未知键静默剥离仍是全仓默认:把 N 的 strict 收紧从一个 schema 推广到整个可授权面(ADR-0078 完整性闸门) examples/schema-catalog: 13 个 grid 示例用了未声明的 cols 键,列数被静… 4 app-shell/views/metadata-admin/clientValidation.ts, plugin-detail/index.tsx
4019 feat(runtime): /analytics 路由按能力条件挂载——没装 service-analytics 连 405 都不再有(N… Studio Part A quick wins: wire the already-registered a… 1 data-objectstack/index.ts
4074 [P2] objectui @object-ui/types hand-declares five action vocabularies … [console] Four remaining inbox/activity entries still h… 5 types/ui-action.ts
4075 [P3] objectui ActionDef's [key: string]: any absorbs every retired and… console: action:button / action:icon / action:menu bind… 2 (1 stay objectui) core/actions/ActionRunner.ts, types/data-protocol.ts
4115 [P2] objectui: a spec-named symbol must be an import, not a declaratio… test(plugin-charts): serve ObjectChart's option-color p… 1 types/widget.ts
4171 [P2] spec: four exported types resolve to any, so "bind the spec-named… docs(ci): stop the Merge Queue section keeping its own … 2 types/index.ts
4463 [runtime/metadata] 作者时规则只存在于 CLI:Studio/REST/MCP 的运行时授权面是第四扇门,26 条规则一条… "Set as Default" is dead on every saved view — handleSe… 1 data-objectstack/metadata-client.ts
4610 spec 双源清账 C3:通知语汇 Notification(Schema)(./api ≠ ./ui)+ NotificationConf… finding(tooling): rule 2's citation window still reads … 1 types/index.ts
4614 spec: dashboard date filter 的 defaultValue 没有作者时校验 —— 拼错的预设名要到浏览器控制台才被… [plugin-dashboard] DashboardGridLayout has no dataset p… 1 (1 stay objectui) core/utils/dashboard-filters.ts
4616 spec/system 通知模板语汇在 C3 后成为零消费方孤儿:EmailTemplate/SMSTemplate/PushNotific… Docs gallery: 35 catalog entries render the red "Unknow… 1 app-shell/views/metadata-admin/clientValidation.ts
4649 Script validation rules are silently skipped when their predicate fail… Unwind the objectstackN striped/bordered/virtualScroll … 1 app-shell/views/metadata-admin/clientValidation.ts
4709 app.homePageId 退役的前提写错了 —— objectui 的 resolveLandingRoute() 一直在读它,现在成了… finding: objectui still declares @objectstack/spec/clie… 2 app-shell/console/AppContent.tsx, app-shell/views/metadata-admin/previews/AppPreview.tsx
4717 [P2/P3] 运行时授权门的 advisory findings 要进响应并被 Studio 渲染 + docs「the gate」补第四… test(data-objectstack): re-point v3-compat's vacuous Pa… 2 changeset render-publish-advisory-findings-5026.md, data-objectstack/metadata-client.ts · changeset note
4829 rest: filterAppForUser treats app hidden flag as builder-only access g… docs(layout): app-shell.mdx 的 AppShellProps 声明块补齐到 7 个 … 3 app-shell/console/AppContent.tsx, app-shell/layout/AppSwitcher.tsx, app-shell/utils/appRoute.ts
5021 主题引擎发出的 9 组 CSS 变量零消费方(--font-size-* / --z-* / --duration-* …):ADR-004… docs(plugin-map): README 按现码重写,不再教包里不存在的那套 API (N) 1 core/theme/ThemeEngine.ts
5074 ViewItemSchema 同时是授权形状和 Studio 往返的 wire 成员 —— 拆成两个 schema 还是保持宽松?(挡住 N… plugin-gantt: schema 上的 viewMode 只被 ResourceWorkload 分支… 1 app-shell/views/metadata-admin/clientValidation.ts
5134 SqlDriver.applyFilterCondition 丢弃编译成空的 $and/$or 子过滤器,而不是套用布尔单位元 —— 与同仓… finding: the spec's nested aria.ariaLabel admits an inl… 1 core/utils/filter-converter.ts
5149 Conditional-visibility predicates (visibleWhen / visibleOn) fail OPEN … governance: agent-instruction files are human-merge onl… 7 components/renderers/form/form.tsx, core/evaluator/ExpressionEvaluator.ts, core/evaluator/fieldRules.ts, core/evaluator/listConditional.ts
5154 fix(spec): 重开 ViewFilterRuleSchema —— 控制台盖的 UI 行 id 让保存筛选条件 422(N 热修)… fix(app-shell,core): 对象列表工具栏 Import 消费 importPredicates… 1 app-shell/views/viewFilterFold.ts
5240 { field: {} }(零个操作符的字段约束)在同仓有三个答案:driver-sql 组合子内 TRUE、顶层抛 INVALID_FIL… schema.userActions is a sixth grid key read but undecla… 2 core/adapters/ValueDataSource.ts, core/utils/filter-converter.ts
5316 objectui 的 metadata-admin 用「授权 schema」校验一份 STORED view —— N 收紧后,给已保存视图… docs(fields): tombstone MasterDetailField as a form-unr… 1 app-shell/views/metadata-admin/clientValidation.ts
5322 空组合子在同仓有两个对立答案:五个后端归约成布尔单位元,service-analytics 的两个编译器 fail-closed 抛错 ——… A field:-prefixed password / email field renders type=&… 4 core/utils/filter-converter.ts
5576 PageComponentSchema.dataSource.view 是声明了但无人消费的绑定:objectui resolveEleme… holdsStudioAccess is unreachable from @object-ui/app-sh… 2 core/data-scope/element-data-source.ts, core/data-scope/ViewDataProvider.ts
5777 InlineActionSchema.params 声明为参数定义数组,但 type:'api' 的活消费者(与 showcase 页)用的… purgeSignedOutClientCaches's try wraps the whole loop, … 2 core/actions/ActionRunner.ts
5811 /analytics/query 仍把 RLS 策略字段名回显给调用方 —— read-scope 拒收的泄漏在姐妹面上没堵,N 只堵了 d… test(app-shell): pin hollow view + personalization over… 1 app-shell/preview/commitHistory.ts
6761 [决策] dataset 的 dimension/measure 声明成内联 locale map 的 label 被生产端整个丢弃 —— … finding(react): five spellings of one "is this a real c… 1 types/base.ts
6776 [移交自 objectui] ComponentPropsMap 未声明 objectui 渲染器实读的 5 个顶层 prop(page:h… finding(console): metadata-admin's 172,651 B eager clos… 1 layout/PageHeader.tsx
6953 PageComponentSchema.dataSource 在 list-view 之外仍无人消费:element:record_pick… [finding] ObjectGantt.referenceArms-6837.test.tsx races… 1 plugin-detail/renderers/record-related-list.tsx
7034 fix(spec): the page-component conversion walk reaches nested container… finding(gate): the version-claim ledger's ci-cd-pipelin… 2 layout/index.ts, layout/PageHeader.tsx
7127 FieldSchema.defaultValue has the same z.unknown() acceptance hole as t… finding(plugin-detail): the record:details registration… 1 plugin-form/schemaDefaults.ts
7137 object-timeline / record:line_items 的查询没有 filter/sort 读点:dataSource.vi… finding(app-shell): InterfacesPillar's block selection … 3 core/utils/sort-query.ts, plugin-timeline/index.tsx
7233 [approvals][console] Bell badge sums unread notifications + pending ap… Handover for the next domain:ui execution-seat PM — wha… 2 app-shell/layout/InboxPopover.tsx, i18n/locales/en.ts
7388 feat(objectql): enforce the select idiom — the option marked default: … plugin-chatbot: the build-progress panel cannot express… 2 app-shell/views/metadata-admin/form-spec.ts, components/renderers/basic/metadata-viewer.tsx
7496 spec: rule the submitBehavior.url semantics — objectuiN dead-ends on i… fix(skills): teach the honest test-double idiom in test… 2 changeset 7122-spec-17-3-0-pin-repointing.md · changeset note
8010 spec: ListView.exportOptions is typed as a bare array, but the only re… test(scripts): check-shell-escape-residue reds on an ag… 2 changeset 6956-listview-export-options-spec-mirror.md, types/zod/objectql.zod.ts · changeset note
8135 fix(rest): meta app by-name answers a permission-denied envelope, not … test(i18n): pin that the two defaults-population walks … 1 data-objectstack/index.ts
8270 [finding] workspace owner lacks manage_metadata in the EE multi-org de… finding(plugin-map): the legacy filter.map warning name… 2 app-shell/views/metadata-admin/PackageFormDialog.tsx
8424 N lands five new public exports in @objectstack/spec/shared — should t… finding(docs): the VS Code page's keybinding example re… 1 app-shell/preview/DraftChangesPanel.tsx
8955 feat(spec): field-level relatedListFilter — declarative default filter… test(console): pin the four object-metric query members… 3 changeset 4664-related-list-declared-filter.md, app-shell/utils/deriveRelatedLists.ts, plugin-detail/synth/buildDefaultPageSchema.ts · changeset note
9612 runtime gate: full runtime-safe rule snapshot for the publish door — t… docs(plugins): author the listViews filter operator in … 3 changeset designer-publish-package-binding.md, app-shell/views/metadata-admin/ResourceEditPage.tsx, data-objectstack/metadata-client.ts · changeset note
10235 Shipped grids display formula columns the platform cannot sort — a con… The console drops an app translation bundle with no obj… 1 plugin-grid/ObjectGrid.tsx

Acceptance notes

  1. Outside the card's two classes (recorded, not carried):
    • apps/console AgentConnectSection.tsx still says "the 9934 channel", a dead objectstack number.
    • The recordDetailsInputs.spec-parity.test.ts doc comment writes objectui#3546 for objectstack's card.
    • Tests' own bare citations were not censused, since tests are outside the class. The describe titles naming 2604, 3405, 3508 or 7233 mean objectstack cards. NOT MEASURED as a population.
    • Published CHANGELOG history is untouched.
  2. Numbers that mean neither repository (10): 432, 586, 772, 787, 844, 1238, 1491, 1852, 1970, and one 2150 sentence (an intermittent CI failure).
    • Three say "cloud PR" outright (1238, 1852, 1970).
    • 772 and 787 pair with objectui#2362, whose title cites cloud's 772.
    • The rest fit neither title.
    • objectstack-ai/cloud answers 403 through this container's proxy, so their cloud reading is NOT MEASURED. They are out of this card's objectstack class and are left as written.
  3. Same family, not bare, not carried here:
    • 294 framework#N citations (83 distinct), qualified by objectstack's former name, including the ones after a slash such as framework#1878/#1891.
    • The three objectui#3821 citations that meant objectstack's card were carried in patch round 1 (item 4 above).
    • Measured, not edited.
  4. Held: the ObjectGrid.tsx pagination comment (see Held).

Generated by Claude Code

… card name its repository

`RETIRED_ACTION_KEYS.execute` (the dev warning for an action that still
carries the retired `execute` key) cited the card that retired the alias by
a bare number, which in this repository resolves to an unrelated docs card.
It now names objectstack-ai/objectstack#3855; the rest of the message is
unchanged. The Studio skill form's `triggerConditions` help text gets the
same treatment: objectstack-ai/objectstack#1878 and
objectstack-ai/objectstack#1895.

Changeset: patch for @object-ui/core and @object-ui/app-shell.

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…names its repository

A bare number in this repository resolves to an objectui item. The census of
bare numbers in non-test package sources (each sentence read against both
repositories' titles, not only the numbers that answer 404) found comments
whose sentence means an objectstack card while the number resolves here to
an unrelated objectui card or pull request. Each 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 quoted generic-substitution
sentence in apiErrorEnvelope.ts also says which card it is: the sharing-rule
dialog card, whose objectui fix (objectui#2920) introduced that substitution.

Comment-only: no code token moves.

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…s an objectstack card

Nine pending changesets cite an objectstack card by a bare number, which in
this repository resolves to an unrelated objectui item. Each gets a dated note
in the form the pending-entry corrections use: the note names the card as
objectstack-ai/objectstack#N and says what it is, and the entry's own text is
kept as the reading of its change. Frontmatter is byte-identical in all nine.

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…10278 rewrites beside

The server-side pagination comment in ObjectGrid.tsx sits directly above the
lines objectui#10278 inserts, so qualifying its citation here makes that PR
conflict. It keeps its original spelling in this change and is recorded as
held by the serial rule; the other two ObjectGrid.tsx citations merge cleanly.

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

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 151 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/10337-widget-input-serializer-key-list.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    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.

.changeset/4730-retire-dead-locale-key-batch.md

  • names RowActionMenu.tsx → packages/plugin-grid/src/components/RowActionMenu.tsx — edited by this change

    • Superseded twin vocabularies. cellRender.* and rowAction.* duplicated a grid.* vocabulary that won. RowActionMenu.tsx is fully i18n-wired and reads grid.openMenu / grid.edit / grid.delete; ObjectGrid.tsx reads grid.empty / grid.yes / grid.no / grid.systemFields. The twins had no reader on either side. - Labels that outlived their control. calendar.agenda labelled a view mode b55a34647 retired from CalendarViewMode (now 'month' | 'week' | 'day'). home.quickActions.createApp*, layout.systemNav.createApp, actionDialog.defaultActionTitle / .ok and grid.bulk.selectPlaceholder sit in namespaces whose consumers are live and wired but demonstrably read other siblings. - Surfaces that left the product. map.* is the strongest form: @object-ui/plugin-map declares no @object-ui/i18n dependency and contains no t() call at all, so it cannot consume a locale string. home.stats.* and recordDetail.viewersTooltip name surfaces nothing renders.
  • names ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    • Superseded twin vocabularies. cellRender.* and rowAction.* duplicated a grid.* vocabulary that won. RowActionMenu.tsx is fully i18n-wired and reads grid.openMenu / grid.edit / grid.delete; ObjectGrid.tsx reads grid.empty / grid.yes / grid.no / grid.systemFields. The twins had no reader on either side. - Labels that outlived their control. calendar.agenda labelled a view mode b55a34647 retired from CalendarViewMode (now 'month' | 'week' | 'day'). home.quickActions.createApp*, layout.systemNav.createApp, actionDialog.defaultActionTitle / .ok and grid.bulk.selectPlaceholder sit in namespaces whose consumers are live and wired but demonstrably read other siblings. - Surfaces that left the product. map.* is the strongest form: @object-ui/plugin-map declares no @object-ui/i18n dependency and contains no t() call at all, so it cannot consume a locale string. home.stats.* and recordDetail.viewersTooltip name surfaces nothing renders.

.changeset/5674-retire-plugin-component-input.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    Migration. Replace PluginComponentInput with ComponentInput — they have named the identical declaration since objectui#4972 converged the plugin-scoped interface onto base.ts, so this is a rename with no shape change:

.changeset/5903-objectgantt-declared-keys.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

  • names src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

.changeset/5905-componentinput-inputtype-tombstone.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    Stale wording corrected in the same pass, because this change falsifies it: base.ts and zod/base.zod.ts both said the fork was "recorded for a ruling; until then this stays a live, writable key", and widget.ts called it "the open fork". All three now record the ruling. A reader who greps the source instead of the card thread was meeting an open fork that no longer existed.

  • names widget.ts → packages/types/src/widget.ts — edited by this change

    Stale wording corrected in the same pass, because this change falsifies it: base.ts and zod/base.zod.ts both said the fork was "recorded for a ruling; until then this stays a live, writable key", and widget.ts called it "the open fork". All three now record the ruling. A reader who greps the source instead of the card thread was meeting an open fork that no longer existed.

.changeset/5905-componentinput-retire-constraint-keys.md

  • names packages/types/src/base.ts → packages/types/src/base.ts — edited by this change

    The retirement kit: ?: never on the interface (packages/types/src/base.ts), so authoring one is a tsc error at the registration site; retirementTombstone() on the Zod mirror (packages/types/src/zod/base.zod.ts), so an authored value is REFUSED at parse time with code: 'invalid_type', the key named in the issue path, and the migration note as the message. Deleting the members outright was the option NOT taken: ComponentInputSchema is a non-strict z.object, which strips an undeclared key silently — one silent no-op traded for another. Pinned in packages/types/src/__tests__/component-input-retired-constraint-keys.test.ts.

.changeset/5928-classname-style-props-rename.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    Why the name had to move. The const declares exactly two keys — className and style, the CSS passthrough attributes a node exposes. The TypeScript StyleProps (base.ts) is the Tailwind-SCALE vocabulary: padding, margin, gap, backgroundColor, textColor, borderWidth, borderColor, borderRadius. Measured on this branch's base with an AST read of both files: 2 keys against 8, sharing ZERO keys. In this package the …Schema suffix otherwise means "runtime mirror of the like-named declaration", so the shared name asserted a mirror relationship that does not exist — and building objectui#5684's parity registry by name pairing duly put the two together and reported drift on a pair that has no counterpart at all.

.changeset/6051-gantt-flat-config-declared-keys.md

  • names packages/types/src/index.ts → packages/types/src/index.ts — edited by this change

    GanttConfig itself gains nine members and is a published type, exported by name from packages/types/src/index.ts: lockField, objectField, summaryExtent, defaultCollapsedDepth, borderColorField, dependencyTypes, timeZone, exportFileName, interactions. The entry file's diff is empty only because the export list already named the type — the widening happened at the declaration.

.changeset/6059-publish-omit-server-resolved-defaults.md

  • names schemaDefaults.ts → packages/plugin-form/src/schemaDefaults.ts — edited by this change

    Both are pure functions over plain data (no React, no registry). The rest of schemaDefaults.ts — seedCreateValues, schemaDefaultValues, isSeedableDefault, isCreateFormMode, SeedContext — stays module-private, and isRuntimeDefault stays @object-ui/core's to publish.

.changeset/6067-component-meta-derive-from-canonical.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    packages/core/src/registry/Registry.ts declared its own ComponentMeta: thirteen keys, of which nine were restated from @object-ui/types' base.ts, four were registry-only (tier, namespace, skipFallback, labelling), and tags / description were absent — although both are declared on the canonical type and on the ComponentMetaSchema zod mirror. Two of the three authorities agreed and the registration surface did not, so those two keys were unwritable at exactly the declaration most component registrations import. That is the same two-key delta objectui#5893 had just closed inside @object-ui/types, arriving a third time on a third declaration, and objectui#5671 had already made the identical move for the sibling type ComponentInput in this very file.

.changeset/6296-conditionbuilder-subject-vocabulary.md

  • names flow-scope.ts → packages/app-shell/src/views/metadata-admin/inspectors/flow-scope.ts — edited by this change

    The builder built every row subject as record. + field name, plus a fixed record.id / user.* / org.* context list. That is correct for all five files that mount it today — six mount sites, since ActionDefaultInspector mounts it twice — because every one of them is a record-scoped site. It is wrong for a flattened-scoped site such as the flow designer's entry condition, where the trigger record's fields are the top-level evaluation context (bare status) and the prior values arrive as previous.FIELD. This repo's own flow-scope.ts already computes that distinction (fieldPrefix: onStart ? '' : 'record.', includePrevious), and objectstack's packages/formula/src/validate.ts defines the two scopes.

.changeset/6306-action-icon-type-resolution.md

  • names action-button.tsx → packages/components/src/renderers/action/action-button.tsx — edited by this change

    Scope is this one renderer. type: schema appears in exactly two files under renderers/action/ — action-button.tsx (already correct) and action-icon.tsx; action:group and action:menu compose their members differently and are untouched.

  • names action-icon.tsx → packages/components/src/renderers/action/action-icon.tsx — edited by this change

    Scope is this one renderer. type: schema appears in exactly two files under renderers/action/ — action-button.tsx (already correct) and action-icon.tsx; action:group and action:menu compose their members differently and are untouched.

.changeset/6329-actionparam-one-authority.md

  • names ActionPreview.tsx → packages/app-shell/src/views/metadata-admin/previews/ActionPreview.tsx — edited by this change

    ActionParam has one authority again (objectui#6329). The name was declared three times, not twice as the card counted: @object-ui/types publishes it — derived from the spec's ActionParamSchema input, with its own parity suite — and ActionDefaultInspector.tsx and ActionPreview.tsx each carried a module-local interface of the same name. app-shell already read the published one elsewhere (utils/resolveActionParams.test.ts), so both locals were shadows. They are deleted, not reconciled against each other, under the 2026-08-25 family ruling 甲A1.

.changeset/6349-name-authority-batch-3.md

  • names resolveBulkActions.ts → packages/plugin-grid/src/resolveBulkActions.ts — edited by this change

    @object-ui/plugin-grid / @object-ui/app-shell — internal, surface unchanged. NamedActionDef was declared identically in resolveBulkActions.ts and resolveLegacyRowActions.ts; the latter is now the one authority and the former re-exports it. OrgTranslate was declared identically in orgErrorMessage.ts and orgRoleLabel.ts; the former is now the one authority and the latter re-exports it. Neither name is on its package's public entry, and every deep-dist module still exports the same name with the same shape.

  • names orgRoleLabel.ts → packages/app-shell/src/console/organizations/orgRoleLabel.ts — edited by this change

    @object-ui/plugin-grid / @object-ui/app-shell — internal, surface unchanged. NamedActionDef was declared identically in resolveBulkActions.ts and resolveLegacyRowActions.ts; the latter is now the one authority and the former re-exports it. OrgTranslate was declared identically in orgErrorMessage.ts and orgRoleLabel.ts; the former is now the one authority and the latter re-exports it. Neither name is on its package's public entry, and every deep-dist module still exports the same name with the same shape.

.changeset/6349-types-internal-name-collisions-batch-1.md

  • names ui-action.ts → packages/types/src/ui-action.ts — edited by this change

    ActionSchema — renamed, because the two shapes are unrelated. crud.ts and ui-action.ts both declared it. Measured member-by-member they share 9 keys out of 28 each: crud.ts extends BaseSchema and pins type: 'action' (a UI node — a button in a component tree), ui-action.ts extends nothing and types type as ActionType (a spec-v2 action definition, with name, locations, params, target). Re-pointing either at the other would silently hand a consumer a different type, so this took the rename branch (objectui#5044 is the precedent for choosing the surviving name). ui-action.ts's declaration is now spelled UIActionSchema — the name src/index.ts has always PUBLISHED it under, via export type { ActionSchema as UIActionSchema }, which is now a plain re-export. The package's public surface is unchanged: ActionSchema still means crud.ts's legacy shape and UIActionSchema still means ui-action.ts's, exactly as before. Nothing outside ui-action.ts imported the old spelling — there is no ./ui-action subpath in exports, so the old name was never reachable from outside the package.

.changeset/6349-types-internal-name-collisions-batch-2.md

  • names data-protocol.ts → packages/types/src/data-protocol.ts — edited by this change

    ValidationFunction — renamed to FieldValidationFunction in field-types.ts. data-protocol.ts declares (value, context?: ValidationContext) => boolean | string; field-types.ts declared (value) => boolean | string | PromiseANGLE-BRACKETS(boolean | string). They disagree at both ends of the arrow — different parameter lists, and a Promise return that the data-protocol signature does not admit — so field-types' is not assignable to data-protocol's in the direction that matters. data-protocol.ts had said so in prose ("may differ from similarly named validation function types in other packages (e.g., in field-types)") for as long as both existed. The published names ValidationFunction (data-protocol's) and FieldValidationFunction (field-types') are unchanged.

.changeset/6396-previous-values-dom-leak.md

  • names packages/types/src/form.ts → packages/types/src/form.ts — edited by this change

    Scope is the runtime leak only. The declared key stays exactly as declared (packages/types/src/form.ts, packages/types/src/zod/form.zod.ts are untouched): it has a live consumer, so there is nothing here for the enforce-or-remove channel.

.changeset/6397-partial-schema-collapse-pin.md

  • names packages/types/src/form.ts → packages/types/src/form.ts — edited by this change

    ⚠️ Dated note, 2026-09-28 — a generic re-spelling of this Omit does not collapse — objectui#9256. Later in this same release objectui#9256 declared a key-remapping OmitDeclared ({ [P in keyof T as P extends K ? never : P]: T[P] }, in packages/types/src/form.ts) and re-spelled the heritage of InputShorthandSchema and UiCalendarSchema with it. Such a mapped type iterates the named members and the index signature separately, so it drops exactly K, keeps every other named member with its modifiers, and keeps the index signature. The same spelling of this alias declares 28 properties at ButtonSchema and 62 at ObjectGridSchema in this release, where the shipped alias declares 1 at each; at this change's own commit, under the same TypeScript, it declares 27 and 61, the source counts in the table above. So "every generic re-spelling collapses" was not true when it was written. The alias is still left as written: re-spelling it would narrow what every instantiation accepts, a contract change and not a pin's business. The PartialSchema docblock and partial-schema-collapse-pin.test.ts carry the correction. The rest of this entry is kept as the reading of this change.

.changeset/6444-evaluator-fault-warn-dedupe.md

  • names fieldRules.ts → packages/core/src/evaluator/fieldRules.ts — edited by this change

    This is the one-per-source rate limit both sibling reporters already carry (warnPredicateFailure in fieldRules.ts, visibilityDiagnostic.ts in @object-ui/react), not a third mechanism. The dedupe key is the predicate's authoring identity — the fault site plus the source text, never the scope it ran against — which is both the siblings' precedent and the defect itself: the 200-row flood is one authored source evaluated against 200 distinct scopes, so a scope-sensitive key would emit all 200 lines again.

.changeset/6473-metadatatypeactions-param-dialog-close.md

  • names ActionParamDialog.tsx → packages/app-shell/src/views/ActionParamDialog.tsx — edited by this change

    The pre-reset paramState.resolve?.(null) is dropped as well, on an enumeration rather than on "resolving twice is a no-op": onOpenChange is reachable from exactly three places, all inside ActionParamDialog, and every one settles the promise before asking for the close — handleSubmit, handleCancel, and the Radix root handler that delegates to handleCancel (the single route Escape, an overlay click and the header close button all take). All four routes are driven in the new test, with a census over ActionParamDialog.tsx so a later call site that skipped the settle is red there instead of leaving a promise pending forever.

.changeset/6475-gantt-block-face-declared.md

  • names plugin-gantt/src/ObjectGantt.tsx → packages/plugin-gantt/src/ObjectGantt.tsx — edited by this change

    The gantt nested-block spelling of a gantt config ({ type: 'object-gantt', gantt: { … } }) had no mirror entry at all: it rode through BaseSchema's .passthrough() entirely unvalidated, and the published TypeScript never taught the shape either — an author writing gantt: { … } got no completion, no type checking, no error on a misspelt member. It was the 28th and last of the keys getGanttConfig (plugin-gantt/src/ObjectGantt.tsx) reads off the schema that objectui#6051 (PR feat(types,plugin-gantt): declare the flattened GanttConfig face ObjectGantt reads (#6051) #6472) did not declare — severed into its own card because, unlike the other 27, declaring it changes what a published tool refuses.

.changeset/6499-inactive-values-retained.md

  • names flow-node-config.ts → packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts — edited by this change

    • New inactiveRetainedKind(field, node, fields) in flow-node-config.ts — a pure read that reports a field rendered ONLY because the stored-value re-show rule fired. It distinguishes 'controller-off' (a real toggle the author can switch back on) from 'no-controller' (the __legacy__ render-only keys, where no such toggle exists and saying otherwise would be a fresh lie). - FlowNodeConfigField renders the notice beside the affected control, with a "Clear value" action so the author can discard the residue deliberately. Read-only inspectors show the notice without the action. - Coverage is every showWhen group in the inspectors, pinned mechanically: all 33 gated fields across the descriptor tables, plus the two runtime producers (an engine-published configSchema and a connector input schema) that mint groups no source file contains.

.changeset/6515-record-form-current-user-normaliser.md

  • names console/AppContent.tsx → packages/app-shell/src/console/AppContent.tsx — edited by this change

    The normaliser moved from console/AppContent.tsx to providers/expressionUser.ts, beside the ExpressionProvider it feeds. That move is what made the fix available: RecordFormPage is lazy()-loaded BY AppContent, so importing the normaliser from its old home would have put a static edge from the split chunk back into the module it was split out of. Both console/AppContent.js and the package entry re-export the name, so buildExpressionUser is published exactly as before.

.changeset/6559-expression-user-input-contract.md

  • names console/AppContent.tsx → packages/app-shell/src/console/AppContent.tsx — edited by this change

    NO RUNTIME BEHAVIOUR MOVES. All four in-repo production call sites pass useAuth().user, typed AuthUser | null, and type cleanly unchanged — two in console/AppContent.tsx, one in views/RecordFormPage.tsx, one in apps/console's InternalFormRoute.tsx. The body is byte-equivalent: the same keys, the same ?? defaults, the same anonymous branch. ⛔ No consumer-side fallback was added; id: u.id ?? null remains the rejected shape (triage ruling 2026-08-26), because a lenient default in the consumer is what AGENTS.md #0.1 forbids and it silently equates "signed in, no id" with "signed out".

  • names views/RecordFormPage.tsx → packages/app-shell/src/views/RecordFormPage.tsx — edited by this change

    NO RUNTIME BEHAVIOUR MOVES. All four in-repo production call sites pass useAuth().user, typed AuthUser | null, and type cleanly unchanged — two in console/AppContent.tsx, one in views/RecordFormPage.tsx, one in apps/console's InternalFormRoute.tsx. The body is byte-equivalent: the same keys, the same ?? defaults, the same anonymous branch. ⛔ No consumer-side fallback was added; id: u.id ?? null remains the rejected shape (triage ruling 2026-08-26), because a lenient default in the consumer is what AGENTS.md #0.1 forbids and it silently equates "signed in, no id" with "signed out".

.changeset/6593-duplicate-package-envelope-unwrap.md

  • names preview/commitHistory.ts → packages/app-shell/src/preview/commitHistory.ts — edited by this change

    The unwrap-then-read order is the one revertCommit already uses for the sibling commit-revert route in preview/commitHistory.ts; this is one consumer converging on that, not a new convention. The route's underlying contract absence (it publishes no response schema, so reading the wrong success typechecks perfectly) stays upstream in objectstack#12038.

.changeset/6597-retire-fieldmeta-referenceto.md

  • names plugin-grid/src/ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    No authoring story survived the search either. ObjectGrid's own relational-meta pass-through (applyRelationalMeta, plugin-grid/src/ObjectGrid.tsx) copies reference_to / reference / display_field / etc. from the SCHEMA field def only, at all three of its call sites — never from an authored column override. No doc, example, or fixture in this repo shows a table column pinning a lookup's target away from what its schema field already says. Under the maintainer's standing startup-stage rule (2026-08-27: deprecated/alias spellings retire immediately, no transition windows), no measured demand selects withdraw.

.changeset/6625-retire-fieldmeta-decimals.md

  • names fields/src/index.tsx → packages/fields/src/index.tsx — edited by this change

    buildFieldMeta computed decimals: overrides.decimals ?? meta?.decimals ?? meta?.scale on every call and the value reached nothing. Re-measured on this branch's base (efdc6c62): zero .decimals member reads across @object-ui/fields, @object-ui/i18n, @object-ui/components, @object-ui/core and plugin-dashboard itself — the only non-comment occurrence was the write being removed here. The positive control in the same query shape fires: .scale member reads hit NumberField.tsx, GridField.tsx and fields/src/index.tsx. So the zero is a finding, not a broken query. The overrides.decimals ?? head of that chain had already lost its only feeder when objectui#6425's ruling removed the authored read from ObjectDataTable.enrich(); RecordDetailDrawer, the only other buildFieldMeta caller, passes no overrides at all. Both halves retire together, so the key leaves in one move.

.changeset/6661-app-launcher-nav-menu-renderers.md

  • names en.ts → packages/i18n/src/locales/en.ts — edited by this change

    Three new strings — the launcher's and the menu's accessible names, and the menu's empty state — are declared under console.nav in en.ts and its nine sibling packs. An inline defaultValue alone is not a fix: it renders English at one call site and leaves the string untranslatable everywhere (objectui#3517).

.changeset/6687-chatbot-surface-authorable.md

  • names packages/types/src/complex.ts → packages/types/src/complex.ts — edited by this change

    Measured on both declaration faces before the fix, each with a control that had to hit: schema.surface appeared 0 times in renderer.tsx against schema.placeholder at 3 (one per registration) and schema.processVisibility at 1; and ChatbotSchema (packages/types/src/complex.ts) declared 34 keys, not this one. Two faces agreeing is what made the zero a reading rather than a bad query.

.changeset/6694-dashboard-lookup-reference-meta.md

  • names packages/fields/src/index.tsx → packages/fields/src/index.tsx — edited by this change

    ⚠️ The copy set is three keys where ObjectGrid's RELATIONAL_META_KEYS is nine, and the difference is measured per key, not preferred. The grid's cells are EDITABLE, so its extra keys drive the inline picker's query (LookupField / UserField read id_field, description_field, lookup_filters, lookupFilters); these two widgets are read-only and their render path ends at a cell renderer. packages/fields/src/index.tsx reads exactly reference_to, reference and display_field off a cell's field prop; titleFormat is never read off a field meta at all (its readers take it off the object schema, which arrives here through useRefObjectSchema(reference_to)), and reference_to_field has zero member reads anywhere in the repo. Copying the other six would mint six members written on every call and read by nothing — precisely what objectui#6625 (decimals) and objectui#6597 (referenceTo) retired from this same file.

.changeset/6726-find-envelope-records-arms.md

  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    | module | what it does | | --- | --- | | components/src/hooks/related-count-store.ts | related-list tab badge count | | components/src/renderers/basic/data-list.tsx | element:repeater rows | | components/src/renderers/basic/elements.tsx | element:number client-side aggregate | | components/src/renderers/basic/record-picker.tsx | element:record_picker options | | plugin-detail/src/renderers/record-activity.tsx | record:activity self-fetch | | plugin-detail/src/renderers/record-history.tsx | record:history self-fetch | | plugin-view/src/ObjectView.tsx | non-grid (kanban / calendar / gallery / timeline) fetch |

.changeset/6771-retire-body-child-list-dialect.md

  • names renderers/layout/containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    Non-rendering readers keep their arm on the same rule, and none of them renders anything: while a renderer still reaches stored body content, a reader that must see the SAME content keeps its arm, or the renderer draws what the reader cannot find. Those are the two tab-subtree walkers in renderers/layout/containers.tsx, app-shell's pageSchemaIntrospect (CONTAINER_KEYS) and PageBlockInspector (STRUCTURAL_PROP_KEYS, the inspector half of a stored properties.body), and the CLI's OBJECTUI_STRUCTURAL_KEYS — a file-IDENTIFICATION marker, where keeping body is what lets an old file still be recognised as an ObjectUI node and therefore refused, instead of silently not judged.

.changeset/6783-readprops-degenerate-config-bag.md

  • names metadata-viewer.tsx → packages/components/src/renderers/basic/metadata-viewer.tsx — edited by this change

    Five modules under packages/components/src/renderers/basic/ — elements.tsx, data-list.tsx, text-input.tsx, record-picker.tsx, metadata-viewer.tsx — each carried a copy of the same reader, { ...(schema?.props ?? {}), ...(schema?.properties ?? {}) }. ?? only replaces null/undefined, so a non-object bag went into the object spread and came back out as indexed keys: for properties: 'not-a-bag', the config bag a renderer received was { '0': 'n', '1': 'o', … '8': 'g' } — nine keys nobody authored. The five copies are now one readProps (renderers/basic/readProps.ts) that asks isConfigBag, and a degenerate bag on either side contributes no keys.

.changeset/6837-reference-to-arm-deletion.md

  • names fields/src/index.tsx → packages/fields/src/index.tsx — edited by this change

    Three readers were deliberately left alone. LookupCellRenderer (fields/src/index.tsx), LookupField and UserField read FieldMetadata — ObjectUI's OWN contract, whose LookupFieldMetadata declares reference_to and never declares reference. They are fed by the emitters above and by published example schemas (examples/schema-catalog/src/schemas/fields-lookup/*.json), so narrowing them would break in-repo producers, and plugin-grid's relationalMetaCopySet.derivation.test.ts re-derives its read set from exactly those three sources — where reference_to is recorded with verdict adapter-stamped. DetailViewFieldSchema is likewise untouched.

.changeset/6938-checkbox-wrapper-class.md

  • names packages/types/src/form.ts → packages/types/src/form.ts — edited by this change

    packages/components/src/renderers/form/checkbox.tsx:36 reads cn("flex items-center space-x-2", schema.wrapperClass) — classes on the wrapper div around the box and its label — and neither the TypeScript interface in packages/types/src/form.ts nor the zod mirror in zod/form.zod.ts declared the key. It compiled through BaseSchema's index signature and parsed through .passthrough(), admitted unexamined. The same key, on the same class of read, is declared on FileUploadSchema and FilterBuilderSchema (objectui#6150); the checkbox was left out only because its doc page's schema block is a six-line summary.

.changeset/6939-kanban-column-cards.md

  • names complex.ts → packages/types/src/complex.ts — edited by this change

    Breaking, deliberately. KanbanColumn declared its card list as items in complex.ts and in the zod mirror complex.zod.ts. Every board reads cards. Measured on origin/main 78a3cc238: KanbanImpl.tsx reads .cards on 12 lines, KanbanEnhanced.tsx on 8, and bucketCardsIntoColumns twice more as col.cards || []; .items had zero read sites in either board (a same-shaped .title control on the same two files returns 8 and 3, so those zeros are readings and not a mis-shaped probe). Both catalog entries, the plugin docs and content/docs/api/schema-reference.md all author cards.

.changeset/6939-objectql-record-source-refinement.md

  • names plugin-gantt/src/ObjectGantt.tsx → packages/plugin-gantt/src/ObjectGantt.tsx — edited by this change

    Both renderers resolve their records from one of three keys, in this order — getDataConfig in plugin-map/src/ObjectMap.tsx and plugin-gantt/src/ObjectGantt.tsx: data, then staticData, then objectName. Both mirrors required objectName alone, so a document authored on staticData drew correctly and was refused by safeValidateSchema — six catalog entries, three per component.

.changeset/6940-rowactions-boolean-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The list view's same-named rowActions in zod/objectql.zod.ts — z.array(z.string()), the legacy bare-name action list on ObjectGridSchema — is a different key that is correct as it stands, is in parity with its own TS twin (rowActions?: string[]), and is not touched.

.changeset/6985-wizard-card-r-alignment.md

  • names anchors.ts → packages/app-shell/src/views/metadata-admin/anchors.ts — edited by this change

    • metadata-admin view create seeds one starter step for a wizard (app-shell anchors.ts): the create body used to emit sections: [] for every form type, which for type: 'wizard' is exactly the shape the tightened spec refuses at parse (D7 — a stepless wizard silently rendered as a plain simple form). Same seed-the-required-shape move the flow anchor makes for its type enum (objectui#2326). Other form types keep the bare [] — only the wizard variant refuses emptiness. - @object-ui/types TSDoc states the ruled wizard boundary where the shared section/form types restate the form-view family: ObjectFormSection.visibleWhen / collapsible / collapsed name the wizard drop + spec-door refusal; ObjectFormSchema.sections states sections-ARE-steps and array-order-is-step- order; allowSkip states the D4 semantics. Type SHAPES are unchanged — the spec's own ruled mechanism is a parse-time refinement over the single shared section schema (D2 option A), which these types mirror at the type level. - Consumer-side behaviour pins (wizardRuledSemantics-6985.test.tsx): the wizard-inert step keys are dropped, never honoured (a denying visibleWhen does not remove a step; collapsible/collapsed: true produce no collapse affordance, with a positive control on the affordance probe); the empty-steps wizard's measured degradation to a simple form is pinned as the shape the spec door now refuses (one-step wizards stay legal — no arity floor); array order is step order (with a reversed-array control). - Installed-spec door pins (wizardSpecDoor-6985.test.ts), gated on a capability probe of the installed FormViewSchema rather than a version string: the post-Card-S half (refusal messages, prescriptions, the authored- false collapse boundary, the wizard-scoped control) activates by itself on the lockfile bump that brings the tightening in; until then the pre-tightening half records the 17.2.x accept-set it measured. steps: is pinned refused on every spec line.

.changeset/7070-no-invented-gantt-date-fields.md

  • names app-shell/src/views/ObjectView.tsx → packages/app-shell/src/views/ObjectView.tsx — edited by this change

    • app-shell/src/views/ObjectView.tsx — the console object page. The inline branch becomes ganttViewOptions, the sibling of calendarViewOptions and timelineViewOptions: the declared block spread whole, title floored at 'name', no date field invented. - plugin-list/src/ListView.tsx — the render branch AND the capability gate. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.
  • names plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    • app-shell/src/views/ObjectView.tsx — the console object page. The inline branch becomes ganttViewOptions, the sibling of calendarViewOptions and timelineViewOptions: the declared block spread whole, title floored at 'name', no date field invented. - plugin-list/src/ListView.tsx — the render branch AND the capability gate. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.
  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    • app-shell/src/views/ObjectView.tsx — the console object page. The inline branch becomes ganttViewOptions, the sibling of calendarViewOptions and timelineViewOptions: the declared block spread whole, title floored at 'name', no date field invented. - plugin-list/src/ListView.tsx — the render branch AND the capability gate. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

.changeset/7088-hidden-jsdoc-single-hide-path.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    Why a comment was worth a changeset: the JSDoc is the authority a later docs correction is measured against, and this one nearly propagated. While splitting the schema-reference hidden row, a reader checked it against base.ts and almost "corrected" the table's "Inverse of visible" — the half that describes shipped behaviour — toward the declaration. That row is unchanged and stays. SchemaRenderer.hiddenVisibleSynonymy.test.tsx now pins the claim the comment makes: the two keys produce the same rendered output, and hidden: true leaves no node that could carry a visibility style.

.changeset/7113-chart-data-model.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    .extend() with a NEW key still works and preserves the fold and the refinement; .optional(), z.discriminatedUnion, z.toJSONSchema and safeValidateSchema are all unaffected. Nothing in this repository calls the throwing combinators on either const, and the published surface already ships refined mirrors (objectql.zod.ts, complex.zod.ts, form.zod.ts, app.zod.ts), so the class is not new — but it is a real behaviour change on a published export and it belongs in the release note rather than in a reviewer's file.

.changeset/7125-dashboard-empty-state-keys-retired.md

  • names DatasetWidget.tsx → packages/plugin-dashboard/src/DatasetWidget.tsx — edited by this change

    Not touched: table.noRows ('No rows to display') and engine.form.noRows (packages/app-shell/src/views/metadata-admin/i18n.ts, read at widgets.tsx) — two different, same-named keys in different namespaces. Nor the comments in WidgetEmptyState.tsx, DatasetWidget.tsx, ObjectDataTable.tsx and PivotTable.tsx that record WHY three widgets with three strings became one shared empty state; the packs' own comment keeps that rationale and now names the retirement instead of a row that is gone.

.changeset/7166-retire-inert-fieldmeta-copies.md

  • names packages/fields/src/index.tsx → packages/fields/src/index.tsx — edited by this change

    applyRelationalMeta writes the copy set onto the fieldMeta that generateColumns hands to ANGLE-BRACKETS(CellRenderer) as the field prop — six JSX passes across the three column-building paths, and nowhere else. For a relational column that resolves to LookupCellRenderer, which reads exactly reference_to, reference, display_field, displayField, reference_field and options; a user column resolves to UserCellRenderer, which destructures { value } and reads no field meta at all. Measured by receiver rather than by count: packages/fields/src/index.tsx, the file holding every cell renderer, contains zero occurrences of the three retired keys, against a control of 22 occurrences of the display_field / displayField / reference_to spellings the cell does read.

.changeset/7178-format-measure-date.md

  • names dataset-format.ts → packages/core/src/utils/dataset-format.ts — edited by this change

    No second date formatter was written. formatDate, formatDateTime, formatRelativeDate and DateDisplayOptions MOVED from @object-ui/fields' barrel down into @object-ui/core (utils/date-display.ts), which is the same remedy objectui#4576 applied to formatDisplayNumber and for the same reason: core is the React-free engine and could not import from a React package, so the alternative was a parallel date convention in dataset-format.ts — exactly the drift that once had a list cell rendering 1.234,5 % beside a dashboard measure's 1.234,5%. @object-ui/fields re-exports all four names unchanged, so no consumer's import path or behaviour changes, and a reference-identity test pins that the cell renderer and the measure formatter call the same function.

.changeset/7182-declared-action-ids-one-rule.md

  • names containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    New on @object-ui/types, beside actionRendersAt: the pure resolveDeclaredActionIds(elements, registeredActions), with the DeclaredActionsResolution / DeclaredActionsRefusal result types (the shape classifier stays module-internal: called with no registry, the function already returns the registry-independent verdict a renderer needs before its lookup). Both renderers call it; the whole-array switch in record-quick-actions.tsx and the per-element normalisation in containers.tsx are gone. The rule is closed: a string is an id, a non-null non-array object is an inline definition, and any other element (null, a number, a nested array) is refused at its index too. An all-id array resolves by name in authored order, first registration winning on a duplicate name; ids that name nothing are reported back with their index for the caller to warn about once its lookup has settled.

.changeset/7200-object-form-section-style-keys-undeclared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The authored-metadata type now agrees with @objectstack/spec, whose FormSectionSchema is a strict object declaring neither key, and with the ruling's rationale (maintainer 2026-09-01, verbatim): "retire the reads … Declaring the keys was weighed and not adopted: it would formally invite free Tailwind strings into authored metadata, the exact class the boundary exists to keep out." A ?: never tombstone was not used: ObjectFormSection has no zod mirror (ObjectFormSchema in zod/objectql.zod.ts does not declare sections), so there is no parse door to refuse at, and a tombstone is still a declaration in completion and in the published .d.ts.

.changeset/7265-types-user-filter-field-derives.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    zod/objectql.zod.ts declared two schemas under names @objectstack/spec/ui already exports. They were triaged separately, by reading their sites, and went different ways.

.changeset/7295-chat-message-avatar-keys.md

  • names packages/types/src/complex.ts → packages/types/src/complex.ts — edited by this change

    packages/plugin-chatbot/src/index.tsx:173–178 reads message.avatar || userAvatarUrl and message.avatarFallback || userAvatarFallback (and the assistant twins), the authoring-to-runtime seam spreads every unlisted key through (chatMessageAdapter.ts, ...passthrough), and the SDUI renderer feeds the authored messages[] straight in — a per-message avatar override renders, is documented, and no authoring-facing type declared it. ChatMessage in packages/types/src/complex.ts has no index signature (objectui#5155, deliberately — none is added here), so an author annotating ChatbotSchema.messages was told a value that renders is an error (TS2353); the zod mirror ChatMessageSchema is a plain strip-mode z.object, so the value parsed green and was silently DROPPED from the parsed output.

.changeset/7313-object-calendar-record-source.md

  • names plugin-calendar/src/ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    ObjectCalendar resolves its records through the shared ladder (resolveRecordSourceConfig in @object-ui/core, called from plugin-calendar/src/ObjectCalendar.tsx): data first, then staticData, then objectName. The published TypeScript interface REQUIRED objectName and declared neither data nor staticData; the published Zod mirror did the same. So an object-calendar node authored on staticData — the route the plugin page documents twice — rendered correctly and was refused by safeValidateSchema, and could not be annotated with its own type (TS2741: Property 'objectName' is missing).

.changeset/7322-object-kanban-component-props.md

  • names ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    Inside ObjectKanban.tsx, three schema-key reads drop their as any: titleField (two sites, now honest because the object-kanban arm declares it) and cardFields / cardTitle (already declared; the casts were redundant). (schema as any).navigation stays — navigation is declared on neither face, so removing the cast would change nothing but the spelling of an index-signature read.

.changeset/7322-object-kanban-group-by-limit.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

  • names packages/plugin-kanban/src/ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    What was measured, on this branch's base (53ded82b). packages/plugin-kanban/src/ObjectKanban.tsx reads schema.groupBy at thirteen sites (lane materialisation at :601 / :625 / :640, card moves at :747 / :865, and their effect deps) and schema.limit at two (:264, $top: schema.limit ?? DEFAULT_KANBAN_LIMIT, and the effect deps at :291). groupField has ZERO read sites anywhere under packages/plugin-kanban/ — against a control of those thirteen groupBy reads in the same query, so the zero is a reading, not a blind grep. Yet the declaration REQUIRED groupField and declared neither groupBy nor limit. Measured from source: the documented, tested, working shape — { type: 'object-kanban', objectName, groupBy, limit } — failed ObjectKanbanSchema.safeParse and safeValidateSchema on the missing groupField, and only ever reached the renderer through BaseSchema's [key: string]: any and .passthrough(), admitted unexamined. An author who followed the declaration wrote groupField and got a board that grouped nothing, with no diagnostic on either face.

.changeset/7352-drill-down-config-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    DrillDownConfigSchema is the zod mirror of DrillDownConfig, and both declarations that carry drillDown reference it — ChartSchema (zod/data-display.zod.ts) and ObjectDataTableSchema (zod/objectql.zod.ts) — so the published validator under @object-ui/types/zod reads the key for the first time (objectui#7352).

.changeset/7363-objectql-union-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

.changeset/7493-componentinput-retire-label-defaultvalue-advanced.md

  • names packages/types/src/base.ts → packages/types/src/base.ts — edited by this change

    The retirement kit: ?: never on ComponentInput (packages/types/src/base.ts), so authoring one is a tsc error at the registration site; retirementTombstone() on ComponentInputSchema (packages/types/src/zod/base.zod.ts), so an authored value is REFUSED at parse time with code: 'invalid_type', the key named in the issue path, and the migration note as the message (one string, both channels). Pinned in packages/types/src/__tests__/component-input-retired-keys-7493.test.ts, which also holds a tree-scoped absence census over every inputs: array under packages/** and apps/**.

.changeset/7499-gantt-non-axis-floors-omitted.md

  • names plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    • plugin-list/src/ListView.tsx — the object-gantt render branch. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.
  • names plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    • plugin-list/src/ListView.tsx — the object-gantt render branch. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

.changeset/7632-shared-record-source-config.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    That ladder is published contract on both faces — packages/types/src/objectql.ts and its zod mirror both ship .describe() strings naming getDataConfig's order (77cb489b4, maintainer ruling 2026-09-02), pinned by objectql-record-source-refinement-6939.test.ts — and it was hand-copied into five plugin components with no gate holding them together. A change to the ruled order had five edit sites and nothing that noticed a missed one; that is the AGENTS.md #0.1 drift class.

.changeset/7655-chatbot-registration-authoring-faces.md

  • names complex.ts → packages/types/src/complex.ts — edited by this change

    New published symbol: ChatbotSharedKey, the string-literal union of the twenty keys all three registrations read. It is exported from complex.ts because an exported interface may not extend a Pick over a private name (TS4022), so it is emitted into dist/complex.d.ts and is reachable through the published @object-ui/types/complex subpath (it is not re-exported from the package entry). It is a census, not an authoring face.

.changeset/7697-combobox-option-root-barrel.md

  • names src/form.ts → packages/types/src/form.ts — edited by this change

    Additive only. ComboboxOption is added to the root barrel's existing named re-export list from ./form.js, next to the sibling option types that were already there (SelectOption, RadioOption). Nothing is removed, retyped or narrowed: the declaration stays in src/form.ts, its three members (value, label, disabled?) are unchanged, and the @object-ui/types/form subpath spelling keeps working exactly as before. Both spellings now resolve to the same declaration.

.changeset/7703-chatbot-dark-keys-retired.md

  • names packages/types/src/complex.ts → packages/types/src/complex.ts — edited by this change

    Each member goes to ?: never on packages/types/src/complex.ts and to retirementTombstone(...) on packages/types/src/zod/complex.zod.ts — both halves, in lockstep, the convention MarkdownSchema.sanitize (objectui#6972), TimelineSchema.timeScale (objectui#6355) and ObjectViewSchema.viewTabBar (objectui#7779) already carry. Each refusal names the key, says why it is retired, and points at what to write instead; one string feeds both the parse-time message and the .describe() metadata, so the two cannot drift.

.changeset/7712-kanban-calendar-filter-input.md

  • names ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    ObjectKanban.tsx sends the authored key to the query as $filter: schema.filter and ObjectCalendar.tsx does the same, and @objectstack/spec's ComponentPropsMap declares filter on both blocks (measured: safeParse accepts it, and refuses an undeclared key by name on the same call). But none of the four registrations that publish those two renderers listed filter in inputs, and sdui-parser's validateTree reports unknown-prop for every key no inputs entry claims. So an author writing the one spelling that WORKS was told it was unknown — objectui#6678's shape, where a correct write draws the same diagnostic as a write that does nothing. That is worse than an inert key: it actively punishes the correct behaviour, and the honest response to it is to delete working metadata.

  • names ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    ObjectKanban.tsx sends the authored key to the query as $filter: schema.filter and ObjectCalendar.tsx does the same, and @objectstack/spec's ComponentPropsMap declares filter on both blocks (measured: safeParse accepts it, and refuses an undeclared key by name on the same call). But none of the four registrations that publish those two renderers listed filter in inputs, and sdui-parser's validateTree reports unknown-prop for every key no inputs entry claims. So an author writing the one spelling that WORKS was told it was unknown — objectui#6678's shape, where a correct write draws the same diagnostic as a write that does nothing. That is worse than an inert key: it actively punishes the correct behaviour, and the honest response to it is to delete working metadata.

.changeset/7722-wrapper-class-five-more.md

  • names form.ts → packages/types/src/form.ts — edited by this change

    Each of renderers/form/switch.tsx, textarea.tsx, date-picker.tsx, select.tsx and renderers/data-display/list.tsx reads schema.wrapperClass onto its wrapper element, and neither the TypeScript interface (form.ts, data-display.ts) nor the zod mirror (zod/form.zod.ts, zod/data-display.zod.ts) declared the key. The reads compiled through BaseSchema's index signature (objectui#5155) and the values parsed through .passthrough(), admitted unexamined. The same key, on the same class of read, is declared on CheckboxSchema (b74a8598d), FileUploadSchema and FilterBuilderSchema (objectui#6150); these five were left out only because their doc pages never listed it.

.changeset/7762-object-grid-export-options-bare-array-refusal.md

  • names ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    What was measured, on this branch's base. The mirror declared NO exportOptions member at all, and BaseSchema is .passthrough(), so ObjectGridSchema.safeParse({ type: 'object-grid', objectName: 'accounts', exportOptions: ['csv', 'xlsx'] }) returned success: true with the array back VERBATIM — as did { formats: ['csv', 'pdf'], compression: 'gzip' }. Nothing on the render path parses, and ObjectGrid.tsx reads schema.exportOptions?.formats and only that, so the authored array then lost SILENTLY to the ['csv', 'json'] default: the useEffect that warns about dropped formats reads .formats too and returns early when it is absent, while !!schema.exportOptions kept the export button on screen. An author declared ['csv', 'xlsx'] and got csv/json with no error, no warning and no console line. The two authoring faces disagreed in the direction opposite to objectui#6956's: the TypeScript interface already declared the object form only, so TS refused what zod admitted.

.changeset/7772-page-block-kanban-group-by-control.md

  • names ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    What was measured, on this branch's base (0c8dbc49). BLOCK_CONFIG['object-kanban'] offered exactly four controls — objectName / groupField / titleField / cardFields. ObjectKanbanSchema.groupBy is REQUIRED on both published faces (objectql.ts:2765 groupBy: string, no ?; objectql.zod.ts:1001 groupBy: z.string(), no .optional()) and had no control at all, while groupField — the only control able to set grouping — has been a retirementTombstone() on the Zod face and ?: never on the TS face since objectui#7322. ObjectKanban.tsx reads schema.groupBy at thirteen sites and groupField at zero (control: those same thirteen hits in the one query, so the zero is a reading).

.changeset/7773-kanban-adapter-groupfield-write.md

  • names ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    The object-kanban renderer never read it: groupField has ZERO hits anywhere under packages/plugin-kanban/, against a control of thirteen schema.groupBy read sites in ObjectKanban.tsx from the same query — so the zero is a reading, not a blind grep. The write was inert; the board grouped by groupBy and groupField rode along unread.

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    Who is NOT affected — the boundary is node-local. Every VIEW-LEVEL groupField read is untouched and still live: it is a legacy alias of the spec's groupByField on the kanban view config, mapped by normalize-list-view.ts, and both adapters still resolve lanes through it (ObjectView.tsx's kanbanCfg.groupField ||, ListView.tsx's groupByField || groupField). Authoring options.kanban.groupField on a list-view or object-view keeps working exactly as documented in packages/plugin-list/README.md. groupField is dead only on the generated object-kanban NODE.

.changeset/7780-object-kanban-record-source.md

  • names packages/plugin-kanban/src/ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    packages/plugin-kanban/src/ObjectKanban.tsx resolves a board's rows in four steps: the pre-fetched data PROP a parent passes (hasExternalData), then bind through useDataScope(schema.bind), then the inline ROW ARRAY on schema.data, and only then a fetch keyed by schema.objectName — rawData = (hasExternalData ? externalData : undefined) || boundData || schema.data || fetchedData, with the fetch itself gated on schema.objectName && !boundData && !schema.data. Every objectName read is guarded. Both published faces nevertheless REQUIRED objectName, so a bind-only or data-only board — one that renders correctly today — was refused by the shipped validator and could not be annotated with its own type.

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    groupBy is untouched and stays REQUIRED (objectui#7322, PR feat(types): declare ObjectKanbanSchema.groupBy and .limit, retire groupField on both faces (objectui#7322 item 1) #7774). A record source and a lane key are different questions: every lane-less document above is still refused at groupBy, and the two readings PR feat(types): declare ObjectKanbanSchema.groupBy and .limit, retire groupField on both faces (objectui#7322 item 1) #7774 excluded from counting as a lane-less mode — the dataSource json fragment in content/docs/utilities/data-objectstack.mdx and ListView.tsx's runtime-generated node — are asserted still-refused in the new pin. The retired groupField tombstone is likewise still refused by name.

.changeset/7804-objectql-handler-key-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The four plain objectql.ts node faces declare the nine handler keys their registered renderers read (the objectql.ts slice): ObjectFormSchema.onCancel / .onError / .onOpenChange / .onStepChange / .onSuccess, ObjectGallerySchema.onCardClick / .onRowClick, ObjectGridSchema.onNavigate and ObjectViewSchema.onNavigate.

.changeset/7804-tree-view-handler-slot.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    'runtime-slot' and not 'retired', measured at this key's own channel. 'retired' publishes "no renderer reads this key, so nothing could ever run it" — true of the two siblings already tombstoned on this arm (onSelectChange, onExpandChange) and flatly false here, since the read is live and INVOKED. ⚠️ No in-repo host builds a tree-view node carrying the key: the channel is wired end to end and only the supplier is absent, which is the same shape as ObjectFormSchema.onStepChange in this card's objectql.ts slice and is not evidence of a dead read. The TypeScript declaration is unchanged and still callable, so a programmatic host supplies it exactly as before.

.changeset/7917-export-breadcrumb-object-tree-zod-schemas.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    AnyComponentSchema declares 107 node component types. 105 of them could be named on the ./zod barrel — ButtonSchema.safeParse(node), which is what a designer, a form builder or a targeted test needs. The arms declaring type: 'breadcrumb' (navigation.zod.ts) and type: 'object-tree' (objectql.zod.ts) could not: both were already export const in their own module, but index.zod.ts — the package's only zod entry point — did not re-export them, so the schemas existed, were maintained, and were applied by the union while no consumer could name them.

.changeset/7963-alert-dialog-footer-keys-retired.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Nothing else moves. These spellings are overloaded across the tree and every other owner is a live key on a different declaration — FormSchema.cancelLabel, objectql.ts's confirmLabel, plugin-designer's ConfirmDialog React props, plugin-grid's def.confirmLabel, and plugin-form's ModalForm / DrawerForm, which build a local cancelLabel from schema.cancelText. None is an AlertDialogSchema; none is touched, and a pin asserts it. No fixture, catalog schema, example app or doc fence authored any of the three on an alert-dialog node, so no shipped document is stranded.

.changeset/7979-package-form-dialog-envelope-reader.md

  • names utils/apiErrorEnvelope.ts → packages/app-shell/src/utils/apiErrorEnvelope.ts — edited by this change

    The read now comes from the one shared rule, readEnvelopeFailureText (utils/apiErrorEnvelope.ts), which prefers the mark over the diagnostic and appends the declared code behind whichever prose won. Create and edit are exactly where an author meets a refusal that names what to fix — a namespace rule, a version already published — and in the 5xx band the door substitutes the generic Internal server error into message while the mark rides through untouched, so on a marked 500/503 the dialog used to show the generic sentence and discard the specific one.

.changeset/7997-detail-view-related-retired.md

  • names RecordDetailView.tsx → packages/app-shell/src/views/RecordDetailView.tsx — edited by this change

    Why it retired. @objectstack/spec declares no DetailView schema at all — every DetailView occurrence in packages/spec/src is prose about this repo's own RecordDetailView.tsx — so this array mirrored no protocol schema and drifted freely: it declared columns as TableColumn[] while the renderer it fed also accepted bare field names, { field, label } and legacy { name, label } spellings. The axis that carried the ruling was measured zero pull: no application code authored the member, both internal producers of a detail-view node (RecordDetailDrawer, renderers/record-details.tsx) synthesize it without related, and the only in-tree authorings carrying real columns were two documents — both rewritten here.

.changeset/8072-input-wrapper-class-mirrored.md

  • names form.ts → packages/types/src/form.ts — edited by this change

    packages/components/src/renderers/form/input.tsx reads cn("grid w-full items-center gap-1.5", schema.wrapperClass) onto the wrapper div around the input and its label. The TypeScript face has declared the key all along (form.ts, docblock "Input wrapper CSS class"); the zod mirror never did, so the value rode through .passthrough() and { type: 'input', wrapperClass: 42 } validated GREEN — while the identical document on any of the other eight schema.wrapperClass readers (checkbox, file-upload, filter-builder — objectui#6150 / b74a8598d; switch, textarea, date-picker, select, list — objectui#7722) was refused at the key.

.changeset/8155-app-root-residue-swept.md

  • names containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    Swept as a class, not as two coordinates. Every other place in this tree that stated app was a bound expression-scope root is corrected in the same change — the diagnostic copy and its byte-pin, the ambient-scope docblocks in @object-ui/react (SchemaRenderer, useExpression), @object-ui/core (ActionRunner.ParamDef.visible, RowPredicateOptions.scope), @object-ui/components (form.tsx, containers.tsx), @object-ui/plugin-detail, @object-ui/plugin-form (docblock and README), @object-ui/app-shell and the console app, plus fourteen test fixtures that transcribed the old bag with an app key. The fixtures in @object-ui/app-shell now call buildExpressionScope instead of transcribing it, so that pair cannot drift again.

.changeset/8166-record-scope-data-root.md

  • names fieldRules.ts → packages/core/src/evaluator/fieldRules.ts — edited by this change

    The fault is loud, not fatal. The verdict a faulting predicate resolves to is unchanged: visibleWhen still fails OPEN, readonlyWhen / requiredWhen still fail permissive (@object-ui/core's fieldRules.ts; the direction is objectui#8069's open question, not this change's). So a record form renders exactly as before except that the console now names the root. Nothing throws.

.changeset/8171-calendar-sort-input.md

  • names ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    objectui#7712's defect, one key over. ObjectCalendar.tsx lowers the authored key onto its own query as $orderby: convertSortToQueryParams(schema.sort), and @objectstack/spec's ComponentPropsMap['object-calendar'] declares sort (measured on 17.2.0: safeParse({ objectName, sort }) returns success: true, while the same strict schema on the same call refuses bogusProp by name — that control is what makes the acceptance a verdict). But neither of the two registrations that publish this renderer — plugin-calendar:object-calendar and view:calendar — listed sort in inputs, and sdui-parser's validateTree reports unknown-prop for every key no inputs entry claims. So an author writing the one spelling that WORKS was told it was unknown — objectui#6678's shape, where a correct write draws the same diagnostic as a write that does nothing.

.changeset/8174-kanban-calendar-filter-sort.md

  • names ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    filter had four declaration faces and only three of them named it: @objectstack/spec declares it (ComponentPropsMap['object-kanban'] and ['object-calendar']), both plugins' registration inputs publish it, and both renderers read it — ObjectKanban.tsx lowers schema.filter onto $filter, ObjectCalendar.tsx lowers schema.filter onto $filter and schema.sort onto $orderby through convertSortToQueryParams. This package's own published faces (the TypeScript interface and its zod mirror) named none of them, so an authored value reached the renderer only through BaseSchema's index signature and the mirror's .passthrough() — admitted, never examined. That is the same reasoning finding(types,plugin-kanban): ObjectKanbanSchema requires groupField (zero read sites) and declares neither groupBy nor limit — no working object-kanban node is assignable to any declared type #7322 used to move groupBy and limit into this same interface.

  • names ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    filter had four declaration faces and only three of them named it: @objectstack/spec declares it (ComponentPropsMap['object-kanban'] and ['object-calendar']), both plugins' registration inputs publish it, and both renderers read it — ObjectKanban.tsx lowers schema.filter onto $filter, ObjectCalendar.tsx lowers schema.filter onto $filter and schema.sort onto $orderby through convertSortToQueryParams. This package's own published faces (the TypeScript interface and its zod mirror) named none of them, so an authored value reached the renderer only through BaseSchema's index signature and the mirror's .passthrough() — admitted, never examined. That is the same reasoning finding(types,plugin-kanban): ObjectKanbanSchema requires groupField (zero read sites) and declares neither groupBy nor limit — no working object-kanban node is assignable to any declared type #7322 used to move groupBy and limit into this same interface.

.changeset/8218-studio-property-panel-de-developerize.md

  • names json-schema-to-fields.ts → packages/app-shell/src/views/metadata-admin/inspectors/json-schema-to-fields.ts — edited by this change

    • Master-detail column headers. A column whose item schema carries no title printed the raw JSON Schema key (actionUrl, actionType) as if it were a column name — in every locale, English included. It now humanises the key, the same convention this tree already applies wherever a title is absent (json-schema-to-fields.ts's prop.title || humanizeKey, and SchemaForm's own grid repeater: s.label || prettify(s.field)). title is an OPTIONAL annotation, so its absence is not off-spec metadata and the renderer has to render something; this is not a lenient contract fallback. The LOCALIZED column name needs an upstream channel that does not exist yet — filed there.

.changeset/8221-retire-legacy-string-sort.md

  • names sort-query.ts → packages/core/src/utils/sort-query.ts — edited by this change

    Director ruling, decision batch Release v0.2.1 with changeset automation #77 (2026-09-07), option B. Three faces disagreed about one key: @object-ui/core implemented the string clause on purpose (sort-query.ts, docblock and all), content/docs/plugins/plugin-map.mdx taught it as sort?: string | SortConfig[], and the html tier answered type-mismatch for it because all seven sort registrations publish type: 'array' alone — while @objectstack/spec refuses the string outright on element-record-picker. Option A (per-block string arms) was rejected by name: it would make one key mean different things on different blocks.

.changeset/8318-jsdoc-default-tag-corrections.md

  • names core/src/actions/ActionRunner.ts → packages/core/src/actions/ActionRunner.ts — edited by this change

    • CRUDDialogSchema.size / .closeOnOutsideClick / .closeOnEscape / .showClose — there is no register('crud-dialog' anywhere, so no node of that type ever reaches a renderer. Recorded once on the interface. Per key, the name census differs: two spellings occur nowhere outside the declaration and its zod twin, and showClose's one other occurrence (renderers/overlay/drawer.tsx:38) belongs to DrawerSchema. - ActionSchema.level — type: 'action' is not a rendered node type, and core/src/actions/ActionRunner.ts, which is what makes method / chainMode / reload / close live, does not read level. - CardSchema.variant — card IS registered, twice, and neither registration reads it: the ui route forwards the key to ui/card.tsx, which spreads onto a div and mentions variant nowhere, and the page route forwards only its designer props. - PageNodeSchema.isDefault — page IS registered, and PageRenderer neither reads the key nor forwards it: the wrapper element gets toDomProps(props), an allow-list that does not carry it.

.changeset/8415-filter-builder-condition-id.md

  • names complex.ts → packages/types/src/complex.ts — edited by this change

    Breaking for authored metadata: a filter-builder CONDITION must now declare id (objectui#8415). It is declared on both published faces — the TypeScript interface FilterBuilderCondition in complex.ts and the Zod mirror FilterBuilderConditionSchema in zod/complex.zod.ts — so a key the renderer has always required is finally validated instead of silently discarded.

.changeset/8466-calendar-color-allday-fields.md

  • names ObjectCalendar.tsx → packages/plugin-calendar/src/ObjectCalendar.tsx — edited by this change

    ObjectCalendar.tsx's getCalendarConfig reads FIVE flat keys off the node, and packages/plugin-calendar/README.md teaches all five in one sentence — "point titleField / startDateField / endDateField / allDayField / colorField at your own fields when they differ." Only three of the five were declared. The other two reached the renderer through BaseSchema's [key: string]: any on the TypeScript face and its .passthrough() on the zod mirror: admitted, never examined. A misspelling therefore left the calendar silently colourless while every published gate passed.

.changeset/8478-describe-line-addresses.md

.changeset/8649-detail-renderer-undeclared-keys.md

  • names record-related-list.tsx → packages/plugin-detail/src/renderers/record-related-list.tsx — edited by this change

    @object-ui/plugin-detail — the annotation-erasing destructure default is gone from three renderers. record-details.tsx, record-highlights.tsx and record-related-list.tsx each annotated schema correctly and then wrote schema = {} as any. A destructuring default's type joins the annotated property type at the binding, so any erased the annotation for every read site in the file — declared keys and undeclared ones alike read any. No published surface moves: the exported annotations were always correct.

.changeset/8650-chart-foreign-dialect-retired.md

  • names ObjectChart.tsx → packages/plugin-charts/src/ObjectChart.tsx — edited by this change

    Also deletes six (schema as any) casts that the published declarations had already made unnecessary — colors, categoryColors and categoryOrder on ChartRenderer, and colors, compareTo and series on ObjectChart (the objectui#8327 bucket-(b) class: declared, then read through a needless cast). No behaviour changes with them; ObjectChart.tsx now has no (schema as any) read left at all.

.changeset/8653-listview-title-retired-rowactiondefs-pinned.md

  • names packages/plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    title — retired. ListView resolved its export filename through schema.label || (schema as any).title. @objectstack/spec/ui's ListViewSchema refuses title by name (unrecognized_keys: ['title']) while ObjectGridPropsSchema accepts it; packages/types mirrors the platform contract rather than ruling over it, so declaring title on ListViewSchema would have made this repo accept what the platform save gate rejects. That asymmetry is also why objectui#6639 could take the declare branch for ObjectGridSchema.title one package over and this site could not. A parse-based census of apps/ examples/ content/ and packages/ found zero list-view nodes authoring title, so the retirement costs no author a filename. Over that same corpus the instrument reports three object-grid nodes carrying the key: two authored ones, both in content/docs/api/schema-reference.md, plus one that is not authored at all — packages/plugin-view/src/ObjectView.tsx composes title: schema.table?.title onto a grid node it builds, so it is a producer writing the key rather than an author declaring it. ObjectGrid's own title reads are untouched — they remain declared, ruled and read.

.changeset/8735-objectql-mirror-docblocks-not-defaulted.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Correct four zod/objectql.zod.ts docblocks that described the behaviour objectui#8317 removed. Since that change the zod mirrors strip imported @objectstack/spec defaults at this package's import boundary, but the docblocks on HttpRequestSchema, ListColumnSchema, SelectionConfigSchema and PaginationConfigSchema still said, in the present tense, that method, prefix.type, type and pageSize are defaulted on parse — the opposite of what each export does. Each now says the key is declared and accepted but NOT defaulted on parse.

.changeset/8738-object-form-fields-description.md

  • names ObjectForm.tsx → packages/plugin-form/src/ObjectForm.tsx — edited by this change

    The registration declared { name: 'fields', type: 'array' } with no description, so an author had nowhere to read that this key's members are bare field names — a different vocabulary from sections[].fields, which also accepts the spec FormFieldSchema object (identity key field, e.g. { field: 'note', colSpan: 2 }). Moving one of those objects to the top-level fields resolves to no name and is skipped by SimpleObjectForm (ObjectForm.tsx) and by buildFlatFields (flatFields.ts, shared by the drawer/modal presentations). Behaviour is unchanged by this entry; it only adds the description text an author would need to avoid the drop before writing it.

.changeset/8767-object-grid-refuses-string-sort.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Migration. Write the array: sort: [{ field: 'name', order: 'desc' }]. Both keys are required. SortConfig.order carries no ? in @object-ui/types (packages/types/src/objectql.ts) and no .optional() in its zod mirror, and the protocol's own reusable SortItemSchema requires order as well — measured: that schema refuses [{ field: 'name' }] with invalid_value at 0.order. Do not omit it: this block's array arm interpolates whatever is present, so an omitted order lowers to $orderby: 'name undefined' today. That is pre-existing behaviour on the arm this change does not touch, and it is filed as a successor card rather than widened into here.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.
  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8802-8257-8008-kanban-gantt-family-retirement.md

  • names complex.ts → packages/types/src/complex.ts — edited by this change

    What each retirement was, measured. Three of the four were registration-only: no schema face in @object-ui/types ever declared kanban-ui, kanban-enhanced or gantt as a component node type, so unregistering is the whole retirement. The bare kanban key was the exception — it had a declared arm on both faces (KanbanSchema in complex.ts and its Zod mirror), and a plain deletion there would have been the objectui#7664 failure: BaseSchema is .passthrough(), so a document naming a dropped key validates green and renders nothing. It therefore retires as a named refusal: the Zod union keeps an arm claiming the literal and answers a { "type": "kanban" } document with a message naming object-kanban as the remedy, while the TypeScript half is the absence of the arm from ComplexSchema and of the key from SchemaRegistry, so tsc refuses it at the authoring site.

.changeset/8827-kanban-empty-state-settled.md

  • names ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    A genuinely empty board still paints DataEmptyState. The reverse regression — "gating on a truthy definition would leave those boards empty forever", named in ObjectKanban.tsx itself — is what the settle contract exists to prevent, and every exit settles: the query succeeding, the query throwing, no readable source, the non-fetch record sources (external, bound and inline data are settled from the first frame), and the schema-only kanban-ui entry, which has no ObjectKanban and therefore no provider and so takes the context's settled default. Lanes, headers, counts and drop targets keep rendering while the rows are in flight; only the claim is withheld.

.changeset/8854-app-shell-readme-flow-draft.md

  • names clientValidation.ts → packages/app-shell/src/views/metadata-admin/clientValidation.ts — edited by this change

    Which door was measured. Not the server, and not the node and edge schemas one at a time: the app-shell metadata admin validates a flow draft client-side by handing the whole draft to the spec's FlowSchema — clientValidation.ts's LOADERS.flow resolves it and ResourceEditPage calls validateMetadataDraft(type, draft) with the editor's entire body. Graded per node and per edge, this block would have reported green while still being refused on save; that is how the identity keys stayed invisible to two previous cards against this same fence.

.changeset/8871-page-node-refuses-breadcrumbs.md

  • names packages/types/src/base.ts → packages/types/src/base.ts — edited by this change

    Accept-set change, deliberately. A page document carrying breadcrumbs used to parse GREEN and render nothing. PageNodeSchema never declared the key and no renderer ever read it, so the array survived purely through BaseSchema's .passthrough(). On the TypeScript face, tsc previously accepted it too, through BaseSchema's own [key: string]: any index signature (the [key: string]: any member of BaseSchema in packages/types/src/base.ts) — the same open door the zod mirror walked through at runtime.

.changeset/8885-object-chart-drilldown-title-compareto.md

  • names ObjectChart.tsx → packages/plugin-charts/src/ObjectChart.tsx — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

.changeset/8913-object-kanban-columns-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

.changeset/8990-object-kanban-groupby-optional.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

  • names packages/plugin-list/src/ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    • packages/plugin-list/src/ListView.tsx generates the node as groupBy: laneField. objectDef loads asynchronously, so laneField is undefined on every load until it lands, and stays undefined whenever the object offers no stageField hint and none of status / stage / state / phase. The renderer serves that node; both published faces refused it. - content/docs/utilities/data-objectstack.mdx documents an object-kanban node that is exactly { type, dataSource }, with no groupBy. ⚠️ This one is weaker and is cited for what it is: that fragment is still refused after this change, at RECORD_SOURCE_REQUIRED, because dataSource is not a rung of the record-source ladder. It shows a lane-less board is a documented authoring; it is not a document this change admits.
  • names ObjectKanban.tsx → packages/plugin-kanban/src/ObjectKanban.tsx — edited by this change

    What a lane-less board does, measured rather than assumed. Every schema.groupBy read in ObjectKanban.tsx is a guarded early-return, so the board degrades instead of breaking: with no lane key and no columns it renders an empty board; with bare-string columns it draws those lanes, titled by the raw strings; card moves are inert (persistCardMove and the move callback both open if (!groupBy) return). ⚠️ Every lane-less board holds zero cards — bucketCardsIntoColumns returns before distributing records when there is no lane key — so omitting groupBy is not a way to configure a board, it is a board that groups by nothing.

.changeset/8992-user-actions-collapse-and-docblock.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    objectql.zod.ts's UserActionsSchema read stripImportedDefaults(Spec).extend({ group, hideFields, rowColor }), an extension that existed only because @objectstack/spec did not declare those three keys while normalizeListViewSchema folded objectui's legacy showGroup / showHideFields / showColor onto them. The protocol adopted all three in 17.3.0 (objectui#5435's ruling), so the extension is now a second local copy of a protocol declaration — the shape two faces start drifting from — and it collapses into the plain by-reference re-export its own note always said it would become.

.changeset/9092-inline-locale-declared-face.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    • AppComponentSchema.label (app.ts) - ObjectGridSchema.label and .description (objectql.ts) - PageNodeSchema.aria.ariaLabel (layout.ts)

.changeset/9172-dashboard-grid-series-label.md

  • names packages/plugin-dashboard/src/utils.ts → packages/plugin-dashboard/src/utils.ts — edited by this change

    Fix DashboardGridLayout composing chart series with no label at all (objectui#9172), so a grid-laid-out dashboard legended a measure like close_date under the raw field key while the read-only DashboardRenderer relay legended the same widget "Close Date". The three-arm label decision (synthetic aggregate name / bundle-or-humanized field label) is now composeSeriesLabel (packages/plugin-dashboard/src/utils.ts), a single authority both relays call, rather than a second copy of the logic.

.changeset/9174-interpolate-fastpath-trim.md

  • names packages/components/src/renderers/layout/containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    At this change page:header's title/subtitle (and the record-title titleFormat) all went through interpolate() in packages/components/src/renderers/layout/containers.tsx. When the template contained a {token} the function collapsed and trimmed whitespace before returning; when it contained no { at all it returned the raw string untouched. A whitespace-only authored title (e.g. ' ') has no token, so it came back unchanged — truthy — and PageHeaderRenderer's {explicitTitle && ANGLE-BRACKETS(h1)} gate drew a blank h1. Because literalTitleText (page.tsx), which decides whether PageRenderer delegates its own heading to the authored header, already trimmed and correctly read "no title", PageRenderer also drew its own implicit heading — two ANGLE-BRACKETS(h1) elements on one document, the broken outline objectui#3434 closed, arriving through a different door.

.changeset/9278-end-outcome-select.md

  • names packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts → packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts — edited by this change

    packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts declared the end group's outcome key as a free-text box with placeholder: 'success · failure'. EndConfigSchema.outcome is a closed enum of completed | refused defaulting to completed, and FlowNodeSchema discriminates an end node's config through it — so both printed words are refused at parse, not ignored at run time. Measured against the installed @objectstack/spec (17.4.0), with the accepted row in the same output so the refusals are a reading rather than a dead probe:

.changeset/9280-record-highlights-entry-icon-retired.md

  • names packages/plugin-detail/src/index.tsx → packages/plugin-detail/src/index.tsx — edited by this change

    • packages/types/src/record-components.ts — RecordHighlightsComponentProps.fields[]'s object arm: { name; label?; icon?; type?; readonly? } → { name; label?; type?; readonly? }. The key is removed, not tombstoned: the contract's arm is $strict, so the refusal an author needs already exists upstream and arrives named (invalid_union at the entry). A ?: never tombstone buys nothing here — it is the remedy for a non-strict mirror that would otherwise strip in silence, which is not this arm. - packages/plugin-detail/src/renderers/record-highlights.tsx — the entry normalizer stops copying icon: f?.icon into the normalized entry. That read was unreachable, not merely unused: no author could feed it past the $strict arm, and HeaderHighlight renders no .icon on the far side either, so the copy had no consumer in either direction. - packages/plugin-detail/src/index.tsx — the registry manifest's fields input description sketched the entry as {name,label?,icon?,type?,readonly?} → {name,label?,type?,readonly?}. The inputs ARE the published contract (gen-manifest.ts serializes them into sdui.manifest.json and sdui-intrinsics.d.ts), so leaving the sketch standing would have gone on teaching AI and human authors a key that gets the whole document refused at publish.

.changeset/9309-object-gallery-filter-destination-typed.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

  • names data.ts → packages/types/src/data.ts — edited by this change

    It was filter?: unknown under the docblock "Query filter, forwarded verbatim as $filter", and $filter is RecordANGLE-BRACKETS(string, any) | FilterArray (QueryParams, data.ts). The declaration therefore named a destination it did not type: an author told to forward the value verbatim got a type error on the key the sentence had just told them to forward, and the way through was as — which un-checks the destination's real type at that call site too. The declaration is now an INDEXED ACCESS on QueryParams, not a copy of its arms, so the two cannot drift.

.changeset/9365-bridgelistview-present-tense.md

.changeset/9375-base-i18n-vocabulary-docblock.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    base.ts said of the INLINE locale map (label / description) and the KEYED bundle reference (ariaLabel) that they "each accept the other's shape vacuously", and the label docblock said the same thing one property over ("a keyed ref typed into this slot is accepted only vacuously"). That was true when objectui#4580 Q2-B wrote it; the installed pin has since closed it, and the sentence now reads as live in published .d.ts bytes while the tree says the opposite.

.changeset/9406-types-root-barrel-two-names.md

  • names form.ts → packages/types/src/form.ts — edited by this change

    form-barrel-mirror-9406.test.ts keeps it closed, and it is DERIVED rather than a pair of presence assertions: it reads form.ts's export list and the root barrel's ./form.js re-export list on every run and names whatever is in the first and not the second. A pin asserting "these two names are present" would pass on the day the next declaration lands in form.ts and is forgotten, which is this class reopening yet again. Names deliberately left off the list get a ledger row carrying the reason instead, and a row goes red once its name reaches the barrel or stops being declared.

.changeset/9511-record-id-is-a-string.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

.changeset/9526-types-root-barrel-command-element-types.md

  • names form.ts → packages/types/src/form.ts — edited by this change

    The change is purely additive: the two names join the root barrel's existing named re-export list from ./form.js, beside CommandSchema. Nothing is removed, renamed or narrowed, the declarations stay in form.ts, and the /form subpath keeps working. It is the third instance of one class, repaired by the same route each time: objectui#7697 for ComboboxOption, and objectui#9406 (director decision batch 133, item 2, letter (a)) for InputShorthandSchema and UiCalendarSchema.

.changeset/9549-tree-filter-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

.changeset/9550-object-tree-root-barrel.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectQLComponentSchema declares the node types an ObjectQL block may be. Every one of its arms was a named export of this package's root barrel except ObjectTreeSchema, which was declared in objectql.ts, applied by the union, and re-exported by the ./zod barrel (objectui#7917) — while no TypeScript consumer could name it. There is no ./objectql subpath to reach around the barrel: the package's exports map is pinned by packages/types/src/__tests__/package-exports-manifest.test.ts, and the root barrel was the only route to this type.

.changeset/9606-object-kanban-card-title.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

.changeset/9628-kanban-column-collapsed-honoured.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The key was declared on both published faces of the object-kanban arm — the lane element of ObjectKanbanSchema (objectql.ts and its Zod mirror) and the runtime lane KanbanColumn (complex.ts and its mirror) — and read by KanbanEnhanced alone, a module no production source imports. An authored { "id": "todo", "title": "To Do", "collapsed": true } therefore parsed green on both faces and reached a board that did nothing with it: KanbanImpl's only collapse is the SWIMLANE row's, held in viewer state under objectui:kanban-collapsed:ANGLE-BRACKETS(swimlaneField) and never keyed to a lane's declared value. That is the ADR-0049 declared-but-unhonoured shape.

  • names complex.ts → packages/types/src/complex.ts — edited by this change

    The key was declared on both published faces of the object-kanban arm — the lane element of ObjectKanbanSchema (objectql.ts and its Zod mirror) and the runtime lane KanbanColumn (complex.ts and its mirror) — and read by KanbanEnhanced alone, a module no production source imports. An authored { "id": "todo", "title": "To Do", "collapsed": true } therefore parsed green on both faces and reached a board that did nothing with it: KanbanImpl's only collapse is the SWIMLANE row's, held in viewer state under objectui:kanban-collapsed:ANGLE-BRACKETS(swimlaneField) and never keyed to a lane's declared value. That is the ADR-0049 declared-but-unhonoured shape.

.changeset/9722-bulk-executor-datasource-face.md

  • names ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    • ObjectGrid.tsx → RecordDetailPanel: removing it type-checks GREEN. It was paying for nothing — both sides already declare the same DataSource | undefined from @object-ui/types. Removed outright. - ObjectGrid.tsx → BulkActionDialog: removing it reddens, and it was paying for TWO things at once — the optional-vs-required arm (the grid declares dataSource?: DataSource, the dialog demands one) AND the bulk-door contravariance. Only the first still needs erasing, so it is now a non-null assertion: today's runtime behaviour is preserved exactly, and any future drift of the face reddens at that site instead of passing silently.

.changeset/9853-grid-non-positive-page-size.md

  • names ObjectGrid.tsx → packages/plugin-grid/src/ObjectGrid.tsx — edited by this change

    Refuse a non-positive pageSize at all three of ObjectGrid.tsx's read points, instead of giving two different answers for one authored value (objectui#9853).

.changeset/9964-related-list-picker-filter-mirror.md

  • names record-related-list.tsx → packages/plugin-detail/src/renderers/record-related-list.tsx — edited by this change

    So one key carried two declarations, with the looser one on the face an author — or an AI writing metadata — reads: unknown offers no shape guidance for a key whose consumer demands a specific shape. Nothing could report the divergence either, because record-related-list.tsx reached the block through four (schema as any).add reads; a cast unwraps the declaration at its own read site, so no compiler ever compared the two.

.changeset/action-callback-retired-7068.md

  • names ui-action.ts → packages/types/src/ui-action.ts — edited by this change

    Where the live meaning lives. Post-success navigation is the spec's onSuccess block, { navigate, openIn }, declared on UIActionSchema (ui-action.ts) and forwarded to the runner (objectui#5934). A success or failure notice is successMessage / errorMessage — adjacent keys on the same legacy ActionSchema, NOT retired, and still accepted on both faces.

.changeset/action-keys-warning-text-5642.md

  • names ActionRunner.ts → packages/core/src/actions/ActionRunner.ts — edited by this change

    Both halves of the message's tail had outlived the change they described. It told the author the key was warned about rather than rejected because ActionDef "still carries [key: string]: any" — objectstack#4075 step 3 deleted that index signature, and actionKeys.pin.test.ts pins the deletion in the opposite direction ({ ActionDef: false, ActionContext: true }), while actionDef-closed-surface.test.ts pins that tsc now rejects exactly such a key at the construction site. And it prescribed promoting the key to an explicit field on ActionDef "(packages/core/src/actions/actionKeys.ts)" — that file holds the INVENTORY (ACTION_DEF_KEYS); the interface is in ActionRunner.ts. The wrong pointer had teeth: an author who followed it edited the inventory alone, which is precisely the half-change the pin test reddens on, since it re-derives the inventory from the interface's AST.

.changeset/app-shell-page-header-subtitle-4761.md

  • names ObjectDataPage.tsx → packages/app-shell/src/views/ObjectDataPage.tsx — edited by this change

    | gauge | result | |---|---| | exports of dist/index.d.ts, through the TypeScript checker | 226 symbols; PageHeader and PageHeaderComponentProps are not among them (controls: AppShell reachable, a nonsense name not) | | exports map | declares exactly . and ./styles.css | | Node resolving @object-ui/app-shell/layout, …/dist/layout/PageHeader.js, …/src/layout/PageHeader.js | ERR_PACKAGE_PATH_NOT_EXPORTED for all three, while the declared entry resolves | | in-repo call sites | 2, both inside this package (ObjectView.tsx, ObjectDataPage.tsx) | | emitted declarations that change | dist/layout/PageHeader.d.ts only — dist/index.d.ts and dist/layout/index.d.ts are byte-identical across the change (8c886251…, f9f4862b…, both legs) |

.changeset/approver-identities-read-positions-5424.md

  • names packages/auth/src/types.ts → packages/auth/src/types.ts — edited by this change

    The retired spelling is not kept as a fallback — pairing the two is what ADR-0090 D3 forbids, and packages/auth/src/types.ts says so on the declaration.

.changeset/calendar-readme-schema-keys-5045.md

  • names packages/types/src/complex.ts → packages/types/src/complex.ts — edited by this change

    README.md's "Schema API / CalendarView" block described a CalendarViewSchema that does not exist. Measured against the interface itself (packages/types/src/complex.ts) and its zod mirror: events — the schema's only required key besides type — was published as events?, so a reader following the README omits it and TypeScript rejects the node; defaultDate was string where the schema says string | Date; and onDateClick was listed as a schema key when it is a CalendarViewProps component prop, sending readers to a different package's surface for a key calendar-view does not have (the schema's key is onDateChange). The block also listed 6 of the schema's 13 keys with nothing saying it was a summary (objectui#5045).

.changeset/component-meta-converge-and-deprecate-alias-5893.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    @object-ui/types published ComponentMeta twice, from two different declarations: base.ts and plugin-scope.ts (the latter published as PluginComponentMeta). They were structural copies, not an alias pair. plugin-scope.ts' ComponentMeta is now export type { ComponentMeta } from './base.js' — the disposition objectui#4580 ruled for the identical shape, a structural copy would reproduce the defect the moment either side moved, and the same move objectui#5671 made for the sibling type ComponentInput in the same file.

.changeset/componentinput-reexport-4972.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    @object-ui/core's ComponentInput (registry/Registry.ts) and @object-ui/types' plugin-scoped ComponentInput (plugin-scope.ts, published as PluginComponentInput) were structural copies of the interface in @object-ui/types' base.ts. Both are now re-exports of that one declaration, which is the disposition objectui#4580 ruled for the identical shape — a structural copy would reproduce the defect the moment either side moved — and the way core/src/types/index.ts already handles SchemaNode.

.changeset/console-form-field-spec-one-declaration-5542.md

  • names views/metadata-admin/form-spec.ts → packages/app-shell/src/views/metadata-admin/form-spec.ts — edited by this change

    objectui#5040 was not a missing key. It was that two hand-written descriptions of one contract drifted, and nothing could notice, because each was only ever checked against itself. PR metadata-admin: FormFieldSpec declares dependsOn, one declaration for both halves #5537 converged the two app-shell descriptions into views/metadata-admin/form-spec.ts. A third survived in apps/console: FormPage.tsx declared its own nine-key interface FormFieldSpec, under the same name, in a different package — so the same failure mode stayed fully available.

  • names form-spec.ts → packages/app-shell/src/views/metadata-admin/form-spec.ts — edited by this change

    @object-ui/app-shell therefore re-exports FormFieldSpec from its package root (type-only, erased at build — nothing is added to the bundle), and FormPage.tsx imports it and deletes the local declaration. Reachability is the load-bearing half: a type that cannot be imported is a type that gets retyped, and retyped copies drift. form-spec.ts itself is untouched.

.changeset/console-formpage-runtime-default-seed-5727.md

  • names schemaDefaults.ts → packages/plugin-form/src/schemaDefaults.ts — edited by this change

    The seed is now guarded by isRuntimeDefault from @object-ui/core — the same published classifier @object-ui/plugin-form's schemaDefaults.ts guards its seeding with, and the one this renderer already reads once removed (through isServerOwnedValue) for the create-mode required carve-out. A runtime default leaves the key ABSENT rather than empty, because absent is precisely the case the engine resolves.

.changeset/console-formpage-visible-predicates-5594.md

  • names renderers/form/form.tsx → packages/components/src/renderers/form/form.tsx — edited by this change

    objectui#2212 recorded this exact symptom and PR fix(form): evaluate view-level FormField.visibleOn with the canonical CEL engine #2214 fixed it — in a different chain: ModalForm → resolveFormViewLayout → @object-ui/plugin-form sectionFields.ts → @object-ui/components renderers/form/form.tsx. FormPage.tsx is on that chain at no point, and Form-view FormField.visibleOn (CEL) is never evaluated — conditional fields always render #2212's regression pin lives with the chain it fixed, so nothing in the suite could see this copy. One contract, two implementations, each only ever checked against itself.

  • names evaluator/fieldRules.ts → packages/core/src/evaluator/fieldRules.ts — edited by this change

    The wiring is Form-view FormField.visibleOn (CEL) is never evaluated — conditional fields always render #2212's ruling applied verbatim rather than a second predicate semantics invented for this renderer, because two form renderers disagreeing about what visibleWhen means would be a worse defect than one renderer ignoring it. The predicate goes through the canonical engine — evalFieldPredicate (@object-ui/core, evaluator/fieldRules.ts) — so the accepted wire shapes (bare CEL string and { dialect, source }), the bound scope (record.* = the live input values, previous.* = the stored record an edit form started from), and the fail-open-but-loud behaviour on an unevaluable predicate are the shared ones by construction. Resolution is canonical-first, visibleWhen ?? visibleOn, matching both sibling readers: sectionFields.ts and app-shell's readVisibility.

.changeset/default-children-retired-5051.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    If you author plugins against the published register-meta table, drop the key. It is gone from skills/objectui/guides/plugin-development.md, which had been teaching it. A meta that still declares it stays valid: ComponentMetaSchema is a plain z.object, and measured on zod 4.4.3 that STRIPS unknown keys rather than rejecting them — so the key is silently dropped from the parse output instead of failing validation. TypeScript authors get the loud signal instead: all three ComponentMeta declarations (@object-ui/types base.ts and plugin-scope.ts, @object-ui/core Registry.ts) no longer offer it, so re-declaring it is now a compile error.

.changeset/evaluateexpression-jsdoc-links-5580.md

  • names ExpressionEvaluator.ts → packages/core/src/evaluator/ExpressionEvaluator.ts — edited by this change

    ExpressionEvaluator.ts declares two things spelled evaluateExpression: the method on ExpressionEvaluator (bare expression, throws) and the module-level export (context bag, fail-soft, delegating to evaluate). The registerFunction block referred to both under the one spelling, four lines apart.

.changeset/flow-entry-condition-builder.md

  • names flow-scope.ts → packages/app-shell/src/views/metadata-admin/inspectors/flow-scope.ts — edited by this change

    The builder is given the trigger record's own vocabulary — bare field names and previous.ANGLE-BRACKETS(field), resolved by flow-scope.ts — rather than the record-scoped default its five other consumers use, so the subjects it offers are the spelling this surface evaluates and teaches. 15 of the 17 entry conditions shipped in the example apps now open as structured rows; the remaining two mix && with a parenthesised || group, which is a grammar limit of the row model and keeps them on raw mode by design.

.changeset/formfieldspec-dependson-5040.md

  • names views/metadata-admin/form-spec.ts → packages/app-shell/src/views/metadata-admin/form-spec.ts — edited by this change

    No runtime behaviour changes: MetadataField already handed dependsOn through and both widgets already read it. What changes is the type face — it now admits what the runtime has always accepted. The two descriptions are one declaration, extracted to a leaf module (views/metadata-admin/form-spec.ts) that both halves import, because SchemaForm.tsx imports ./widgets.js and a back-edge would close a cycle. SchemaForm.tsx re-exports FormFieldSpec and VisibilityPredicate, so every existing importer is unaffected.

.changeset/host-dispatch-action-keys-5611.md

  • names actions/actionKeys.ts → packages/core/src/actions/actionKeys.ts — edited by this change

    Adds an exported HOST_DISPATCH_ACTION_KEYS (sole member overrideNotice) to actions/actionKeys.ts and unions it into KNOWN_ACTION_KEYS, which is the fourth input to that set and the first one that is not an authored-surface mirror. Measured before and after on the exact dispatch the bar composes: the warning went from one call naming overrideNotice to none, KNOWN_ACTION_KEYS grew by exactly one member, and an action carrying a real typo alongside it still warns — naming targt only.

.changeset/humanize-label-single-home-5444.md

  • names ObjectChart.tsx → packages/plugin-charts/src/ObjectChart.tsx — edited by this change

    humanizeLabel turns a stored value into a display string when nothing else resolves it — an option with no declared label, an object name, a chart axis member. It existed twice, byte for byte: once in @object-ui/fields (read by plugin-grid, plugin-gantt, plugin-detail and by that package's own renderers) and once as a deliberate local copy in plugin-charts' ObjectChart.tsx, whose comment said it was there "to avoid a dependency on @object-ui/fields".

.changeset/i18nlabel-inverted-pin-5612.md

  • names ui-action.ts → packages/types/src/ui-action.ts — edited by this change

    The I18nLabel "inverted pin" now watches the premise it claims to watch, and ui-action.ts no longer imports a symbol it never uses (objectui#5612, objectui#5613).

.changeset/list-user-actions-collision-5398.md

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    The harvest now reads the object block only. Both userActions read sites in ListView.tsx carry a comment naming the collision, and __tests__/ListView.userActionsCollision.test.tsx pins each clause of it: the two shapes, a producer that manufactures the view one, the harvest's blindness to it, and the projection that must keep the object's operand with a toolbar block — or an empty block — present on the view.

.changeset/listview-comment-pair-4559.md

  • names ListView.tsx → packages/plugin-list/src/ListView.tsx — edited by this change

    Two comment corrections in ListView.tsx (objectui#4559, objectui#4966). No runtime behaviour changes and the emitted bundle is byte-identical; the published .d.ts does change, which is why this is a patch rather than an empty frontmatter.

.changeset/object-view-unmirrored-keys-7779.md

  • names packages/plugin-view/src/ObjectView.tsx → packages/plugin-view/src/ObjectView.tsx — edited by this change

    What was measured. Every reading was taken on the object-view node renderer (packages/plugin-view/src/ObjectView.tsx, registered by plugin-view/src/index.tsx) with schema.objectName / schema.layout as the positive controls of the same schema.KEY query, so each zero is a reading; the repo-wide census of viewTabBar finds the key in no source file outside @object-ui/types (two doc tables listed it as authorable and are corrected here). The spec side was read through the installed pin (@objectstack/spec@17.2.0, ui entry, 117 exported object schemas walked; control keys objectName / columns / navigation / listViews hit): the three spec-modelled keys are optional slots on ListViewSchema and ObjectListViewSchema; the six local keys have no spec slot anywhere.

.changeset/objectchart-schema-anchor-7946.md

  • names ObjectChart.tsx → packages/plugin-charts/src/ObjectChart.tsx — edited by this change

    • ObjectChartProps.schema is ObjectChartSchema; the published .d.ts no longer says props: any. ObjectChartProps is exported. - The four keys are declared on BOTH copies, with value types taken from their READ sites (ChartRendererProps for xAxisKey / series, ObjectChart.tsx for filter) rather than copied from any producer's literal — except where @objectstack/spec already owns the shape, which is aggregate: that one is declared BY REFERENCE as ChartAggregate / ChartAggregateSchema, so the authoring door here and at the react-page publish gate are one shape and cannot drift into two dialects. - colors converges: the zod mirror has declared it since objectui#3913 and the TS interface did not, a drift no ratchet could see because a mirror-only key is in neither of the parity guard's two difference ledgers.

.changeset/param-dialog-title-fallback-4282.md

  • names ui-action.ts → packages/types/src/ui-action.ts — edited by this change

    title is declared on no action surface in the ecosystem: it is absent from @objectstack/spec's ActionSchema (44 keys walked at spec 17.0.0), from @object-ui/core's ActionDef and its pinned ACTION_DEF_KEYS / SPEC_ACTION_KEYS inventories, and from @object-ui/types' renderer view (ui-action.ts) and crud.ts ActionSchema / BaseSchema. None of the four action renderers — action:button, action:icon, action:group, action:menu — forwards it either. So the right-hand side of that || could not be reached by authored metadata: a fallback that cannot fire, which is the "declared is not enforced" shape objectstack#4075 exists to reduce. Nothing a user hits changes; the line now reads exactly one key, matching the description line directly below it.

.changeset/paramtofield-reference-rule-derives-from-core-5312.md

.changeset/plugin-component-input-deprecate-5674.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    @object-ui/types' entry point publishes ComponentInput as PluginComponentInput. Until objectui#4972 that alias pointed at a genuinely different declaration: plugin-scope.ts restated its own nine-key ComponentInput. objectui#5671 converged that declaration onto base.ts, so the alias became a second published name for the same type, carrying no information the first does not. Two published names for one type is a shape that costs readers a step and gives AI-authored code a coin-flip between spellings.

.changeset/plugin-detail-8937-parent-scope-residue.md

  • names RelatedList.tsx → packages/plugin-detail/src/RelatedList.tsx — edited by this change

    • packages/plugin-detail/README.md (it is in files[], so it ships). It said the node's filter is AND-combined with { [relationshipField]: parentId }, full stop. Since objectui#7299 the parent condition is compiled to match the relationship field's arity, so a multi-valued relationship gets { [relationshipField]: { $contains: parentId } } instead. The paragraph now states both spellings and names the arbiter (@objectstack/spec/data's isMultiValueField). - The claim that the SQL driver decides arity on that same predicate. It does not: driver-sql gates the equality family on its own storage question, which reads multiple as truthy on ANY type. The two rules therefore disagree for a type outside MULTI_CAPABLE_TYPES carrying multiple: true. objectui#9184 moved the arity compiler into @object-ui/core's parent-scope seam and carried the claim with it, so the correction is recorded there — the seam now states the driver's measured rule, records the divergence as a divergence, and points at the upstream card that owns which of the two rules is right (objectstack#17469). RelatedList.tsx's pointer comment and the objectui#7299 test header carried the same sentence and are corrected to match.

.changeset/plugin-form-readme-classname-quantifier-5131.md

  • names packages/components/src/renderers/form/form.tsx → packages/components/src/renderers/form/form.tsx — edited by this change

    README.md's "Not a FormField key" table said a field-level className is "read on exactly one pseudo-field, type: 'section-divider'". That quantifier holds only for the renderer's explicit read — className={fp.className} on the section-divider branch of packages/components/src/renderers/form/form.tsx. The same renderer forwards every key it did not destructure, and className is not among the names taken off the field config, not among the ones stripRendererOnlyProps removes, and so rides {...fieldProps} into renderFieldComponent, whose built-in input branch spreads it onto ANGLE-BRACKETS(Input). A field-level className therefore lands visibly on ordinary built-in controls, and a reader taking "exactly one" literally concludes the opposite of what the code does (objectui#5131).

.changeset/publish-envelope-one-spelling-6962.md

  • names metadata-client.ts → packages/data-objectstack/src/metadata-client.ts — edited by this change

    The two methods sit ~250 lines apart in metadata-client.ts and both POST /api/v1/meta/:type/:name/publish. publishDraft tolerated a dispatcher-shaped envelope and returned the inner object; publish returned the body as parsed. Nothing said which was right, and the card explicitly refused to settle it from PublishMetaItemResponseSchema alone — an inference from a declaration is not a measurement of the server.

.changeset/record-alert-cta-label-i18n-4998.md

.changeset/record-detail-param-dialog-title-5610.md

  • names ui-action.ts → packages/types/src/ui-action.ts — edited by this change

    title is declared on no action surface in the ecosystem: it is absent from @objectstack/spec's ActionSchema (44 keys walked at spec 17.0.0), from @object-ui/core's ActionDef and its pinned ACTION_DEF_KEYS / SPEC_ACTION_KEYS inventories, and from @object-ui/types' renderer view (ui-action.ts) and crud.ts ActionSchema / BaseSchema. None of the four action renderers — action:button, action:icon, action:group, action:menu — forwards it either. So the right-hand side of that || could not be reached by authored metadata: a fallback that cannot fire, which is the "declared is not enforced" shape objectstack#4075 exists to reduce. Nothing a user hits changes; the line now reads exactly one key, matching the description line directly below it.

.changeset/record-picker-label-placeholder-i18n-5637.md

  • names renderers/layout/containers.tsx → packages/components/src/renderers/layout/containers.tsx — edited by this change

    KNOWN GAP, unchanged by this release: the sibling label read sites in renderers/layout/containers.tsx compose translateLabel(pickLocalized(…), language), and that second helper is not applied here — translateLabel and its KNOWN_LABEL_DICT are module-private to that file. Only the locale-map resolution lands in this change; a plain-English string label is still rendered verbatim in every language, exactly as before.

.changeset/retire-components-action-param-dialog-5685.md

  • names src/views/ActionParamDialog.tsx → packages/app-shell/src/views/ActionParamDialog.tsx — edited by this change

    • import { ActionParamDialog } from '@object-ui/components' — no drop-in replacement is published. The surviving implementation is @object-ui/app-shell's ActionParamDialog (src/views/ActionParamDialog.tsx), rendered by app-shell's action runtime (useConsoleActionRuntime, RecordDetailView) rather than exported standalone. A host that needs its own param form builds on @object-ui/fields' shared field widgets (resolveFormWidgetType / getLazyFieldWidget, ADR-0059) — the same seam the surviving dialog renders through.

.changeset/text-input-description-aria-describedby-5735.md

  • names renderers/form/form.tsx → packages/components/src/renderers/form/form.tsx — edited by this change

    Before this the paragraph and the input were siblings with no programmatic relationship: a screen reader moving to the field announced the label and the value and never the helper text. The label half of the same block was already wired (htmlFor against the input's id), which is what made the gap specific to description rather than a general absence of a11y wiring — and the identical key authored on a field INSIDE renderers/form/form.tsx has been announced all along, so one authoring key behaved two ways depending on which container the author reached for. It no longer does.

.changeset/theme-clientvalidation-dead-entry-5715.md

  • names clientValidation.ts → packages/app-shell/src/views/metadata-admin/clientValidation.ts — edited by this change

    Removed the dead theme: entry from clientValidation.ts's LOADERS table, which read ThemeSchema off @objectstack/spec/ui — a symbol the spec retired upstream (objectstack 35ad101bc, which deleted the whole ui/theme.zod.ts module). theme was never a registered metadata type, so metadata-admin never asked for it (objectui#5715).

.changeset/uniqueness-deprecation-jsdoc-4765.md

  • names packages/types/src/data-protocol.ts → packages/types/src/data-protocol.ts — edited by this change

    Corrects the @deprecated prescription on UniquenessValidation in packages/types/src/data-protocol.ts, which pointed authors at spellings the platform no longer accepts (objectui#4765).

.changeset/zod-base-schema-mirror-parity-4605.md

  • names base.ts → packages/types/src/base.ts — edited by this change

    The new pin is DERIVED rather than a hand-written key list: it reads the mirror's own .shape and compares each key against the declaration, so the next widening of base.ts that forgets this file turns it red with no list to maintain. It reads .shape and not keyof z.inputANGLE-BRACKETS(…) because that spelling was measured vacuous — .passthrough() collapses the inferred key union to bare string, and a pin written over it resolved never while five keys were demonstrably narrow. Two guards pin the derivation against both degenerations (never and string).

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with 2eaf5be27 (merge-base with origin/main): 144 file(s) changed outside .changeset/, read against 1713 pending declaration(s) that publish a body (2314 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3105.5 KB 3149.4 KB
Main entry chunk (gzip) 149.4 KB 350 KB
Entry file index-9YsDjpB2.js —
Status PASS —

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


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.72KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.92KB 133.97KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.02KB 14.87KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.56KB 36.67KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.49KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 163.08KB 42.10KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.59KB 22.47KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

…ectui's is objectstack's

Two PackageFormDialog.tsx comments and the pending violet-donkeys-brake
changeset cite the generic-substitution card under this repository's name.
In objectui that number is the check-i18n-en-drift script pull request; the
card meant is objectstack-ai/objectstack#3821, the sharing-rule dialog card
whose objectui repair (objectui#2920) introduced the substitution. The two
comments now name it; the pending entry gets a dated note in this change's
form, with its frontmatter byte-identical. The test file's doc comment stays:
tests are outside the class.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3105.5 KB 3149.4 KB
Main entry chunk (gzip) 149.4 KB 350 KB
Entry file index-9YsDjpB2.js —
Status PASS —

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


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.72KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 558.92KB 133.97KB
core (index.js) 9.94KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.99KB 63.22KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.58KB 4.90KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.25KB 2.17KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 52.02KB 14.87KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 137.56KB 36.67KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.49KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 163.08KB 42.10KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.07KB 9.15KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.59KB 22.47KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.26KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.30KB 6.99KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

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

Inputs: card objectui#11016 (body and all five comments: triage 5876435318, claim 5882822760, os-dev-reports 5883390493 and 5883448045, amendment 5883408510), PR objectui#11041 (body, 155-file list, net diff against main 2eaf5be27), and the 43 check-runs on the head with filter=latest: 40 success, 3 skipped (the two coverage matrix rows and dependabot). Context reads over REST only: both repositories' titles for every number the diff qualifies, the base text of the ten noted pending entries, objectui#2920 and its commit 53642d4fe, objectstack commit 79c46da90, and five objectui titles the diff leaves bare.

① Derived judgments

  • Shape of the change — right. 144 non-test packages/*/src files across 24 packages and 11 .changeset/*.md (1 new, 10 pending); no test file touched. 341 changed source lines = 337 comment lines + the 2 runtime-string lines + the 2 round-1 PackageFormDialog.tsx lines, matching the body's counts; the only file whose line count moves is apiErrorEnvelope.ts (+4 lines of docblock prose). Every source hunk I read is a comment except the two declared string literals, so the C4 claim (142 identical comment-stripped prints, 2 differing) is consistent with the diff.
  • Public surface that moves — two string values, both right. @object-ui/core RETIRED_ACTION_KEYS.execute: only (#3855) becomes (objectstack-ai/objectstack#3855); the rest of the message, including "rename the key to target", is byte-identical. Qualified rather than dropped is right: objectstack 3855 is live ("[P3] Retire the three deprecated aliases"), triage item 1 asked for the qualified form, and ruling 5860244997 Q1 = A covers dead cards only. @object-ui/app-shell default-schemas.ts triggerConditions.description: (#1878/#1895) becomes both qualified; objectstack 1878 (metadata property liveness audit) and 1895 ("Designer authoring gaps (live prop, no Studio editor)") fit "previously only hand-editable", while objectui 1878/1895 are a console-ai fix and a dependency bump. The value sits in a Record typed unknown, so no type moves. No key, accept set, refusal decision or code path moves anywhere else.
  • Census verdicts — sampled by me, right in every sampled site. All 105 distinct numbers the diff writes as objectstack-ai/objectstack#N were fetched from both repositories (210 GETs): every one answers 200 in both, and the objectstack titles match the body's table independently. Sentence read against both titles for 22 numbers over some 40 sites, among them 1319 (language switch needs a page refresh), 3371 (command palette record hits), 7233 (bell badge sums; objectui 7233 is the open PM handover), 2604 (create/edit surface), 4829 (app hidden flag), 3447 (runtime-resolved approvers), 3508 (approver lookup), 1885 (disabled CEL ignored), 2169 (Mark Done handler), 5149 (predicates fail open), 2212 (findData pagination), 3165 (state_machine on INSERT), 7137 (timeline read sites), 5021 (theme CSS variables), 8270 (manage_metadata), 6776/7034 (PageHeader props), 8955 (relatedListFilter), 4709 (homePageId premise): the objectstack title fits the sentence and the objectui title does not, in each.
  • Numbers left bare beside a requalified one — right. 6305 in ObjectCalendar.tsx/ObjectKanban.tsx is objectui's "drop the deprecated width from the drawer default"; PR 4236 in the render-publish entry is objectui's "render the runtime authoring gate's advisory findings after a save"; objectui #2693, objectui#3287, objectui#3320 each fit their sentence; 2212 stays bare in form.tsx where it means objectui's visibleOn card, the split the body describes.
  • The quoted (#3821) and triage item 4 — the dev's correction is right. objectstack's own 79c46da90 writes "keep their generic substitution (fix(scripts): check-i18n-en-drift 的显式 base 提为权威,解析不出即失败 (#3766) #3821) for anything unmarked" and "the console's fix(scripts): check-i18n-en-drift 的显式 base 提为权威,解析不出即失败 (#3766) #3821 generic substitution": the writer's bare number names objectstack's card, so [objectstack-ai/objectstack#3821] inside the quote is the faithful substitution. Triage's premise that neither 3821 is the card is falsified as reported: objectui#2920 (commit 53642d4fe, titled "(objectstack#3821)") is where a refused write's verbatim error.message first became localized copy, the generic substitution itself. The four added docblock lines say exactly that, and the three "holds by construction" siblings in form.tsx, ObjectCalendar.tsx, ObjectKanban.tsx mean the same card. The other bracketed quotations (5240 twice, 4075, 4115) follow the same rule.
  • Pending-changeset notes — right, frontmatter untouched by construction. All ten hunks are pure insertions starting after the frontmatter (base lines 16, 32, 47, 38, 9, 27, 12, 14, 10, 6). Each note sits after the paragraph it reads and names the right card, checked against the base text: 4664 ("PR test(console): pin the four object-metric query members (objectui#8071 slice 8) #8955" beside objectstack#8704), 6956 ("pre-test(scripts): check-shell-escape-residue reds on an agent-tree document no scan root reaches (#7413) #8010"), 7122 (the "#7496 family" and the quoted 17.2.0 spelling, while its own #7122 stays bare), 9137 ("objectstack#5473 and chore(deps): bump @sentry/react from 10.56.0 to 10.57.0 #1752"), dashboard-aria ("AiChatPage 发给 agent 的四条确认文本仍按 UI 语言取值:zh 控制台 + 英文会话把「确认,开始搭建。」发进英文线程,planAnswerMessage 更是完全没有会话语言门控 #3896 audit close-out"), designer-publish ("#9612's"), gantt and kanban (the quoted @deprecated tag for 2578), render-publish ("since test(data-objectstack): re-point v3-compat's vacuous PaginatedResult block at real ObjectStackAdapter.find() #4717"), violet-donkeys-brake ("ADR-0112 / objectui#3821"). Three of the ten (7122, gantt, kanban) have empty frontmatter, so those notes are inert for release text; harmless, and within triage direction 3 as written.
  • Round-1 fold-in (amendment 5883408510) — right. The two PackageFormDialog.tsx objectui#3821 comments now read objectstack-ai/objectstack#3821; the entry's note is in the same form as the other nine; the test file's doc comment is untouched as the amendment excludes it. The file's two bare 8270 lines are qualified in the same pass (objectstack 8270 is the manage_metadata finding).
  • Gates. The head's check-runs answer every derived gate family: Lint, Type Check, Test shards 1 to 8, Test (dist pins), Build & E2E, Changeset Declaration / Bump Policy / Fixed Group Check / Claim Re-read / Overwrite Report, Control Byte Scan, Line Citation Gate, Governed Surface Queue Guard, Internal Docs Link Check, all success. The two U+FFFD characters in the body's table are the relay corruption the seat named (objectstack#20571); the diff carries no such byte.

② Semver level

  • .changeset/11016-cross-repo-bare-citations.md: patch for @object-ui/core and @object-ui/app-shell. Right. The diff publishes exactly two changed string values, a dev-warning message and a Studio help-text description, with no key, type, accept set or code path moving; patch is the level for a user-visible text change. The other 22 packages change comments only and version with the fixed group (Changeset Fixed Group Check, Bump Policy and Declaration all success). Not skip-changeset, rightly, because runtime text moves.
  • The ten dated notes add release prose to pending entries and leave every frontmatter byte-identical, so no other package's level moves.
  • Clause-②: no — right. Pointers in prose, comments and one refusal message move to the repository they mean; no accept set widens or narrows.

③ Boundary flags

  • open_questions: [] in both reports. Nothing to answer.
  • Deviation 1, the held ObjectGrid.tsx pagination comment (2212, meaning objectstack's findData card): objectui#10278 inserts directly beneath it, and qualifying it grew the merge-tree conflict markers from 2 to 3, so it was reverted (5d8eefd71). Answered: the claim's serial rule allows a census edit only outside the other PR's hunks, so holding is the claim-compliant outcome, not a breach, and it is recorded in the body's Held section and Acceptance note 4. Escalated to the seat, as an acceptance note and not a blocker: this PR closes the card with one in-class site still bare and no carrier named; carry that line at objectui#10278's ACCEPT or close.
  • Deviation 2, type-check run for @object-ui/core only: answered by the head's Type Check check-run (success) and the eight test shards.
  • Deviations 3 and 4, commit-trailer form and a pre-push amend of the first commit message: process only, no bearing on the diff; no pushed history was rewritten. Answered.
  • Triage item 4's premise: falsified with evidence and corrected in place, naming what the number means, which is what item 4 asked for. Answered (see ①).
  • Out-of-scope findings: finding 1 of report 5883390493 was folded in by amendment 5883408510 and is in the diff. Findings 2 (ten numbers meaning neither repository; objectstack-ai/cloud answers 403 through the proxy, so NOT MEASURED), 3 (294 framework#N citations, qualified by the former name), 4 (tests' own bare citations NOT MEASURED, plus the two leftovers the card itself names: apps/console 9934 and the recordDetailsInputs test doc comment), and round 1's finding (the PackageFormDialog test doc comment's objectui#3821) are recorded in the PR's Acceptance notes with carrier none. Consistent with triage's scope (non-test packages/*/src and pending changesets); whether the framework#N family or the test population gets a card is triage's call, and the Acceptance notes give it the measurements.

Implemented-by: claude/issue-11016-cross-repo-bare-citations
Reviewed-by: session_011p7ikEivgXefNDaE5S5Uec

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 29, 2026 04:29
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 29, 2026
Merged via the queue into main with commit 63ab761 Sep 29, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11016-cross-repo-bare-citations branch September 29, 2026 04:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment