Skip to content

feat(types)!: refuse both content channels on the E3 residual (nine object views, detail-view, email, password) and repair the shorthand Omit erasure (objectui#9256) - #10897

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-9256-e3-residual
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-9256-e3-residual

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Part of #9256
Clause-②: yes

Clause-② yes, as the claim declared: twelve published arms stop accepting an authored children, and two published TypeScript faces stop erasing the members they inherit. Both narrow an accept set; a contract review is owed before landing.

The E3 residual that the maintainer's ruling on objectui#8284 (comment 5861449497, Q2 A) moved onto this card: keys with a published arm whose renderer reads neither content channel. It also carries the ruling's execution parameter 3, the InputShorthandSchema / UiCalendarSchema TypeScript Omit erasure. objectui#9256 stays open for the rest of family D.

What changed

  • Narrowed (12 keys): object-grid, object-form, object-kanban, object-map, object-tree, object-view, object-gantt, object-calendar, object-chart, detail-view, email, password.
    • TypeScript face: body?: never and children?: never, each with a docblock naming what the node renders instead.
    • zod mirror: body and children are two retirementTombstone members fed ONE string from the new neitherContentChannelGuidance builder in zod/tombstone.zod.ts. Both stay MEMBERS, so zod-mirror-parity's key sets stay equal.
    • body was already refused on these arms (by BaseSchema, objectui#6771), except on the email / password TypeScript face, which the Omit erased. It is restated because BaseSchema's refusal names children as the remedy, and children is dead here too.
  • Omit erasure repaired: InputShorthandSchema and UiCalendarSchema now inherit through OmitDeclared (form.ts, not exported). It is a key-remapping mapped type: it drops exactly the named keys and keeps every other named member and the index signature.
    • ui:calendar gains no refusal of its own. Its face now re-exposes what CalendarSchema declares, so the published TypeScript face refuses body, children and a mode outside the declared enum, which the erased face accepted. Its mirror (a .extend() of that one) already refused them.
    • I measured the ui:calendar renderer anyway (renderers/form/calendar.tsx, typed CalendarSchema). It reads defaultValue, mode and value, and no channel.
  • Held (3 keys): br, hr, img. See "Held, and the question it leaves" below.

Per-key measurement, taken on origin/main 0c50f1863 before any edit

Instrument. The TypeScript compiler API, ⛔ not grep. It builds one program per workspace package from that package's own tsconfig.json: 40 programs over 1573 source files, on a BUILT tree (turbo build 42/42 first), with @object-ui/types resolving to packages/types/dist. It files every .body / .children read (property access, string element access, object destructuring) under the declared type of its receiver.

  • 547 channel reads were filed.
  • Lit controls fire: ButtonSchema 1, DivSchema 1, CardSchema 1, ContainerSchema 1 (each children).
  • Receiver-reachability control: the same program sees every narrowed declaration as a receiver of the keys its renderer reads. The zeros below are readings, not blindness.
key registration(s) claiming it registration hop → reader, and the type it reads the node as body / children reads under that type receiver reads (reachability) arm, TS face: before → after arm, zod face: before → after disposition
object-grid plugin-grid:object-grid (+ console registerLazy of the same plugin) ObjectGridRenderer (any) → ObjectGrid · ObjectGridSchema 0 / 0 158 reads, 38 keys body refused (BaseSchema), children accepted → both refused same → both refused by name narrowed
object-form plugin-form:object-form ObjectFormRenderer (any) → ObjectForm · ObjectFormSchema 0 / 0 200 / 44 same same narrowed
object-kanban plugin-kanban:object-kanban (+ lazy) ObjectKanbanRenderer (any) → ObjectKanban · ObjectKanbanSchema 0 / 0 67 / 13 same same narrowed
object-map plugin-map:object-map (+ lazy) ObjectMapRenderer (any) → ObjectMap · ObjectMapSchema 0 / 0 30 / 16 same same narrowed
object-tree plugin-tree:object-tree (+ lazy) ObjectTreeRenderer (any) → ObjectTree · ObjectTreeSchema 0 / 0 13 / 8 same same narrowed
object-view plugin-view:object-view (and the view alias) ObjectViewRenderer (any) → ObjectView · ObjectViewSchema 0 / 0 112 / 19 same same narrowed
object-gantt plugin-gantt:object-gantt (+ lazy) ObjectGanttRenderer (any) → ObjectGantt · ObjectGanttSchema 0 / 0 61 / 48 same same narrowed
object-calendar plugin-calendar:object-calendar (+ lazy) ObjectCalendarRenderer (any) → ObjectCalendar · ObjectCalendarSchema 0 / 0 40 / 12 same same narrowed
object-chart plugin-charts:object-chart (+ lazy) ObjectChartBlock (any) → ObjectChart · ObjectChartSchema 0 / 0 123 / 15 same same narrowed
detail-view plugin-detail:detail-view DetailViewRenderer (any) → DetailView · DetailViewSchema 0 / 0 195 / 31 same same narrowed
email ui:email (field:email stands down) any wrapper spreads the node into InputRenderer · InputSchema 0 / 0 23 / 17 BOTH accepted (erased Omit) → both refused body refused, children accepted → both refused by name narrowed
password ui:password (field:password stands down) same as email 0 / 0 23 / 17 same as email same as email narrowed
br ui:br html-elements factory (any), void tag: passes undefined as the child reads neither (the one schema?.children read is behind the void-tag guard) n/a (any) body refused, children accepted (family arm) → unchanged same → unchanged held
hr ui:hr same same n/a same same held
img ui:img same same n/a same same held

The residual count stays 15: no key reads children today. 12 are narrowed and 3 are held.

any-typed receivers, attributed rather than assumed.

  • Every hop above is any-typed. Each hop body was read: none contains a channel read.
  • The any-typed reads in the eleven hosting files and packages were attributed one by one:
    • React children destructured off internal components' own props (SchemaRenderer passes no node child as a React child);
    • document.body and err.body;
    • TreeNode.children on the record hierarchy ObjectTree builds;
    • FeedItem.body;
    • record:alert's own props.body, which is another registration.
  • The html factory's schema?.children read sits behind isVoid ? undefined : ….

Delegation hosts, checked for pass-through. Every SchemaRenderer call in the ten object/detail packages was traced. The node it renders is built one of three ways:

  • key by key — ObjectForm / ModalForm / DrawerForm / TabbedForm / SplitForm / WizardForm all build their form node that way, and the form renderer DOES draw children, which is why this was checked;
  • from a sub-key — DetailView's header / footer / tab content, ObjectChart's drill-down table;
  • or from a generated object-* node — ObjectView assembles object-kanban, object-calendar, object-gallery, object-timeline, object-gantt, object-map, object-tree and object-chart from named keys, and every one of those reads neither channel (for gallery and timeline: packages/plugin-list and packages/plugin-timeline hold no node-channel read).

No host spreads its own node into a node that reads children.

Generic traversers (validateChildren in core, sdui-parser validateTree, the metadata-admin preview canvases, the vscode validator) walk children to validate or preview. They render nothing and are node-agnostic, as for every row family D already holds.

objectui#9910 cross-check. None of the 12 narrowed registrations declares a children slot input: a grep over their registration files finds 0 hits, and the lit control is html-elements.tsx / div.tsx, which do.

Producers. pnpm census:body-dialect --keys over the 15, plus ui:calendar and input, with div / card / page / button / p / h1 as lit controls in the same pass: 8981 files, 2744 candidate nodes.

  • 0 nodes author children on any of the 15.
  • 1 node authors body on ui:calendar: it was the family-D TRIPWIRE test line (test bucket), moved by this change.
  • The controls read div 170 / card 183 / page 47 children.
  • Producers derived: none. Nothing was migrated.

The Omit repair — measured on the BUILT d.ts

A probe program under packages/components resolved @object-ui/types to packages/types/dist/index.d.ts (--traceResolution). It carried 15 @ts-expect-error pins (the 10 object/detail children, email children, password body, email label: 42, and the ui:calendar children and mode: 'default'), a lit control (const n: number = 'x'), and 12 channel-free controls.

  • On this branch: exit 0 — every directive used, every control compiles, the lit control fires.
  • On the base dist: exit 2 with 15 × TS2578, and the lit control is still used.
  • The emitted dist/form.d.ts declares OmitDeclared locally and both heritage clauses use it.

Red on base, then green — one-shot, the restore proven by state

The predictions were written to a file BEFORE the mutation. The mutation was git checkout 0c50f1863 -- THE-SEVEN-DECLARATION-FILES, with every test file at HEAD. It was proven by 7/7 blob hashes equal to BASE plus anchor counts (neitherContentChannel 0, OmitDeclared 0). The run sat under trap … EXIT INT TERM with absolute paths.

reader mutated (BASE arms) restored (HEAD 14fd13c51)
vitest, the new pin file RED exit 1 — 73 failed / 90 passed; exactly the predicted 12 × 5 children families + 12 body-message rows + 1 nested row GREEN 163 / 163
tsc -p packages/types/tsconfig.test.json RED exit 2 — 18 × TS2578 and 3 × TS2322 (the Eq pins) in the new file, plus 3 in zod-mirror-parity naming the two re-collapsed pairs and the stale KnownDrift row; 0 elsewhere GREEN exit 0
built-d.ts probe (types rebuilt; dist markers 0 → 29 / 6) RED exit 2, 15 × TS2578 GREEN exit 0

The restore was proven by 7/7 blob hashes equal to HEAD, git diff HEAD empty and git status clean, both after the restore and at the end.

⚠️ The body rows on the ten object/detail arms are GREEN on base, by design: BaseSchema already refused body there. Only their MESSAGE changes, and the message rows are the ones that turn red. ?: never is erased before vitest runs, so the TypeScript half is read by tsc alone. The vitest run cannot see it.

Serial constraints

Collateral that the repair and narrowing made true or false — each measured, none widened

  • zod-mirror-parity.test.ts:
    • The two Omit COLLAPSE rows (32 + 26 keys) leave MirroredUndeclared. Its figures move from 4 / 60 to 2 / 2, and the class note records the emptying.
    • Restoring the named members NARROWED those faces: a collapsed face accepted every key at any. So this is not the "declare the keys" remedy that ledger refuses.
    • The repaired shorthand face now carries InputSchema's onChange runtime slot. It enters KnownDrift as inherited drift: one entry, one key. After the merge with PR objectui#10890 (which took ai.zod.ts#AIFormAssistSchema out, one entry and two keys), the table holds 49 entries / 88 keys, and both header sites say so.
    • The union-arm non-vacuity leg had no multi-arm entry left in this ledger. It now takes the same reader's arm-walking on KnownDrift and re-arms here when a multi-arm entry lands.
  • object-view-spec-parity.test.ts: body / children are redeclared envelope keys on object-view now. They are triaged into SANCTIONED_LOCAL as refusal-only surface, like viewTabBar, and the declared-surface figure moves 24 → 26.
  • CalendarSchema's texts on both faces said the TypeScript Omit "collapses … and carries no member". That became false; they are corrected.
  • Two comments that spelled the old plain-Omit heritage (index.ts, form-barrel-mirror-9406.test.ts) are corrected.
  • scripts/check-handler-key-read-sites.mjs caught my first spelling. It was a computed spread (...helper(…)) that the gate cannot resolve, so it stopped judging all eleven arms and its detail-view onTabChange waiver read stale. The fix, the second commit, declares both members explicitly. Now 49 / 49 reads are judged and 0 are left unjudged.

Held, and the question it leaves

br / hr / img read neither channel, but their only published arm is HtmlElementSchema: ONE object over 38 tags, whose renderer draws children for the other 35 (p, h1, …). Refusing the key on three tags means splitting that family arm, or refining it per tag. Both change a published contract's shape.

  • The option the ruling adopted (option A in measurement 5859897857) reads: "leaving the three void tags to the tier because their arm is the shared HtmlElementSchema family whose per-tag split was ruled out (objectui#9067)".
  • The parser tier already names them: the registration declares no children slot on a void tag, so validateTree reports not-a-container.
  • A HELD control in the new pin file records the shared-arm fact, so the hold is visible.

That the brief listed them among the keys to narrow is recorded as a conflict in the report, ⛔ not resolved here by guessing.

Gates (at HEAD 14fd13c51, exit codes captured by redirect-then-capture; heavy runs through the shared verify lock)

gate result
@object-ui/types build (tsc + vite + dist completeness) exit 0 — 132 emitted files verified
@object-ui/types type-check (tsc --noEmit + examples + tsconfig.test.json) exit 0
pnpm exec vitest run packages/types/ (parity, node-slot, arm, mirror, family-D and the new pins) 259 files / 5670 tests, exit 0
pnpm exec vitest run scripts/ 177 passed + 2 skipped of 179 files / 5317 tests, exit 0
consumer type-check — every package naming a narrowed type (28 packages: the ten object plugins, app-shell, components, core, fields, cli, react, runner, console, schema-catalog, vscode-extension …) exit 0, 28 × type-check: Done
pnpm --filter @object-ui/types lint 0 errors; 0 findings on any added line (eslint JSON over the 13 touched files)
check:control-bytes · check:new-line-citations (0 new) · changeset:check · check-changeset-presence · check:changeset-claims · check:pending-changeset-literals exit 0 each
check:doc-types · check:doc-snippets · check:doc-examples · check:skill-examples · check:doc-fences · check:doc-example-ids (against the built types) exit 0 each
check:handler-key-reads · check:component-surface-parity · check:prompt-keys · check:registry-bare-names · check:spec-symbols · check:readme-exports · pnpm check (CLI self-check) exit 0 each
governed guard --test over the 14 paths NOT GOVERNED

NOT MEASURED:

  • check:sdui-registration-pins exits 2 without a console build. The diff touches no registration and no sideEffects array. Left to CI.
  • The 4-way pnpm test shards beyond packages/types and scripts/, plus test:dist and E2E: left to CI.

Merge round — head 31bb63bcb (merges main at c30c8dd4c)

The one conflict was the two KnownDrift header figures in zod-mirror-parity.test.ts. It was resolved by RECOUNTING the merged table with the test's own AST reader, not by picking a side:

tree KnownDrift
base 0c50f1863 49 entries / 89 keys
PR objectui#10890 removes ai.zod.ts#AIFormAssistSchema −1 entry / −2 keys (48 / 87 on c30c8dd4c)
this branch adds form.zod.ts#InputShorthandSchema +1 entry / +1 key (50 / 90 on 14fd13c51)
merged 31bb63bcb 49 entries / 88 keys

The population bullet and the KNOWN_DRIFT restatement both read 49 / 88, and the bullet keeps both histories in landing order. The other ledgers read the same as before: MirroredUndeclared 2 / 2, UnmirroredDeclared 12 / 84, RuntimeOnlyDeclared 3 / 7, WiderThanDeclared 6 / 7. The merge head differs from main by exactly this PR's 14 files.

gate at 31bb63bcb result
zod-mirror-parity + content-channel-e3-residual-9256 2 files / 200 tests, exit 0
@object-ui/types build · type-check (incl. tsconfig.test.json) exit 0 · exit 0
pnpm exec vitest run packages/types/ (incl. PR objectui#10890's ai-zod-arms-10859 / ai-node-faces-agree-10874 and the family-D file PR objectui#10714 edited) 261 files / 5696 tests, exit 0
pnpm exec vitest run scripts/ 177 passed + 2 skipped of 179 files / 5322 tests, exit 0
check:control-bytes · check:new-line-citations · changeset:check · check-changeset-presence · check:changeset-claims · check:pending-changeset-literals · check:handler-key-reads exit 0 each

Acceptance notes — out of scope, not fixed here

  • input reads neither channel as well. InputSchema: 0 channel reads, 17 keys read; the registration declares no children slot.
    • It is this card's remaining family-D name, and it was not in this claim.
    • Its old hold-out ground ("a TS Omit carries nothing") is gone with this repair: a tombstone on InputSchema now propagates on both faces.
    • Carrier: the next objectui#9256 slice.
  • PartialSchema's docblock in index.ts says every generic re-spelling of its Omit collapses for the same keyof T reason. OmitDeclared is a generic spelling that does not: this PR measures it on two faces.
    • Carrier: the next objectui#9256 slice, which touches the same Omit subject. objectui#6397, that alias's card, is closed.
    • Noted, not filed.
  • The family-D test header still records InputSchema as "family E, frozen" and DetailViewSchema as unattributable. Both readings are superseded by this change.
    • Carrier: the next objectui#9256 slice.
    • Noted, not edited: PR objectui#10714 held that file while this PR was written. It has since merged, so the next slice edits the header freely.

Generated by Claude Code

…op the shorthand Omit erasing inherited members

Part of objectui#9256 (the 15-key E3 residual the ruling on objectui#8284,
Q2 A, moved onto that card).

Twelve registrations have a published arm yet their renderer reads neither
content channel: the nine object-* views, detail-view, email and password.
Both body and children are now ?: never on the TypeScript face and a
by-name refusal on the zod mirror (neitherContentChannel, a pair of
retirementTombstone members), each kept a member so the parity ratchet's
key sets stay equal. The message names what the node renders instead.

InputShorthandSchema and UiCalendarSchema were spelled as a plain Omit
over an interface carrying BaseSchema's index signature, which erased
every inherited member on the published face. Both now inherit through
OmitDeclared, a key-remapping Omit that keeps the named members; the two
Omit COLLAPSE rows leave the MirroredUndeclared ledger and the inherited
onChange runtime slot enters KnownDrift.

br, hr and img are held: their only arm is the 38-tag HtmlElementSchema
family, whose renderer draws children for the other 35.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
…ding a call

A computed spread in a zod arm is a shape check-handler-key-read-sites
cannot follow, and the gate stops judging an arm whose member set it
cannot resolve: the spread blinded it on all eleven arms and turned its
detail-view onTabChange waiver stale. Each arm now declares body and
children explicitly as retirementTombstone members fed one string from
neitherContentChannelGuidance, so the gate reads every arm again
(0 reads left unjudged).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 60 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/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/5905-componentinput-inputtype-tombstone.md

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

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

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

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

  • 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/6105-tombstone-refusal-message.md

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

    One shared mechanism carries the text into both channels. retirementTombstone() (zod/tombstone.zod.ts) takes the guidance string ONCE and writes it to both z.never({ error }) — the parse-time issue message — and .describe() — the generated JSON-Schema and docs surface, unchanged. One string, so the two cannot drift.

.changeset/6124-handler-keys-json-refusal.md

.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/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/6349-name-authority-batch-3.md

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

    @object-ui/components — ComboboxOption now IS @object-ui/types' declaration. The component declared its own { value, label }, a strict subset of the ComboboxOption that @object-ui/types declares for ComboboxSchema.options and mirrors in form.zod.ts ({ value, label, disabled? }). The component now re-exports the types declaration (through the @object-ui/types/form subpath — the root barrel does not publish the name), so the name ComboboxOption exported from @object-ui/components gains the optional disabled?: boolean member. Every value that type-checked before still does — nothing narrows and no key changes type; the one thing that moves is keyof ComboboxOption, so a consumer that EXHAUSTS the type (a Record over its keys) will need the new key. Note that the Combobox component itself does not read option.disabled — that member was already declared on the @object-ui/types face and is now visible on this one too; it is recorded as a separate finding, not changed here.

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

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

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

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

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

.changeset/6594-headercolor-mirror-enum.md

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

    The nearest precedent is fc62bb490 (.changeset/5853-tablecolumn-type-canonical-union.md), which narrowed TableColumn.type on the same three-ends pattern and exported a TABLE_COLUMN_TYPES tuple for the zod mirror to build its enum from. That shape is not available here and the difference is structural, not a preference: packages/types/src/views.ts is a type-only module, so a tuple there would add a runtime export to the package barrel (a value export cannot ride the barrel's export type block) and a runtime import edge from the zod entry into views.js. fc62bb490 had a second reason to export — producers needed its normalizeTableColumnType() at their emit seam — and headerColor has no producer that needs a runtime value. The literals are therefore written on each half and the anti-drift guarantee is carried by the pin above, which also covers the third end a shared tuple could not reach: the renderer, in a package @object-ui/types must not depend on.

.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/6938-checkbox-wrapper-class.md

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

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

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

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

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

  • names form.zod.ts → packages/types/src/zod/form.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/7287-resolve-title-field-shared-ladder.md

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

    def.primaryField — a DetailViewSchema key (@object-ui/types views.ts), read off an OBJECT def and ranked ABOVE the canonical nameField ADR-0079 Phase 2 made the pointer (AGENTS.md Commandment #0.1). No producer can put it there: @objectstack/spec's object schema is a strictObject that answers unrecognized_keys: ['primaryField'], and ObjectSchema.create() throws — which is why objectstack#6326 deleted the identical read from two lint rules. A census across both repos found zero object payloads carrying it (the only writers are three test fixtures), and primaryField appears in zero files of the shipped @objectstack/spec@17.2.0 dist against 68 for nameField. Same shape as the undeclared objectDef.titleField read objectui#6531 measured and Five more consumer-side reads of the undeclared object-level titleField survive #6531 — in ObjectView view-config fallbacks and a useRecordSearch memo key #6557 removed. DetailViewSchema.primaryField is untouched and still honoured by DetailView's own header — it is a view key, and on a view it is legitimate.

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

.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/7530-predicate-envelope-declared.md

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

    • ExpressionWire (type, main entry) — the TypeScript wire union, in packages/types/src/expression.ts. - ExpressionWireSchema (@object-ui/types/zod) — its runtime twin, hoisted out of zod/form.zod.ts (where it was module-private) into zod/expression.zod.ts and imported by both base.zod.ts and form.zod.ts. One envelope type, reused by reference; no second spelling.
  • names form.zod.ts → packages/types/src/zod/form.zod.ts — edited by this change

    • ExpressionWire (type, main entry) — the TypeScript wire union, in packages/types/src/expression.ts. - ExpressionWireSchema (@object-ui/types/zod) — its runtime twin, hoisted out of zod/form.zod.ts (where it was module-private) into zod/expression.zod.ts and imported by both base.zod.ts and form.zod.ts. One envelope type, reused by reference; no second spelling.

.changeset/7586-primary-field-consumer-reads.md

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

    primaryField is a DetailViewSchema key (@object-ui/types views.ts) — a view key, which DetailView.resolveDisplayTitle reads off schema and is welcome to. Read off an object def it is undeclared: @objectstack/spec's object schema is a strictObject answering unrecognized_keys: ['primaryField'], and ObjectSchema.create() throws. primaryField appears in zero files of the shipped @objectstack/spec@17.2.0 dist, against 68 for the canonical nameField. objectstack#6326 removed the identical read from two lint rules; objectui#7287 / PR fix(plugin-detail): resolveTitleField delegates to the shared ADR-0079 ladder #7585 removed it from resolveTitleField. These two survived it — and three of this repo's own changelogs already called the probe "not a spec property — always undefined" while the code kept honouring it.

.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/7694-chart-series-chart-type-alias-refusal.md

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

    The new aliasKeyRefusal() helper (zod/tombstone.zod.ts, internal — not re-exported) reuses retirementTombstone's primitive, z.never({ error }).optional().describe(), deliberately not handlerKeyRefusal's z.custom: measured, z.toJSONSchema throws on a z.custom arm ("Custom types cannot be represented in JSON Schema") and represents a z.never arm as { not: {} } with its description. z.toJSONSchema(ChartDataSeriesSchema) succeeded before this change and still does — it now lists chartType as a refused property carrying the guidance, 11 properties to 12.

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

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

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

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

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

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

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

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

.changeset/7735-zod-mirrors-stop-authoring-defaults.md

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

    What changed. All 41 .default() call sites under packages/types/src/zod/ are removed — layout.zod.ts 22, crud.zod.ts 11, form.zod.ts 5, views.zod.ts 2, app.zod.ts 1. @object-ui/components reconciles the third face objectui#8229 found: flex's registration defaultProps.align seeded 'center', the value its own renderer never applies, so a designer-made node laid out differently from a hand-authored one; it now seeds 'start'.

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

    What changed. All 41 .default() call sites under packages/types/src/zod/ are removed — layout.zod.ts 22, crud.zod.ts 11, form.zod.ts 5, views.zod.ts 2, app.zod.ts 1. @object-ui/components reconciles the third face objectui#8229 found: flex's registration defaultProps.align seeded 'center', the value its own renderer never applies, so a designer-made node laid out differently from a hand-authored one; it now seeds 'start'.

.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/8072-input-wrapper-class-mirrored.md

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

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

.changeset/8338-retire-toast-action.md

  • 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/8478-zod-pins-form-layout.md

.changeset/8499-node-slot-registered-arms.md

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

    • SemanticElementSchema (zod/layout.zod.ts) — the seven HTML sectioning tags renderers/layout/semantic.tsx registers: aside main header nav footer section article. - HtmlElementSchema (zod/layout.zod.ts) — the 37 safe flow/inline tags renderers/basic/html-elements.tsx registers (h1…h6, p, a, ul, img, …), plus the per-tag keys that module forwards to the DOM (href, target, rel, title, src, alt, width, height, dateTime, cite). ⚠️ Dated note, 2026-09-27 — that set has since gained code — objectui#10756. At this change TAGS and this arm both named 37 tags; both now name 38, and the parity pin counts 38. The rest of this entry is kept as the reading of this change. - InputShorthandSchema (zod/form.zod.ts) — email / password, the two aliases renderers/form/input.tsx registers onto the input renderer with inputType pinned. inputType is deliberately NOT declared on this arm: the wrapper spreads its own value last, so an authored one is overwritten. - UiCalendarSchema (zod/form.zod.ts) — ui:calendar, the date-picker primitive renderers/form/calendar.tsx registers under exactly that key (skipFallback, because bare calendar belongs to the plugin-calendar view).

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

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

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

    Why ADR-0049 and not a fresh ruling. 12b599219 refused actions on this same node and, by its own comments, ruled on that key ONLY — its ruling is not borrowed here. What reaches this key is the standing enforce-or-remove gate, which this repository applies to this exact face: packages/types/src/zod/tombstone.zod.ts's retirementTombstone is documented as the "ADR-0049 RETIREMENT TOMBSTONE" helper and is internal to these zod modules, 63 changesets cite the ADR, and PageNodeSchema already carried one of its refusal arms one member up. 12b599219 left this key parsing on purpose so that retiring it would be a decision rather than an accident, and wrote a pin saying so; that pin is flipped, not deleted.

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

.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/9067-zod-barrel-named-arms.md

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

    • InputShorthandSchema (zod/form.zod.ts) — the email / password shorthand arm. - UiCalendarSchema (zod/form.zod.ts) — ui:calendar, the date-picker primitive renderers/form/calendar.tsx registers, a different component from the calendar plugin view that owns the bare literal.

.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/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/9406-types-root-barrel-two-names.md

  • names form-barrel-mirror-9406.test.ts → packages/types/src/__tests__/form-barrel-mirror-9406.test.ts — edited by this change

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

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

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

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

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

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

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

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

  • names views.ts → packages/types/src/views.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/views.zod.ts → packages/types/src/zod/views.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/9526-types-root-barrel-command-element-types.md

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

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

  • names form-barrel-mirror-9406.test.ts → packages/types/src/__tests__/form-barrel-mirror-9406.test.ts — edited by this change

    form-barrel-mirror-9406.test.ts had found these two names and ledgered them as undecided, because objectui#9406's ruling covered exactly two other names. Both rows are gone now, and that pin holds the pair to the barrel list the same way it holds every other name form.ts exports.

.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/9659-node-recursion-point-inert-clause.md

  • names content-channel-family-d-9256.test.ts → packages/types/src/__tests__/content-channel-family-d-9256.test.ts — edited by this change

    One reading in a neighbouring table got a line, not a rewrite. In content-channel-family-d-9256.test.ts the plain chatbot row lists children only, which on the two TWIN faces still means "body held out and live" — and objectui#9639 had to re-point that table's LIVE CONTROL at a twin precisely because the plain face refuses body now, for objectui#8572's reason rather than this table's. Measured at the time: body ACCEPTED on chatbot-enhanced and chatbot-floating, REFUSED on chatbot. ⚠️ That hold-out has since ended and not by a decision on either card: objectui#6771 retired body on BaseSchema itself, so the twins had no content channel left to inherit and each now declares the same NEITHER-channel tombstone its children sentence already asserted, pointing at requestBody. The row is annotated as one-sided so the next reader does not take it for a two-sided reading. ⛔ No assertion in that table moved.

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

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

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

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3095.5 KB 3104.5 KB
Main entry chunk (gzip) 148.5 KB 350 KB
Entry file index-C3MHuY3p.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.57KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
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.17KB 10.58KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
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.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
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) 557.59KB 133.60KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 226.44KB 63.00KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
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) 51.96KB 14.83KB
plugin-charts (index.js) 83.99KB 22.86KB
plugin-chatbot (index.js) 197.67KB 46.90KB
plugin-dashboard (index.js) 136.82KB 36.44KB
plugin-designer (index.js) 216.42KB 44.47KB
plugin-detail (index.js) 233.48KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.11KB 62.72KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.01KB 28.49KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.00KB 9.09KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 88.42KB 22.18KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.52KB 1.36KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
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) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.27KB 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: 14fd13c5193022bc067c5f888cf030238779c53f

Isolated adversarial review of PR objectui#10897 (objectui#9256, family D, Part of slice: the E3 residual of ruling 5861449497 on objectui#8284, Q2 A, plus execution parameter 3). Read: the card and all 21 comments (claim 5862473256, dev report 5863336147), PR objectui#9589's ACCEPT 5691898972, the ruling and measurement 5859897857 (row E3 and the option-A text), objectui#9067 and objectui#9910, the PR body, diff, file list and check-runs, the branch as refs/review/pr-10897 against origin/main 35d68c4ce. The dev report was treated as a claim; every figure below was re-derived. CI on the head, read at 2026-09-28T04:46Z: 43 check-runs, 40 success, 3 skipped (dependabot and the two coverage rows), 0 failure, last completion 2026-09-28T04:35:57Z; the PR is draft, mergeable_state: clean.

① Derived judgments

Reads — each of the 12 reads neither channel, re-derived at the source.

  • SchemaRenderer (packages/react/src/SchemaRenderer.tsx) destructures children: _children, body: _body out of the props bag before the spread, so neither key reaches any renderer as a prop; the only route left is schema.children / schema.body on the node the registration hands over.
  • object-view: ObjectViewRenderer is any-typed and hands the node to ObjectView. Its generateViewSchema builds every sub-view (object-kanban, object-calendar, object-gallery, object-timeline, object-gantt, object-map, object-tree, object-chart) from baseProps (an object literal starting objectName: schema.objectName, key by key) plus spreads of viewOptions.KIND / kanbanCfg, which are sub-keys of the node, never the node itself; gridSchema and the record object-form node are literals too. No ...schema spread exists in packages/plugin-view/src.
  • object-form: ObjectFormRenderer is typed schema: any and hands the node to ObjectForm. The four ...schema spreads in ObjectForm.tsx feed the internal TabbedForm / WizardForm / SplitForm component props, and all six form nodes the package renders (ObjectForm flat path, ModalForm / DrawerForm baseFormSchema, TabbedForm, SplitForm, WizardForm) are object literals opening type: 'form' as const, objectName: schema.objectName, … with no node spread. The form renderer's live children read is therefore never fed by an object-form node.
  • detail-view: every SchemaRenderer call in packages/plugin-detail renders a sub-key — header, footer, header actions[], tab.content, field.render, the related-list viewSchema — through toRenderableSchema; the only ...schema spread in the package is record-alert.readProps.ts, another registration.
  • email / password: the wrappers are (props: any) ⇒ InputRenderer {...props} schema={{ ...props.schema, inputType: … }}; InputRenderer types the node as InputSchema and reads label, id, required, wrapperClass and the DOM props off the already-stripped bag. No channel read.
  • The other object views: ObjectKanban spreads ...effectiveSchema into the internal KanbanImpl (whose only children is the React render-prop of DndBridge); ObjectChart spreads ...schema into ChartRenderer, which contains no children / body token at all; grid, map, tree, gantt, calendar hold no node spread into a SchemaRenderer call.
  • Void tags: html-elements.tsx draws isVoid ? undefined : renderChildren(schema?.children) and declares the children slot input only when !isVoid, so br / hr / img read neither and the objectui#9910 tier already names them.
  • objectui#9910 cross-check: name: 'children' appears in no registration of the twelve; the lit control (html-elements.tsx, div.tsx) fires.

Shape — PR objectui#9589's family-D shape on both faces. TS: body?: never and children?: never with a docblock each. Zod: two retirementTombstone members (z.never({ error }).optional().describe(…)) kept as members, fed one string by the new neitherContentChannelGuidance(node, route, renders) in tombstone.zod.ts; the message names the key, the card, NEITHER content channel, and What it renders instead:, and does not fall back to BaseSchema's Did you mean … children remedy. Each "renders instead" list is true against the declaration: the grid's columns / filter / sort / grouping / selection, the form's fields / sections / customFields / mode / formType, the kanban's groupBy / cardFields, map / gantt / calendar / tree field pairs, the chart's chartType / aggregate / series, detail-view's header?: SchemaNode, footer?: SchemaNode and DetailViewTab.content: SchemaNode | SchemaNode[], and InputSchema's label / placeholder / value / defaultValue / description / error / required. One improvement over the precedent: both members are spelled explicitly so check-handler-key-read-sites can resolve the arm (the first commit's computed spread blinded it; the second commit repaired that).

OmitDeclared — measured on an emitted d.ts, both heads. Probe (scratchpad, global tsc 6.0.2): form.ts and its local closure (base.ts, expression.ts, select-option.ts) emitted with --declaration --emitDeclarationOnly from the PR head and from the merge-base 0c50f1863; the two @objectstack/spec type imports are unresolvable there and touch none of the members below. The compiler API over the emitted form.d.ts:

  • head: InputShorthandSchema declares 34 members = InputSchema's 34 minus type / inputType plus its own four, zero missing, zero extra, zero modifier or type drift, index signature [string]: any kept; UiCalendarSchema 27 = CalendarSchema's 27, same result. body and children resolve to ?: undefined (the never tombstones), label to ?: string, onChange to ?: (value: string | number) ⇒ void, mode to the three-literal enum.
  • base: the same two faces declare 2 and 1 members (type, inputType; type) with 32 and 26 inherited members missing, which is the erasure the ruling's parameter 3 names.
  • A ten-pin file (both channels on email / password / ui:calendar, label: 42, mode: 'default', inputType on the shorthand, and onChange: 'not-a-function') plus a lit control and five controls: head exits with exactly the lit control's TS2322; base exits with nine TS2578 (only the shorthand's own inputType pin fires), the lit control, and four failed Eq controls. ui:calendar declares no new tombstone — its two come from CalendarSchema — but its published TS face does newly refuse body, children and a wrong mode; the changeset says exactly that, and the PR body's "gains NO new refusal" is declaration-level wording that under-reads the face.
  • The hidden narrowing is real and is named: with the collapse gone every inherited member binds to its declared type, so onChange: 'x' and value: true now fail on email where any key type-checked before. The changeset states the class ("a wrongly typed inherited member … no longer type-check there") with two examples, says the index signature is kept, and KnownDrift gains the InputShorthandSchema: onChange row. Adequately named; the BREAKING note covers it.

