chore(docker-dev): site-b-2 is Cluster:Roles-only, site-a-2 pins a miscased Cluster:Roles entry (archreview 01/S-12, 01/C-9)

T11: site-b-2 drops OTOPCUA_ROLES entirely — Cluster:Roles is its sole role source, the rig's
only node that can exhibit the two-role-authority split (01/S-12). Expected to fail every
deploy on a pre-R3-04 build.

T12: site-a-2 pins Cluster__Roles__0="Driver" (capital D) as the standing 01/C-9 case-mismatch
pin, keeping cluster-SITE-A verbatim. Pre-fix this un-elects the SITE-A Primary.

Combined into one commit (deviation from the plan's two separate T11/T12 commits): the header
comment block documenting all six nodes' role sources interleaves both nodes on adjacent lines,
so a clean split was not practical. Recorded in the plan's Execution notes.

Compose edits only — the rig is NOT brought up as part of this change.
This commit is contained in:
Joseph Doherty
2026-08-20 10:32:18 -04:00
parent b8d2d50006
commit 985de0b6ad
3 changed files with 40 additions and 8 deletions
+17 -4
View File
@@ -47,10 +47,15 @@
# Traefik). Both are Akka seed nodes for the MAIN mesh
# ONLY, each listing ITSELF first (2026-07-22) so either
# can cold-start while the other is down.
# site-a-1, site-a-2 OTOPCUA_ROLES=driver,cluster-SITE-A — driver-only
# site-a-1, site-a-2 OTOPCUA_ROLES=driver,cluster-SITE-A — driver-only.
# site-a-2 additionally pins a miscased Cluster__Roles__0=
# "Driver" (R3-04, archreview 01/C-9 standing pin).
# site-b-1, site-b-2 OTOPCUA_ROLES=driver,cluster-SITE-B — members of their
# OWN 2-node mesh (self-first seeded within the pair, NOT
# off central). They serve no UI, but they DO expose OPC UA
# off central) — EXCEPT site-b-2, which sets NO OTOPCUA_ROLES
# at all and is Cluster:Roles-only (R3-04, archreview 01/S-12
# standing pin — the rig's one node that can exhibit the
# two-role-authority split). They serve no UI, but they DO expose OPC UA
# data-plane endpoints (4842-4845) and authenticate those
# users against the same shared GLAuth (via the *ldap-env
# anchor); central manages + deploys to them over the
@@ -713,7 +718,13 @@ services:
# Bootstrap-guard enablement demo — see site-a-1. site-a-2 is the HIGHER address, so the guard
# makes it probe site-a-1 and join it (peer-first) rather than race-form its own cluster.
Cluster__BootstrapGuard__Enabled: "true"
Cluster__Roles__0: "driver"
# R3-04 (01/C-9) standing pin: 'Driver' (capital D) — a deliberately miscased plain role.
# EffectiveRoles normalizes it silently (Program.cs and AkkaClusterOptions.Roles both still
# gossip lower-case 'driver'), so post-fix this node behaves identically to site-a-1; pre-fix
# every one of the four role-scoped validators skipped its driver-scoped rules for this node,
# and site-a elected no Primary (RedundancyStateActor.SelectDriverPrimary matches ordinally).
# cluster-SITE-A keeps its own spelling verbatim by design — do not "fix" that half.
Cluster__Roles__0: "Driver"
Cluster__Roles__1: "cluster-SITE-A"
# Mesh command transport (per-cluster mesh Phase 2, made mandatory by Phase 6) — see
# central-1/site-a-1.
@@ -850,7 +861,9 @@ services:
# cluster on simultaneous start (split brain).
site-b-1: { condition: service_healthy }
environment:
OTOPCUA_ROLES: "driver,cluster-SITE-B"
# R3-04 (01/S-12) standing pin: this is the rig's ONLY Cluster:Roles-ONLY node — deliberately
# no OTOPCUA_ROLES at all (every other node sets both, which is why neither R3-04 finding could
# reproduce on the rig before this). Cluster__Roles__0/1 below are this node's sole role source.
# Per-cluster mesh Phase 4: no ConfigDb string on driver-only site nodes (see site-a-1).
Cluster__Hostname: "0.0.0.0"
Cluster__Port: "4053"