namespace ZB.MOM.WW.OtOpcUa.ControlPlane.Redundancy;
///
/// A read-only view of the cluster's driver membership, as the manual-failover control sees it.
///
///
/// The current driver Primary — the oldest Up driver member, the same node
/// names — or when
/// there is no Up driver member at all.
///
///
/// Every Up driver member, oldest first. A manual failover needs at least two: with one
/// there is nothing to fail over to.
///
public sealed record ManualFailoverSnapshot(string? PrimaryAddress, IReadOnlyList DriverAddresses)
{
/// Whether a failover can be performed — i.e. a peer exists to take over.
public bool CanFailOver => DriverAddresses.Count >= 2;
}
///
/// Operator-initiated, graceful swap of the driver Primary.
///
///
///
/// The mechanism is a cluster Leave of the current Primary, never a Down. The
/// leaving node hands its singletons over through the normal cluster-leave phases,
/// CoordinatedShutdown runs, ActorSystemTerminationWatchdog exits the process,
/// the service supervisor restarts it, and it rejoins as the youngest member — so the
/// survivor becomes the oldest Up driver member and therefore Primary. ServiceLevel 250
/// moves with it and OPC UA clients re-select.
///
///
/// Mesh-scope caveat. Until the per-cluster mesh work lands
/// (docs/plans/2026-07-21-per-cluster-mesh-design.md) the Primary is elected once per
/// Akka mesh, not per application Cluster row. On a fleet running several application
/// clusters in one mesh this acts on the whole mesh's Primary. The UI says so.
///
///
public interface IManualFailoverService
{
/// Reads the current driver membership from live cluster state.
ManualFailoverSnapshot GetSnapshot();
///
/// Gracefully removes the current driver Primary from the cluster so its peer takes over.
///
/// The authenticated identity performing the failover; recorded in the audit event.
///
/// The address of the node asked to leave, or when the failover was
/// refused because no driver peer exists (in which case nothing was changed and nothing audited).
///
Task FailOverDriverPrimaryAsync(string actor);
}