chore(mesh): mark Phase 2 task 8 complete; record the orphaned-client follow-up

Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
Joseph Doherty
2026-07-22 17:32:49 -04:00
parent 5468b79d19
commit 4eca87f04d
2 changed files with 18 additions and 2 deletions
@@ -1002,3 +1002,17 @@ git commit -m "docs(mesh): Phase 2 live-gate record"
- **The AdminUI's `Ok = true` already means "dispatched", not "applied".** Phase 2 moves that lie to a new transport without making it worse; do not let a reviewer believe Phase 2 introduced it.
- **`redundancy-state` is bidirectional and carries two unrelated message types** (`RedundancyStateChanged` central→node, `OpcUaProbeResult` node→node on the same topic). It is explicitly **out of scope** here — but note `RedundancyStateActor` builds its snapshot from `Cluster.State`, so it is genuinely mesh-bound and is the hardest thing standing between here and Phase 6.
- **`alerts` has a node-local subscriber** (`HistorianAdapterActor`), so Phase 5 cannot simply move it to gRPC without keeping a node-local leg.
---
## Follow-ups found during execution (not fixed in Phase 2)
- **`DefaultMeshClusterClientFactory`'s generation counter is per factory instance, and its clients
are top-level actors.** Production creates one factory per `CentralCommunicationActor` and captures
it in the props closure, so the counter survives a supervision restart and names stay unique — that
part is sound. What is *not* handled: the clients are `system.ActorOf`, not children, so a restart
of the comm actor loses `_client` without stopping it and leaves an orphaned ClusterClient dialling
receptionists forever. Harmless today (nothing sends to it) but it is a leak per restart, and it
will matter in Phase 6 when there is one client per cluster. Found by
`MeshClusterClientBoundaryTests`, which hit the name collision the moment a second factory was
constructed on the same system.