Files
zeekayandHanzo Dev 30885479ab call: the plane carries ZAP, not JSON
The op-call plane marshalled its body with encoding/json. That put a text
format inside the binary protocol: two services on one host, holding the same
struct in memory, serialized it to JSON and parsed it back to cross a socket.
JSON is the BOUNDARY encoding — it belongs on the REST routes a browser reaches
and in the MCP envelope an agent reads — and it has no business between our own
processes.

internal/zapenc derives a wire layout from the In/Out type itself: fields take
slots in declaration order, each aligned to its own width, which is the rule
zap's own schema builder applies. Nothing is named on the wire — a field IS its
offset — so the bytes on the socket are the bytes in memory, and the type
declaration is the schema both ends read. bool, every sized int/uint, float,
string, bytes, nested structs, pointers and slices cross; a map or an interface
is refused at encode rather than dropped, because a field that silently does
not cross is how a callee decides on a value nobody sent.

Refusals cross as ZAP too, status intact, so errors.As still recovers the
*HTTPError the callee returned.

op.invoke takes its decoder as a PARAMETER, so there is still exactly ONE
handler core under REST, MCP, CLI and the plane. The encoding belongs to the
transport; the contract is the same op either way.

The layout is the type, so the compatibility rule is: append fields at the end,
and only at the end. Reordering, inserting or retyping changes the wire.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-29 06:15:26 -07:00
..