/** * Deterministic WebRTC role election. * * Both ids must come from the **same signal server's identity space**. One human has a * separate account - and therefore a separate actor id - on every signal server they are * provisioned on, so comparing a home id against a foreign actor id is not antisymmetric: * each side compares its own home id against the other's foreign id, and both can elect * themselves initiator (glare) or neither can (no offer ever sent). */ export function shouldInitiatePeerConnection( localActorId: string | null | undefined, remoteActorId: string | null | undefined ): boolean { const local = localActorId?.trim(); const remote = remoteActorId?.trim(); if (!local || !remote) return false; if (local === remote) return false; return local < remote; } /** * Perfect-negotiation politeness, derived from the same election so the two can never * disagree: the elected initiator is the impolite side and keeps its offer, the other * side rolls back. Falls back to polite when the local actor id is unknown, so an * unidentified client yields instead of deadlocking the negotiation. */ export function isPoliteOnOfferCollision( localActorId: string | null | undefined, remoteActorId: string | null | undefined ): boolean { return !shouldInitiatePeerConnection(localActorId, remoteActorId); }