nervネルフ

Two protocols

magi's own wire is CBOR. The family's speaks JSON and CBOR both, and nothing is negotiated — a body says which encoding it is in its first byte.

plate 02two protocols, three transports, two encodings

Which wire is which

wirebetweenencoding
magi's owna front end and its session, and a session and its own tool peersCBOR, always, inside an envelope carrying a protocol version
the familymagi and casper, melchior, balthasar — and sessions with each otherJSON by default, CBOR on request; the reply comes back in whichever the call arrived in

The framing is the same on both: a big-endian u32 byte count, then that many bytes. Self-delimiting, so a peer that dies mid-frame is caught at the length rather than misparsed deeper in.

Two shapes

A call expects an answer. An event does not, and nothing ever replies to one. The difference is whether anybody is waiting.

a call, and its reply
→ {"call":"recall","args":["how do we run the tests"]}
← {"ok":true,"family":1,"n":2,"result":[ … ]}

an event. nobody replies.
→ {"event":"doing","busy":true,"working_for":7,"waiting":0}

The reply, field by field

fieldmeaning
okwhether the call was answered. A refusal is false with a zero exit status.
familywhich revision of the wire this reply is written in. A newer one is refused by name; an older one is not.
nhow many values came back.
resultthe values, always a list. A client that unpacks reads a bare-value server as having returned nothing at all, so the bug presents as an empty memory rather than as an error.
errorwhy not, when ok is false.
faultwhich kind of no. Its absence means refused — the answer that costs a feature rather than a turn.

Asking for CBOR

Every one-shot door takes --cbor; every socket answers in whatever it was asked in. The three siblings agree byte for byte.

$ casper tools --cbor | xxd | head -1
00000000: a4 62 6f 6b f5 66 66 61 6d 69 6c 79 01 61 6e 01  {ok: true, family: 1, n: 1, …}

$ balthasar needs --cbor | xxd | head -1
00000000: a4 62 6f 6b f5 66 66 61 6d 69 6c 79 01 61 6e 05  the same prefix
Nothing is negotiated. JSON's top level here is an object or an array, so it begins { or [. CBOR's is a map or an array, whose first byte is 0x800xBF. The ranges do not overlap, so reading the encoding off the body is a reading rather than a guess — and a peer that has never heard of CBOR is unaffected.

Refusals, and the other kind

A refused verb is {"ok":false,…} with exit status zero. A real error arriving as “exited 1” is indistinguishable from the binary being missing, and the two need different responses: one is a bug to report, the other is a sibling to carry on without.

faultmeansthe caller should
refusedthe verb was declinedcarry on without that feature
unavailablenothing answered — no socket, a dead socket, a connection that diedcarry on without the sibling
failedthe write did not landnot assume what it handed over was recorded
malformedthe reply was not the shape the family agreedreport it — this is a bug, not a condition