diff --git a/docs/Redundancy.md b/docs/Redundancy.md index 2d8a5dff..c0fd7345 100644 --- a/docs/Redundancy.md +++ b/docs/Redundancy.md @@ -305,6 +305,16 @@ through the production bootstrap: a lone non-first seed comes Up; a disabled win absent from its own seed list never self-forms. The two negative cases each carry a positive control (an explicit self-join) so they cannot pass merely because the node was unformable. +> **Live gate: PASSED (docker-dev, 2026-07-22).** Drilled on the six-node rig, defect first and fix +> second. On the pre-change image, `central-2` started alone (central-1 stopped) and logged **zero** join +> events in 70 s — the `InitJoin` loop, observed rather than argued. On the rebuilt image the same node +> logged the self-form warning **10 s** after start and `Leader is moving node [central-2] to [Up]`, then +> came up with all four admin singletons. A `site-a-2` recreated while central-1 was still down logged +> *"self-form fallback inactive: this node … is not in its own seed list"* and stayed out — the island +> guard on the real topology. Restarting `central-1` produced `Welcome from [central-2]`: it joined the +> self-formed cluster instead of starting a second one, and the four site nodes then joined through it — +> six members, **one** cluster. + ## Primary data-plane gate (writes, acks, alerts emit) Three data-plane surfaces are **Primary-gated** so a warm standby never touches a shared field device or duplicates a fleet-wide publish: inbound operator **writes** (`DriverHostActor.HandleRouteNodeWrite`), native-alarm **acks** (`HandleRouteNativeAlarmAck`), and the native/scripted **alerts emit** (`ForwardNativeAlarm` / `ScriptedAlarmHostActor.OnEngineEmission`). All three route through one policy — `PrimaryGatePolicy.ShouldServiceAsPrimary(localRole, driverMemberCount)` (`OtOpcUa.Runtime.Drivers`):