diff --git a/internal/link/access_act_test.go b/internal/link/access_act_test.go index 17278bb..32baa52 100644 --- a/internal/link/access_act_test.go +++ b/internal/link/access_act_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - occ "git.novox.be/novox/mesh-contracts/go/clients/operatorchannelclient" - oc "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel" + occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" + oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/internal/link/engineseat.go b/internal/link/engineseat.go index 4d47ace..ad7ca02 100644 --- a/internal/link/engineseat.go +++ b/internal/link/engineseat.go @@ -10,7 +10,7 @@ import ( "time" "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" - oc "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel" + oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/catalogue" "github.com/nats-io/nats.go" diff --git a/internal/link/handacts.go b/internal/link/handacts.go index bb0cf84..6592603 100644 --- a/internal/link/handacts.go +++ b/internal/link/handacts.go @@ -13,9 +13,9 @@ import ( "sync" "time" - occ "git.novox.be/novox/mesh-contracts/go/clients/operatorchannelclient" "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" - oc "git.novox.be/novox/mesh-contracts/go/seats/operatorchannel" + occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" + oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/delivery" ) @@ -58,6 +58,13 @@ const ( ActSeatListAgain = "seat-list-again" ) +// SeatListCallers are who may call the engine's two seat-list verbs: every operator's session and the healers (novox/hq +// ADR 0636 §7, the node-engine seat's definition: the operator and the healers). +var SeatListCallers = stdio.VerbCallers{ + ActSeatList: {stdio.AnyPerson, "mesh-healers"}, + ActSeatListAgain: {stdio.AnyPerson, "mesh-healers"}, +} + // The states of an act: asked, done and refused are also the seat's events. const ( HandAsked = nodeengine.EventAsked @@ -228,11 +235,17 @@ func (h *HandActs) Call(c EngineCall) (any, error) { } return h.Compose(arg("module")) case ActSeatList: + if err := SeatListCallers.Allowed(c.Verb, c.Caller); err != nil { + return nil, err + } if h.SeatList == nil { return nil, errors.New("this engine reads no seat list yet: its node agent has not started") } return h.SeatList() case ActSeatListAgain: + if err := SeatListCallers.Allowed(c.Verb, c.Caller); err != nil { + return nil, err + } if h.SeatListAgain == nil { return nil, errors.New("this engine reads no seat list yet: its node agent has not started") } diff --git a/internal/link/handover_test.go b/internal/link/handover_test.go index 6dd537a..54665ae 100644 --- a/internal/link/handover_test.go +++ b/internal/link/handover_test.go @@ -264,7 +264,9 @@ func TestALinkThatHearsHandOversIsGivenTheQueues(t *testing.T) { Composition: func(module, digest string, diff bool) (any, error) { return map[string]any{"module": module, "digest": digest, "diff": diff}, nil }, - Compose: func(module string) (any, error) { return map[string]any{"composed": true, "retried": module}, nil }, + Compose: func(module string) (any, error) { return map[string]any{"composed": true, "retried": module}, nil }, + SeatList: func() (any, error) { return map[string]any{"held": true}, nil }, + SeatListAgain: func() (any, error) { return map[string]any{"read": true}, nil }, // ADR 0618 §3: what this engine states it reads, and when it last stated it. ManifestReads: func() ([]string, time.Time) { return []string{"form:a", "seat:b"}, time.Date(2026, 11, 4, 10, 0, 0, 0, time.UTC) @@ -299,6 +301,12 @@ func TestALinkThatHearsHandOversIsGivenTheQueues(t *testing.T) { {"packages", EngineToolSubject("packages", "n1") + " " + `{"write":true}`, `"key":null,"wrote":true`}, {"packages", EngineToolSubject("packages", "n1") + " " + `{"write":"true"}`, `"note":"the engine has written no key for this node yet`}, {"manifest-reads", EngineToolSubject("manifest-reads", "n1"), `"manifest-reads":["form:a","seat:b"],"node":"n1","stated-at":"2026-11-04T10:00:00Z","v":1`}, + // ADR 0636 §7: the seat-list verbs answer every operator's session and the healers, no other module. + {"seat-list", "mesh.seat.node-engine.call.seat-list.n1.person~jochen", `"held":true`}, + {"seat-list-again", "mesh.seat.node-engine.call.seat-list-again.n1.person~jochen", `"read":true`}, + {"seat-list-again", "mesh.seat.node-engine.call.seat-list-again.n1.ace~mesh-healers", `"read":true`}, + {"seat-list-again", "mesh.seat.node-engine.call.seat-list-again.n1.ace~messenger", `not on the holder's caller list for seat-list-again`}, + {"seat-list-again", EngineToolSubject("seat-list-again", "n1"), `no caller the tool runner proved`}, {"unserved", "mesh.seat.node-engine.call.unserved.n1.x", `"error":"the node seat node-engine serves no verb \"unserved\""`}, } { subject, body, ok := strings.Cut(row.subject, " ") diff --git a/internal/link/run.go b/internal/link/run.go index 96c9bd8..fd13c56 100644 --- a/internal/link/run.go +++ b/internal/link/run.go @@ -7,7 +7,7 @@ import ( "fmt" "time" - occ "git.novox.be/novox/mesh-contracts/go/clients/operatorchannelclient" + occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" ) // Membership is what a node needs to reach its mesh again, held by the caller.