docs(health): oldest-Up-member is the active-node rule (0.3.0)
Rewrites the active-node sections of the spec and shared contract, which described the leader-based design that both consumers rejected. - SPEC §2.3 replaced: the rule, the ordered RolePreference, why a node holding none of the preferred roles is Unhealthy rather than Healthy, and the data payload. §4 (IActiveNodeGate) and the tier table follow. - SPEC §6 marked historical: it still tells adopters to use ActiveNodeHealthCheck(role: "admin") and AkkaActiveNodeGate, which is the advice that produced the defect. Kept for provenance, annotated so nobody follows it again. - GAPS: gaps L1/L2 recorded as closed the wrong way, reopened, then closed at 0.3.0 — including the part worth remembering, that both apps adopted the shared check as specified, hit it live, and reverted to private copies, so the surface reached zero consumers by being avoided rather than unused. - Index rows updated with the consumer-visible changes and both app branches.
This commit is contained in:
@@ -17,6 +17,28 @@ reach the shared `ZB.MOM.WW.Health` library. Status legend: ⛔ gap · 🟡 part
|
||||
> until someone re-walks them. They also predate HistorianGateway, which is absent from every
|
||||
> table below.
|
||||
|
||||
> **⚠️ Gaps L1/L2 were closed the WRONG WAY, then reopened and closed properly at `0.3.0`
|
||||
> (2026-07-24).** Everything below about the active-node check describes the leader-based design and
|
||||
> is **superseded** — read [`spec/SPEC.md`](spec/SPEC.md) §2.3 for the current rule.
|
||||
>
|
||||
> L1 shipped `ActiveNodeHealthCheck` selecting by `ClusterState.Leader` / `RoleLeader`, and L2 backed
|
||||
> `AkkaActiveNodeGate` the same way. Leadership is **address**-ordered (host, then port) with no
|
||||
> relationship to time, while cluster-singleton placement is **age**-ordered. The two agree on a
|
||||
> freshly-formed cluster — so every unit test and happy-path rig passed — and diverge permanently
|
||||
> after any restart: the restarted node rejoins youngest but keeps its address, so if it holds the
|
||||
> lower address it becomes leader while the singletons stay on the other node. During a partition
|
||||
> both sides also compute themselves leader.
|
||||
>
|
||||
> Both apps adopted L1/L2 as written, both hit the defect on live rigs, and both **reverted to
|
||||
> private copies** (ScadaBridge `OldestNodeActiveHealthCheck`, OtOpcUa `ClusterPrimaryHealthCheck`).
|
||||
> The result was that the package's whole active-node surface had **zero consumers** — avoided, not
|
||||
> unused. `0.3.0` promoted those two copies into one `ClusterActiveNode` primitive, rebuilt the check
|
||||
> and the gate on it, and both apps migrated back and deleted their copies.
|
||||
>
|
||||
> **The lesson worth keeping:** a shared component can be adopted, green, and still wrong, when the
|
||||
> only fixture that distinguishes right from wrong is a cluster whose oldest member is not its
|
||||
> lowest-addressed one. The library now pins exactly that fixture.
|
||||
|
||||
## Divergence vs spec
|
||||
|
||||
### §1 Endpoint tiers
|
||||
|
||||
Reference in New Issue
Block a user