Collateral.

  • zod-mirror-parity.test.ts: the two Omit COLLAPSE rows leave MirroredUndeclared (4 / 60 → 2 / 2, the class note records the emptying); KnownDrift 49 / 89 → 50 / 90 at both header sites, and those figures are read back by headerFigures(…) against keyTotal('KnownDrift'), so they are pinned, not prose. The union-arm leg now falls back from MirroredUndeclared to ledgerEntryMembers('KnownDrift') under the same reader whenever this ledger holds no multi-key entry: a reader that stopped walking arms still reddens on KnownDrift, and the leg re-arms on this ledger when a multi-arm row returns. Not weakened.
  • object-view-spec-parity.test.ts: body / children are now redeclared envelope keys on the mirror; redeclaredEnvelopeKeys pin moves to the four-key set, SANCTIONED_LOCAL gains both as refusal-only surface like viewTabBar, declared-surface 24 → 26, and the "keeps SANCTIONED_LOCAL honest" leg still requires that the spec models neither. Honest.
  • content-channel-family-d-9256.test.ts: this PR's hunks sit at base lines 219–225 and 559–588; PR objectui#10714's sat at 68–79 and 430–453 — at least 106 lines apart, and feat(components,types)!: a list item and a tabs item draw content only, and both item faces refuse body by name (objectui#9590) #10714 has since merged (412818870); git merge-tree of the head onto origin/main is clean and the merged file keeps toHaveLength(31). The removed line was the file's own TRIPWIRE, whose comment said that when the collapse is repaired it goes RED and is to become a @ts-expect-error pair; the pair lives in the new file because the claim required pins in a NEW file, and the ui:calendar mirror row in the family-D file is untouched. A firing tripwire honoured, not a silencing.

Producers. pnpm census:body-dialect --keys takes the population as input (resolvePopulation, keySource: '--keys') and counts children per node, so the objectui#9545 blindness the 9589 review recorded does not apply. Re-run at the head over the 15 plus ui:calendar, input, and div / card / page as controls: 8979 files, 2449 candidate nodes; the only body / children hits on the 17 are the PR's own two controls in the new test file (object-grid nested, br HELD); the controls read div 172 / card 183 / page 47 children. Real producers: 0. The dev's single body hit on ui:calendar (the family-D tripwire line) is gone at the head, consistent with the removal.

Clause-②: yes is declared on the PR body's second line and is right: twelve published faces stop accepting children, and two stop accepting every key at any.

② Semver level

minor with an explicit BREAKING note is the correct spelling: objectui AGENTS.md's version policy forbids major in any changeset (one fixed group), and both .changeset/9256-list-timeline-content-channels.md (PR objectui#9589) and .changeset/9256-content-channel-family-d.md use the same paragraph. Every sentence of .changeset/9256-e3-residual-content-channels.md checks true: body was already refused on the ten object / detail nodes on both faces (base.ts body?: never; base.zod.ts body: aliasKeyRefusal('body', 'children', …), whose message is the Did you mean pointer at children the new text replaces) and by the zod mirror on email / password (InputSchema.omit keeps it); the repaired faces carry every inherited member and keep the index signature (probe above); the calendar / ui:calendar refusal texts change wording only (the diff touches the two strings and nothing else on those arms). The CalendarSchema docblock now says the tombstone reaches UiCalendarSchema on both faces, TS half in the new file and mirror half as the family-D row — both true. The migration line is correct per key: detail-view renders header, footer and a tab's content (all SchemaNode slots); the others render no node slot, so "drop it or place it beside the node in a container that reads children" is the only true remedy.

③ Boundary flags

  1. The br / hr / img hold. Consistent with Q2 A as the maintainer adopted it: the option-A text in 5859897857 that batch Release v0.3.1 #229 approved reads "leaving the three void tags to the tier because their arm is the shared HtmlElementSchema family whose per-tag split was ruled out (objectui#9067)", and objectui#9067's ruling 5644019053 did decline "splitting the families into 44 per-tag schemas" as expansion for an unmeasured consumer — its subject was barrel naming, and a two-arm flow / void split for narrowing is a different, unruled shape (the dev's option B), so "ruled out" is a fair but slightly broader reading than 9067 as written. The tier is real (validateTree reports not-a-container because the void tags declare no children slot) and the HELD control pins the shared-arm fact. Tension to record: the ruling's own enumeration lists br, hr, img among the 15 that "move to objectui#9256", and the claim asked for all 15. The seat owes the card a written disposition — either "the tier is the refusal, the residual closes at 12" or a routed decision on B / C — or objectui#8284's E3 row (15) never reconciles.
  2. input as the next slice. True as noted: InputRenderer reads no channel and the registration declares no children slot. When InputSchema gains its pair, the shorthand's restated body / children become duplicates of the inherited ones on both faces (same never, same tombstone shape) — harmless, but the restatement docblock should then say so.
  3. The objectui#6397 note. Correct in substance: PartialSchema is { type } & Partial(Omit(T, 'type')), and its docblock's sentence that "every generic re-spelling collapses for the same keyof T reason" is now demonstrably false. But objectui#6397 is CLOSED, so "carrier: objectui#6397, noted, not filed" names an owner that cannot receive it — the seat should file a card or reopen.
  4. Family-D header staleness. Confirmed at the head: "family E, frozen" and "unattributable" in the header, plus two remarks (near the header's ui:calendar bullet and the mirror-row comment) that still describe the TS heritage as a plain Omit. The stated reason not to edit — the file being held by PR objectui#10714 — is gone since 412818870 merged; the carrier is the next family-D slice.
  5. Site-level serial at current heads. origin/main has moved eight commits past the base; three of this PR's files were also touched on main (objectql.ts, objectql.zod.ts, the family-D test) and git merge-tree is clean. The four PRs the body maps are all merged (docs: cite landing commits where pending changesets and source comments name 30 objectui issues that answer 404 (objectui#10803, batch 4) #10875 is the base; fix(core,plugin-view,types): the density fold tests an own key; the flat-property warning and NamedListView's docblock stop naming retired channels (objectui#10868) #10883 merged before the claim; feat(components,types)!: a list item and a tabs item draw content only, and both item faces refuse body by name (objectui#9590) #10714 and fix(plugin-view): the host delegation reads a named view's remaining protocol members off the named view (objectui#10758) #10884 after). Not mapped, although open before the PR (three of them before the first commit): fix(types,cli): 20 of the ADR-0080 public blocks validate, and the ratchet counts the namespaced half (objectui#10872, batch 1) #10888, fix(types,plugin-designer)!: the app wizard saves a document the spec accepts — a separator without label, branding kept on edit, no Layout control (objectui#10867) #10889, fix(types)!: the AI node declarations stop offering members no runtime honours (objectui#10874) #10890, docs: cite landing commits where pending changesets and source comments name 41 objectui issues that answer 404 (objectui#10803, batch 5) #10892. Of those, fix(types)!: the AI node declarations stop offering members no runtime honours (objectui#10874) #10890 rewrites the same two KnownDrift header lines this PR rewrites (**49 entries** … **89 keys** → 48 / 87 there, 50 / 90 here; "49 of the registered pairs" → 48 there, 50 here): a textual conflict for whichever lands second, and the recount is semantic — both landed as-is give 49 / 88, which the headerFigures readers pin. fix(types,cli): 20 of the ADR-0080 public blocks validate, and the ratchet counts the namespaced half (objectui#10872, batch 1) #10888 (+50 at EXCLUSIONS, same file), docs: cite landing commits where pending changesets and source comments name 41 objectui issues that answer 404 (objectui#10803, batch 5) #10892 (one-line docblock hunks in objectql.ts, nearest 55 lines from this PR's insertions) and fix(types,plugin-designer)!: the app wizard saves a document the spec accepts — a separator without label, branding kept on edit, no Layout control (objectui#10867) #10889 (index.ts line 53 vs this PR's 172) are disjoint. zod/index.zod.ts and packages/cli are untouched, as required.
  6. Carrier. needs:contract-review is hung on neither the PR (labels: package: types, tests) nor the card; the dev reported it owed and outside its write budget. This record is the review; the seat hangs and strips per protocol.
  7. PR body — what is not true or not right. (a) "Every open PR's hunks re-mapped at branch time … No site had to be left" is false for fix(types,cli): 20 of the ADR-0080 public blocks validate, and the ratchet counts the namespaced half (objectui#10872, batch 1) #10888 / fix(types,plugin-designer)!: the app wizard saves a document the spec accepts — a separator without label, branding kept on edit, no Layout control (objectui#10867) #10889 / fix(types)!: the AI node declarations stop offering members no runtime honours (objectui#10874) #10890 / docs: cite landing commits where pending changesets and source comments name 41 objectui issues that answer 404 (objectui#10803, batch 5) #10892 (item 5). (b) "ui:calendar gains NO new refusal" under-reads the published TS face (① above); the changeset is the accurate text. (c) The body carries line addresses ("hunks at 68–77 and 430–452", "base lines 222 and 562–585", "docblock at 2236–2243", "after base line 2210"), the form objectui AGENTS.md [WIP] Update documentation for project #11 bans in a PR body, and the squash takes the PR text into main's history — rewrite those sentences by symbol and quoted string before landing (a body edit, no new head). (d) The first commit's co-author trailer names a model, a dev-disclosed deviation; the squash commit takes the PR text, so it does not reach main. Everything else checked — the instrument description, the per-key table, the ablation shape, the OmitDeclared claims, check:handler-key-reads repair, the governed-guard reading (re-run: 14 paths, NOT GOVERNED), the changeset claims — reads true.

Implemented-by: claude/issue-9256-e3-residual
Reviewed-by: session_01DuWo5bdP9SdVebamn99GGk

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 28, 2026 04:51
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 28, 2026
One conflict, in packages/types/src/__tests__/zod-mirror-parity.test.ts:
both sides rewrote the two KnownDrift header figures. Resolved by
RECOUNTING the merged KnownDrift table with the test's own AST reader,
not by picking a side:

  base 0c50f18                          49 entries / 89 keys
  objectui#10874 (c30c8dd) drops
    ai.zod.ts#AIFormAssistSchema          -1 entry  / -2 keys
  objectui#9256 (this branch) adds
    form.zod.ts#InputShorthandSchema      +1 entry  / +1 key
  merged                                  49 entries / 88 keys

Both header sites (the population bullet and the KNOWN_DRIFT ratchet
restatement) now read 49 / 88, and the bullet keeps both histories in
landing order.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Sep 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3095.5 KB 3104.5 KB
Main entry chunk (gzip) 148.4 KB 350 KB
Entry file index-CnslznlU.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.58KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
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.17KB 10.58KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
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.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
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) 557.59KB 133.60KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 226.44KB 63.00KB
fields (index.js) 261.01KB 66.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
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) 51.96KB 14.83KB
plugin-charts (index.js) 83.99KB 22.86KB
plugin-chatbot (index.js) 197.67KB 46.90KB
plugin-dashboard (index.js) 136.82KB 36.44KB
plugin-designer (index.js) 215.03KB 44.21KB
plugin-detail (index.js) 233.48KB 61.79KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.11KB 62.72KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.01KB 28.49KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.00KB 9.09KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 88.42KB 22.18KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
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) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.27KB 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: 31bb63bcbd77818333f99e958193908ddcb0963f

Delta review of PR objectui#10897 at the merge head, after record 5863631182 (PASS on 14fd13c51). Isolated and adversarial; REST reads only; one write, this comment. Read: the r3 PR body, the branch as refs/review/pr-10897, origin/main at 6a7f24e92 (which now carries PRs objectui#10890 c30c8dd4c, #10889 73433769a, #10892 b8e09415c and #10888 6a7f24e92), the PR's event timeline, and the check-runs on the head. The dev's merge-round report was treated as a claim; every figure below was re-derived. CI on the head, polled every 60 s until settled and read at 2026-09-28T05:21Z: 43 check-runs, 40 success, 3 skipped (dependabot and the two coverage rows), 0 failure — all eight Test (shard N/8) rows, Type Check, Lint, Test (dist pins), Spec Main Shape Gate and Build & E2E among the successes; last completion 2026-09-28T05:19:49Z. The PR is out of draft, mergeable_state: clean, auto_merge: null, not merged.

① Derived judgments

The merge itself. 31bb63bcb has exactly two parents, 14fd13c51 (the reviewed head) and c30c8dd4c (main when PR objectui#10890 landed); the old head is an ancestor of the new one, so no rebase and no force-push. git diff --stat c30c8dd4c 31bb63bcb is exactly this PR's 14 files at +1051 / −151, the same figures as the old net change against 0c50f1863. git merge-tree of the head onto the current origin/main 6a7f24e92 — three PRs past the merge parent, #10888's EXCLUSIONS block and index.zod.ts arms included — writes a tree with no conflict.

Net change at the new head versus net change at the old head. The two unified diffs, normalised by dropping hunk headers and blob ids, differ in three places and nowhere else: the KnownDrift population bullet (old PR-side line "50 entries … 90 keys — 49 / 89 until" is now "49 entries … 88 keys — 48 / 87 until"), the sentence that chains the histories ("It was 46 / 84 until objectui#10859" is now "It was 49 / 89 until objectui#10874", with #10890's paragraph following and #10859's after it), and the KNOWN_DRIFT restatement ("50 of the registered pairs" is now "49 of the registered pairs"). Every declaration, mirror, tombstone, pin, changeset line and other ledger row is byte-identical to the reviewed head. The family-D test at the new head differs from the old head by exactly PR objectui#10714's three hunks (the header and the ListItem / Tabs CONTROL rows); this PR's two forced edits there survive — the ../form import carries CalendarSchema alone and the TypeScript-face array lists 31 entries against toHaveLength(31).

The recount, re-derived from the merged table with the compiler API (the KnownDrift interface's members, union arms counted as keys):

tree KnownDrift multi-key entries
base 0c50f1863 and 35d68c4ce 49 / 89 17
c30c8dd4c (PR objectui#10890 removed ai.zod.ts#AIFormAssistSchema, two keys) 48 / 87 16
14fd13c51 (this PR added form.zod.ts#InputShorthandSchema: onChange) 50 / 90 17
31bb63bcb 49 / 88 16

The dev's table is right in every cell. Both header sites read the merged figure — the population bullet "49 entries in KnownDrift, 88 keys across them — 48 / 87 until objectui#9256 …" and the restatement "49 of the registered pairs carry TYPE drift TODAY" — and the four headerFigures readers that pin them ((\d+) entries in KnownDrift, … (\d+) keys across them, and (\d+) of the registered pairs carry TYPE drift TODAY) match those exact spellings. The bullet keeps both histories in landing order: #10859 (46 / 84 → 49 / 89), then #10874 via PR #10890 (→ 48 / 87), then this PR (→ 49 / 88). The other four ledgers are unchanged and agree with their headers: MirroredUndeclared 2 / 2 (0 multi-key entries, so the union-arm leg takes its fallback on KnownDrift, which still holds 16 multi-key entries — the leg is live), UnmirroredDeclared 12 / 84, RuntimeOnlyDeclared 3 / 7, WiderThanDeclared 6 / 7.

Consistency with what landed on main since the review. PR objectui#10890 changed ai.ts, ai.zod.ts, the AI pin files and, in zod-mirror-parity, the two header sites plus the AIFormAssistSchema row; none of this PR's pins names an AI arm, the merged ledger carries neither a duplicate nor a lost row, and the only shared lines were the two the merge resolved. PR objectui#10714's family-D edits touch the ListItem and Tabs item rows and the header; this PR's rows and its ui:calendar mirror row are untouched. PR objectui#10888 (merged after the merge head) adds public-block arms to AnyComponentSchema and 50 EXCLUSIONS lines to the parity file; it moves no KnownDrift figure (origin/main still counts 48 / 87) and touches none of the twelve arms whose refusal the new pins read through AnyComponentSchema. Nothing is now inconsistent with this PR's pins or ledgers.

The changeset is byte-identical to the reviewed one and cites no ledger figure; every sentence checked in record 5863631182 still holds against the merged tree.

② Semver level

Unchanged: @object-ui/types: minor with the explicit BREAKING note, the spelling objectui AGENTS.md's no-major policy and PR objectui#9589's changeset set. Nothing in the merge round touched a published face.

③ Boundary flags

  1. r3 PR body — what is true. The merge-round subsection's table, the "both header sites say so" claim, the four other ledger figures, "no rebase, no force-push", "differs from main by exactly this PR's 14 files", the merge-tree reading against b8e09415c (now also true against 6a7f24e92), the past-tense serial section, the fixed ui:calendar sentence, and the removal of every line address — all verified. The gate table at 31bb63bcb is the dev's reading; CI on the head is the reader of record (top of this comment).
  2. r3 PR body — what is stale. (a) The acceptance note still says the family-D test header is "held by PR objectui#10714", that the file is one "PR objectui#10714 is amending", and names "PR objectui#10714 or the next family-D slice" as carrier — feat(components,types)!: a list item and a tabs item draw content only, and both item faces refuse body by name (objectui#9590) #10714 merged at 412818870 (03:38Z), and the body's own serial section says so; the carrier is the next family-D slice. (b) "PRs objectui#10888, fix(types,plugin-designer)!: the app wizard saves a document the spec accepts — a separator without label, branding kept on edit, no Layout control (objectui#10867) #10889 and docs: cite landing commits where pending changesets and source comments name 41 objectui issues that answer 404 (objectui#10803, batch 5) #10892 are textually disjoint. fix(types,plugin-designer)!: the app wizard saves a document the spec accepts — a separator without label, branding kept on edit, no Layout control (objectui#10867) #10889 and docs: cite landing commits where pending changesets and source comments name 41 objectui issues that answer 404 (objectui#10803, batch 5) #10892 have since merged too" — fix(types,cli): 20 of the ADR-0080 public blocks validate, and the ratchet counts the namespaced half (objectui#10872, batch 1) #10888 merged as 6a7f24e92 at 04:52Z, before the r3 body was applied at 05:08Z. (c) "Carrier: objectui#6397" is still a closed card (flag 3 of the prior record stands). (d) "an undeclared mode" describes a value outside the declared enum, wording only. Fix for (a)–(c): a body edit before the squash; no new head needed.
  3. Landing state. The timeline shows ready_for_review and auto_merge_enabled at 04:51Z (five minutes after the PASS record), added_to_merge_queue at 04:52Z, removed_from_merge_queue at 05:05Z on the conflict. The PR is still out of draft and auto_merge now reads null — the queue removal dropped it, exactly the case objectui AGENTS.md names — so nothing is armed, and re-arming is the seat's act once this record and green CI on 31bb63bcb are both in hand. needs:contract-review was never hung on either carrier (flag 6 of the prior record); the two contract-review records on this thread are the review.
  4. Still owed on the card, unchanged from the prior record: the written disposition of the br / hr / img hold, the closed-carrier objectui#6397 note, and the family-D header staleness. None is a defect in this diff.

Implemented-by: claude/issue-9256-e3-residual
Reviewed-by: session_01DuWo5bdP9SdVebamn99GGk

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit 775e079 Sep 28, 2026
44 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-9256-e3-residual branch September 28, 2026 05:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants