Commit Graph

8 Commits

Author SHA1 Message Date
Joseph Doherty bcec88ef70 fix(cluster): all four role-scoped validators read the authority — 'Driver' no longer skips every driver rule (archreview 01/C-9) 2026-08-20 09:51:23 -04:00
Joseph Doherty 4d2dfb5b50 test(mesh): step 7 — replace the boundary test with MeshGrpcBoundaryTests and sweep the comments
MeshGrpcBoundaryTests replaces the MeshClusterClientBoundaryTests deleted in step 1. Three
self-seeded single-member clusters sharing the ActorSystem name, joined ONLY by gRPC, driving
the REAL CentralCommunicationActor -> MeshGrpcCommandDialer -> Kestrel h2c ->
MeshCommandAuthInterceptor -> NodeCommandGrpcService -> NodeCommunicationActor -> EventStream:

  1. No_cross_mesh_Akka_association_forms_between_central_and_either_site — the program's own
     point, kept as a test rather than a live-gate note: each cluster stays single-member and
     none ever holds another's address as a member.
  2. One_dispatch_through_central_reaches_a_node_in_every_cluster_mesh — the fan, with each
     site holding its OWN per-cluster PSK, so a dial that selected the wrong cluster's key
     would be refused at the far side.
  3. Falsifiability_control_a_dial_carrying_the_wrong_cluster_key_delivers_nothing — without
     it, (2) cannot distinguish "the gRPC boundary carried it" from "something else in the
     process did". The same node then accepts the right key, so the silence is the auth gate
     and not a dead endpoint.

All three run fully offline — no Docker fixture — and pass.

Comment sweep across every remaining clusterclient|receptionist hit in src/ and tests/:
the program label becomes "mesh gRPC command plane", and every comment that described the
deleted transport as live now describes what actually runs (Dps = pair-local default,
Grpc = cross-mesh). mesh_transport.proto's header/service comments are reworded; no message,
field or enum is touched — the contract is locked. MeshCommActorPathTests is reshaped rather
than retired: the two paths still exist and still matter, but what a mismatch costs is now a
misleading Unavailable from the gRPC ingress rather than a silently dropped receptionist send.

The only surviving mentions of the old names are the ones that must survive: the fail-closed
rules that name "ClusterClient" as a retired value refused at boot, their tests, and this
test class's own account of what it replaces.
2026-08-06 15:58:36 -04:00
Joseph Doherty af3b0c3146 refactor(mesh): step 6 — delete the ClusterClient mode value; split topology now requires Grpc
MeshTransportOptions.ModeClusterClient is gone. MeshTransportOptionsValidator accepts Dps or
Grpc and nothing else, so a node left carrying the string "ClusterClient" is now REFUSED at
boot naming MeshTransport:Mode and both remaining values — deliberately fail-closed rather
than falling back to Dps, which on a split-topology node would deliver nothing at all. A new
fact pins exactly that.

SplitTopologyTransportValidator tightens from an allow-list of two to Grpc only, as its own
comment said it would once ClusterClient was deleted. Dps on a cluster-role node stays
refused; the rule is still an explicit allow-list, so a typo'd mode fails too.

Tests: the two ClusterClient-mode facts in MeshTransportOptionsValidatorTests are deleted
(their Dps siblings already assert the same rule for the one remaining non-Grpc mode), the
SplitTopology fixtures move to Grpc, and the three-mode Theories in
ControlPlaneStarterOrderTests / CentralCommunicationActorTests become two-mode.
2026-08-06 15:49:42 -04:00
Joseph Doherty 85ca86e955 refactor(mesh): step 5 — delete MeshTransport:CentralContactPoints, its rules and its compose entries
The property, the four validator rules that graded it (empty / non-akka.tcp / actor-path
suffix / one-bad-among-good) and all twelve docker-compose entries (6 nodes x 2) are gone.
The compose comment blocks that explained "/system/receptionist is appended at construction
time" and the client's contact rotation go with them, and the surrounding prose now
describes the Grpc command plane it actually runs.

CentralGrpcEndpoints' doc no longer says it "replaces" the Akka contact points — there is
nothing left to replace — and ContactRefreshSeconds' failure message names the node
dispatch set rather than the ClusterClient contact points.

`rg CentralContactPoints src tests docker-dev` is now empty.
2026-08-06 15:45:21 -04:00
Joseph Doherty e1db90f9c9 fix(mesh): 1B.1 review follow-ups
Two review items from Task 1B.1, both diagnostic:

1. CentralCommandGrpcService's "actor not ready" Warning omitted the peer and
   the correlation id while the decode-failure Warning six lines above carried
   both. These are the only two ways an ack fails to reach the coordinator, and
   an operator has to correlate either against the node's own log. Decoding has
   already succeeded on this path, so the DECODED correlation id is free.

2. A fused driver,admin,cluster-MAIN node under Mode=Grpc owes BOTH validator
   surfaces at once (driver keys AND ConfigServe:GrpcListenPort). The two blocks
   are independent `if`s; chained as `else if` a fused central node would be
   graded on one surface only and boot with nowhere for any ack to land. Pinned
   from both sides plus the fully-configured pass.
2026-08-06 08:42:11 -04:00
Joseph Doherty 7e7df337cc feat(mesh): CentralCommandService on the ConfigServe listener 2026-08-06 08:41:52 -04:00
Joseph Doherty aa21f61fa0 feat(mesh): Grpc mode value + validation 2026-08-06 03:02:16 -04:00
Joseph Doherty 5439f14804 feat(mesh): MeshTransportOptions — dark switch between DPS and ClusterClient
Phase 2 Task 0. Binds a validated `MeshTransport` section selecting which
transport carries central->node commands, defaulting to Dps so nothing changes
until the rig gate passes.

The validator exists because every fault it catches otherwise surfaces as an
ABSENCE -- a deployment that never arrives, an alarm ack that does nothing --
which has no stack trace and no failing node to point at. Two of the shapes it
rejects are ported from the sister project's shipped mistakes: a contact point
carrying an actor-path suffix, and (documented in the options XML) a template
listing the node's OWN remoting port as a central contact, which is a permanent
failure in the initial-contact rotation.

Contact points are required only under ClusterClient mode; requiring them under
the default would make the section mandatory on admin-only nodes that have no
reason to carry them.

Sabotage-verified: relaxing the empty-contacts guard and the actor-path-suffix
guard turns exactly those two tests red, and nothing else.

Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
2026-07-22 10:39:37 -04:00