Module assigner client: the placement and seat-holders states by name, and the machines a placement names (ADR 0634 §4; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 15:28:18 +01:00
parent 57dd579234
commit 54a42db4ec
2 changed files with 59 additions and 0 deletions
@@ -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` (`<module>.<state>`) and binds
// to (`<module>_<state>`): 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>.node` or, in the form before, `placement.<node>`. 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
}
@@ -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)
}
}