Skip to content

RFP: replicas, declared bidirectional replication over the transmit family #50

Description

@cardmagic

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

  1. 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.
  2. 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?
  3. 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.
  4. 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.
  5. 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

  1. Prototype the echo suppression rule behind the existing transmit tests, and prove a two-runtime pair converges instead of looping.
  2. 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).
  3. Revise the fixture file if origin lands, with consuming tests in both repositories.
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions