The assigner's state and verb placement are assignments, with its events, tools, views and every caller; the assigner copies the retired state at its start (issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 22:13:20 +01:00
parent 369ebd092d
commit 0eafb2fe95
164 changed files with 1699 additions and 1498 deletions
@@ -12,8 +12,8 @@ import (
"time"
"git.novox.be/novox/mesh-contracts/go/seats/meshbroker"
"git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
"git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshnodeenroller"
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
"git.novox.be/novox/mesh-contracts/identity-and-access/go/clients/meshvaultclient"
"git.novox.be/novox/mesh-contracts/identity-and-access/go/seats/meshvault"
@@ -57,17 +57,17 @@ func TestTheCopiedComposerComposesAsTheControllers(t *testing.T) {
t.Run("every node's compositions are read by their named readers alone and written by their node", everyNodesCompositions)
t.Run("a module's ledger is written by its ledger account alone", aLedgerIsWrittenByItsLedgerAccountAlone)
t.Run("the bus module's process alone keeps every module's bus state and serves the broker's verbs", theBusModulesProcessKeepsBusState)
// ADR 0567 §3, §9: a node reads every key of the seat's placement and its candidates (it composes with the whole
// ADR 0567 §3, §9: a node reads every key of the seat's assignments and its candidates (it composes with the whole
// proposal laid over), and none of its open proposals; it writes neither.
reads := strings.Join(NodeComposeReads("laptop"), " ")
for bucket, granted := range map[string]bool{PlacementBucket: true, PlacementCandidatesBucket: true,
PlacementProposalsBucket: false} {
for bucket, granted := range map[string]bool{AssignmentsBucket: true, AssignmentsCandidatesBucket: true,
AssignmentsProposalsBucket: false} {
if strings.Contains(reads, "$JS.API.DIRECT.GET.KV_"+bucket+".>") != granted || strings.Contains(reads, "$KV."+bucket+".laptop") {
t.Errorf("a node is granted %s: %v, want %v", bucket, !granted, granted)
}
}
// It hears the creation of those two buckets, and of no other.
if got := NodeComposeAdvisories(); len(got) != 2 || got[0] != "$JS.EVENT.ADVISORY.STREAM.CREATED.KV_mesh-delivery-assigner_placement" ||
if got := NodeComposeAdvisories(); len(got) != 2 || got[0] != "$JS.EVENT.ADVISORY.STREAM.CREATED.KV_mesh-delivery-assigner_assignments" ||
got[1] != "$JS.EVENT.ADVISORY.STREAM.CREATED.KV_mesh-delivery-assigner_candidates" {
t.Errorf("a node hears the creation of %v", got)
}
@@ -513,11 +513,11 @@ func TestTheCopiedComposerComposesAsTheControllers(t *testing.T) {
vault := ClaimedSeat{Seat: "mesh-vault", Scope: "mesh", Serves: []string{"get", "accept", "secret-ask", "issued",
"rotate", "move-in", "node-key", "own", "move-asks"}}
controller := ClaimedSeat{Seat: "mesh-controller", Scope: "mesh", Serves: strings.Split("tools,calls,status,nodes,"+
"node,placement-export,modules,seats,builds,plans,delivery-plan,delivery-order,delivery-check,deliver,"+
"node,assignments-export,modules,seats,builds,plans,delivery-plan,delivery-order,delivery-check,deliver,"+
"delivery-stop,delivery-backups-again,delivery-walks,plan,assign,unassign,pin,unpin,push,rotate,give,issued,"+
"secret-move,secret-ask,issue,token,settings,command,queue,cancel,clear,replay,try,kill,pause,resume,hand-act,"+
"drill,warranted,hand-acts,durations,conditions,healers,doctor,upgrade,bus,retire,cleanup,judge-directories,"+
"root-free,dead-letters,data,build,artifacts,held,collect,move-placement,move-config,mirrors,images", ",")}
"root-free,dead-letters,data,build,artifacts,held,collect,move-assignments,move-config,mirrors,images", ",")}
at := "nats://10.0.0.1:4222"
wanted := map[string]struct {
w WantedAccount
@@ -790,7 +790,7 @@ func healthChecks(t *testing.T) {
}
// ADR 0571 clause 1: a read naming another module's log is issued to the reader as a log it reads, never writes.
if m := MembershipFor("a", Declared{Module: IndexerModule, Reads: []string{builds.BuildLogRead, "x.y"}},
Placements{Logs: map[string]bool{builds.BuildLogRead: true}}); len(m.Logs) != 1 || m.Logs[0].Writes ||
Assignments{Logs: map[string]bool{builds.BuildLogRead: true}}); len(m.Logs) != 1 || m.Logs[0].Writes ||
m.Logs[0].Stream != "LOG_mesh-delivery-builder_build-log" || m.Logs[0].Name != builds.BuildLogRead {
t.Errorf("the indexer's membership issues the logs %+v", m.Logs)
}
@@ -873,7 +873,7 @@ func healthChecks(t *testing.T) {
{"a flat event of a node seat held by a module is said flat", Declared{Module: "pause", Holds: []Seat{{Name: "node-power",
Scope: "node", Emits: []string{"slept"}}}}, "mesh.seat.node-power.event.slept", true},
} {
m := MembershipFor("a", c.d, Placements{})
m := MembershipFor("a", c.d, Assignments{})
listed := m.SeatTraffic != nil && slices.ContainsFunc(m.SeatTraffic.Publish, func(p string) bool { return p == c.subject })
perms, err := PermissionsFor(Principal{Kind: KindNodeTools, Node: "a", Carries: []Declared{c.d}})
if err != nil {
@@ -1019,7 +1019,7 @@ func everyNodesCompositions(t *testing.T) {
!MayPublish(runner, "$JS.API.DIRECT.GET.KV_composed-two.$KV.composed-two.two.node") {
t.Errorf("the runtime carrying the provisioner cannot read every node's compositions")
}
m := MembershipFor("one", Declared{Module: "mesh-delivery-view", Reads: []string{ComposedRead}}, Placements{})
m := MembershipFor("one", Declared{Module: "mesh-delivery-view", Reads: []string{ComposedRead}}, Assignments{})
if !slices.ContainsFunc(m.State, func(s StateIssued) bool {
return s.Name == ComposedRead && s.PerNode && s.Bucket == ComposedBucketPrefix && !s.Writes
}) {