launchFederatedCoreAdmission

fun CoroutineScope.launchFederatedCoreAdmission(node: RaftNode, seam: Seam, rosterChannel: Seam, core: Set<NodeId>)

Cross-server learner admission for the federated server-core placement — the federated generalisation of launchCoreLearnerAdmission.

A federated game runs one Raft cluster whose players are spread over several core servers, each connected to the players nearest it. A leader's seam roster is only its own local players plus the other servers, so launchCoreLearnerAdmission alone would never admit a player behind a different server — that player is never added to the config, so the leader never replicates to it and its matchIndex can never advance. This loop closes that gap by having every core server share its local roster with every other core member, so the leader admits from the union of all servers' rosters.

Launched on every core member (self-gated by the placement to self ∈ [core]); it runs three coroutines on this scope:

  • Publish. Unicast (never broadcast) this server's local players (seam.peers − core) to the other connected core members over rosterChannel. Two structural triggers, both timer-free: (a) whenever a core member newly appears in seam.peers, send to that member — connection precedes peer-visibility, so the arriving member's tag-6 collector is already subscribed by the time it shows up here, and this send lands even at a simultaneous boot with the far player already attached; and (b) whenever this server's local roster changes (a player joins/leaves), send the new roster to all connected core members. Every send is a single-addressee Seam.sendTo, never a fan-out.

  • Receive & reactive re-publish. Collect rosterChannel, accepting a roster frame only if its sender is a core member (NodeId(sender.value) ∈ core) — the first-hop authenticity check, parallel to the relay's spoof validation, that stops a spoke player from injecting membership. Accepted rosters are kept per sender in a MutableStateFlow. Whenever a frame carries new information (a first-heard sender or a changed roster) this node re-publishes its own roster — a second self-heal for rosterChannel's best-effort (replay = 0) subscribe-race, complementing the appearance trigger above. The receive collector runs under a retry-with-backoff loop, so a transient failure never permanently stops this node from learning rosters.

  • Admit. Whenever this node is the leader, admit the first peer in (seam.peers − core) ∪ union(remote rosters) that is neither a core voter nor already a learner — add-only, learners-only (never removes, never touches the voter set). The role gate hands the loop between core nodes on a leadership change automatically; because rosters flow to every core member continuously, a new leader already holds every server's roster and is never blind to a far player (H2).

A failed membership change is tolerated and re-attempted after CORE_ADMISSION_RETRY_BACKOFF, exactly as in launchCoreLearnerAdmission.