serve8: a process's bus declares the seat verbs it serves
Builds: design 47 G A-107, A-109, A-110 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -13,8 +13,8 @@ const ProcessBusField = "bus"
|
||||
|
||||
// ProcessBus is what one process of a module does on the bus (novox/hq ADR 0436 §1, §2, §3, §5): its own bus
|
||||
// account, granted exactly this and nothing of the module's other grants or the tool runner's — never a seat
|
||||
// to hold or serve, never a tool call or seat verb answered, never a restricted stream heard, never a
|
||||
// warrant published (§3, §5).
|
||||
// to hold, never a restricted stream heard, never a warrant published (§3, §5). It answers a seat's verb only
|
||||
// where it declares it in Serves (design 47 G A-107, A-109).
|
||||
type ProcessBus struct {
|
||||
// Emits are the events this process emits, named locally, as the module's own Emits names them
|
||||
// (EmitsAll): a process emits only what its module may emit as a whole.
|
||||
@@ -28,6 +28,10 @@ type ProcessBus struct {
|
||||
// Invokes are the tools and seat verbs this process calls, each <module>.<tool> or a role's
|
||||
// seat:<seat>.<verb> (as Manifest.Invokes), or * for every tool on the mesh.
|
||||
Invokes []string `json:"invokes,omitempty"`
|
||||
// Serves are the seat verbs this process answers directly over the bus (design 47 G A-107, A-109, A-110), each
|
||||
// seat:<seat>.<verb>: the grants part composes the process account's subscribe of the verb's call and tool
|
||||
// subjects from it, and, for a verb whose seat definition says chunks: true, the chunk and ack subjects.
|
||||
Serves []string `json:"serves,omitempty"`
|
||||
// Removes are what a tools bundle's account may remove from the bus, from a closed set (BusRemovals; novox/hq ADR
|
||||
// 0564 Limits 4): declared alone, by the module holding mesh-broker, never by a process.
|
||||
Removes []string `json:"removes,omitempty"`
|
||||
@@ -88,8 +92,8 @@ func (m Manifest) BusAccounts() []BusAccount {
|
||||
return out
|
||||
}
|
||||
|
||||
// UnmarshalJSON reads a process's bus strictly: an unknown key — serves, a seat to hold or claim, or
|
||||
// anything else that would answer a tool call or a seat's verb — is refused here, by name (novox/hq ADR
|
||||
// UnmarshalJSON reads a process's bus strictly: an unknown key — a seat to hold or claim, or
|
||||
// anything else that would answer a tool call — is refused here, by name (novox/hq ADR
|
||||
// 0436 §3).
|
||||
func (b *ProcessBus) UnmarshalJSON(raw []byte) error {
|
||||
type plain ProcessBus
|
||||
@@ -97,7 +101,7 @@ func (b *ProcessBus) UnmarshalJSON(raw []byte) error {
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&p); err != nil {
|
||||
return fmt.Errorf("a process's bus is {emits, queues, state, asks, invokes, keeps}: %w", typedUnknown(err))
|
||||
return fmt.Errorf("a process's bus is {emits, queues, state, asks, invokes, serves, keeps}: %w", typedUnknown(err))
|
||||
}
|
||||
*b = ProcessBus(p)
|
||||
return nil
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package catalogue
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func strSliceEqual(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
@@ -11,3 +16,16 @@ func strSliceEqual(a, b []string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestProcessBusReadsServesAndRefusesUnknownKeys(t *testing.T) {
|
||||
var b ProcessBus
|
||||
if err := json.Unmarshal([]byte(`{"serves":["seat:mesh-broker.snapshot-get","seat:mesh-broker.list"]}`), &b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strSliceEqual(b.Serves, []string{"seat:mesh-broker.snapshot-get", "seat:mesh-broker.list"}) {
|
||||
t.Errorf("serves = %v", b.Serves)
|
||||
}
|
||||
if err := json.Unmarshal([]byte(`{"holds":["x"]}`), &ProcessBus{}); err == nil {
|
||||
t.Error("an unknown key was accepted")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user