Skip to content

[Decision] Is an authored handler EXPRESSION a supported dialect? 56 mirrors say function, 11 say string, and both appear in files that mirror the other #6182

Description

@yinlianghui-tw

Blocked-by: #7344

Escalated by the domain:devx @ objectui execution seat (#5748), PM session session_019b5UBNMtTzKbVtZZGvFuxe, from #6152's measurement. ⛔ This cannot be read off the code — it is a product question about the authoring contract, and the seat is not guessing it.

RULED 2026-08-25 (maintainer, batch adjudication, verbatim 「同意」): Option A — the handler-expression string dialect is NOT a supported authoring form. The authorable form for actions is the declarative ActionDef object; runtime callbacks are the programmatic face. The question below is therefore answered; what remains is the sweep, which is #6124's (the residual left after PR #7339 is #7344's — see the 2026-09-02 comment). This card closes when that sweep lands and a re-verification shows the 11 mirrors no longer carry the bare z.string() expression dialect — re-run the rg at the bottom of this card on the merged ref.

The measurement

A census of every on* key mirrored in packages/types/src/zod/ found 73 mirrored handler keys in two incompatible dialects:

dialect count
z.function() 56
z.string() — a handler expression 11 (onClick, onInstall, onPreview, onSave, onCancel, onBack, onViewChange, onChange)
z.any() 3
named schema 3

⚠️ Both dialects appear in files that also mirror the other, so this is not a clean per-file or per-surface split that could be inferred. Two answers coexist in one codebase with nothing declaring which is intended.

Why it needed a person

The two dialects make incompatible promises to an author:

  • z.function() cannot be satisfied by any serialized authored document. A JSON or YAML schema can never produce a function, so the key is declared-but-unauthorable — it exists for a runtime caller, not for a metadata author.
  • z.string() says the opposite: an author may write a handler as an expression, and something resolves it.

objectui#4453 already narrowed one such key to typeof === 'function', so an authored string handler is silently DROPPED (packages/plugin-calendar/src/calendar-view-renderer.tsx:322-331). The ruling confirms that direction: the 11 z.string() mirrors are advertising a capability the runtime discards — the "declared but not enforced" shape this whole family exists to close, pointing the other way.

What it decided

It changes the remedy for a lane already in flight. #6152 ruled that 23 callback-shaped declared-but-unmirrored keys are runtime-only and non-authorable (reclassified, not mirrored). Under the ruling as issued:

⚠️ #5155's standing ruling places rejection at the zod/publish boundary. That makes these mirrors the authoritative statement of what an author may write — which is exactly why two contradictory statements in that layer mattered more than they would in prose.

What is NOT being asked

⛔ Not asking anyone to pick a favourite. Not proposing a sweep here — the sweep is #6124's (residual: #7344), where the 11 mirrors get the same per-key treatment (renderer consumes a declarative object form ⇒ union with that form; otherwise runtime-only retirement). ⛔ #6152's option A is not blocked by this and should land on its own.

Reproduce (also the close condition — run it on the merged ref)

rg -n 'on[A-Z][A-Za-z]*:\s*z\.(function|string|any)' packages/types/src/zod/

Refs: #6124 / PR #7339 (the function-site sweep, landed 2026-09-02) · #7344 (the residual sweep this card is blocked on) · #6152 (where it was measured, and the lane it changes) · #6058 / PR #6149 (the ledger that surfaced it) · #4453 (an authored string handler is dropped) · #5155 (rejection lives at the zod/publish boundary) · #6122 / PR #6142 (no renderer reads 16 schema-level event slots).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:blocked

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions