Summary
Give bidirectional replication a first-class surface: two runtimes declare a replica pair, each stages transmits for the operations the other mirrors, and each ingests the other's envelopes. The transmit family (#47, #48, shipped in #49 with the engine route) provides the mechanism; this proposal names the missing declaration. This is the feature that earns the "replica" name.
Why this is deferred
Wiring register_transmit at both ends of a pair already works today, but only for one direction at a time. Point both directions at each other and the pair loops: an ingested operation applies through an internal message, the actor's operation stages a transmit unconditionally, and the mirrored apply transmits straight back. Echo suppression is the design problem, and it deserves its own review rather than a rider on #49.
Design questions
- Echo suppression. A plausible default:
Actor#transmit stages nothing when the current turn applies a message whose idempotency key carries the transmit: prefix, so a replayed operation never re-transmits. A multi-hop topology (A → B → C) then needs an explicit forwarding override, because suppression at B would stop the chain.
- Declaration API. What form earns the name: a class-level
replicate_to on the actor, or a runtime-level pairing that wires register_transmit, the engine route policy, and the resolver in one declaration?
- Identity. A replica pair needs a bijective actor type mapping. The current
resolve_actor_type / transmission_actor_type_resolver are one-way; a pair declaration should derive both directions from one mapping.
- Conflict posture. Per-actor ordered replay gives last-writer-wins in arrival order. Document single-writer-per-actor as the supported convention first; divergence detection (periodic state digest exchange) is a separate follow-up.
- Wire contract. Loop prevention across more than two runtimes likely needs an
origin field in the envelope. That is a contract revision, so it lands in compatibility/transmit-envelopes.json and both runtimes together.
Plan
- Prototype the echo suppression rule behind the existing transmit tests, and prove a two-runtime pair converges instead of looping.
- Settle the declaration API against a real pair (the Rails QA app and a Node runtime already exercise both directions one way at a time).
- Revise the fixture file if
origin lands, with consuming tests in both repositories.
- Documentation, roadmap, parity ledger, both changelogs, both suites green.
References
#47, #48, the shipped transmit family and engine route in #49, and solid-objects-js#17 / solid-objects-js#18.
Summary
Give bidirectional replication a first-class surface: two runtimes declare a replica pair, each stages transmits for the operations the other mirrors, and each ingests the other's envelopes. The transmit family (#47, #48, shipped in #49 with the engine route) provides the mechanism; this proposal names the missing declaration. This is the feature that earns the "replica" name.
Why this is deferred
Wiring
register_transmitat both ends of a pair already works today, but only for one direction at a time. Point both directions at each other and the pair loops: an ingested operation applies through an internal message, the actor's operation stages a transmit unconditionally, and the mirrored apply transmits straight back. Echo suppression is the design problem, and it deserves its own review rather than a rider on #49.Design questions
Actor#transmitstages nothing when the current turn applies a message whose idempotency key carries thetransmit:prefix, so a replayed operation never re-transmits. A multi-hop topology (A → B → C) then needs an explicit forwarding override, because suppression at B would stop the chain.replicate_toon the actor, or a runtime-level pairing that wiresregister_transmit, the engine route policy, and the resolver in one declaration?resolve_actor_type/transmission_actor_type_resolverare one-way; a pair declaration should derive both directions from one mapping.originfield in the envelope. That is a contract revision, so it lands incompatibility/transmit-envelopes.jsonand both runtimes together.Plan
originlands, with consuming tests in both repositories.References
#47, #48, the shipped transmit family and engine route in #49, and solid-objects-js#17 / solid-objects-js#18.