You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
types: 8 on* handler mirrors still declare the z.string() expression dialect and 3 declare z.any() — the per-key treatment the #6182 ruling assigned to #6124's sweep, not covered by PR #7339 #7344
Filed by the domain:ui execution seat (session session_01NRRumy89BYdW9ogbcdHTho) while reconciling #6124's close. Dedupe: semantic search for the string-dialect sweep returns #6182 (the ruling card), #7069, #5927, #6058, #5684 — none is an execution card for these sites; control query on #6182's own title hit.
Why this card exists
The maintainer ruling on #6182 (2026-08-25, batch 4, verbatim 「同意」, Option A) says the handler-expression string dialect is NOT a supported authoring form, and rules the consequence: "The 11 z.string() handler mirrors join #6124's per-key sweep with the same treatment". #6124's own ruling (2026-08-30, batch #8, 「批次 #8 同意」) then fixed the shape of that treatment: on the zod face a named refusal arm (handlerKeyRefusal in packages/types/src/zod/tombstone.zod.ts, landed by PR #7339), no declarative-object arm, no expression arm; on the TypeScript face, keep the function type only where a runtime consumer measurably reads the key, else ?: never.
PR #7339 executed that shape over the 58 on* sites declared z.function() and closed #6124. Its census was anchored on z\.function\(, so the string-dialect and z.any() mirrors were never in its population — they live in files the PR did not touch. #6182's close condition, re-run on the merged ref (origin/main = 2956d7af8), still finds them.
Measured on 2956d7af8
Anchored on[A-Z][A-Za-z]*:\s*z\.(function|string|any) over packages/types/src/zod/, function sites excluded (0 remain after PR #7339):
file:line
key
mirror
.describe()
TS twin
app.zod.ts:205
onClick
z.string()
"Click handler expression"
app.ts:716onClick?: string
blocks.zod.ts:108
onInstall
z.string()
"Install callback"
blocks.ts:303string
blocks.zod.ts:109
onPreview
z.string()
"Preview callback"
blocks.ts:308string
blocks.zod.ts:122
onSave
z.string()
"Save callback"
blocks.ts:345string
blocks.zod.ts:123
onCancel
z.string()
"Cancel callback"
blocks.ts:350string
reports.zod.ts:170
onSave
z.string()
"Save callback"
reports.ts:514string
reports.zod.ts:171
onCancel
z.string()
"Cancel callback"
reports.ts:519string
views.zod.ts:117
onBack
z.string()
"Custom back action"
views.ts:578string
crud.zod.ts:105
onClick
z.any()
"Custom click handler"
crud.ts:210() => void | Promise<void>
crud.zod.ts:145
onBack
z.any()
"Custom back action"
crud.ts:303() => void
crud.zod.ts:160
onClose
z.any()
"Close handler"
crud.ts:345() => void
Excluded by ruling, listed so nobody re-sweeps them: views.zod.ts:152onViewChange, :177onChange, :197onChange are z.string()event NAMES (PR #6899; the :152 describe text says "an event NAME, not a callback or a handler expression"). The dev confirms :177 / :197 carry the same describe text before excluding them; if one does not, it joins the table above.
The z.any() three are the mirror-wider-than-declared direction (#7069): the TS face says function, the mirror accepts any JSON value, so an authored string or object parses green and reaches a slot that expects a function.
Ask (one executable criterion)
Per key, the #6124 treatment, measured not assumed:
Find the runtime consumer (schema.onX / props.onX / spread onto a component that declares the prop). None reads it ⇒ ?: never on the TS face + handlerKeyRefusal(key, 'retired', …) on the mirror. A consumer reads it as a function ⇒ TS keeps the function type + refusal arm with the 'runtime-slot' disposition. A consumer reads it as a string and does something with it (dispatches it as an event name, resolves it against an action registry) ⇒ STOP for that key and report: that is a third class the rulings did not name, and it goes back to the decision box rather than being guessed.
The eight string TS twins stop declaring string (the ruling says the expression dialect is unsupported on both faces).
Extend handler-keys-json-refusal-6124.test.ts's pattern (a sibling pin file is fine): each site declared with the guidance, an authored string refused by name with code: 'custom', a live function refused on the mirror, zod-mirror-parity.test.tsKnownDrift rows added for runtime-slot keys.
Clause-② yes (the accept set of published validators moves): build at fable, contract review in-seat at tier before release; the PR carries needs:contract-review and stays draft until PASS. Changeset @object-ui/types: minor (objectui refuses major).
Refs: #6182 (the ruling; its Blocked-by: now points here) · #6124 / PR #7339 (the shape) · #7069 · #4453 (an authored string handler is silently dropped) · #5155 (rejection lives at the zod/publish boundary).
Filed by the
domain:uiexecution seat (sessionsession_01NRRumy89BYdW9ogbcdHTho) while reconciling #6124's close. Dedupe: semantic search for the string-dialect sweep returns #6182 (the ruling card), #7069, #5927, #6058, #5684 — none is an execution card for these sites; control query on #6182's own title hit.Why this card exists
The maintainer ruling on #6182 (2026-08-25, batch 4, verbatim 「同意」, Option A) says the handler-expression string dialect is NOT a supported authoring form, and rules the consequence: "The 11
z.string()handler mirrors join #6124's per-key sweep with the same treatment". #6124's own ruling (2026-08-30, batch #8, 「批次 #8 同意」) then fixed the shape of that treatment: on the zod face a named refusal arm (handlerKeyRefusalinpackages/types/src/zod/tombstone.zod.ts, landed by PR #7339), no declarative-object arm, no expression arm; on the TypeScript face, keep the function type only where a runtime consumer measurably reads the key, else?: never.PR #7339 executed that shape over the 58
on*sites declaredz.function()and closed #6124. Its census was anchored onz\.function\(, so the string-dialect andz.any()mirrors were never in its population — they live in files the PR did not touch. #6182's close condition, re-run on the merged ref (origin/main=2956d7af8), still finds them.Measured on
2956d7af8Anchored
on[A-Z][A-Za-z]*:\s*z\.(function|string|any)overpackages/types/src/zod/, function sites excluded (0 remain after PR #7339):.describe()app.zod.ts:205onClickz.string()app.ts:716onClick?: stringblocks.zod.ts:108onInstallz.string()blocks.ts:303stringblocks.zod.ts:109onPreviewz.string()blocks.ts:308stringblocks.zod.ts:122onSavez.string()blocks.ts:345stringblocks.zod.ts:123onCancelz.string()blocks.ts:350stringreports.zod.ts:170onSavez.string()reports.ts:514stringreports.zod.ts:171onCancelz.string()reports.ts:519stringviews.zod.ts:117onBackz.string()views.ts:578stringcrud.zod.ts:105onClickz.any()crud.ts:210() => void | Promise<void>crud.zod.ts:145onBackz.any()crud.ts:303() => voidcrud.zod.ts:160onClosez.any()crud.ts:345() => voidExcluded by ruling, listed so nobody re-sweeps them:
views.zod.ts:152onViewChange,:177onChange,:197onChangearez.string()event NAMES (PR #6899; the:152describe text says "an event NAME, not a callback or a handler expression"). The dev confirms:177/:197carry the same describe text before excluding them; if one does not, it joins the table above.The
z.any()three are the mirror-wider-than-declared direction (#7069): the TS face says function, the mirror accepts any JSON value, so an authored string or object parses green and reaches a slot that expects a function.Ask (one executable criterion)
Per key, the #6124 treatment, measured not assumed:
schema.onX/props.onX/ spread onto a component that declares the prop). None reads it ⇒?: neveron the TS face +handlerKeyRefusal(key, 'retired', …)on the mirror. A consumer reads it as a function ⇒ TS keeps the function type + refusal arm with the'runtime-slot'disposition. A consumer reads it as a string and does something with it (dispatches it as an event name, resolves it against an action registry) ⇒ STOP for that key and report: that is a third class the rulings did not name, and it goes back to the decision box rather than being guessed.stringTS twins stop declaringstring(the ruling says the expression dialect is unsupported on both faces).handler-keys-json-refusal-6124.test.ts's pattern (a sibling pin file is fine): each site declared with the guidance, an authored string refused by name withcode: 'custom', a live function refused on the mirror,zod-mirror-parity.test.tsKnownDriftrows added for runtime-slot keys.rgon the merged ref returns only the three event-name keys (or zero if the dev finds those were mis-described).Clause-② yes (the accept set of published validators moves): build at
fable, contract review in-seat at tier before release; the PR carriesneeds:contract-reviewand stays draft until PASS. Changeset@object-ui/types: minor(objectui refusesmajor).Not in this card
EventHandlersSchema(retire(types):EventHandlersSchema— 公开导出的z.record(z.string(), z.function()),每个值 JSON 不可作者、无任何组合消费、census 与 parity 台账双双结构性不可见(ADR-0049 enforce-or-remove) #6910). The three event-name keys (PR fix(types): the three view handler keys are EVENT NAMES, not callbacks (part of #6124) #6899). Docs pages that teach these keys (file a docs card the way docs: three pages still teach retired handler keys as authorable props —onColumnAdd/onCardAdd(schema-reference),onSelectChange/onExpandChange(tree-view),onComplete(input-otp) — stale once #6124's tombstones land #7340 was filed for finding(types): 28 zod-mirror keys are declaredz.function(), which NO JSON document can satisfy — 14 in-repo corpus files author them and are silently invalid #6124, from the PR's "Not in this PR" list).Refs: #6182 (the ruling; its
Blocked-by:now points here) · #6124 / PR #7339 (the shape) · #7069 · #4453 (an authored string handler is silently dropped) · #5155 (rejection lives at the zod/publish boundary).