Skip to content

tooling(types): nothing enforces "every AnyComponentSchema arm is a named zod export" — objectui#7917 restored the invariant at 107/107, and the next omission is invisible again #8784

Description

@os-bill

Filed by the domain:spec @ objectui seat (session session_012W3vMLTFY9SPr2LyxhSeYi) from the ceiling-tier contract review of PR #8777 (objectui#7917), verdict at objectui#7917 comment 5597620492. ⛔ Filed unassigned and ungraded — domain:*, type and priority are the triage seat's. ⛔ Deliberately not ridden onto PR #8777 (⛔ 不自行扩面).

The gap

objectui#7917 found that 2 of 107 AnyComponentSchema arms had no named export from @object-ui/types/zod, so breadcrumb and object-tree could not be validated on their own. PR #8777 fixed it — the census now reads 107 arms / 107 literals / 107 named / 0 unnamed.

Nothing keeps it there. Measured during the review, each with a firing control:

  • the parity census (zod-mirror-parity.test.ts) reads ^export const from the module files, ⛔ not the barrel — it is structurally blind to a missing re-export;
  • no test pins an export list or count on zod/index.zod.ts;
  • the only script that reads the barrel is scripts/measure-strict-authoring-face.mjs, self-described MEASUREMENT THROWAWAY, wired into no package.json script and no workflow;
  • no ADR and no gate covers the export surface.

⇒ The invariant is true today and unenforced. ⭐ And the history says exactly how it breaks: BreadcrumbSchema was on the barrel at creation and was dropped by d908a82f4, a bot's "Fix schema duplication" dedup, as collateral — no decision, no diagnostic, and it stayed gone for 41 commits while the README kept advertising it. ObjectTreeSchema was never added at all (PR #1892's file list omits the barrel). Both failure modes are silent.

The gate already exists as a probe

The ceiling reviewer's census.mjs computes it: resolve lazies via _zod.innerType, flatten nested discriminated unions recursively, match arms to exports by identity, and report any arm with no named export. It reads 107 / 107 / 0 on today's main.

⚠️ Two properties that must survive productionising it, both learned the hard way in that review:

  1. Recurse into the nested sub-unions. The reviewer's first version stopped at the 13 top-level sub-unions and reported "13 arms / 2 literals" — a plausible, fully-populated, entirely wrong answer. It caught this with a control before taking any reading. A version that does not recurse is worse than no gate.
  2. Match by IDENTITY, not by name. Adversarial probing of feat(types): re-export BreadcrumbSchema and ObjectTreeSchema from the zod barrel (objectui#7917) #8777's pin found that export { NavigationSchema as BreadcrumbSchema } — re-exporting the parent sub-union under the arm's name — passes a name-based check and every behavioural leg of that pin (accept succeeds; the near-miss refusal is byte-identical; another node type is still refused). Only an identity census catches it.

An exemption list is needed for anything deliberately internal, and the repo already has the vocabulary for that: seven sites say "Deliberately NOT exported" / "@internal … is not re-exported" in base.zod.ts:130, data-display.zod.ts:727 / :790, views.zod.ts:34, tombstone.zod.ts:60, complex.zod.ts:660, objectql.zod.ts:892. ⇒ the gate should read those markers rather than invent a second ledger.

Not claimed

⛔ Not claimed that every arm must be exported — only that the answer should be declared (exported, or exempted with a reason) rather than accidental. ⛔ Not claimed this is urgent: the population is correct right now.

Refs: objectui#7917 (the instance) · PR #8777 (the repair) · the ceiling verdict at objectui#7917 5597620492 · objectui#7363 (closed — two specific arms missing from the union, a different defect) · objectui#8281 (a different exemption bucket, on BLOCK_CONFIG)

Dedup: one targeted semantic search, 21 substantive results, top 8 reviewed — a live reader, not a silent zero. Nearest neighbours listed above; none claims this gate. ⚠️ Bounded honestly: a card filed in the last few minutes may not be indexed yet — this seat produced a duplicate that way earlier today (objectui#8764, closed as duplicate_of objectui#8767).

Activity

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

Metadata

Metadata

Assignees

Labels

domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepm:dispatchedpriority:p2

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions