S3 sdk-queue-invoke: QueueInvoke, and a seat lists its states and stream kinds

Builds: design 47 G A-231, §601, A-102, A-128 (A-343, A-344)

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-13 11:37:11 +01:00
parent 9ac5ba2364
commit 1d1900c083
4 changed files with 70 additions and 0 deletions
+6
View File
@@ -26,10 +26,16 @@ func SeatFromDefinition(d seatdef.Definition) Seat {
Optional: v.Optional, Replaces: v.Replaces})
}
for _, st := range d.States {
s.States = append(s.States, st.Name)
if st.View {
s.Views = append(s.Views, st.Name)
}
}
for _, a := range d.Accepts {
if a.Stream != "" {
s.AcceptedOn = append(s.AcceptedOn, a.Stream+"."+a.Name)
}
}
for _, r := range d.Receives {
rv := Receivable{Kind: r.Kind, Comment: r.Comment, Dirs: r.Dirs, Offered: r.Offered}
if r.Shape != nil {
+43
View File
@@ -0,0 +1,43 @@
package catalogue
import (
"slices"
"testing"
"git.novox.be/novox/mesh-sdk/go/seatdef"
)
// A seat's compiled form lists the states its definition declares and the kinds it accepts on a stream (design 47 G A-102,
// A-128); a seat without either lists none, as before.
func TestSeatFromDefinitionListsItsStatesAndStreamKinds(t *testing.T) {
s := SeatFromDefinition(seatdef.Definition{Seat: "mesh-provisioner", Scope: "mesh",
States: []seatdef.State{{Name: "plans", View: true}, {Name: "provisions"}},
Accepts: []seatdef.Message{{Name: "step", Stream: "check"}, {Name: "step"}}})
if !slices.Equal(s.States, []string{"plans", "provisions"}) || !slices.Equal(s.Views, []string{"plans"}) ||
!slices.Equal(s.AcceptedOn, []string{"check.step"}) {
t.Errorf("states = %v, views = %v, accepted on = %v", s.States, s.Views, s.AcceptedOn)
}
bare := SeatFromDefinition(seatdef.Definition{Seat: "x", Scope: "mesh"})
if bare.States != nil || bare.AcceptedOn != nil {
t.Errorf("a bare seat lists %v, %v", bare.States, bare.AcceptedOn)
}
}
// A queue invoke `seat:<seat>.accept.<queue>` is split by one helper (design 47 G A-231); a verb invoke is not one.
func TestQueueInvoke(t *testing.T) {
for _, row := range []struct {
invoke, seat, queue string
ok bool
}{
{"seat:node-build-go.accept.check", "node-build-go", "check", true},
{"seat:x.verb", "", "", false},
{"seat:x.accept.a.b", "", "", false},
{"seat:x.accept.", "", "", false},
{"node-tools.x", "", "", false},
} {
seat, queue, ok := QueueInvoke(row.invoke)
if seat != row.seat || queue != row.queue || ok != row.ok {
t.Errorf("QueueInvoke(%q) = %q, %q, %v", row.invoke, seat, queue, ok)
}
}
}
+15
View File
@@ -18,3 +18,18 @@ func SeatInvoke(invoke string) (seat, verb string, ok bool) {
seat, verb, ok = strings.Cut(rest, ".")
return seat, verb, ok && seat != "" && verb != ""
}
// QueueInvoke splits an invoke `seat:<seat>.accept.<queue>`, by which an asker names a build seat's queue it asks (design 47 G
// §544, §601, A-231), into its seat and queue; ok is false for anything else. The one reader of that form: the manifest
// validator, the indexer's served-verb edge and the grants part read it here.
func QueueInvoke(invoke string) (seat, queue string, ok bool) {
seat, verb, ok := SeatInvoke(invoke)
if !ok {
return "", "", false
}
queue, isQueue := strings.CutPrefix(verb, "accept.")
if !isQueue || queue == "" || strings.Contains(queue, ".") {
return "", "", false
}
return seat, queue, true
}
+6
View File
@@ -45,9 +45,15 @@ type Seat struct {
// Serves carries each verb in full — name, description, schema — because a role's tools are the
// mesh's to define and an agent's to call (novox/hq ADR 0132, design 33 §2).
Serves []Verb
// States are the names of the state the seat's holder keeps, which a module reads by `seat:<seat>.<state>` (design 47 G
// A-116, A-128). Compiled from the definition's states.
States []string
// Views are the names of the states the seat offers as views, which a module follows by `consumes`
// `seat:<seat>.views.<state>` (design 47 G §616, §699). Compiled from the definition's states marked `view`.
Views []string
// AcceptedOn are the accepted kinds that ride a stream, each as `<stream>.<kind>`, which a part names in `invokes` as
// `seat:<seat>.<stream>.<kind>` (design 47 G A-102, §415). Compiled from the definition's accepts.
AcceptedOn []string
// Receives is what other modules may contribute to the seat's holder, by kind (novox/hq ADR
// 0212): each kind is text in the tool's own grammar, placed by the holder with
// ${contribution:<seat>:<kind>}. Compiled, never stored: like the protocol, it is the mesh's