From 54a42db4ec8df8cdd240d858df1183cfb3df10cc Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 15:28:18 +0100 Subject: [PATCH] =?UTF-8?q?Module=20assigner=20client:=20the=20placement?= =?UTF-8?q?=20and=20seat-holders=20states=20by=20name,=20and=20the=20machi?= =?UTF-8?q?nes=20a=20placement=20names=20(ADR=200634=20=C2=A74;=20issue=20?= =?UTF-8?q?1966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- .../clients/meshmoduleassignerclient/reads.go | 37 +++++++++++++++++++ .../meshmoduleassignerclient/reads_test.go | 22 +++++++++++ 2 files changed, 59 insertions(+) create mode 100644 placement/go/clients/meshmoduleassignerclient/reads.go create mode 100644 placement/go/clients/meshmoduleassignerclient/reads_test.go diff --git a/placement/go/clients/meshmoduleassignerclient/reads.go b/placement/go/clients/meshmoduleassignerclient/reads.go new file mode 100644 index 0000000..99fa9fd --- /dev/null +++ b/placement/go/clients/meshmoduleassignerclient/reads.go @@ -0,0 +1,37 @@ +package meshmoduleassignerclient + +import ( + "sort" + + seat "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" +) + +// The holder of the seat and the names a reader of its states declares in its `reads` (`.`) and binds +// to (`_`): named here once, by the seat's state, so no reader builds them from a module's name +// (ADR 0634 ยง4; the lead's ruling of 2026-11-05). +const ( + // Module is the module that holds the seat mesh-module-assigner. + Module = "mesh-delivery-assigner" + // PlacementRead and SeatHoldersRead are the states `placement` and `seat-holders`, as a manifest's `reads` names them. + PlacementRead = Module + "." + seat.StatePlacement + SeatHoldersRead = Module + "." + seat.StateSeatHolders + // PlacementBucket and SeatHoldersBucket are the states' buckets. + PlacementBucket = Module + "_" + seat.StatePlacement + SeatHoldersBucket = Module + "_" + seat.StateSeatHolders +) + +// MachineNames is every machine the seat places modules on, sorted, from its state `placement` as a reader holds its +// keys: each with a node key `.node` or, in the form before, `placement.`. Module keys and keys of the +// state's other kinds are passed over. +func MachineNames(keys map[string][]byte) []string { + seen := map[string]bool{} + out := []string{} + for k := range keys { + if node, _, kind, err := ParseKey(k); err == nil && kind != ModuleKind && !seen[node] { + seen[node] = true + out = append(out, node) + } + } + sort.Strings(out) + return out +} diff --git a/placement/go/clients/meshmoduleassignerclient/reads_test.go b/placement/go/clients/meshmoduleassignerclient/reads_test.go new file mode 100644 index 0000000..40223bd --- /dev/null +++ b/placement/go/clients/meshmoduleassignerclient/reads_test.go @@ -0,0 +1,22 @@ +package meshmoduleassignerclient + +import ( + "reflect" + "testing" +) + +func TestTheStatesAreNamedBySeatAndState(t *testing.T) { + for got, want := range map[string]string{PlacementRead: "mesh-delivery-assigner.placement", SeatHoldersRead: "mesh-delivery-assigner.seat-holders", + PlacementBucket: "mesh-delivery-assigner_placement", SeatHoldersBucket: "mesh-delivery-assigner_seat-holders"} { + if got != want { + t.Errorf("got %q, want %q", got, want) + } + } +} + +func TestMachineNamesAreTheNodesAKeyNames(t *testing.T) { + keys := map[string][]byte{"g14.node": nil, "g14.app": nil, "ace.node": nil, "placement.novox": nil, "want.x.y": nil, "bad": nil} + if got, want := MachineNames(keys), []string{"ace", "g14", "novox"}; !reflect.DeepEqual(got, want) { + t.Errorf("MachineNames = %v, want %v", got, want) + } +}