ADR 0266 — A discovered schema’s unions are judged by its server
Invariants: I2, I13. Follows ADR 0205.
Context
A connection restores each discovered tool’s JSON Schema into Zod (zodObjectFromJsonSchema)
and parses the call’s arguments against it before sending them, so a CLI coerces argv to the
right types and refuses a missing field without a round trip. That schema is the remote’s
presentation, not its contract. ADR 0205 joins a discriminated union into one object for
models: the discriminator becomes an enum and a field every variant shares becomes an
unlabelled anyOf of the variants’ shapes. Every accepted value still passes; which shape
goes with which discriminator value is gone by design.
Parsed locally, such an anyOf is a plain union, and a wrong value inside it can only be
refused with every branch listed. A consuming project’s lesson tool with a 12-variant block
union answered a missing artifactId with No union branch matched — branch 1 … and 6 more branches, while its server, holding the original schema, answered data.artifactId.
Putting the correlation back into the schema — oneOf with a const discriminator, or a
discriminator map — would undo the reason the join exists (weaker models drop oneOf), and a
map would be a vendor keyword outside the one schema profile every provider is served
(ADR 0047).
Decision
A schema restored from a foreign document is marked at the boundary as one whose unions the
remote judges. When the local parse of a call fails, the invalid_union refusals of such a
schema are set aside: if nothing else was refused, the coerced arguments are sent unchanged
and the remote’s refusal is what the caller sees; if something else was, only that is
reported. A schema authored in this process keeps its full verdict, union summary included.
Consequences
A wrong value inside a union of a discovered tool costs one round trip and is named by the
server exactly as on its own transports. A missing field, a wrong scalar or an unknown key
outside a union is still refused before anything is sent, and no longer carries union lines
beside it. A foreign server that does not validate its input sees the values its own schema
advertised as acceptable; that is its contract to keep. Proven end to end against a real
stitchkit MCP server with flattenUnionInput in tests/connections-remote-union-verdict.test.ts.