Skip to content

feat(types,plugin-kanban,sdui-parser)!: retire quickAdd on object-kanban and stop forwarding it (objectui#8285) - #11231

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-8285-object-kanban-quickadd-retire
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-8285-object-kanban-quickadd-retire

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #8285
Clause-②: yes

objectui's half of ruling B (director seat, decision batch #91, comment 5583979207): "The board does not grow an inline record-creation write path", object-kanban.quickAdd is retired, and objectui stops forwarding it. @objectstack/spec 17.5.0 (installed since objectui#11086) already carries the spec half as a retiredKey(...) tombstone. The Clause-②: yes line is copied from the claim (comment 5912959131): the published @object-ui/types face narrows, and the inert-quick-add code leaves @object-ui/sdui-parser's diagnostic payload.

What changed

  • @object-ui/types: ObjectKanbanSchema.quickAdd is now ?: never (TypeScript face) and retirementTombstone(...) (zod mirror). An authored value is refused BY NAME (invalid_type at quickAdd, with the remedy), not stripped. I used the existing tombstone helper; no new helper. The onQuickAdd docblock is rewritten because this change made its old wording false. See the open question below.
  • @object-ui/plugin-kanban: ObjectKanban stops forwarding quickAdd. Its effectiveSchema now carries quickAdd: undefined. KanbanRenderer is byte-identical. The OBJECT_KANBAN_INPUTS docblock now records the retirement instead of the "PREMATURE" carve-out.
  • @object-ui/sdui-parser: I deleted the interim kanban-quick-add.ts module, its wiring in validate.ts and its four barrel exports. The references to the deleted symbol in body-dialect.ts and its test are removed too.
  • Pins: I rewrote the tripwire, renamed quickAddIsDiagnosedNotDropped-8285.test.ts to quickAddRetiredNotForwarded-8285.test.tsx. I rewrote kanban-quick-add-8285.test.ts for the new state and added object-kanban-quick-add-retired-8285.test.ts. The 8801 and 8802 pins used quickAdd: true as a "live member" control, so it is removed from those lists.
  • Docs: content/docs/plugins/plugin-kanban.mdx and content/docs/api/schema-reference.md. Both passages said the key "still parses" and that the tier answers inert-quick-add, and both are false after this change. Only prose changed; no fenced block moved.
  • Changeset: .changeset/8285-object-kanban-quick-add-retired.md, minor ×3 with BREAKING wording and a migration section. Per objectui's version rule, a breaking change is minor, never major.

The premises, measured (dispatch Zone 2)

  1. Spec tombstone: confirmed. In the worktree's node_modules/@objectstack/spec (17.5.0), ComponentPropsMap['object-kanban'].quickAdd is a retiredKey(...). Parsing { objectName, quickAdd: true } gives success=false with one issue: code=invalid_type, path=["quickAdd"], keys=undefined, and a message that starts "object-kanban property quickAdd was removed in @objectstack/spec 17 (ADR-0049)". quickAdd: false is refused the same way. Controls on the same call: bogusProp gives unrecognized_keys with keys=["bogusProp"], and { objectName } alone gives success=true.
  2. Why the tripwire stayed green: the helper read one issue shape only. The old refusedByName collected issue.keys. zod fills keys only on unrecognized_keys. A tombstone declares the key as never, so its refusal is invalid_type at the key's path with no keys. The helper therefore returned [] whether the spec published the key or retired it. The row's bogusProp control is an unrecognized_keys issue, so it could not fail for the reason the row was meant to catch. On the base commit, the two 8285 files ran 18/18 green with the key already retired. The new refusedByName reads both shapes and has a control for each.
  3. Tags: one, not two. object-kanban is the only ComponentRegistry.register(...) call for ObjectKanbanRenderer. kanban retired with objectui#8802 and kanban-ui with objectui#8257, and both read has() === false in the new row 5. kanban-ui's Quick Add pair now lives on the exported KanbanRenderer component, and ObjectKanban also renders that component. So I cut the key upstream, in ObjectKanban, where the schema that KanbanRenderer reads is built. Every object-kanban entry point goes through ObjectKanban: the tag, the published kanbanComponents['object-kanban'] map and a host mounting ObjectKanban directly. Cutting only in ObjectKanbanRenderer, the file the claim names, would have missed the map. The tombstone text names KanbanRenderer, not a kanban-ui tag, because a document naming that tag is now an unknown-component error.
  4. Zod member: done with the neighbours' construct. retirementTombstone() is what the groupField and allowCollapse members next to it use.
  5. Html tier: I deleted the interim diagnostic. The same validateTree probe over an object-kanban manifest gives, with the module: quickAdd=true produces warning / inert-quick-add, and quickAdd=false falls through to warning / unknown-prop ("has no prop quickAdd"). Without it, both produce warning / unknown-prop, and compile() stays ok=true. That message is now true on every face: the spec, both @object-ui/types faces, the registry inputs and the renderer. On this tier it is also the whole remedy, because a constrained-JSX page cannot write the handler, so deleting the key is the only edit open to its author. The retired body dialect keeps its own replacement diagnostic for a different reason: it has a replacement spelling (children) to name. quickAdd has none. Severity is unchanged (warning), so no page that saves today stops saving.

Measurements

All runs are at head 5218c1fa1a (this branch with main merged at dded788ada), and heavy ones went through the shared verify lock. Exit codes were captured before any pipe.

  • Build: turbo run build --filter='@object-ui/plugin-kanban^...' --concurrency=2, 12/12 tasks successful. This includes @object-ui/sdui-parser's own check-dist-completeness.
  • Type-check: pnpm --filter X type-check gives exit 0 for @object-ui/types, @object-ui/plugin-kanban and @object-ui/sdui-parser. All three new or rewritten test files are in the tsconfig.test.json programs (--listFiles, 1 hit each), so the type-level pins really run.
  • Tests: pnpm exec vitest run packages/plugin-kanban/ packages/sdui-parser/ packages/types/, plus a 16-file sweep. The sweep is the console registry↔spec ledger, public-contract, the handler-key and doc-type script tests, the schema-catalog corpora, and the cli validate, app-shell block-config, plugin-view and plugin-list consumers of the object-kanban arm, and the doc readers. Result: 391 files, 8375 tests passed, VERDICT command-exit 0.
  • Gates, all exit 0: check-changeset-presence (15 source files of 3 released packages, 1 changeset), check-changeset-no-major, check:control-bytes, check:handler-key-reads, check:new-line-citations, check:phantom-deps, check:unused-deps, check:doc-types, check:doc-fences, check:changeset-claims, check:pending-changeset-literals, check:test-path-roots, check:unreferenced-sources, check:self-import, check:spec-symbols, check:installed-pin-claims, check:component-surface-parity, check:designer-field-key-parity. The governed-surface guard says NOT GOVERNED.
  • ESLint, narrowed and declared: the 13 changed TS/TSX files, 0 errors. The population is the config's own **/*.{ts,tsx} blocks, and the count of 13 comes from --format json. The config enables no type-aware linting (no parserOptions.project, no projectService), so this diff cannot move the verdict on any file it does not touch. Warnings on the four edited source files are identical to base, 31/23/34/1.
  • NOT MEASURED: check:doc-snippets and check:doc-examples exit 2 (PRECONDITION NOT MET, they need a broad build), but no fenced line changed in the docs diff (0 lines). check:sdui-registration-pins and check:readme-exports need console and whole-tree builds and were not run. This diff adds or changes no registration, and no README names the four removed exports.

Ablations, each done through ablation-replace.mjs with an on-disk anchor count and blob-hash proof, and restored to blob == HEAD with an empty git diff HEAD:

  • Remove the quickAdd: undefined cut. The renderer pin's row 1 goes red (expected [ button …, … ] to have a length of +0 but got 2, one control per lane). The other 4 rows stay green, row 2 included. That row is the control: the same query finds the host pair's control.
  • Turn the zod tombstone back into a boolean. 3 rows go red (both refusal rows, and the describe-channel row) and 3 stay green (still declared, near miss, bare node), as predicted.
  • Type reverse check. A quickAdd: true literal typed ObjectKanbanSchema, planted in @object-ui/plugin-kanban against the rebuilt @object-ui/types dist, fails with TS2322: Type 'true' is not assignable to type 'undefined'. My first attempt was a no-op that the tool refused: the replacement contained the anchor, so the count did not drop and tsc never ran. I re-anchored it and ran it again.

Open question: onQuickAdd on object-kanban (not settled here)

With quickAdd retired and no longer forwarded, ObjectKanbanSchema.onQuickAdd still reaches the board by identity; the handlerKeyDispositionsMeasured-7804 and kanban-handler-slots-7664 pins still hold. But the board never calls it, because the control needs both halves. Retiring it too would need a ?: never tombstone and a 'retired' disposition. check:handler-key-reads refuses that while a renderer still reads the key off the document, and its static walk reaches KanbanRenderer's schema.onQuickAdd read through ObjectKanban. So the read on the ObjectKanban path would first have to move off KanbanRenderer's schema, without changing the host pair. The ruling names quickAdd only, so I left the slot as it is and wrote the question into the card report.

Cross-repo consequence (not filed)

objectstack keeps its own copy of this parser, and its objectui-lockstep.json still lists inert-quick-add, recorded against objectui db11afd4967c. At objectstack's next .objectui-sha bump, check:sdui-lockstep will name that code as present on one side only, and their copy should drop it the same way. That is the lockstep working as designed, so I have noted it rather than filed it.

Acceptance notes

  • index.tsx's OBJECT_KANBAN_INPUTS docblock still says "both ObjectKanbanRenderer tags" in its heading. That has been stale since objectui#8802 and this change does not touch it. Noted, not fixed.

Generated by Claude Code

…anban and stop forwarding it (objectui#8285)

Ruling B (decision batch #91): the board does not grow an inline
record-creation write path. `@objectstack/spec` 17.5.0 already tombstones
`ComponentPropsMap['object-kanban'].quickAdd`; this is objectui's half.

- types: `ObjectKanbanSchema.quickAdd` is `?: never` on the TS face and a
  `retirementTombstone()` on the zod mirror, refused by name.
- plugin-kanban: `ObjectKanban` no longer forwards `quickAdd` to the board,
  on every object-kanban entry point. `KanbanRenderer` keeps the pair for a
  React host that mounts it directly.
- sdui-parser: the interim `inert-quick-add` diagnostic and its four exports
  are removed; the tier's own `unknown-prop` is accurate now that every face
  refuses the key.
- The tripwire that stayed green after the spec retirement is rewritten: its
  helper read only `issue.keys`, which zod fills on `unrecognized_keys`
  issues, and a tombstone reports `invalid_type` at the key's path.

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

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 56 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/10872-container-children-channel.md

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

    Also in this change, with no behaviour change: objectql.zod.ts's two public-block arms (object-metric, object-master-detail-form) build their properties member with the same propsBag helper as the other public-block arms, instead of a byte copy of it. The member's description text is unchanged.

.changeset/11068-grid-declared-keys.md

  • names schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was wrong. ObjectGridSchema declared eight keys the grid never read. An author who wrote description, emptyState, name, placeholder, rowSpecActions or bulkSpecActions on an object-grid got no type error, no validator refusal and no effect. The reference example in schema-reference.md taught description and showFilters as if they worked. It now authors only keys the grid reads.

.changeset/3917-retire-action-condition-branch.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    • ActionCondition is removed from @object-ui/types (and from the barrel export). - ActionSchema.condition is retyped to the predicate the runtime actually honours: boolean | string | { dialect?: string; source: string } — the same three arms ActionRunner's own ActionDef.condition carries, and the same vocabulary visible and disabled use. - ActionConditionSchema is removed from @object-ui/types/zod (and from the zod barrel); the condition key now validates against that predicate union. - The two teaching sites (content/docs/core/enhanced-actions.mdx Conditional Execution, content/docs/api/schema-reference.md ActionSchema table) are rewritten to the live vocabulary: condition is a gate; a branch is expressed as separate actions with mutually exclusive conditions.

.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 packages/sdui-parser/src/index.ts → packages/sdui-parser/src/index.ts — edited by this change

    The write was measured as a no-op before it was deleted, and re-measured on this branch's base rather than inherited from the card. A structural census over every inputs: array in the repository (211 regions, all tracked TS/TSX/JS sources) scores inputType at exactly ONE authoring site — the plugin-markdown registration — against name 953, type 969, label 966, description 194, enum 119, required 86 and binding 4 in the same pass over the same regions, so the instrument was not blind. The other 192 in-repo inputType hits are a DIFFERENT face: FormField.inputType (zod/form.zod.ts), the text-input renderer's prop, and SchemaBuilder.inputType, none of which sit on a ComponentInput. The publication path is unchanged and was re-confirmed: packages/sdui-parser/src/index.ts forwards exactly seven keys per input — name, type, of, required, enum, binding, description — so an authored inputType could not reach the published sdui.manifest.json even in principle.

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

  • names packages/sdui-parser/src/index.ts → packages/sdui-parser/src/index.ts — edited by this change

    All four were declared on ComponentInput and read by nothing, on either path. No consumer reads them off a ComponentInput value, and the manifest serializer (packages/sdui-parser/src/index.ts) forwards exactly seven keys per input — name, type, of, required, enum, binding, description — so a value authored here could not reach the published sdui.manifest.json even in principle. Re-measured on this branch's merge-base rather than inherited from the card: a structural census over every inputs: array in the repository (219 regions, all tracked files) scores min 0, max 0, step 0 and placeholder 0, against name 926, type 926, description 161, enum 114 and required 87 in the same pass over the same regions — the instrument was not blind.

.changeset/6152-object-form-unmirrored-members.md

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

    ObjectFormSchema in @object-ui/types (objectql.ts) declared a set of members that its zod mirror in @object-ui/types/zod had never heard of. Every one of them is read by the object-form renderer (ObjectForm in @object-ui/plugin-form). The two published faces answered differently:

.changeset/6170-retire-timeline-dead-keys.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Also in this change: the in-repo example packages/types/examples/data-display-examples.json (its timeline node authored all three) is migrated to items / variant; the two content/docs/api/schema-reference.md snippets that authored events: [] now author items: []; and the plugin-timeline docs callout says retired rather than deprecated.

.changeset/6896-retire-chart-inline-data.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ One correction to the record the ruling rests on. The ruling states zero authorship of a populated series[].data outside tests across packages/ / apps/ / examples/. The re-measurement finds one such site inside those roots — packages/types/examples/data-display-examples.json (2 series) — plus four outside them, in documentation: content/docs/api/schema-reference.md (3) and content/docs/core/report-schema.mdx (1).

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

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — 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/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/6951-tree-view-data-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What was measured, on this branch's base. TreeViewSchema declared two spellings for its one inline-nodes slot — nodes (read second) and data (read third: boundData || schema.nodes || schema.data || [] at renderers/data-display/tree-view.tsx:105), both declared by objectui#6150. data had been REQUIRED until 777e5c6f4 (PR fix(types): tree-view mirror stops requiring the limb it reads third (group 2 of objectui#6939) #7533) made it optional, so this retirement starts from a declared-and-optional member on both faces. The in-repo corpus at the retirement: seven tree-view nodes under examples/schema-catalog and packages/types/examples plus one content/docs fence — six on nodes, two on data (packages/types/examples/data-display-examples.json and content/docs/api/schema-reference.md), both rewritten; no package source authored either spelling.

.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/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/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/sdui-parser/src/index.ts → packages/sdui-parser/src/index.ts — edited by this change

    No manifest ever published them, so no consumer could ever have read them. sdui-parser's serializer (packages/sdui-parser/src/index.ts) forwards exactly seven keys per input — name, type, of, required, enum, binding, description — so a value authored under any of the three never reached sdui.manifest.json, the generated JSX .d.ts, or a diagnostic; its boundary type has no slot for them; the registry's data-source seam reads name only; and neither the designer nor the app-shell inspectors consult registry inputs at all. A structural census over every inputs: array in the repository (re-measured on this change's merge-base, name 951 and type 951 as the controls) counted the writes: label 908, defaultValue 245, advanced 9 — written on nearly every registration, read by nothing.

.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/7664-kanban-arm-plugin-dialect.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Migration. Author boards in the plugin dialect — objectName + groupBy for an object-bound board, or columns[].cards[] with badges for a static one. Replace DeclarativeKanbanSchema imports with KanbanSchema (from @object-ui/types, or the Zod KanbanSchema from @object-ui/types/zod; @object-ui/plugin-kanban re-exports the same KanbanSchema type). Delete draggable (drag-and-drop is always on) and column color (style a lane through className). content/docs/api/schema-reference.md's kanban section now documents this dialect.

.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.

.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.

.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.

.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/7997-detail-view-related-retired.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Documentation. packages/plugin-detail/README.md and content/docs/api/schema-reference.md stop teaching the retired array and gain a migration block each.

.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.

.changeset/8268-testid-emitted-as-data-testid.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    The other direction — retiring the promise — was considered and declined. It is what c1fe272ad did for BaseSchema.hidden, but that key had a working behaviour to describe and zero named consumers, and the ruling's decline turned on exactly that. This promise already has carriers outside the type declaration: content/docs/api/schema-reference.md states it as a table row and authors testId in that page's own base-schema example, @object-ui/cli's OBJECTUI_STRUCTURAL_KEYS identifies a file as an ObjectUI schema node by this key, at this change ObjectGridSlotKey / ObjectFormSlotKey pin it, SchemaBuilder.testId() writes it, and ADR-0054 C4 — shipped — reads "the renderer emits data-testid … derived from metadata".

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

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

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — 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/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.
  • names object-kanban-allow-collapse-retired-8801.test.ts → packages/types/src/__tests__/object-kanban-allow-collapse-retired-8801.test.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 bare-kanban-node-key-retired-8802.test.ts → packages/types/src/__tests__/bare-kanban-node-key-retired-8802.test.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 content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — 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 content/docs/plugins/plugin-kanban.mdx → content/docs/plugins/plugin-kanban.mdx — edited by this change

    The diagnostic's remedy text moves from a tag to a component. It used to end "render ANGLE-BRACKETS(kanban-ui) from a React host that passes onQuickAdd". That sentence is falsified by this change: kanban-ui is no longer a node type key, so a page written to the old advice draws unknown-component. It now names KanbanRenderer from @object-ui/plugin-kanban — still exported, still forwarding both halves by identity — which is the surviving way to get the pair. content/docs/plugins/plugin-kanban.mdx says the same thing the same way.

.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/8885-object-chart-drilldown-title-compareto.md

  • 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 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/9187-record-highlights-layout-two-values.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    ⚠️ The census behind this narrowing covers this repository only, and it found no in-repo authoring to migrate: every in-tree layout: 'grid' belongs to a different component (detail-view in content/docs/api/schema-reference.md and phase2-schemas.test.ts, ai-recommendations in packages/plugin-ai/README.md), and the one in-repo consumer of this interface that writes a layout (p1-spec-alignment.test.ts) writes 'horizontal'. So no document in this repository stops type-checking. A TypeScript consumer outside this repo that wrote grid is not observable from here and gets a compile error (TS2322) naming the key — which is why the FROM/TO is spelled out above.

.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).

.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/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.

.changeset/calendar-view-schema-converge.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Runtime renderer behaviour is unchanged. @object-ui/plugin-calendar's README and content/docs/api/schema-reference.md are repaired to the converged surface in the same change, so no copy of the old contradiction survives.

.changeset/issue-5373-retire-crud-schema.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    crud had four declaration faces and no registered renderer, for the whole life of the key: the TS interface (packages/types/src/crud.ts), the zod mirror (packages/types/src/zod/crud.zod.ts), a dedicated branch in validateSchema that affirmatively PASSED it, and CRUDBuilder in @object-ui/core. A node spelling it painted the OBJUI-001 "Unknown component type" panel, and content/docs/api/schema-reference.md published it as reference material — so a reader (or an AI author) who copied the page got a red panel.

  • names api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    Authoring crud is now REFUSED BY NAME rather than passed or silently ignored. validateSchema returns an error with code: 'RETIRED_TYPE' on schema.type — at any depth, since it is what validateChildren recurses with — so assertValidSchema throws and isValidSchema answers false. The message names the migration: object-grid for the record table with its toolbar, filters, pagination and row/batch actions, object-form for the create/edit form, and detail for the record view. api/schema-reference.md is rewritten around those shapes.

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

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    listViews stays unmirrored, on the ruling's own fallback clause. The declaration's value is the local NamedListView — 64 declared top-level members (⚠️ re-taken at objectui#8980, which added the seventeen the protocol declares on this surface to the 47 this entry first measured), of which the renderer reads 21 off a named view. data is one of the 21 now: it used to reach the renderer through an as any cast on the named-view config in packages/plugin-view/src/ObjectView.tsx and be declared nowhere, and the objectui#8980 ruling declared it by name — objectui#7928's open half, answered. The spec's ViewSchema.listViews is a record of the STRICT ObjectListViewSchema, which requires columns and refuses options, ObjectQL tuple filters and default — that is, it refused the named views this package's own README and content/docs/api/schema-reference.md taught when this entry was written ({ label: 'All Users' } fails at columns; filter: [["owner", "=", "..."]] fails at filter.0), and objectui#8255 has since rewritten them in the spec shape. Mirroring the spec value would have lost documented behaviour; mirroring the local value would enforce 43 unread members (64 declared, minus the 21 that are both declared and read) into the contract — the very thing ruling B refused for the six local keys. The key therefore stays in the parity ledger with that measurement, pinned, until the maintainer decides its value type. It is not papered over with z.any().

.changeset/table-renderer-declared-column-contract-5350.md

  • names content/docs/api/schema-reference.md → content/docs/api/schema-reference.md — edited by this change

    What makes this site different from its three siblings is that the alias was not merely tolerated, it was published. content/docs/api/schema-reference.md §TableSchema shipped a copyable { "name": "id", "label": "#" } example and a property row reading "Column definitions with name, label, …", while packages/types declared the opposite pair. Docs and type disagreed about one type they both call TableColumn, each internally consistent. Retiring the alias without correcting the page would have turned a documented, working example into a silently broken one, so both halves land together: the page now authors accessorKey/header. The same row also advertised a render property that TableColumn has never declared — the renderer's hook is cell — and that claim is dropped rather than re-spelled.

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 c021b3529 (merge-base with origin/main): 17 file(s) changed outside .changeset/, read against 1819 pending declaration(s) that publish a body (2429 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3576.3 KB 3607.4 KB
Main entry chunk (gzip) 149.7 KB 350 KB
Entry file index-aGrEwEgD.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.88KB 6.25KB
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) 569.03KB 136.04KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 228.91KB 63.54KB
fields (index.js) 261.19KB 66.27KB
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) 40.88KB 11.46KB
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.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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.17KB 15.06KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 138.73KB 37.05KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 242.01KB 63.55KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.30KB 44.19KB
plugin-gantt (index.js) 172.43KB 42.85KB
plugin-grid (index.js) 230.79KB 63.39KB
plugin-kanban (index.js) 48.46KB 15.12KB
plugin-list (index.js) 116.28KB 28.88KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 32.26KB 9.42KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
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.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
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) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
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.82KB 7.15KB
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: 5218c1fa1a86c0d228d727a1277bb114f14327d5
Local-runs: none

Inputs: card #8285 (body and all 13 comments, the ruling 5583979207, the claim 5912959131, the dev report 5914966376), PR #11231 (body, 18-file list, net diff merge-base dded788ada to head 5218c1fa1a, +560/−607, a merge commit of f59d138f4e with main), the head's check-runs, and the installed spec at the @objectstack/spec@17.5.0 tag (objectstack 0f6dcac5e9). Read-only: git show / git diff / git grep at refs and REST GETs; nothing built, run or re-run.

① Derived judgments

Judged against ruling B and the spec tombstone, not against the report's prose. At the tag, ObjectKanbanPropsSchema.quickAdd is retiredKey(...) and the ADR-0087 registry carries page.component.object-kanban.quickAdd, so the objectui half owed is exactly "stop forwarding it" plus the mirror's narrowing plus the interim's removal.

  1. The cut, @object-ui/plugin-kanban — RIGHT. ObjectKanban's effectiveSchema literal is { ...schema, data, columns, className, swimlane fallback, quickAdd: undefined }: the explicit member sits after the spread, so an authored or host-supplied quickAdd is overwritten, and the KanbanRenderer call's schema={{ ...effectiveSchema, countsAreWindowed, onCardClick }} re-adds nothing. Every object-kanban entry reaches that literal: ObjectKanbanRenderer (the one ComponentRegistry.register for this renderer) renders ObjectKanban inside ElementDataSourceGate, and the published kanbanComponents['object-kanban'] is ObjectKanban itself, so a cut in index.tsx's ObjectKanbanRenderer (the claim's named file) would have missed the map and a direct mount. The dev's move to the producer is the right reading of the claim's "stop on a breach and explain", and the report explains it. Accept-set: no producer, host included, can switch the control on through object-kanban; the renderer accepts nothing new.

  2. KanbanRenderer byte-identical in behaviour — RIGHT. index.tsx's diff is the OBJECT_KANBAN_INPUTS docblock only (every changed line is a comment line); quickAdd={schema.quickAdd} and onQuickAdd={schema.onQuickAdd} still forward, and KanbanRendererProps.schema still types quickAdd?: boolean. Row 2 of the new pin mounts the real exported component with both halves: one control per lane renders and the host function is called with ('doing', 'Gamma'). That is the ruling's "kept where a host supplies the function", held on the component the pair now lives on since kanban-ui retired (types: does 'kanban-enhanced' get a declared arm? — its registration reads onColumnToggle / enableVirtualScrolling / virtualScrollThreshold and no schema in @object-ui/types declares the type at all (split from #7742) #8257).

  3. @object-ui/types, both faces — RIGHT. Zod: retirementTombstone(guidance), which at this head is z.never({ error: guidance }).optional().describe(guidance), the identical construct to the allowCollapse (finding(types): ObjectKanbanSchema.allowCollapse is the SAME zero-read key one arm over — declared on both faces, read by no registered board, and outside batch #70's reach #8801) and defaultSort neighbours; it refuses true and false with invalid_type at path quickAdd, keeps absence, and the .describe() string is the parse message (pinned). TS: quickAdd?: never with @deprecated, the allowCollapse?: never neighbour's shape; the onQuickAdd and conditionalFormatting docblocks that named quickAdd as live are rewritten. A tombstone rather than a deletion is right: BaseSchema ends .passthrough() and carries an index signature, so a deleted member would be kept silently and type as any (the new pin's near-miss row quickAdded shows that other path). Accept-set: quickAdd leaves the object-kanban arm on both published faces, aligned with the spec.

  4. @object-ui/sdui-parser, the interim deleted — RIGHT. kanban-quick-add.ts, its validate.ts dispatch and the four barrel exports (checkKanbanQuickAdd, INERT_QUICK_ADD, QUICK_ADD_HOST_TYPES, QUICK_ADD_KEY) go. The ruling's words are "the spec refusal by name replaces that diagnostic once it lands", and the module's own docblock said "THIS FILE IS THAT INTERIM … scheduled for removal by the same change that lands the spec pin". The tier's answer reverts to warning/unknown-prop, which is now true on every face (spec, both types faces, registry inputs, renderer); severity is unchanged so no page that saves today stops saving; the pipeline row proves ok can still go false. No importer of the four names remains at the head outside the two 8285 tests, where they are string literals asserting absence. The body-dialect.ts and body-dialect-6771.test.ts edits only drop comment citations of the deleted symbol.

  5. Why the old tripwire stayed green (dev item d) — RIGHT, checked at the tag. retiredKey(guidance) is a z.never() whose error is a function returning the guidance, then .optional().describe('[REMOVED] …'). Parsing quickAdd: true yields one invalid_type issue at path ['quickAdd'] and no keys; the old helper flattened issue.keys ?? [], read [], and not.toContain('quickAdd') passed with the key already retired, while its bogusProp control is an unrecognized_keys issue (which does carry keys) and so could not fail for the same reason. The rewritten helper reads both shapes (keys on unrecognized_keys, the single-segment path otherwise), carries a control for each on the same schema, and reddens on the reversal path, because a boolean face parses true to success.

  6. Pins — RIGHT. quickAddIsDiagnosedNotDropped-8285.test.ts is replaced by quickAddRetiredNotForwarded-8285.test.tsx (the cut through the real registry and SchemaRenderer, the host pair, the spec by name, the html tier on the live manifest, the one registered tag with kanban and kanban-ui reading has() === false); kanban-quick-add-8285.test.ts is rewritten for the new state (unknown-prop for true, false and the $expr marker, the retired code emitted for no value, barrel absence with checkRetiredBodyDialect as the control); object-kanban-quick-add-retired-8285.test.ts is new (compile-time never and not-any pins, runtime invalid_type, the describe channel, the near miss, the bare node). The 8801 and 8802 pins drop quickAdd: true from their live-member controls, which the tombstone would otherwise redden. The dropped source-grep row ("ObjectKanban supplies no onQuickAdd") is superseded by row 1, which supplies both halves and asserts no control, a stronger reading than a grep.

  7. Docs — RIGHT. content/docs/plugins/plugin-kanban.mdx and content/docs/api/schema-reference.md both said the key "still parses" and the tier answers inert-quick-add; both false after this diff; prose only, no fenced line moved. At the head no packages/*/README.md, no content/docs/guide/*.md, nothing under skills/ and nothing under apps/ outside the console ledger names quickAdd, so AGENTS.md Add automated testing infrastructure and CI/CD workflows #2's README half is discharged by absence.

  8. Premise 3 corrected (one tag, not two) — RIGHT. object-kanban is the sole registration; the tombstone remedy names the KanbanRenderer component rather than a retired tag, which would now be an unknown-component error.

Check-runs on the head (read twice; second read after the diff review): 30 success, 3 skipped (the two coverage entries and dependabot), 0 failed, and nine NOT YET CONCLUDED, named and neither adopted as pass nor read as fail: Spec Main Shape Gate, Test (shard 1/8), Test (shard 2/8), Test (shard 3/8), Test (shard 4/8), Test (shard 5/8), Test (shard 6/8), Test (shard 8/8), Type Check. Type Check is the run that concludes the compile-time pins in items 3 and 6, and the shards conclude the vitest rows; the merge gate reads their conclusions when they land. Concluded green among the ones this diff exercises: Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read, Changeset Overwrite Report, Test (dist pins), Test (shard 7/8), Build & E2E, Build Docs, Doc Snippet Type Check, Doc Component Type Check, Line Citation Gate, Governed Surface Queue Guard, Lint, Bundle Analysis.

② Semver level

Changeset .changeset/8285-object-kanban-quick-add-retired.md: @object-ui/types, @object-ui/plugin-kanban and @object-ui/sdui-parser at minor, BREAKING stated in the body with a Migration section. The diff changes source in exactly those three released packages (content/docs is the site, in the fixed group's ignore list). Level: objectui's version rule (AGENTS.md 版本号策略) pins the fixed group's major to @objectstack's and says an objectui breaking change is minor with the breaking semantics in the body; major is mechanically refused by check-changeset-no-major, and Changeset Bump Policy concluded success on this head. RIGHT.

Prose, line by line: (i) "BREAKING — quickAdd is retired on object-kanban … objectui's half; @objectstack/spec 17.5.0 already tombstones the same key" — true at the tag. (ii) "onQuickAdd is a host-supplied function that no JSON document can carry, and ObjectKanban supplies none of its own, so an authored quickAdd: true parsed green and drew nothing" — true of the parse (spec 17.4 and both types faces accepted it); the html tier did warn, which the card's premise correction 5611358942 records, and this line speaks of the parse, not the tier, so it is not a false line. (iii) the types bullet (?: never, retirementTombstone(), invalid_type at quickAdd, the passthrough reason) — verified in ① item 3. (iv) the plugin-kanban bullet (three entry points, both halves, KanbanRenderer unchanged) — verified in ① items 1 and 2. (v) the sdui-parser bullet (the four names, the interim status, unknown-prop true on every face, severity unchanged) — verified in ① item 4. (vi) Migration (delete the key; mount KanbanRenderer; drop the inert-quick-add branch) — consistent with the tombstone's own prescription at the tag. (vii) "Unchanged: onQuickAdd stays a runtime slot … never called" — true; see ③.

The earlier interim changeset .changeset/8285-kanban-quickadd-html-diagnostic.md (PR #8922) is still pending on this head, and the sdui-parser CHANGELOG.md at the head has zero inert-quick-add lines, so the four exports were carried by main for twenty days and by no release. Removing them is RIGHT: the ruling, the module's docblock and that changeset's own 2026-09-29 dated note (added by #11073, "the diagnostic's own removal belongs to the change that ruled it") all declared it interim. The new changeset is honest about it: it names the four exports and the code by name, and the dev declared the pending twin in the report. If both consume in one release the CHANGELOG will read "New exports …" and then "removed …" in one version, an accurate sequence rather than a contradiction. Not blocking; a second dated note on the interim changeset naming this PR (the #11073 shape) would make that entry self-explaining, and the seat may ask for it or let it be.

Clause-②: yes — RIGHT, on the stronger ground: @object-ui/types is released and ObjectKanbanSchema.quickAdd narrows from boolean to never on both published faces. The claim's second reason (the inert-quick-add code leaving the Diagnostic payload) is weaker than stated because that code never reached a release, but one published narrowing is enough for yes.

③ Boundary flags

Dev deviations, each answered:

  1. Surface beyond the claim — (a) cut in ObjectKanban.tsx rather than index.tsx: RIGHT, ① item 1. (b) packages/types/src/objectql.ts: RIGHT, it is the same member's other face; the mirror-parity and type-level pins require it, and leaving quickAdd?: boolean would publish on the TS face a key the zod face refuses. (c) the two docs pages: RIGHT, owed by AGENTS.md Add automated testing infrastructure and CI/CD workflows #2 (not done until docs reflect the code), prose only. (d) the 8801 and 8802 pins: RIGHT, "the zod pins the arm change moves" is the claim's own surface. (e) body-dialect.ts and its test: RIGHT, a comment citing a deleted symbol is a stale citation. None of the five widens the accept-set or the public surface beyond what the ruling orders.
  2. The tripwire renamed as well as rewritten: RIGHT; the old name stated the retired interim and each guarded fact has a successor row.
  3. main merged by merge commit, no rebase: RIGHT; the diff judged is merge-base to head. origin/main has since moved to c021b35299 and the PR reads mergeable: true.
  4. Interim changeset left untouched: answered in ②; not blocking.
  5. Zero label writes: RIGHT, nothing was owed.

open_questions[0] — retire ObjectKanbanSchema.onQuickAdd on object-kanban as well: my reading is that it does NOT block this PR. Ruling B's words retire quickAdd and keep the pair where a host supplies the function; onQuickAdd is already refused by name on the JSON face (the runtime-slot arm), and the TS docblock at this head states that on this element it arrives and is never called. A ?: never there needs the ObjectKanban path's read moved off KanbanRenderer's schema first, because check:handler-key-reads refuses a retired disposition while a renderer reads the key, and that restructure is a design choice the ruling did not make. Escalated to the seat as a follow-up card decision, with the dev's four-axis case for option A on record; not decided here.

Out-of-scope findings: (i) objectstack's parser copy and its objectui-lockstep.json still stamp inert-quick-add; that surfaces at objectstack's next .objectui-sha bump through check:sdui-lockstep, the designed port path, not this PR's. (ii) the OBJECT_KANBAN_INPUTS docblock heading still says "both ObjectKanbanRenderer tags", stale since #8802; comment-only, noted. Reviewer's own, same class: apps/console/src/__tests__/registry-inputs-spec-parity.test.ts keeps narrative comments describing the key as "PREMATURE, not permanent" and the sibling host as "honouring the same pair by identity"; its live data is current (LAZY_BLOCK_RULED_CARVE_OUTS is empty and HARVESTED lists object-kanban / quickAdd at 17.5.0), so this is historical prose in a file outside this diff. Not blocking.

Nothing blocking found. The nine unconcluded check-runs are named in ① and are neither adopted nor pre-empted by this verdict.

Implemented-by: claude/issue-8285-object-kanban-quickadd-retire
Reviewed-by: session_0122Knsowci76D2rBWReCzzZ

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 16:16
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 6f864cf Sep 30, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-8285-object-kanban-quickadd-retire branch September 30, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

plugin-kanban: quickAdd is inert on object-kanban / kanban — ObjectKanban never supplies the onQuickAdd runtime slot the control is gated on

2 participants