Problem
zap_transport.py (PR #21) ships the envelope-encode/decode layer for PaymentOffer / PaymentProof but does not specify the connection-level semantics that two switchboard endpoints use when talking ZAP to each other:
- How does a session open? (Magic frame, version negotiation, optional capability flags.)
- What is the retry policy when a frame is lost? (Idempotency, sequence numbers, backoff.)
- Is there an explicit sequence number, or is ordering implicit in TCP / QUIC?
- How is a session closed cleanly, and what is the in-flight-frame state at close?
Without this, every consumer (switchboard, luxfi/zap Go consumer, LP-183 precompile reference impl) rolls their own handshake. They will diverge.
Proposed Approach
Write the v1.0 wire spec covering:
- Handshake frame: magic
"ZAP!" + protocol version + capability bitmask (PQ envelope support, nested-x402 support, MPP-session support). Side initiating handshake sends; responder accepts or rejects with explicit error tag.
- Sequence semantics: add a
seq field (8 bytes, big-endian) in every ZAP frame. Receiver tracks the highest-seen seq per session, drops out-of-order frames as duplicates.
- Retry policy: sender retries on no-ACK within RTT*2 (default 200ms, configurable), exponential backoff up to 5s, then session drop. ACK is a 4-byte sequence echo back.
- Idempotency: every
PaymentOffer carries a request_id (uuid v4); duplicate request_ids within the same session are treated as retries of the same offer, not new ones.
- Session close: explicit FIN frame; in-flight unACK'd frames are surfaced to the application layer as a list of orphaned sequence numbers for resubmit.
Acceptance Criteria
References
Problem
zap_transport.py(PR #21) ships the envelope-encode/decode layer forPaymentOffer/PaymentProofbut does not specify the connection-level semantics that two switchboard endpoints use when talking ZAP to each other:Without this, every consumer (switchboard, luxfi/zap Go consumer, LP-183 precompile reference impl) rolls their own handshake. They will diverge.
Proposed Approach
Write the v1.0 wire spec covering:
"ZAP!"+ protocol version + capability bitmask (PQ envelope support, nested-x402 support, MPP-session support). Side initiating handshake sends; responder accepts or rejects with explicit error tag.seqfield (8 bytes, big-endian) in every ZAP frame. Receiver tracks the highest-seen seq per session, drops out-of-order frames as duplicates.PaymentOffercarries arequest_id(uuid v4); duplicate request_ids within the same session are treated as retries of the same offer, not new ones.Acceptance Criteria
docs/zap-wire-spec-v1.0.mdpublishedzap_transport.pyimplements the full v1.0 semanticsReferences