Files
zeekay 9f22e43b50 rpc: real Target-based promise pipelining (Session + Pipeliner)
The call envelope has always carried Target @8, but zapgen hardcoded
Target: rpc.NoTarget in every generated method, so Go could DECODE a
pipelined envelope yet never ORIGINATE or RESOLVE one — pipelining was a
no-op. Make the canonical Target model real on both sides.

Client (origination): rpc.Session allocates unique non-zero PromiseIDs and
builds Calls — Origin (Target=NoTarget) and Pipeline (Target=prior.ID).
zapgen now emits a *rpc.Session-backed client: M(...) originates, MOn(on
rpc.Promise) pipelines on a prior answer (payload supplied server-side).
NoTarget is no longer hardcoded — it flows through one shared invoke<M>
path. Both forms return the call's own rpc.Promise so chains compose.

Server (resolution): rpc.Pipeliner wraps a generated Dispatch<Iface> and is
the per-connection promise table: records each OK answer under its
PromiseID, substitutes a resolved Target's Body for the dependent's Payload
before dispatch, QUEUES a dependent whose Target hasn't resolved yet until
it does, and REFUSES (StatusBadRequest, never hangs) a dependent whose
Target answered non-OK or was Finished. Finish(id) bounds the table.

Wire-compatible: Target=NoTarget is the non-pipelined call, so a Pipeliner
and a plain dispatcher are byte-identical on the wire; a non-pipelining
peer (any other runtime) interoperates trivially.

Proven end-to-end in rpc/pipeline_test.go (auth->getResource): single-pass
resolution, server-side queuing when the dependent arrives first, a 3-deep
A->B->C chain, non-OK/Finished targets refused, Finish waking a parked
dependent, and Target riding on the wire byte-for-byte. Full suite green
under -race. Docs: README + LLM.md describe the one canonical model and the
Rust capnp PromisedAnswer boundary honestly.
2026-06-21 01:49:48 -07:00
..