From 0b99a5f423cd113e506db5fcc20081f778793c35 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 05:47:39 +0000 Subject: [PATCH 1/3] =?UTF-8?q?wip(types):=20retire=20EventHandlersSchema?= =?UTF-8?q?=20=E2=80=94=20INCOMPLETE,=20ledger=20row=20deliberately=20unto?= =?UTF-8?q?uched?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⛔ NOT a finished change. The public export `EventHandlersSchema` (`z.record(z.string(), z.function())`) and its barrel line are removed and the knowledge is preserved as a NOTE at the declaration site, per the maintainer ruling on objectui#6124 (decision batch #8, reconfirmed batch #25) recorded on objectui#6910. The third half of that ruling — deleting the parity-ledger row `'base.zod.ts#EventHandlersSchema'` in `packages/types/src/__tests__/zod-mirror-parity.test.ts` — is NOT in this commit. That file is held by the open PR #8763, and this seat's dispatch forbids editing it. So this tree is RED BY CONSTRUCTION: `zod mirror parity — the population is closed > no map entry names a const that no longer exists` fails with `['base.zod.ts#EventHandlersSchema']`. Measured, not predicted. No PR is opened from this commit. It exists so the NOTE and the measurements survive the hand-off. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012W3vMLTFY9SPr2LyxhSeYi --- packages/types/src/zod/base.zod.ts | 32 +++++++++++++++++++++++++++-- packages/types/src/zod/index.zod.ts | 1 - 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/types/src/zod/base.zod.ts b/packages/types/src/zod/base.zod.ts index 3e5229a96d..cb0f5be82f 100644 --- a/packages/types/src/zod/base.zod.ts +++ b/packages/types/src/zod/base.zod.ts @@ -718,9 +718,37 @@ export const ComponentConfigSchema = ComponentMetaSchema.extend({ export const HTMLAttributesSchema = z.record(z.string(), z.any()).describe('HTML attributes'); /** - * Event Handlers + * Event handlers — NOTE, not a declaration. There is deliberately no + * event-handlers const here (objectui#6910). + * + * `EventHandlersSchema`, a `z.record(z.string(), z.function())`, stood at this + * spot until objectui#6910 retired it under ADR-0049 enforce-or-remove + * (maintainer ruling on objectui#6124, decision batch #8, reconfirmed in batch + * #25). It was a published export of `@object-ui/types/zod` that **no JSON + * document could ever satisfy** — every value it accepted had to be a function + * — and that nothing in this package composed. It could therefore neither + * admit a correct authoring nor refuse a wrong one: an author reading the + * published surface got no signal in either direction, which is exactly the + * shape ADR-0049 exists to remove. + * + * Why no JSON-authorable replacement can be written here, i.e. why this is a + * NOTE and not a narrower schema: on the JSON face handlers are not values at + * all. Events are declared on the node as `BaseSchema.events` — an event-name + * string keying `ActionSchema[]` — and actions are DATA dispatched by + * `@object-ui/core`, never functions (AGENTS.md commandment #4). The + * function-valued face is a TypeScript prop shape, declared as `EventHandlers` + * in `../base.ts`; a zod mirror of it would mirror something that never + * crosses the wire. + * + * ⚠️ Do not conclude from a clean sweep that no second one of these exists. + * Both standing instruments are structurally blind to this shape: the + * `z.function()` census matches the `key: z.function(` spelling and a record's + * VALUE type is not a key, and `../__tests__/zod-mirror-parity.test.ts` + * exempts index signatures by design ("no keys to compare"). This note, not a + * gate, is what records the absence. + * + * Precedent of the same shape: objectstack#12009 / PR #13413. */ -export const EventHandlersSchema = z.record(z.string(), z.function()).describe('Event handlers'); /** * The two CSS passthrough attributes a node exposes: a Tailwind class string and diff --git a/packages/types/src/zod/index.zod.ts b/packages/types/src/zod/index.zod.ts index 4d26387c03..3e0a96a161 100644 --- a/packages/types/src/zod/index.zod.ts +++ b/packages/types/src/zod/index.zod.ts @@ -80,7 +80,6 @@ export { ComponentMetaSchema, ComponentConfigSchema, HTMLAttributesSchema, - EventHandlersSchema, ClassNameStylePropsSchema, } from './base.zod.js'; From ee48fcee7bd6265959286da0beeb28962e735e22 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 02:48:34 +0000 Subject: [PATCH 2/3] retire(types): remove EventHandlersSchema, finish the ledger and prose halves Completes the retirement the WIP commit on this branch left deliberately incomplete. The public export and its barrel line were already gone; this commit removes the parity-ledger row the removal reddens, repairs the one docblock the removal falsifies, and declares the change. - zod-mirror-parity.test.ts: delete the self-contained two-line EXCLUSIONS entry for the removed const. Its stale-entry census reads exported consts off disk, so the row went red the moment the export left; the sibling HTMLAttributesSchema entry shares the same reason string and is untouched. - handler-keys-json-refusal-6124.test.ts: the docblock over MIRROR_FILES said base.zod.ts "holds only EventHandlersSchema ... and no named key", which the removal makes false. Rewritten to state why base.zod.ts is not one of the nine mirror files; the block is kept, since it is what explains the census population. - base.zod.ts: correct the NOTE. It claimed handlers are authored as BaseSchema.events, an event-name string keying ActionSchema[]. Checked against the tree rather than inherited: BaseSchemaCore declares no events member, nothing reads schema.events, and every authored events in the corpus is TimelineSchema.events, an unrelated array. The NOTE now points at the real JSON face -- handlerKeyRefusal() and the node-type spelling -- and records the stale sketch as a trap rather than repeating it. - One changeset, scored minor by the presence gate's own verdict, with no BREAKING banner: the four-repo consumer census is zero. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt --- .../6910-retire-event-handlers-schema.md | 41 +++++++++++++++++++ .../handler-keys-json-refusal-6124.test.ts | 10 +++-- .../src/__tests__/zod-mirror-parity.test.ts | 2 - packages/types/src/zod/base.zod.ts | 20 +++++++-- 4 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 .changeset/6910-retire-event-handlers-schema.md diff --git a/.changeset/6910-retire-event-handlers-schema.md b/.changeset/6910-retire-event-handlers-schema.md new file mode 100644 index 0000000000..29b222ff49 --- /dev/null +++ b/.changeset/6910-retire-event-handlers-schema.md @@ -0,0 +1,41 @@ +--- +'@object-ui/types': minor +--- + +`EventHandlersSchema` is removed from `@object-ui/types` (objectui#6910). + +**FROM** `EventHandlersSchema`, a `z.record(z.string(), z.function())` exported +from the zod base module and re-exported from the zod barrel, **TO** *nothing*. +There is no replacement export, and deliberately so. + +**Nothing that worked stops working, because nothing could have worked.** Every +value the record accepted had to be a function, so no JSON document could ever +satisfy it, and nothing in this package composed it into a field. It could +therefore neither admit a correct authoring nor refuse a wrong one — an author +reading the published surface got no signal in either direction, which is the +shape ADR-0049 enforce-or-remove exists to delete. Ruled by the maintainer on +objectui#6124 (decision batch #8) and reconfirmed in batch #25. + +**What to author instead.** Behaviour is authored as a NODE TYPE — an `action:` +node with a declared action, the spelling PR #6498 established. The per-node +`on*` handler keys that do exist are declared through `handlerKeyRefusal()`, +which refuses every value, an authored object and a live function alike, and +carries that same remedy in its own message. The function-valued face is a +TypeScript prop shape and is untouched by this change: the `EventHandlers` +interface is still declared and still exported. + +**Not marked breaking, and that is a measurement rather than an assumption.** A +consumer census for this symbol scored zero live imports in each of objectui, +objectstack, cloud and hotcrm. The objectui and objectstack legs were re-taken +on this branch under a positive control that fires in the same corpus; the +cloud and hotcrm legs are carried forward from the published reading on +objectstack#15886 rather than re-taken here. That is a reading taken at this +commit and nothing re-derives it afterwards: a TypeScript consumer outside +those four repositories that imported the symbol gets a compile error naming +it, and the FROM/TO above is what such a consumer needs. + +⚠️ **No gate reports a second export of this shape.** Both standing instruments +are structurally blind to it — the `z.function()` census matches a +`key: z.function(` spelling and a record's VALUE type is not a key, and the zod +mirror parity ledger exempts index signatures by design. A NOTE at the former +declaration site, not a gate, is what records the absence. diff --git a/packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts b/packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts index 0f3cd02812..ed46845f45 100644 --- a/packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts +++ b/packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts @@ -411,10 +411,12 @@ const RETIRED: readonly Site[] = [ const ALL_SITES: readonly Site[] = [...RUNTIME_SLOT, ...RETIRED]; -/** The nine mirror files the census covers; `base.zod.ts` holds only - * `EventHandlersSchema` (a record, objectui#6910's card) and no named key. - * `objectql.zod.ts` joined with objectui#6576 — it declared no handler key - * at all until `ObjectDataTableSchema.onRowClick`. */ +/** The nine mirror files the census covers; `base.zod.ts` is not among them — + * it declares no named handler key. The record-valued `EventHandlersSchema` + * that once stood there was never one either, and objectui#6910 retired it; + * the NOTE left at its site records why no JSON-authorable handler record + * replaces it. `objectql.zod.ts` joined with objectui#6576 — it declared no + * handler key at all until `ObjectDataTableSchema.onRowClick`. */ const MIRROR_FILES = [ 'complex.zod.ts', 'data-display.zod.ts', diff --git a/packages/types/src/__tests__/zod-mirror-parity.test.ts b/packages/types/src/__tests__/zod-mirror-parity.test.ts index 569983e261..141ca29f04 100644 --- a/packages/types/src/__tests__/zod-mirror-parity.test.ts +++ b/packages/types/src/__tests__/zod-mirror-parity.test.ts @@ -3075,8 +3075,6 @@ const EXCLUSIONS: Readonly> = { "a bare vocabulary with no `.shape`; it is checked where a mirrored KEY declares it", 'base.zod.ts#HTMLAttributesSchema': "an index signature, not a declared key set — there are no keys to compare", - 'base.zod.ts#EventHandlersSchema': - "an index signature, not a declared key set — there are no keys to compare", 'complex.zod.ts#CalendarViewModeSchema': "a bare vocabulary with no `.shape`; it is checked where a mirrored KEY declares it", 'complex.zod.ts#DashboardWidgetTypeSchema': diff --git a/packages/types/src/zod/base.zod.ts b/packages/types/src/zod/base.zod.ts index cb0f5be82f..3f452e7a44 100644 --- a/packages/types/src/zod/base.zod.ts +++ b/packages/types/src/zod/base.zod.ts @@ -733,13 +733,27 @@ export const HTMLAttributesSchema = z.record(z.string(), z.any()).describe('HTML * * Why no JSON-authorable replacement can be written here, i.e. why this is a * NOTE and not a narrower schema: on the JSON face handlers are not values at - * all. Events are declared on the node as `BaseSchema.events` — an event-name - * string keying `ActionSchema[]` — and actions are DATA dispatched by - * `@object-ui/core`, never functions (AGENTS.md commandment #4). The + * all. The per-node `on*` handler keys that do exist are declared through + * `handlerKeyRefusal()` in `./tombstone.zod.ts`, which refuses EVERY value — + * an authored object and a live function alike — and carries the remedy in + * its own message: author behaviour as a NODE TYPE, an `action:` node with a + * declared action, the spelling PR #6498 established. A record of function + * values is that same unauthorable shape with the key set left open as well, + * so narrowing it could only make the refusal harder to read. The * function-valued face is a TypeScript prop shape, declared as `EventHandlers` * in `../base.ts`; a zod mirror of it would mirror something that never * crosses the wire. * + * ⚠️ `BaseSchema` declares NO `events` key, and this note asserted that it did + * until the claim was checked against the tree. AGENTS.md's abridged protocol + * sketch shows `events?: Record` and its action-system + * commandment authors one, but `BaseSchemaCore` has no such member, no + * renderer reads `schema.events`, and every authored `events` in the corpus is + * `TimelineSchema.events`, an unrelated array. `BaseSchemaCore` is + * `.passthrough()`, so a node written from that sketch is KEPT, judged by + * nothing and run by nothing. ⛔ Do not send an author there; the finding is + * carded separately. + * * ⚠️ Do not conclude from a clean sweep that no second one of these exists. * Both standing instruments are structurally blind to this shape: the * `z.function()` census matches the `key: z.function(` spelling and a record's From 53df540f0847ca38db6b27586bda9238644840bc Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 03:22:44 +0000 Subject: [PATCH 3/3] fix(types): drop a born-false census clause from the retirement NOTE Contract review F1 (MAJOR). The NOTE's warning paragraph asserted that "every authored events in the corpus is TimelineSchema.events, an unrelated array". That was wrong in both directions on the day it was written, and the whole comment block is emitted into the published .d.ts, so it shipped. The instrument behind the claim was the defect: it matched only the JSON-quoted "events": spelling, which cannot see a TypeScript object literal. Re-measured here over the tracked files under packages/, apps/ and examples/ with a control that fires, the object-literal form finds the node-level record shape the paragraph warns about, plus hook and validation string arrays; and of the files declaring a timeline node, the only ones carrying an events key are the declaration itself and a refusal probe. TimelineSchema.events is authored zero times. No replacement count is written. The paragraph now states the mechanism, which does not rot -- nothing declares the key and nothing reads it, so whatever a document writes there, no renderer runs it -- and points at the card that carries the census. A census answer frozen into a comment is what AGENTS.md commandment #9 forbids, and this note had reproduced that defect inside the very fix performed to record it; the paragraph now says so. The operative instruction is unchanged: BaseSchemaCore is .passthrough(), such a node is kept, judged by nothing and run by nothing, do not send an author there. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt --- packages/types/src/zod/base.zod.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/types/src/zod/base.zod.ts b/packages/types/src/zod/base.zod.ts index 3f452e7a44..9b5b728e8f 100644 --- a/packages/types/src/zod/base.zod.ts +++ b/packages/types/src/zod/base.zod.ts @@ -747,12 +747,15 @@ export const HTMLAttributesSchema = z.record(z.string(), z.any()).describe('HTML * ⚠️ `BaseSchema` declares NO `events` key, and this note asserted that it did * until the claim was checked against the tree. AGENTS.md's abridged protocol * sketch shows `events?: Record` and its action-system - * commandment authors one, but `BaseSchemaCore` has no such member, no - * renderer reads `schema.events`, and every authored `events` in the corpus is - * `TimelineSchema.events`, an unrelated array. `BaseSchemaCore` is - * `.passthrough()`, so a node written from that sketch is KEPT, judged by - * nothing and run by nothing. ⛔ Do not send an author there; the finding is - * carded separately. + * commandment authors one, but `BaseSchemaCore` declares no such member and + * nothing reads `schema.events`: whatever a document writes under that key, + * no renderer runs it. `BaseSchemaCore` is `.passthrough()`, so such a node is + * KEPT, judged by nothing and run by nothing. ⛔ Do not send an author there. + * ⛔ No count of authored `events` keys is stated here — objectui#9553 carries + * that census. A census answer frozen into a comment is the defect AGENTS.md + * commandment #9 forbids, and this note shipped one once already: the first + * version of this paragraph named a total that was wrong on the day it was + * written, and it reached the emitted `.d.ts` before review caught it. * * ⚠️ Do not conclude from a clean sweep that no second one of these exists. * Both standing instruments are structurally blind to this shape: the