Skip to content

feat(types,plugin-kanban)!: retire ObjectKanbanSchema.onQuickAdd; the object-kanban path renders an internal board that takes the quick-add pair as props (objectui#11234) - #11269

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-11234-kanban-onquickadd-retire
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-11234-kanban-onquickadd-retire

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Fixes #11234
Clause-②: no (narrowing)

Retires ObjectKanbanSchema.onQuickAdd on object-kanban on both faces, completing ruling B of the director seat's decision batch #91 (5583979207, recorded on objectui#8285): the object-bound board does not grow an inline record-creation write path, and the Quick Add pair stays with a React host. Direction is option A of the PR objectui#11231 dev, as adopted in the card; no inline creation path is added, and KanbanRenderer's host pair is unchanged.

What changed

  • @object-ui/types: ObjectKanbanSchema.onQuickAdd is ?: never on the TypeScript face (objectql.ts), and handlerKeyRefusal('onQuickAdd', 'retired', 'Quick Add handler') on the zod mirror (zod/objectql.zod.ts). The JSON face still refuses the key by name with code custom; the guidance now says RETIRED instead of RUNTIME SLOT.
  • @object-ui/plugin-kanban:
    • A new internal module src/KanbanBoardCore.tsx holds the board body that used to live in KanbanRenderer: the bucketing memo, the lazy KanbanImpl, and the Suspense fallback. It takes the Quick Add pair ONLY as explicit props (quickAdd, onQuickAdd), and its schema type is KanbanRendererProps['schema'] with those two keys omitted, so a schema.onQuickAdd read written into it fails type-check. It is not re-exported from the index.tsx barrel.
    • KanbanRenderer (public) now renders KanbanBoardCore and passes schema.quickAdd / schema.onQuickAdd. Its props interface is byte-identical, and so is what a host gets.
    • ObjectKanban renders KanbanBoardCore and passes neither half. The old quickAdd: undefined line on effectiveSchema is removed, because nothing on this path reads schema.quickAdd any more; the comment in its place says where the cut now is.
    • Why the module move was needed: check:handler-key-reads refuses a retired disposition while a renderer reachable from the registration reads the key off the document. The object-kanban path reached KanbanRenderer's schema.onQuickAdd read. After this change, the gate's census for object-kanban holds one row, onCardClick [runtime-slot], read in KanbanBoardCore.tsx.
  • Docs: content/docs/plugins/plugin-kanban.mdx (the handler-key paragraph and the "Quick Add is a React-host capability" section) and content/docs/api/schema-reference.md (the ObjectKanbanSchema handler-keys callout, and one clause of the quickAdd callout).
  • Changesets: .changeset/11234-object-kanban-onquickadd-retired.md, with minor on @object-ui/types (a narrowing, breaking semantics stated in the body) and patch on @object-ui/plugin-kanban (no public props moved). Three pending entries that this release would otherwise ship with a false sentence are amended, one sentence each, with every other byte and the frontmatter unchanged: 8285-object-kanban-quick-add-retired.md (its closing note said onQuickAdd stays a runtime slot), 7804-object-kanban-handler-keys-judged.md (it said onCardClick and onQuickAdd are both runtime slots) and 8285-kanban-quickadd-html-diagnostic.md (it said onQuickAdd is a runtime slot).

Pins

  • JSON face, by name, and TS face never: new packages/types/src/__tests__/object-kanban-on-quick-add-retired-11234.test.ts.
    • Runtime legs: the key is refused as custom at path onQuickAdd, for an action object and for a live function. The .describe() text is the parse message. A near-miss key is kept. The CLI union refuses a whole node carrying the key.
    • The retired-disposition leg reads RETIRED for onQuickAdd against onCardClick on the same arm and helper, which still reads RUNTIME SLOT. That onCardClick reading is the lit control.
    • Type-level pins: Equal to undefined, not any, not callable, and an @ts-expect-error on a literal that writes the key. The sibling slot onCardClick is still callable.
  • The host pair still draws and calls (control): quickAddRetiredNotForwarded-8285.test.tsx row 2, unchanged. KanbanRenderer with quickAdd: true plus a function draws one control per lane, and a submitted title reaches the host.
  • An object-kanban node draws no Quick Add: the same file's row 1, unchanged, through the real registry and the real board. It was already green before this change, because quickAdd was cut. The readings that discriminate on onQuickAdd itself flip in two files, each with onCardClick as the lit control on the same render:
    • handlerKeyDispositionsMeasured-7804.test.tsx suite 2: the board receives onQuickAdd: undefined and quickAdd: undefined, while the authored onCardClick runs once.
    • kanban-handler-slots-7664.test.tsx suite 1.
  • Ablation (below): re-declaring the key as a runtime slot turns the retired-disposition pin red on each face.

Ledger rows moved with it:

  • the objectui#6124 ledger: the row moves from RUNTIME_SLOT to RETIRED, 61 + 21 becomes 60 + 22 with the total unchanged at 82, and the type blocks move the key from KeepsFunction to RetiredIsNever;
  • zod-mirror-parity: onQuickAdd leaves the objectql.zod.ts#ObjectKanbanSchema drift entry, and the header key total goes 87 to 86 with its history sentence;
  • the objectui#7340 docs census: 29 retired members, objectql.ts 2, and onQuickAdd joins the unambiguously retired names;
  • the objectui#7804 and objectui#7664 plugin-kanban readings: suite 3 of 7664 now derives the read sites from both bodies, and adds a barrel pin that KanbanBoardCore is not published;
  • check-handler-key-read-sites.test.ts: onQuickAdd leaves the object-kanban census, the arm reads retired, and the onCardClick row's file is KanbanBoardCore.tsx.

Three source-reading pins had to be re-pointed at the moved text:

  • the objectui#9357 arity pin's index.tsx hop is now the hand-off to KanbanBoardCore;
  • the objectui#8932 firing control finds the live board's lazy import in KanbanBoardCore.tsx;
  • the objectui#8801 schema-channel end is now KanbanBoardCore's signature.

Measured producers of onQuickAdd on object-kanban: 0 in both repos

  • objectui (this branch): tracked files naming onQuickAdd, excluding tests and markdown, number 7 at the final head. They are KanbanImpl.tsx (the board's props), index.tsx (the host face), the two declarations, one comment in the gate script, KanbanBoardCore.tsx (its internal prop pair), and one comment in ObjectKanban.tsx. None writes the key onto an object-kanban node. Lit control on the same instrument: 7 non-test files write a type: 'object-kanban' node, and 2 JSON files in examples/schema-catalog carry object-kanban. JSON/YAML files naming onQuickAdd: 0.
  • objectstack origin/main 4d0b9cd54 (read-only git grep): onQuickAdd appears only in docs, CHANGELOGs, comments and diagnostic message text (component.mdx, the sdui-parser interim diagnostic and its test, the spec CHANGELOG, a conversions/registry.ts note). packages/spec/src/ui/component.zod.ts has 0 hits for onQuickAdd. Lit control on the same instrument: quickAdd hits 17 files, component.zod.ts among them.

Verification

All runs from the worktree root, through os-verify-lock, with NODE_OPTIONS=--max-old-space-size=4096. Pass counts are read from the vitest summary line, not from exit codes. Final head is b1e88910f. Its two commits over e2bf34b97 are changeset text only, so the test and type-check runs below at e2bf34b97 stand; the changeset gates were re-run at b1e88910f (last table row).

Run Head Result
pnpm exec vitest run packages/plugin-kanban/src/ (verbose) 611112e0e 64 files passed, 421 tests passed
8 named pins: the types 11234 / 6124 / zod-mirror-parity / 7340 / 8285 files, sdui-parser kanban-quick-add-8285, react 9357, scripts check-handler-key-read-sites 611112e0e 8 files passed, 487 tests passed
pnpm exec vitest run packages/types/ plus the 14 test files outside types/scripts that import plugin-kanban (console, schema-catalog, app-shell, cli, core, i18n, plugin-calendar, plugin-list, runner) e2bf34b97 308 files passed, 8232 tests passed
pnpm exec vitest run scripts/__tests__/ (whole root suite, owed because docs were edited) e2bf34b97 177 passed, 2 skipped (179 files); 5371 passed, 2 skipped tests
pnpm --filter @object-ui/types type-check (3 tsc projects; the test project lists 294 test files, the new pin among them) e2bf34b97 exit 0
pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-kanban^...' build (13 packages), then pnpm --filter @object-ui/plugin-kanban type-check e2bf34b97 build exit 0; type-check exit 0 with 0 error TS. The rebuilt packages/types/dist/objectql.d.ts carries onQuickAdd?: never, so the plugin read the new typings
check:handler-key-reads e2bf34b97 exit 0, every judged read declared, 2 exempted by ledger
check-changeset-presence, check-changeset-no-major, check:control-bytes, check:new-line-citations e2bf34b97 all exit 0; 0 new cross-file line citations
check-i18n-call-site-keys, check-i18n-en-drift, check-i18n-dead-keys (the kanban.uncategorized translation hook moved modules) e2bf34b97 all exit 0
node scripts/markdown-test-inputs.mjs --audit e2bf34b97 exit 0: 107 candidate files adjudicated, 78 entries present
pnpm exec eslint --format json over the 16 changed code files e2bf34b97 0 errors, 96 warnings. Every pre-existing file has the same message count as the base version linted through stdin; the 2 new files have 0
check-governed-queue-guard --test over the 19 paths e2bf34b97 NOT GOVERNED
check-changeset-presence, changeset:check, check:changeset-claims, check:pending-changeset-literals, check-governed-queue-guard --test over the 22 paths b1e88910f all exit 0; NOT GOVERNED

Declared narrowing: repo-wide pnpm lint and the full pnpm test farm are left to CI. eslint's population is its own files: ['**/*.{ts,tsx}'] block. The file count, 16, is read from the JSON output. eslint.config.js configures no projectService and no parserOptions.project, so linting is not type-aware and this diff cannot move a verdict on an untouched file.

Ablation: re-declare onQuickAdd as a runtime slot, one face at a time

Run on the committed head e2bf34b97 through objectstack's scripts/ablation-replace.mjs in wrap mode, inside a script with its own trap restore, under the lock. The predictions were written before the run.

  • Zod leg: 'retired' becomes 'runtime-slot' in objectql.zod.ts. The anchor went x1 to x0 and the blob c106c73cb1ec to 6b9fc742c9d5. Vitest over the 11234 pin and the 6124 ledger read 2 failed, 341 passed. The two failures are exactly the predicted legs: the 11234 retired-disposition leg, and the 6124 "guidance wording distinguishes a runtime slot from a retired key" leg.
  • TS leg: onQuickAdd?: never; becomes the callable in objectql.ts. The anchor went x1 to x0 and the blob dde43cddfea1 to afedc0cab24b. tsc -p packages/types/tsconfig.test.json exited 2 with 5 errors:
    • the 11234 pin: TS2344 twice (tombstone, not-callable) and TS2578 (the @ts-expect-error became unused);
    • the 6124 RetiredIsNever row: TS2344;
    • zod-mirror-parity's type-map ledger: TS2322, because the drift entry is owed again. This fifth error was not in the written prediction. It is the right direction, since the ledger answers to the faces.
  • Restore proven: git diff HEAD over both paths is 0 bytes, both blob hashes equal HEAD's, and git status --porcelain has 0 lines.

Acceptance notes (observations; nothing filed)

  • Three pending changesets said onQuickAdd is, or stays, a runtime slot on object-kanban, which would ship false in the same release: 8285-object-kanban-quick-add-retired.md, 7804-object-kanban-handler-keys-judged.md and 8285-kanban-quickadd-html-diagnostic.md. Each false sentence is amended in this PR, and the rest of each file, frontmatter included, is byte-identical. The seat added the three files to the claim's file surface.
  • The objectui#6124 ledger's RetiredIsNever type block has no ObjectKanbanSchema['onCardMove'] row. That key's never is pinned by a source read in the 7804 suite 3 leg instead. Not added here.
  • A few comments still say "KanbanRenderer's lazy boundary", and several tests' pre-warm comments say their '../KanbanImpl' specifier matches index's. The lazy import now lives in KanbanBoardCore.tsx. It resolves to the same module, so the pre-warm imports still hit the cache. The comments are not swept; per AGENTS.md they get repaired when a change touches those files anyway. I fixed the ones on lines this change touched.
  • The retired guidance text is the shared handlerKeyRefusal wording (the node-type remedy). The practical remedy for this key, mounting KanbanRenderer, is carried by the TS docblock, the docs and the changeset, the same as for onCardMove.
  • The card body says Clause-②: yes; the PM claim says no (narrowing). This body copies the claim's line, as the dispatch order directs.

Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec (a dispatched os-dev run; branch claude/issue-11234-kanban-onquickadd-retire).


Generated by Claude Code

…ect-kanban renders an internal board (objectui#11234)

`ObjectKanban` now renders the internal `KanbanBoardCore`, which takes the
Quick Add pair only as explicit props, and supplies neither half. The
exported `KanbanRenderer` renders the same board and passes
`schema.quickAdd` / `schema.onQuickAdd` unchanged, the host pair ruling B
keeps. With no read of the key left on the `object-kanban` path,
`ObjectKanbanSchema.onQuickAdd` becomes `?: never` on the TypeScript face
and `handlerKeyRefusal(..., 'retired', ...)` on the zod mirror.

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…anban; move its ledger rows (objectui#11234)

- new `object-kanban-on-quick-add-retired-11234.test.ts`: refused by name on
  the JSON face, `never` on the TS face, and RETIRED against the lit
  `onCardClick` runtime slot on the same arm;
- objectui#6124 ledger: the row moves from RUNTIME_SLOT to RETIRED (60 + 22);
- zod-mirror-parity: the key leaves the `ObjectKanbanSchema` drift entry (86 keys);
- objectui#7340 census: 29 retired members, `onQuickAdd` unambiguously retired;
- objectui#7804 / #7664: the object-kanban board now receives no Quick Add pair,
  with `onCardClick` as the lit control; the read sites split across
  `KanbanRenderer` and the internal `KanbanBoardCore`;
- check-handler-key-read-sites: `onQuickAdd` leaves the object-kanban census and
  its arm reads `retired`.

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…re-point two source-reading pins (objectui#11234)

The two docs passages now say `onQuickAdd` is retired on `object-kanban`, with
the pair on `KanbanRenderer` for a React host. The objectui#9357 arity pin
quotes the hand-off to `KanbanBoardCore` as the `index.tsx` hop, and the
objectui#8932 firing control finds the live board's lazy import in
`KanbanBoardCore.tsx`. One changeset.

Claude-Session: https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec
Co-authored-by: Claude <noreply@anthropic.com>
…al board (objectui#11234)

The objectui#8801 pin quoted `KanbanRenderer`'s signature as the component
the `object-kanban` schema spread stops at. `ObjectKanban` renders the
internal `KanbanBoardCore` now, so the pin quotes that render and that
component's signature.

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

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 62 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.

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743); the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair — but at that time the ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction, not that nothing was there. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger requires every registered pair's mirrored-but-undeclared key set to equal that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

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

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Where the non-pair is recorded now. zod-mirror-parity.test.ts keys its existing EXCLUSIONS entry — the mechanism that accounts for every exported const with no TypeScript declaration to mirror, each with its stated reason — to ClassNameStylePropsSchema. Named for its own two keys, the const leaves no like-named declaration for a name-derived pairing to reach for.

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

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743) — the same retirement objectui#5903's entry carries, for the same clause and the same reason; the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair, at a time when that ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger reconciles every registered pair's mirrored-but-undeclared key set against that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.changeset/6150-undeclared-but-consumed-keys.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ AMENDED, and the amendment ships in this same release. The TreeViewSchema slice (604476d97) gave the key a zod arm after all — a NAMED REFUSAL (handlerKeyRefusal(key, 'runtime-slot', label)), never a shape — because "no mirror entry" is not neutral under BaseSchema.passthrough(): it meant an authored { "type": "tree-view", "onNodeClick": { "action": "toast" } } parsed GREEN, survived the parse, and reached a call site that expects a function. ⇒ the three clauses this bullet used to carry are no longer true of the code shipping beside it. The key is now a MEMBER of TreeViewSchema.shape and an authored value is refused BY NAME at path onNodeClick; it has LEFT zod-mirror-parity.test.ts's RuntimeOnlyDeclared for that file's KnownDrift; and it is no longer "the first pair to sit there without also sitting in UnmirroredDeclared" — draining it emptied that difference, so RuntimeOnlyDeclared is now a SUBSET of UnmirroredDeclared and the union of the two equals UnmirroredDeclared itself. ⛔ objectui#6152's ruling is untouched by any of this: what the key still does not have, and never will, is a z.function() shape — no serialized document could satisfy one.

.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/6175-column-state-persistence.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Nothing is retired. Both spellings remain declared on DataTableSchema; onColumnReorder stays declared and stays unwired, exactly as the RuntimeOnlyDeclared ledger in zod-mirror-parity.test.ts records it. Which of the two survives is a declared-surface ruling that stays open and is deliberately not settled here.

.changeset/6639-objectgrid-title-mirrored.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The gain is the typed refusal: the mirror's .passthrough() base was already admitting any title unexamined, and it now enforces the declared string. zod-mirror-parity.test.ts's UnmirroredDeclared ledger records the key as worked off — the ledger's first shrink by repair (97 + 1 mirrored + 23 reclassified is what the seeded "121" now means).

.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/7344-handler-string-any-mirrors.md

.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/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/7654-floating-chatbot-trigger-icon-tombstone.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Every other tombstone in this package pairs ?: never with a retirementTombstone() refusal on the Zod twin. There is no twin here to carry one: FloatingChatbotConfig has no Zod mirror at all, and floatingConfig sits in the UnmirroredDeclared ledger (zod-mirror-parity.test.ts, complex.zod.ts#ChatbotSchema). BaseSchema is .passthrough(), so the whole floatingConfig object rides through unvalidated — before this change and after it. Minting a mirror to host a refusal would be the declared-but-UNMIRRORED axis (objectui#6152), a different defect: a key can be mirrored and inert, or unmirrored and live, and fixing one says nothing about the other. This change does not widen into it.

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

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The pair moves from zod-mirror-parity.test.ts's RuntimeOnlyDeclared to its KnownDrift, which empties the former of the one entry the latter did not also hold — so the two unmirrored ledgers are now in a containment relation, and the cross-ledger figure that recorded their difference states the containment instead.

.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/8338-retire-toast-action.md

  • names handler-keys-json-refusal-6124.test.ts → packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts — edited by this change

    Not handlerKeyRefusal(). action is ⛔ not a handler key: it is a VALUE key whose NESTED member was a function. So it takes the ADR-0049 retirement helper (invalid_type, and ?: never on the declaration) and not objectui#6124's named-refusal arm (custom, with a TS twin that stays callable for a runtime slot). The two helpers are pinned apart in handler-keys-json-refusal-6124.test.ts, whose census counts 45 runtime slots + 22 retired on* sites — a non-handler key has no seat in it.

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The parity ledgers drain with it, every figure re-derived by zod-mirror-parity.test.ts's own AST and mirror instruments rather than stepped by hand: KnownDrift 42 entries / 64 keys → 41 / 63 (the entry's whole content, so the entry went too — the ledger's first loss by RETIRING a key rather than by moving either face toward the other), and WiderThanDeclared 23 / 36 / 47 arms, split 6 / 30 / 0 / 11 → 22 / 35 / 45, split 6 / 29 / 0 / 10. The pair itself stays registered, so EXPECTED_MIRROR_PAIRS does not move.

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

.changeset/8572-chatbot-body-retired.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Why this key and not another. It was the ONE place in this vocabulary where body did not mean "what goes inside this component": zod-mirror-parity.test.ts carried the pair under KnownDrift as "two different meanings of one key", and the same collision was the whole reason chatbot was the single arm of the component union whose output was not assignable to SchemaNode. Both ledger rows move with this change, and the two pins that recorded the old state are INVERTED rather than deleted (see below).

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

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ The declaration alone would not have been enough, and this is the reusable part. A TypeScript declaration does not run at parse time. The hand-written zod mirror is the only face in this repository that can refuse an authored number, so narrowing the declaration without the mirror would have shipped declared !== enforced on a published surface — and zod-mirror-parity.test.ts would have stayed GREEN through it, because that instrument asserts a mirror accepts everything its declaration declares and a mirror left WIDER passes. Both faces moved together for that reason.

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

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Who is NOT affected: every correctly typed document, and every document that never wrote these keys — absent stays valid on all nine. No renderer changed. The parity ledger (zod-mirror-parity.test.ts) records the move: UnmirroredDeclared 14 entries / 96 keys to 14 / 87, the ObjectViewSchema entry re-derived into the SPEC-DERIVED half because the mirror now references the spec in code.

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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3583.7 KB 3607.4 KB
Main entry chunk (gzip) 149.9 KB 350 KB
Entry file index-NKQfQtae.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) 570.05KB 136.37KB
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.24KB 66.29KB
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) 41.23KB 11.53KB
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) 216.32KB 44.56KB
plugin-detail (index.js) 244.74KB 64.46KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.69KB 44.62KB
plugin-gantt (index.js) 173.03KB 43.07KB
plugin-grid (index.js) 231.37KB 63.54KB
plugin-kanban (index.js) 48.62KB 15.21KB
plugin-list (index.js) 116.42KB 28.89KB
plugin-map (index.js) 23.50KB 7.82KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.05KB 9.67KB
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

…n object-kanban too (objectui#11234)

The pending objectui#8285 changeset closed with an "Unchanged" note saying
`ObjectKanbanSchema.onQuickAdd` stays a runtime slot. This PR retires it in
the same release, so that note would ship false. It now says the key is
retired on `object-kanban` by objectui#11234 and the Quick Add pair on
`KanbanRenderer` is unchanged. The rest of that file, frontmatter included,
is byte-identical. This change's own changeset drops its "supersedes" note,
which the amendment made false.

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) 3583.7 KB 3607.4 KB
Main entry chunk (gzip) 149.9 KB 350 KB
Entry file index-NKQfQtae.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) 570.05KB 136.37KB
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.24KB 66.29KB
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) 41.23KB 11.53KB
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) 216.32KB 44.56KB
plugin-detail (index.js) 244.74KB 64.46KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.69KB 44.62KB
plugin-gantt (index.js) 173.03KB 43.07KB
plugin-grid (index.js) 231.37KB 63.54KB
plugin-kanban (index.js) 48.62KB 15.21KB
plugin-list (index.js) 116.42KB 28.89KB
plugin-map (index.js) 23.50KB 7.82KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.05KB 9.67KB
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

…untime slot on object-kanban (objectui#11234)

The pending objectui#7804 entry said `onCardClick` and `onQuickAdd` are both
declared as runtime slots, and the pending objectui#8285 html-diagnostic entry
said `onQuickAdd` is a runtime slot. This PR retires `onQuickAdd` on
`object-kanban` in the same release, so both sentences would ship false. Each
false sentence is amended; the rest of each file, frontmatter included, is
byte-identical.

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) 3583.7 KB 3607.4 KB
Main entry chunk (gzip) 149.9 KB 350 KB
Entry file index-NKQfQtae.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) 570.05KB 136.37KB
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.24KB 66.29KB
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) 41.23KB 11.53KB
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) 216.32KB 44.56KB
plugin-detail (index.js) 244.74KB 64.46KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.69KB 44.62KB
plugin-gantt (index.js) 173.03KB 43.07KB
plugin-grid (index.js) 231.37KB 63.54KB
plugin-kanban (index.js) 48.62KB 15.21KB
plugin-list (index.js) 116.42KB 28.89KB
plugin-map (index.js) 23.50KB 7.82KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.05KB 9.67KB
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: b1e88910fab5d5137e221e54363aa65d87a3b66f
Local-runs: none

Inputs: card objectui#11234 (body and its 4 comments: claim 5917775317, dev reports 5919636549, 5919687375, 5919732925), PR objectui#11269 (body, 22-file list, net diff against main at the head), and the latest check-runs on the head. Head files read for context through the contents API only: packages/plugin-kanban/src/index.tsx, ObjectKanban.tsx, KanbanImpl.tsx, InlineQuickAdd.tsx, useQuickAddReorder.ts, package.json, the 8285 and 7340 pins, and .github/workflows/ci.yml.

Gate verdicts on the head (check-runs, filter=latest, read after the last run completed at 2026-09-30T21:22Z): 43 runs, 40 success, 3 skipped (Test (coverage), Test (coverage shard), dependabot, all skipped by their own triggers), 0 failing, 0 in progress. Green among them: Type Check (which carries check:handler-key-reads), Lint, all 8 Test shards, Test (dist pins), Build and E2E, Build Docs, Spec Main Shape Gate, README Export Check, Changeset Fixed Group Check, Changeset Declaration, Changeset Bump Policy, Changeset Claim Re-read, Changeset Overwrite Report, Governed Surface Queue Guard, Control Byte Scan, Line Citation Gate, Inert vi.mock Specifier Check, Pre-Install Import Graph Check, Bundle Analysis, the four doc checks, Skill Example Check, Skill Guide Path Check, Skill Eval Token Check, Action Ref Convention, Shell Escape Residue Scan, Docs Route Eager Closure Check, Live E2E (informational) and label. No run was still in progress when this record was judged.

① Derived judgments

  1. Retirement on both faces — RIGHT. packages/types/src/objectql.ts: onQuickAdd?: never; with a docblock that names the ruling, the gate and the remedy. packages/types/src/zod/objectql.zod.ts: handlerKeyRefusal('onQuickAdd', 'retired', 'Quick Add handler'). Accept-set effect: the JSON face refused the key by name before and after (same custom code, same path; only the guidance wording moves from RUNTIME SLOT to RETIRED), so the JSON accept set is unchanged; the TypeScript accept set narrows (a typed host writing the key on an ObjectKanbanSchema now errors). Pinned by the new object-kanban-on-quick-add-retired-11234.test.ts: Equal to undefined, IsAny false, not callable, an @ts-expect-error on a writing literal that turns TS2578 if the tombstone widens, onCardClick still callable as the lit control, the never-declared near miss onQuickAdded falling through to the index signature; at runtime custom at path onQuickAdd for an action object and for a function, the .describe() text equal to the parse message, the near miss accepted (this arm is not strict), the CLI union refusing the whole node and accepting the bare node; and the disposition leg reading RETIRED for onQuickAdd beside RUNTIME SLOT for onCardClick through the same helper.

  2. KanbanBoardCore is internal — RIGHT. New module packages/plugin-kanban/src/KanbanBoardCore.tsx. index.tsx at the head imports it (line 18) and its export list carries no KanbanBoardCore and no star re-export (exports: KANBAN_UNCOLUMNED_ID, bucketCardsIntoColumns, the type and hook re-exports, KanbanRendererProps, KanbanRenderer, kanbanComponents, ObjectKanbanRenderer). package.json exports is . and ./style.css only, so the module is unreachable by deep import as well. 7664's new barrel leg measures this at runtime (KanbanRenderer a function, KanbanBoardCore absent). The type claim holds: KanbanRendererProps['schema'] (index.tsx 216-253) is a closed object type with no index signature, so KanbanBoardCoreSchema, the Omit of it minus quickAdd and onQuickAdd, really lacks both keys and a schema.onQuickAdd read inside the module fails type-check. The KanbanBoardCore to index import cycle touches no binding at evaluation time (bucketCardsIntoColumns is an exported function declaration read at render; the module's top level only calls React.lazy and createSafeTranslation), the same shape ObjectKanban to index already has.

  3. KanbanRenderer unchanged for a host, with the control — RIGHT. KanbanRendererProps (index.tsx 215-320) sits outside every diff hunk and is byte-identical. The body now renders KanbanBoardCore with quickAdd={schema.quickAdd} and onQuickAdd={schema.onQuickAdd} as explicit props, and every other value it used to hand LazyKanban (bucketed columns, onCardMove, onCardClick, className, coverImageField, conditionalFormatting, objectFields, swimlaneField, countsAreWindowed) reaches KanbanImpl through the same props from the same schema identity, so the memo dependencies are unchanged. Control: quickAddRetiredNotForwarded-8285.test.tsx row 2 (a host mounts KanbanRenderer with quickAdd: true plus a function; a control per lane draws and a submitted title reaches the host) is untouched by the diff. No inline creation path was added anywhere: ObjectKanban at the head passes objectFields, onCardMove and schema to KanbanBoardCore and neither half of the pair (quickAdd and onQuickAdd occur in that file in comments only, lines 1231-1233 and 1616).

  4. check:handler-key-reads green with a one-row census — RIGHT, and green on the head as a gate verdict: the step Verify every handler key a registered renderer reads is declared by its arm (pnpm check:handler-key-reads, ci.yml line 345) is step 13 of the Type Check job on this head (job 110098290070), and it completed success, with the job's relevance filter set to a full run because packages/** and scripts/** changed (the filter skips only markdown, content/**, docs/**, apps/site/** and .changeset/**). The census pin scripts/__tests__/check-handler-key-read-sites.test.ts now asserts object-kanban.onQuickAdd absent from the census, the surviving onCardClick row's file as packages/plugin-kanban/src/KanbanBoardCore.tsx, and the arm's members onCardClick: 'runtime-slot', onCardMove: 'retired', onQuickAdd: 'retired'; the reading is right, because the registration walks ObjectKanbanRenderer to ObjectKanban to KanbanBoardCore, which reads schema.onCardClick alone, while KanbanRenderer's schema.onQuickAdd read sits in a body no registration reaches.

  5. Ledger moves — RIGHT, each one:

    • objectui#6124 (handler-keys-json-refusal-6124.test.ts): the onQuickAdd row moves from RUNTIME_SLOT to RETIRED, 61 + 21 becomes 60 + 22 with ALL_SITES still 82 unique ids; the type block moves ObjectKanbanSchema['onQuickAdd'] from KeepsFunction to RetiredIsNever.
    • zod-mirror-parity.test.ts: 'objectql.zod.ts#ObjectKanbanSchema' narrows to 'onCardClick'; the header goes 87 to 86 keys with the history sentence. Right: a matched pair of tombstones is not drift.
    • objectui#7340 (component-docs-retired-handler-keys-7340.test.ts): the retired census 28 to 29, objectql.ts 1 to 2, and onQuickAdd joins UNAMBIGUOUSLY_RETIRED_NAMES in alphabetical position. Right: after this diff no @object-ui/types document interface declares an onQuickAdd callable; the remaining callables are KanbanRendererProps['schema'] and KanbanImpl's props, both component props of @object-ui/plugin-kanban.
    • objectui#7804 (handlerKeyDispositionsMeasured-7804.test.tsx): suite 2's onQuickAdd leg flips from "arrives by identity" to onQuickAdd: undefined, quickAdd: undefined, quickAddRan: 0 with cardClickRan: 1 as the lit control on the same render; the prop-channel leg adds onQuickAdd: false; suite 3 reads retired on the mirror and never on the twin.
    • objectui#7664 (kanban-handler-slots-7664.test.tsx): suite 1 flips (onQuickAdd: undefined, quickAdd: undefined beside two 'function' controls); suite 3 derives the reads from both bodies (own: ['onQuickAdd'], board: ['onCardClick'], whose union is the old two-key reading), pins the schema={schema} hand-off, adds the barrel leg, and reads the object-kanban path's keys as onCardClick [runtime-slot] alone.
  6. The removed quickAdd: undefined line in ObjectKanban — RIGHT, dead after the move. At the head effectiveSchema (ObjectKanban.tsx 1224-1241) is the ...schema spread plus data, columns, className and swimlaneField, and it is spread into the schema handed to KanbanBoardCore, whose type omits both keys and whose body reads neither; KanbanImpl gates the control on the quickAdd and onQuickAdd PROPS, which ObjectKanban never passes. An untyped quickAdd riding the spread reaches no read. The runtime pin is 8285 row 1 (the real registry, quickAdd: true plus a function on an object-kanban node, zero Add card buttons, the handler never called), untouched; that file's one source read is the registration-key regex over index.tsx, not the removed line, so nothing quoted the line.

  7. The three re-pointed source-reading pins outside the named list — RIGHT, each: objectui#9357 (packages/react) re-points its index.tsx hop from onCardClick={schema.onCardClick} to the KanbanBoardCore schema={schema} hand-off, and the declaration it reads stays on the unchanged KanbanRendererProps; objectui#8932 (kanbanEnhancedRetired-8932.test.ts) expects its lit control filesReferencing(LIVE) to name KanbanBoardCore.tsx, which is where the ./KanbanImpl lazy import now lives (index.tsx no longer declares LazyKanban); objectui#8801 (object-kanban-allow-collapse-retired-8801.test.ts) reads the schema-channel end as KanbanBoardCore's destructuring signature plus the KanbanBoardCore element in ObjectKanban.tsx. Each keeps its reading and re-points only the quoted text. The packages/react file ships nothing, and the seat added it to the file surface.

  8. Both ablation legs — RIGHT as a red-first proof, accepted on the report (no re-run under the read-only rule). Predictions written first; run on the committed e2bf34b97 through ablation-replace.mjs wrap mode with a trap restore. Zod leg ('retired' to 'runtime-slot'): 2 failed, 341 passed, exactly the predicted legs (the 11234 disposition leg and the 6124 guidance-wording leg). TS leg (never to the callable): tsc exit 2 with 5 errors: the 11234 pin's TS2344 twice and TS2578, the 6124 RetiredIsNever row's TS2344, and zod-mirror-parity's TS2322, which was not predicted and is disclosed; it is the ledger answering to the face, the right direction. Restore proven: 0-byte git diff HEAD, both blob hashes equal to HEAD's, empty porcelain.

  9. The 0-producer census with lit controls — conclusion RIGHT, one instrument reading WRONG on the head. The PR body's "tracked files naming onQuickAdd, excluding tests and markdown, number 5" is stale at b1e88910f: KanbanBoardCore.tsx (the prop pair) and ObjectKanban.tsx (the replacement comment) both name the key, so the count is 7 (InlineQuickAdd.tsx and useQuickAddReorder.ts at the head name it nowhere). Neither uncounted file writes the key onto an object-kanban node, one declares an internal prop and one is a comment, so 0 producers holds on the head, with the lit controls as reported (7 non-test files write a type: 'object-kanban' node; in objectstack quickAdd hits 17 files including component.zod.ts while onQuickAdd hits 0 outside docs, changelogs, comments and message text). Not blocking: the count is narrative in the PR body, no shipped text carries it, and the narrowing's safety rests on the 0, which the diff itself confirms for the two uncounted files.

  10. Docs — RIGHT. content/docs/api/schema-reference.md: the handler-keys callout now names onCardClick the sole runtime slot and both others tombstones (onCardMove since objectui#9342, onQuickAdd since objectui#11234), and the quickAdd callout drops the "runtime slot" wording. content/docs/plugins/plugin-kanban.mdx: the handler paragraph splits, the Quick Add section says both halves are retired on an object-driven board, @objectstack/spec refuses quickAdd (right: the spec never declared onQuickAdd), and the remedy is to delete both keys and mount KanbanRenderer. Build Docs, Doc Snippet Type Check, Doc Component Type Check and Internal Docs Link Check are green on the head.

Public-surface summary: @object-ui/types narrows ObjectKanbanSchema.onQuickAdd from a callable to never (TypeScript accept set narrows; JSON accept set unchanged, guidance wording only). @object-ui/plugin-kanban adds no export and changes no prop type; KanbanRendererProps is byte-identical, KanbanRenderer behaves identically, and ObjectKanban is identical for a host (the never-called function no longer reaches the board implementation's props, which no host observes). packages/react changes a test only. Nothing widens anywhere.

② Semver level

  • .changeset/11234-object-kanban-onquickadd-retired.md: '@object-ui/types': minor, '@object-ui/plugin-kanban': patch. RIGHT: the types face narrows, which the body states as BREAKING and objectui's version-alignment rule scores minor; plugin-kanban adds no export, changes no prop type and no host-visible behaviour, so patch. packages/react ships nothing (test only) and correctly has no entry. Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Overwrite Report and Changeset Claim Re-read are green on the head.
  • Clause-②: no (narrowing) — RIGHT; it matches claim 5917775317 and the PR body's second line. Nothing widens: the JSON face refused the key by name before and after, and the TypeScript face narrows.
  • The three amended pending changesets: each is one hunk with the frontmatter untouched (the hunks begin at lines 4, 5 and 40, outside each file's --- block), and each is true at the head:
    • 7804-object-kanban-handler-keys-judged.md: onCardClick is declared as an objectui#6124 RUNTIME SLOT, and onQuickAdd "was declared the same way here; objectui#11234 retires it on object-kanban in the same release, so it is ?: never on the TypeScript face and refused BY NAME as RETIRED". True (objectql.ts, objectql.zod.ts). The following "Until now neither was declared anywhere" stays a true history sentence.
    • 8285-kanban-quickadd-html-diagnostic.md: onQuickAdd "takes a function, which no parsed page can write … objectui#11234 retires onQuickAdd on object-kanban in the same release; it remains a host-supplied prop on KanbanRenderer's schema". True (index.tsx 236 and 346).
    • 8285-object-kanban-quick-add-retired.md: the closing note now reads that ObjectKanbanSchema.onQuickAdd is retired on object-kanban too, by objectui#11234 in the same release, and the Quick Add pair on KanbanRenderer is unchanged. True.
    • The new changeset's last sentence, that the objectui#8285 entry's closing note is amended in this change, is true.

③ Boundary flags

open_questions: empty in all three dev reports; none to answer.

Deviations (report 5919636549), each answered:

  1. quickAdd: undefined removed — answered in ① item 6: dead after the move, behaviour pinned by 8285 row 1.
  2. Three source-reading pins edited outside the named list, one in packages/react — answered in ① item 7; test-only; the seat supplemented the file surface with them.
  3. plugin-kanban patch where the order left the bump open — answered in ②: right.
  4. The plugin-kanban directory run and the 8 named pins ran at 611112e0e, not the final head — accepted: the last code commit e2bf34b97 touched one types test file and the types, importer and root-scripts suites ran there; the two later commits are changeset text only; and the check-runs on b1e88910f are the verdicts of record in any case.
  5. Attribution trailer — no model identifier appears in the diff or the PR body; nothing for the contract to judge.
  6. Card body Clause-②: yes against claim Clause-②: no (narrowing) — answered: the claim binds, the PR body carries no (narrowing), and ② confirms it. ESCALATED to the seat as a card-text inconsistency to reconcile on close (the card's Direction paragraph still says Clause-②: yes); no PR change is owed.

Follow-up reports 5919687375 and 5919732925 declare no deviations; their out-of-scope findings (the three pending changesets that would ship false) were taken into the PR and are judged in ②.

Noted-not-filed observations:

  • The objectui#6124 RetiredIsNever type block has no ObjectKanbanSchema['onCardMove'] row — pre-existing since objectui#9342, neither introduced nor widened here; that key's never is read off source by 7804 suite 3 and its runtime RETIRED row exists. ESCALATED to the seat as a one-row ledger addition for a follow-up (the report names no carrier); not blocking.
  • Stale "KanbanRenderer's lazy boundary" and pre-warm comments — answered: the import('./KanbanImpl') lazy boundary moved to KanbanBoardCore.tsx and resolves to the same module id, so pre-warm imports of '../KanbanImpl' still hit the module cache, and 8932's lit control measures the new location. Comment-only, AGENTS.md opportunistic repair. Accepted.
  • The stale census count (① item 9) is this record's own observation for the seat; not blocking.

Implemented-by: claude/issue-11234-kanban-onquickadd-retire
Reviewed-by: session_011p7ikEivgXefNDaE5S5Uec

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 21:26
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 52aad5c Sep 30, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11234-kanban-onquickadd-retire branch September 30, 2026 21:41
huangyiirene pushed a commit that referenced this pull request Sep 30, 2026
Carries main through PR #11267, #11268, #11269, #11271, #11273 and #11274.
No conflicts.

Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh
Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Oct 7, 2026
…, mirror two chatbot keys, file eighteen runtime slots by name (objectui#6152, round 4) (objectstack-ai#11285)

Refs objectstack-ai#6152
Clause-②: yes (narrowing). The two mirrors widen `@object-ui/types/zod`
and the strict authoring face to keys the TypeScript face already
invited and the renderers read (`requestBody`, `floatingConfig`). The
four retirements (`label.content`, `report.chartConfig`,
`report.reportType`, `detail-view.autoDiscoverRelated`) narrow both
faces at once, under the startup no-gradualism rule. It is priced in
`.changeset/6152-unmirrored-round4.md` as `minor`, with the break
stated.

Round 4 of objectui#6152, dispatched under claim `5919877490` (the
`domain:devx` seat 2, session `session_01TdiauJaVCHuj45EzZGUxHh`, on the
maintainer's direct order). The rulings are the seat review
`5914490915`: Q1 B, Q2 A, Q3 B. ⛔ This is a draft from a dispatched dev:
do not mark it ready and do not enable auto-merge. The card stays open,
because `ObjectGridSchema`, the spec-derived pairs and three
`DataTableSchema` keys (below) are not this round's.

## What changed

1. **Q1 B: `LabelSchema.content` is retired.** It is `?: never` on
`form.ts` and a `retirementTombstone` on `form.zod.ts` that names the
kept spellings `text` and `label`. The `label` renderer drops its third
read limb (`schema.text || schema.label`). Re-measured: 0 documents
author it (JSON, Markdown JSON fences and typed literals); its only
author was a test in `form-renderers.test.tsx`, which now pins the
refusal. Which of `text` / `label` is canonical is not decided here.
2. **Q2 A: `DetailViewSchema` `activities`, `comments`, `history` and
`recordNavigation` go to `RuntimeOnlyDeclared` by name.** Each has a row
with its reason on `RuntimeOnlyNamedAllowList`, in round 3's shape. They
carry host-fetched runtime data, and `recordNavigation.onNavigate` is a
required function.
3. **Q3 B, under objectui#7654 ruling B: `displayMode` keeps its
TypeScript-only refusal.** It gets no zod arm, because stored designer
documents carry `displayMode: 'floating'` (pinned by
`chatbot-display-mode-retired.test.ts`). The ledger entries no longer
call the mirror half "owed"; the key stays listed by decision.
Separately, after a reader census for each:
- `ChatbotSchema.requestBody` is mirrored through the shared pick. All
three chatbot registrations read it (`body: schema.requestBody`).
- `ChatbotFloatingSchema.floatingConfig` is mirrored through a
module-private restatement of `FloatingChatbotConfig`. That restatement
judges the six members `FloatingChatbot` destructures, and carries the
`triggerIcon` tombstone's runtime half that the objectui#7654 tripwire
asked for.
4. **The three zero-read candidates are retired on both faces.** They
are `ReportComponentSchema.chartConfig`,
`ReportComponentSchema.reportType` and
`DetailViewSchema.autoDiscoverRelated`, each `?: never` plus a
`retirementTombstone`. `reportType`'s one in-code producer,
`specReportToPresentation` in `spec-report.ts`, no longer writes it, and
`LegacyReportPresentationLike` no longer declares it.
5. **`DataTableSchema`: 14 of 17 keys go to `RuntimeOnlyDeclared` by
name.** They are produced only in code, by `ObjectGrid`'s in-code
`data-table` node or `RelatedList`'s, and authored by no document. Three
keys fit none of the classes, so the round stopped at them (see
"Stopped" below).
6. **The pagination corpus fix, carried from round 3.**
`components-basic-pagination/with-item-count.json` no longer authors
`pageSize` / `totalItems`, which neither face declares and nothing
reads. The plaintext interface block on
`content/docs/components/basic/pagination.mdx` stops listing them, and
its section is retitled from "With Page Size" to "On a Later Page".
7. **Changesets.** One new: `.changeset/6152-unmirrored-round4.md`
(`@object-ui/types` minor, `@object-ui/components` minor, with the break
stated). Four dated, append-only corrections were added, each 2 lines
with frontmatter unchanged: `6639-objectgrid-title-mirrored.md` (the
stale "97 + 1 + 23" sentence),
`7654-floating-chatbot-trigger-icon-tombstone.md`,
`7655-chatbot-registration-authoring-faces.md` and
`9447-detail-view-handler-key-refusal.md`. Every other pending changeset
was re-read after the merges, including the 8 that landed since the
base, and none is made false by this round.

## Ledger totals, before and after

These are read by the file's own pins (`objectui#7279` derives every
figure) and re-counted with the TypeScript parser on the final head.

| ledger | before (`origin/main` `e420df3`) | after (`2cc4ab9`) |
| --- | --- | --- |
| `UnmirroredDeclared` | 9 entries / 44 keys: 3 / 14 spec-derived, 6 /
30 local | **6 / 20**: 3 / 14 spec-derived, 3 / 6 local |
| `RuntimeOnlyDeclared` | 4 / 9 | **4 / 27** |
| `RuntimeOnlyNamedAllowList` | 1 entry / 2 rows | 3 / 20 |
| cross-ledger | 2 of the 4 are in `UnmirroredDeclared`; union 11 = 9 +
2 | **1 of the 4**; union **9** = 6 + 3 |
| `KnownDrift` | 49 / 86 | 49 / 86, unchanged. This round does not edit
its total line; PR objectstack-ai#11269's 87 to 86 edit is kept as merged. |
| `WiderThanDeclared`, `MirroredUndeclared` | 3 / 3, 2 / 2 | unchanged |

The 24 keys that left `UnmirroredDeclared` moved by three routes, which
must not be added up as one repair: 2 were mirrored, 4 were retired, and
18 were reclassified by name. The reclassification is one move seen from
both ledgers: it is not new debt, and it mirrors nothing.

## Per-key table

| pair · key | measured (type-checker read census over 5548 sources;
authored census over tracked JSON, Markdown JSON fences and `type`
literals) | route |
| --- | --- | --- |
| `label` · `content` | 1 read (the third limb in `label.tsx`), 0
documents (1 test) | retired on both faces; the read is dropped |
| `report` · `chartConfig` | 0 typed reads. The untyped
`widget?.chartConfig` hits are plugin-dashboard's `DatasetWidget`
(`widget: any`, a dashboard widget), which plugin-report never imports.
0 documents | retired on both faces |
| `report` · `reportType` | 0 reads; one in-code producer
(`specReportToPresentation`); 0 documents | retired on both faces; the
producer write is removed |
| `detail-view` · `autoDiscoverRelated` | 0 reads (typed or untyped), 0
documents | retired on both faces |
| `chatbot` · `requestBody` | 3 reads (all three chatbot registrations)
| mirrored (shared pick) |
| `chatbot-floating` · `floatingConfig` | 1 read
(`floatingConfig={schema.floatingConfig}`); 6 of 7
`FloatingChatbotConfig` members read, and `triggerIcon` 0 | mirrored,
with a `FloatingChatbotConfig` restatement |
| `chatbot`, `chatbot-floating` · `displayMode` | 0 reads; stored
documents carry it | unchanged by ruling (TypeScript-only refusal) |
| `detail-view` · `activities` (7 reads), `comments` (4), `history` (7)
| host-fetched rows; 0 documents | `RuntimeOnlyDeclared` by name |
| `detail-view` · `recordNavigation` | 11 reads; its value carries a
required function | `RuntimeOnlyDeclared` by name |
| `data-table` · `disableInnerScroll`, `manualPagination`,
`manualSearch`, `manualSorting`, `page`, `rowActionDefs`,
`rowClassName`, `rowCount`, `rowStyle`, `search`, `selectionResetKey`,
`showAddRow`, `showSelectionCount`, `sort` | read by `data-table`;
produced only in code (`ObjectGrid`, `RelatedList`); 0 docs and 0
catalog documents | `RuntimeOnlyDeclared` by name; the reasons are on
the allow-list |
| `data-table` · `editable`, `singleClickEdit` | read; produced in code
by `ObjectGrid`; 0 documents, but `data-table.mdx` lists both and
teaches `editable: true` | **stopped**, ruling needed |
| `data-table` · `selectionStyle` | read; 0 producers and 0 documents (0
hits in objectstack too) | **stopped**, ruling needed |

## Runtime probe for the three zero-read retirements

AGENTS.md requires more than a source census, because leftover keys
reach a renderer as spread props. So the probe used the real
`SchemaRenderer` and the real registry, and varied only the key. It was
a one-off: the files were deleted afterwards and `git diff HEAD` is
empty.

- `report`: the DOM is identical with and without `chartConfig` plus
`reportType` (797 = 797 characters, byte-equal). Lit control: changing
`title` changes the DOM (805).
- `detail-view`: the DOM is identical with and without
`autoDiscoverRelated: true`, after normalising React's `useId` tokens.
The only raw difference was `radix-_r_5_` against `radix-_r_d_`. The
data-source and `fetch` call log is identical:
`getObjectSchema(account)` and two `security/explain` fetches. Lit
control: changing `title` changes the DOM (5943 against 5951).

## Ablations

The predictions were written at `4c272dc` before any run, and every leg
was restored with the blob equal to `HEAD` and `git diff HEAD` empty.

- **A1:** plant a `LabelSchema` literal carrying `content` into
`label.tsx`. Components `tsc --noEmit` exits 2 with exactly one TS2322
there (`'string' is not assignable to type 'undefined'`), as predicted.
This red direction also shows the consumer read the rebuilt `.d.ts`.
- **A2:** restore the four `zod/*.zod.ts` files to base `f61dab1`.
`unmirrored-declared-round4-6152.test.ts` reads `27 failed | 6 passed
(33)`, exactly as predicted, and `tsc -p tsconfig.test.json` exits 2
with its only error in the ledger reconciliation of
`zod-mirror-parity.test.ts`.
- **A3:** rename the allow-list row `rowCount` to `rowCountRenamed`.
`tsc -p tsconfig.test.json` exits 2 with exactly two TS2344, at the two
allow-list pins, as predicted.

## Verification on the final head `2cc4ab9`

This round resumed after two container restarts, so every run below was
redone on `2cc4ab9`. That head carries `origin/main` `e420df3`, merged
twice (never rebased): once through PR objectstack-ai#11275, and before that through
PRs objectstack-ai#11267, objectstack-ai#11268, objectstack-ai#11269, objectstack-ai#11271, objectstack-ai#11273 and objectstack-ai#11274. Each run went
through the shared verify lock with at most 2 workers.

- `@object-ui/types`: `type-check` (the `--noEmit`,
`tsconfig.examples.json` and `tsconfig.test.json` legs) exits 0; `vitest
run packages/types/` gives 299 files and 7498 tests passed; `build`
exits 0 (138 emitted files verified).
- Consumers, from the type-checker census: `type-check` exits 0 with 0
TS errors for `components`, `plugin-report`, `plugin-detail` and
`plugin-chatbot`. `vitest run packages/plugin-report/
packages/plugin-chatbot/` plus `form-renderers.test.tsx` gives 78 files,
827 passed and 7 skipped. All 228 `plugin-detail` test files, run in two
halves, give 227 files passed plus 1 skipped, and 2264 tests passed plus
8 skipped.
- Zod-face consumers: `vitest run examples/schema-catalog/
packages/cli/` plus the 17 app-shell files that import
`@object-ui/types/zod` or sit in `metadata-admin/previews/__tests__`
give 77 files and 2741 tests passed.
- Gates, all exit 0: `check:changeset-claims`,
`check:pending-changeset-literals`, `check-changeset-presence` (16
source files of 2 released packages, 1 changeset),
`check-changeset-no-major`, `check-changeset-fixed`,
`check-changeset-overwrite` (report-only; its 4 findings are the 4 dated
appends above), `check:control-bytes` (9717 files), `check:doc-fences`,
`check:doc-snippets` (697 of 697 blocks judged, 0 failed),
`check:doc-examples`, `check:doc-types`, `check:doc-example-ids`,
`check:doc-example-readers`, `check:skill-examples`,
`check:handler-key-reads`, `check:component-surface-parity`
(report-only), `check:designer-field-key-parity`,
`check:element-data-source-declaration`, `check:new-line-citations` (0
new), `check:prompt-keys`, `check:readme-exports`, `check:spec-symbols`,
`check:test-path-roots`, `check:unreferenced-sources` and
`check-type-check-coverage`. `doc-snippets` and `doc-examples` ran after
the scoped build their own `--build-filter` names (35 turbo tasks, all
successful).
- Lint, narrowed: `eslint --no-inline-config --format json` over the 16
lintable changed files gives 0 errors. All 16 were judged and 0 were
ignored, a population read from eslint's own output. The 39 warnings are
pre-existing `no-explicit-any`, and the diff adds no explicit `any`.
`eslint.config.js` declares no `parserOptions.project` or
`projectService`, and no custom rule in `eslint-rules/` reads the disk,
so this diff cannot move any untouched file's verdict. The repo-wide
`pnpm lint` is CI's.
- Governed surface: `check-governed-queue-guard.mjs --test` over the 23
paths reports NOT GOVERNED.
- NOT MEASURED:
- `check:sdui-registration-pins`: it needs a console build, and this
diff changes no registration.
  - The full `pnpm test` farm and repo-wide lint: CI's.
- `plugin-grid`: its code and tests are untouched. The 14 reclassified
keys moved between two test ledgers and no declaration changed.

## Stopped (ruling needed; reported in the card report with options)

- `DataTableSchema.editable` and `singleClickEdit`. `data-table` reads
both and `ObjectGrid` sets both in code, while no document authors them.
But `content/docs/components/complex/data-table.mdx` lists both in its
interface block and teaches `editable: true`. Filing them runtime-only
would contradict that page. Mirroring them would rest on no authored
document, and, from the source, an authored `editable: true` stages cell
edits locally and persists nothing without the `onRowSave` /
`onCellChange` function slots.
- `DataTableSchema.selectionStyle`. `data-table` reads it (`'always'` or
`'hover'`), and nothing authors or produces it in either repository.
- Noted, not narrowed: `ChatbotSchema.floatingConfig` has 0 reads on the
`chatbot` node (only `chatbot-floating` reads it), which makes it an
ADR-0049 narrowing candidate. The `chatbot` half of
`floating-chatbot-trigger-icon-retired.test.ts` pins its absence as a
tripwire.

## Parallel discipline

PR objectstack-ai#11269 and PR objectstack-ai#11273 edited `zod-mirror-parity.test.ts` in disjoint
hunks: the `KnownDrift` total line, the Kanban entry and one
`EXCLUSIONS` row. Both merges were clean. This round's ledger edits stay
in the `UnmirroredDeclared` / `RuntimeOnlyDeclared` /
`RuntimeOnlyNamedAllowList` blocks, their prose totals and its own
pairs' entries. Every prose total was reconciled to the measured count
above. The diff does not touch `zod/objectql.zod.ts`,
`zod/index.zod.ts`, `zod/nested-component-walk.ts`,
`strict-authoring-face.ts`, `zod/README.md`, `field-types.ts`, the
`DetailViewField` member, or `data-table.tsx` (read only).

## Acceptance notes

- 23 files, under the ~25-file size guard, so no pair was cut.
- Every pending changeset this round made false carries a dated append.
The ones it leaves true were re-read:
`7654-chatbot-display-mode-tombstone.md`, `6150-…`, `7804-…`, `6175-…`,
`7722-…`, `7947-…` and `8072-…`.

Session: `https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh`

---
_Generated by [Claude
Code](https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants