ADR 0065 — Flat collisions preserve every known JSON kind
- Status: Accepted — extends ADR 0044, preserves the flat presentation boundary of ADR 0050, and supersedes ADR 0044’s rule that genuinely different kinds become unknown.
- Date: 2026-08-08
Context
flattenUnionInput joins a discriminated object union into one conservative
presentation object without nested oneOf or anyOf. ADR 0044 retained a
shared base type when colliding variants agreed, but a property that was a
string in one branch and an array or object in another still became {}.
The executable Zod contract remained correct. The model-facing document did
not: every branch exposed a finite JSON kind, yet the projection discarded all
of them and requireTypedProperties correctly rejected the resulting surface.
Decision
A colliding property collects every provable JSON Schema base kind from direct
type, const, enum, and recursively from oneOf or anyOf branches.
- One non-null kind produces the existing scalar
typeprojection. - Several kinds produce a deterministic
typearray. integerplusnumberwidens tonumberbecause every integer is a number.nullis retained alongside every non-null kind.- A same-kind object or array collision remains a loose object or array; branch structure and incompatible constraints are not invented.
- If any participating branch has no provable kind, the collision remains untyped. An unresolved reference or free-form schema is evidence that the projection does not know, not permission to guess.
The multi-type projection carries no kind-specific sibling keywords. It is a
sound superset of every original branch and preserves flat mode’s guarantee of
no oneOf or anyOf in a structurally flattenable discriminated union. The
unflattened mode remains the lossless representation when a caller needs exact
discriminator-to-branch relationships.
Consequences
- Known object/array, string/number and scalar/nested-union collisions no longer
degrade to
{}. findUntypedPropertiesaccepts these fields through their ordinarytypekeyword; no validator exception or allowlist is required.- MCP, Agent, manifests and schema validation see the same immutable document because the change lives in the shared presentation projection.
- Runtime parsing, transforms, lifecycle, hooks and error normalization remain owned by the original Zod contract and canonical tool runner.
- Flat mode remains intentionally lossy: a type array describes legal JSON kinds, not the exact correlations between a discriminator and each shape.