Curated transcripts from the PLMB-037 (Supervisor + Router Runtime) design sessions,
focused on the observation that the bridge (lib/fabric/bridge.ml) is a
natural transformation between two stream representations — not a morphism.
The bridge is a natural transformation between representations; a ZMQ-native handler is not a bridge at all. — Architect agent
R7: the bridge is NOT a morphism, it is a natural transformation between two concrete stream representations.
— bridge.ml module comment
The bridge transforms between ZMQ topic-framed sockets (the fabric's internal representation) and port-multiplexed stdin/stdout (the agent binary's protocol). A ZMQ-native agent bypasses the bridge entirely — it is a direct embedding, not a transformation.
The Architect agent identified the naturality during the
PLMB-037 Step 5c review, distinguishing bridge (natural transformation) from ZMQ handler (direct embedding).
This informed the module boundary decision: ZMQ handler goes in zmq_agent.ml, not bridge.ml.
None of substance. The natural transformation (bridge) is preserved for stdio agents, and the ZMQ handler is correctly understood as a direct embedding rather than a bridge.
A natural transformation η : F ⇒ G is a family of morphisms satisfying naturality squares. What happens inside each component is unconstrained by naturality — naturality only requires that the squares commute. The bridge's internal Promise is coordination within the codomain representation. It is invisible to the algebra.
The theory critic confirmed: internal coordination (Eio promises, mutexes) within the bridge does not pollute the categorical semantics. The design correctly separates categorical concerns from operational concerns (lifecycle, shutdown ordering, resource management).
The orchestrating agent (Research/Consul) wrote detailed review prompts for each subagent. The naturality observation emerged unprompted — it was not in the instructions.
The original plan proposed eliminating the bridge by having the agent binary speak ZMQ directly,
with a transport abstraction (agent_transport.ml) providing stdio and ZMQ backends.
make_zmq_handler
be in bridge.ml or a separate module? Is the two-backend transport abstraction unnecessary complexity?
Does tool dispatch through pipe adapters add too many layers?The Architect responded (unprompted) with the key observation: "The bridge is a natural
transformation between representations; a ZMQ-native handler is not a bridge at all" — answering
the make_zmq_handler location question by reframing the entire module boundary in categorical terms.
After incorporating all first-round feedback, the revised plan dropped the transport abstraction,
made agents ZMQ-only, put the ZMQ handler in zmq_agent.ml, and added startup handshake + shutdown protocol.
ready handshake well-defined? Is the shutdown protocol (D6) ordering sound?
Is unlimited ZMQ buffering (ZMQ_SNDHWM=0) correct given pipes had finite buffers?endpoints parameter the right contract? Should there be a stdio fallback in main.ml?The bridge mux fibre hung when ctrl_in had no upstream writer. The fix used an Eio.Promise
as a shutdown signal. Three agents reviewed in parallel:
ctrl_in on data EOF violate product semantics? Is the mux-source-counting scheme
the right structural choice? "Focus on whether the internal coordination mechanism is principled or ad hoc."Eio.Fiber.first cancellation of
T.recv well-tested? Is there a race where a ctrl_in message is partially written during cancellation?Eio.Fiber.first correctly cancel T.recv? Race condition with run_in_systhread mid-cancellation?
Is Eio.Promise.resolve idempotent? Memory/GC concerns? Performance of spawning two fibres per recv call?The Theory Critic produced the most detailed naturality analysis here: "A natural transformation η : F ⇒ G is a family of morphisms satisfying naturality squares. What happens inside each component is unconstrained by naturality."