Files
mesh-catalog/modules/claude-licence-manager/cmd/manager/whole_integration_test.go
T
jschoubben b1da6344a8 Join 11: merge origin/main (the licence manager in parts, issue 1409)
The conflict in the old cmd/claude-licence-manager/tools_test.go resolves to both sides: main
moved it to cmd/manager, and the join's count of binding.changed.<consumer> under its family
goes into the moved TestResyncSaysEachOnce. The whole-module test's runtime refused
binding.changed.<consumer> because the manifest names the family binding.changed: it now
accepts a key that extends a named family by further parts, as A-134 says the event.

Builds: design 47 G A-134

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 14:05:51 +01:00

1007 lines
33 KiB
Go

//go:build integration
package main
// The manager whole against a real bus (design 39 bus-and-switch §9, §23, §26, §28, §29, §46, B41): the
// built binary, played over its real stdin and stdout as the node's tool runtime plays it (tools/call with the caller in
// _meta; mesh/state.* from a real nats-server's key-value buckets, mesh/log.* from the logs' real streams, mesh/publish
// and mesh/seat.publish onto their subjects). What the manager asks of
// other parts is played beside it: the vault's licence-put and get, a node's claude_code_grant and its holdings-changed,
// the operator channel's tell, and the vendor's token and usage endpoints. A condition is taken off the operator
// channel's subject and decoded by its client, the contract the router reads (B41); the router itself is not run.
import (
"bufio"
"context"
"crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"sync"
"testing"
"time"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"golang.org/x/crypto/nacl/box"
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"
"git.novox.be/novox/mesh-sdk/go/testbus"
. "claude-licence-manager/internal/licences"
)
const (
licenceA = "first@example.org"
licenceB = "second@example.org"
)
// consumers are the four nodes bound to licenceA.
var consumers = []string{"anchor", "home-server", "laptop", "workstation"}
// seed keeps what a running manager kept before this start: two subscriptions, their grants and access tokens in the
// vault, and four consumers bound to the first.
func (m *mesh) seed() {
m.t.Helper()
now := time.Now()
far := now.Add(30 * 24 * time.Hour).UnixMilli()
licences, err := m.js.KeyValue(m.ctx, Publisher+"_licences")
if err != nil {
m.t.Fatal(err)
}
bindings, err := m.js.KeyValue(m.ctx, Publisher+"_bindings")
if err != nil {
m.t.Fatal(err)
}
for i, l := range []struct{ name, account, refresh, access string }{
{licenceA, "acct-a", "rt-a", "at-a"}, {licenceB, "acct-b", "rt-b", "at-b"}} {
grant, _ := json.Marshal(FullGrant{AccessToken: l.access, RefreshToken: l.refresh, ExpiresAt: far})
m.secrets[SecretName(KeyFor(l.name), PartGrant)] = string(grant)
m.secrets[SecretName(KeyFor(l.name), PartAccess)] = l.access
v, _ := json.Marshal(Licence{Name: l.name, Kind: "subscription", AccountUUID: l.account, Email: l.name,
RefreshFingerprint: Fingerprint(l.refresh), AccessExpiresAt: far, RefreshExpiresAt: far,
AdoptedAt: int64(i + 1), RotatedAt: now.UnixMilli(), Generation: 1})
if _, err := licences.Put(m.ctx, KeyFor(l.name), v); err != nil {
m.t.Fatal(err)
}
}
for i, c := range consumers {
v, _ := json.Marshal(BindingState{Licence: licenceA, Kind: "subscription", Generation: int64(1013 + i),
Since: now.UTC().Format(time.RFC3339), Why: "bound", By: Itself})
if _, err := bindings.Put(m.ctx, c, v); err != nil {
m.t.Fatal(err)
}
}
}
// ---- the vendor ----------------------------------------------------------------------------------------------
// vendor answers the token endpoint by refresh token and the usage endpoint by access token, and counts its calls.
type vendor struct {
mu sync.Mutex
calls int
logins map[string][2]string // refresh token: the next access token and the account
usage map[string]float64 // access token: the weekly percentage; the session window is answered empty (C4)
server *httptest.Server
}
func newVendor(t *testing.T) *vendor {
v := &vendor{logins: map[string][2]string{}, usage: map[string]float64{}}
v.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
v.mu.Lock()
defer v.mu.Unlock()
v.calls++
if r.URL.Path == "/token" {
_ = r.ParseForm()
l, ok := v.logins[r.PostForm.Get("refresh_token")]
if !ok {
http.Error(w, `{"error":"invalid_grant"}`, http.StatusBadRequest)
return
}
in := int64(8 * 3600)
_ = json.NewEncoder(w).Encode(map[string]any{"access_token": l[0], "expires_in": in,
"account": map[string]string{"uuid": l[1]}})
return
}
u, ok := v.usage[strings.TrimPrefix(r.Header.Get("authorization"), "Bearer ")]
if !ok {
http.Error(w, `{"error":"unknown token"}`, http.StatusUnauthorized)
return
}
resets := time.Now().Add(3 * time.Hour).UTC().Format(time.RFC3339)
// As the vendor answers since it retired the session limit: the session window with no utilization (C4).
_ = json.NewEncoder(w).Encode(map[string]any{"five_hour": map[string]any{"utilization": nil, "resets_at": nil},
"seven_day": map[string]any{"utilization": u, "resets_at": resets}})
}))
t.Cleanup(v.server.Close)
return v
}
func (v *vendor) set(access string, weekly float64) {
v.mu.Lock()
v.usage[access] = weekly
v.mu.Unlock()
}
func (v *vendor) called() int {
v.mu.Lock()
defer v.mu.Unlock()
return v.calls
}
// ---- the runtime -----------------------------------------------------------------------------------------------
type wire struct {
ID json.RawMessage `json:"id,omitempty"`
Method string `json:"method,omitempty"`
Params json.RawMessage `json:"params,omitempty"`
Result json.RawMessage `json:"result,omitempty"`
Error *struct {
Message string `json:"message"`
} `json:"error,omitempty"`
}
// said is one event the manager said, or one call it asked of another part.
type said struct {
key string
body json.RawMessage
}
// mesh is the bus, the state directory and the parts beside the manager, kept across its starts.
type mesh struct {
t *testing.T
ctx context.Context
nc *nats.Conn
js jetstream.JetStream
bin string
// toolsBin is the tools bundle's binary.
toolsBin string
dir string
vendor *vendor
own issued // what the manager's own runtime is issued from its manifest (C1)
mu sync.Mutex
said []said
news chan struct{}
secrets map[string]string // the vault: a secret's name and its value
calls map[string][32]byte // the vault: licence-put's open calls and the private key made for each
callArgs map[string]map[string]any
holdings []Holdings // the agent modules: what each node says it holds when asked
logins map[string]FullGrant // the agent modules: the login each node hands over, by node
conditions []oc.Condition
}
func newWholeMesh(t *testing.T) *mesh {
t.Helper()
// The manager runs as its own account, never in the machine's tool runner, whose account is issued none of its
// logs or states (C1): this player plays that runtime of its own, issuing what the manifest names and nothing else.
own := manifestIssued(t)
if own.RunsAs != Publisher {
t.Fatalf("the manager declares runs-as %q: it would run in the machine's tool runner, not as its own account", own.RunsAs)
}
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
dir := t.TempDir()
// The module's two bundles, each loaded by the same runtime (design 39 parts §2, §3).
bin, toolsBin := filepath.Join(dir, "claude-licence-manager"), filepath.Join(dir, "claude-licence-manager-tools")
for out, from := range map[string]string{bin: ".", toolsBin: "../tools"} {
build := exec.Command("go", "build", "-o", out, from)
build.Stderr = os.Stderr
if err := build.Run(); err != nil {
t.Fatalf("%s does not build: %v", from, err)
}
}
nc, err := nats.Connect(testbus.URL(t))
if err != nil {
t.Fatal(err)
}
t.Cleanup(nc.Close)
js, err := jetstream.New(nc)
if err != nil {
t.Fatal(err)
}
// What the bus module creates from the manifest's templates (§1 to §9) before the manager's want moves (§50).
for s := range own.States {
if _, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: Publisher + "_" + s, History: 8}); err != nil {
t.Fatal(err)
}
}
// Each log with the cap its logs section names (C3), as the bus module creates it.
raw, err := os.ReadFile(filepath.Join(moduleDir, "module.json"))
if err != nil {
t.Fatal(err)
}
var manifest struct {
Logs []json.RawMessage `json:"logs"`
}
_ = json.Unmarshal(raw, &manifest)
bounds := logsSection(manifest.Logs)
for l := range own.Logs {
mib, _ := bounds[l]["max-mib"].(float64)
if _, err := js.CreateStream(ctx, jetstream.StreamConfig{Name: "LOG_" + Publisher + "_" + l,
Subjects: []string{"mesh.log." + Publisher + "." + l + ".>"}, MaxBytes: int64(mib) << 20}); err != nil {
t.Fatal(err)
}
}
_ = os.MkdirAll(filepath.Join(dir, "state"), 0o700)
if err := os.WriteFile(filepath.Join(dir, "settings.json"), []byte("{}"), 0o600); err != nil {
t.Fatal(err)
}
m := &mesh{t: t, ctx: ctx, nc: nc, js: js, bin: bin, toolsBin: toolsBin, dir: dir, vendor: newVendor(t), own: own,
news: make(chan struct{}, 1), secrets: map[string]string{}, calls: map[string][32]byte{},
callArgs: map[string]map[string]any{}, logins: map[string]FullGrant{}}
sub, err := nc.Subscribe("mesh.seat.operator-channel.accept.condition.>", func(msg *nats.Msg) {
c, err := occ.DecodeCondition(msg.Data)
if err != nil {
t.Errorf("a condition the operator channel's client does not decode: %v: %s", err, msg.Data)
return
}
if want, _ := occ.ConditionSubject(Publisher); msg.Subject != want {
t.Errorf("a condition said on %s, not %s", msg.Subject, want)
}
m.mu.Lock()
m.conditions = append(m.conditions, c)
m.mu.Unlock()
m.notify()
})
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = sub.Unsubscribe() })
return m
}
func (m *mesh) notify() {
select {
case m.news <- struct{}{}:
default:
}
}
// until waits for what to hold, woken by each event, call and condition the manager says, never by a timer of its own.
func (m *mesh) until(what string, ok func() bool) {
m.t.Helper()
deadline := time.After(60 * time.Second)
for {
m.mu.Lock()
done := ok()
m.mu.Unlock()
if done {
return
}
select {
case <-m.news:
case <-deadline:
m.t.Fatalf("never: %s", what)
}
}
}
// count is how many of what was said have key; under mu.
func (m *mesh) count(key string) int {
n := 0
for _, s := range m.said {
if s.key == key || strings.HasPrefix(s.key, key+".") {
n++
}
}
return n
}
// of is the bodies said under key; under mu.
func (m *mesh) of(key string) []map[string]any {
var out []map[string]any
for _, s := range m.said {
if s.key == key || strings.HasPrefix(s.key, key+".") {
var b map[string]any
_ = json.Unmarshal(s.body, &b)
out = append(out, b)
}
}
return out
}
// conditionsOf is each condition said with key, in order; under mu.
func (m *mesh) conditionsOf(key string) []oc.Condition {
var out []oc.Condition
for _, c := range m.conditions {
if c.Key == key {
out = append(out, c)
}
}
return out
}
// started is one start of the binary.
type started struct {
*mesh
in io.WriteCloser
cmd *exec.Cmd
next int
pending map[string]chan wire
pmu sync.Mutex
subs []string
}
// start starts the manager as its runtime launches it, with the module's words (ADR 0192).
func (m *mesh) start() *started {
m.t.Helper()
return m.load(m.bin)
}
// load starts one bundle's binary as the module's runtime loads it, with the module's words, which the runtime hands
// to every bundle of the module (ADR 0192).
func (m *mesh) load(bin string) *started {
m.t.Helper()
cmd := exec.CommandContext(m.ctx, bin)
cmd.Env = append(os.Environ(), "MESH_LICENCE_STATE="+filepath.Join(m.dir, "state"),
"MESH_LICENCE_SETTINGS="+filepath.Join(m.dir, "settings.json"), "MESH_NODE=novox", "MESH_MODULE="+Publisher,
"MESH_ANTHROPIC_TOKEN_ENDPOINT="+m.vendor.server.URL+"/token", "MESH_ANTHROPIC_USAGE_ENDPOINT="+m.vendor.server.URL+"/usage")
in, _ := cmd.StdinPipe()
out, _ := cmd.StdoutPipe()
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
m.t.Fatal(err)
}
p := &started{mesh: m, in: in, cmd: cmd, pending: map[string]chan wire{}}
m.t.Cleanup(p.stop)
go p.serve(out)
return p
}
// stop ends this start, as the runtime does when the module moves.
func (p *started) stop() {
_ = p.in.Close()
_ = p.cmd.Process.Kill()
_ = p.cmd.Wait()
}
func (p *started) send(v map[string]any) {
raw, _ := json.Marshal(v)
p.pmu.Lock()
defer p.pmu.Unlock()
_, _ = p.in.Write(append(raw, '\n'))
}
func (p *started) answer(id json.RawMessage, result any, err error) {
if err != nil {
code := -32000
if errors.Is(err, jetstream.ErrKeyExists) {
code = -32010 // a lost compare-and-set, as the runtime says it
}
p.send(map[string]any{"id": id, "error": map[string]any{"code": code, "message": err.Error()}})
return
}
p.send(map[string]any{"id": id, "result": result})
}
func (p *started) serve(out io.Reader) {
scanner := bufio.NewScanner(out)
scanner.Buffer(make([]byte, 1<<20), 1<<24)
for scanner.Scan() {
var w wire
if json.Unmarshal(scanner.Bytes(), &w) != nil {
continue
}
if w.Method == "" {
var key string
_ = json.Unmarshal(w.ID, &key)
p.pmu.Lock()
ch := p.pending[key]
delete(p.pending, key)
p.pmu.Unlock()
if ch != nil {
ch <- w
}
continue
}
go p.handle(w)
}
}
func (p *started) kv(state string) (jetstream.KeyValue, error) {
return p.js.KeyValue(p.ctx, Publisher+"_"+state)
}
func (p *started) handle(w wire) {
var a struct {
State string `json:"state"`
Key string `json:"key"`
Value json.RawMessage `json:"value"`
Revision uint64 `json:"revision"`
Subject string `json:"subject"`
Body json.RawMessage `json:"body"`
Pattern string `json:"pattern"`
}
_ = json.Unmarshal(w.Params, &a)
if why := p.refused(w.Method, w.Params); why != nil {
p.answer(w.ID, nil, why)
return
}
if strings.HasPrefix(w.Method, "mesh/log.") {
p.log(w)
return
}
switch w.Method {
case "mesh/state.get":
kv, err := p.kv(a.State)
if err != nil {
p.answer(w.ID, nil, err)
return
}
e, err := kv.Get(p.ctx, a.Key)
if errors.Is(err, jetstream.ErrKeyNotFound) {
p.answer(w.ID, nil, nil)
return
}
if err != nil {
p.answer(w.ID, nil, err)
return
}
p.answer(w.ID, map[string]any{"key": e.Key(), "value": json.RawMessage(e.Value()), "revision": e.Revision(), "at": e.Created()}, nil)
case "mesh/state.put", "mesh/state.create", "mesh/state.update":
kv, err := p.kv(a.State)
var rev uint64
if err == nil {
// A key's own time to live is the bus's; no test here lives as long as one (a lease's two minutes).
switch w.Method {
case "mesh/state.put":
rev, err = kv.Put(p.ctx, a.Key, a.Value)
case "mesh/state.create":
rev, err = kv.Create(p.ctx, a.Key, a.Value)
default:
rev, err = kv.Update(p.ctx, a.Key, a.Value, a.Revision)
if err != nil {
err = fmt.Errorf("%w: %v", jetstream.ErrKeyExists, err)
}
}
}
p.answer(w.ID, map[string]any{"revision": rev}, err)
case "mesh/state.keys":
kv, err := p.kv(a.State)
if err != nil {
p.answer(w.ID, nil, err)
return
}
keys, err := kv.Keys(p.ctx)
if errors.Is(err, jetstream.ErrNoKeysFound) {
keys, err = []string{}, nil
}
sort.Strings(keys)
p.answer(w.ID, keys, err)
case "mesh/state.delete":
kv, err := p.kv(a.State)
if err == nil {
err = kv.Delete(p.ctx, a.Key)
}
p.answer(w.ID, map[string]any{}, err)
case "mesh/state.history":
kv, err := p.kv(a.State)
if err != nil {
p.answer(w.ID, nil, err)
return
}
out := []map[string]any{}
h, err := kv.History(p.ctx, a.Key)
if errors.Is(err, jetstream.ErrKeyNotFound) {
p.answer(w.ID, out, nil)
return
}
for _, e := range h {
op, v := "put", json.RawMessage(e.Value())
if e.Operation() != jetstream.KeyValuePut {
op, v = "delete", nil
}
out = append(out, map[string]any{"key": e.Key(), "value": v, "revision": e.Revision(), "op": op, "at": e.Created()})
}
p.answer(w.ID, out, err)
case "mesh/publish":
p.answer(w.ID, map[string]any{}, p.nc.Publish("mesh.mod."+Publisher+".event."+a.Key, a.Body))
p.say(a.Key, a.Body)
if a.Key == HoldingsAsked {
p.answerHoldings()
}
case "mesh/seat.publish":
p.answer(w.ID, map[string]any{}, p.nc.Publish(a.Subject, a.Body))
case "mesh/subscribe":
p.pmu.Lock()
p.subs = append(p.subs, a.Pattern)
p.pmu.Unlock()
p.answer(w.ID, map[string]any{}, nil)
case "mesh/ask":
result, err := p.asked(a.Key, a.Body)
p.say("ask "+a.Key, a.Body)
p.answer(w.ID, result, err)
default:
p.answer(w.ID, nil, errors.New("nats: no responders available for request"))
}
}
// refused is the runtime's refusal of what the manager's own account was not issued (C1): a state or a log its
// manifest does not ask for, an ask its invokes do not name, an event its emits do not name; nil when it was issued.
func (p *started) refused(method string, params json.RawMessage) error {
var a struct {
State string `json:"state"`
Log string `json:"log"`
Key string `json:"key"`
}
_ = json.Unmarshal(params, &a)
switch {
case strings.HasPrefix(method, "mesh/state.") && !p.own.States[a.State]:
return fmt.Errorf("%s keeps no state called %q", Publisher, a.State)
case strings.HasPrefix(method, "mesh/log.") && !p.own.Logs[a.Log]:
return fmt.Errorf("%s keeps no log called %q", Publisher, a.Log)
case method == "mesh/ask" && !p.own.mayAsk(a.Key):
return fmt.Errorf("this account may not call %s", a.Key)
case method == "mesh/publish" && !p.own.emits(a.Key):
return fmt.Errorf("%s does not emit %s", Publisher, a.Key)
}
return nil
}
func (p *started) say(key string, body json.RawMessage) {
p.mu.Lock()
p.said = append(p.said, said{key: key, body: append(json.RawMessage(nil), body...)})
p.mu.Unlock()
p.notify()
}
// answerHoldings is each node's agent module hearing holdings.asked and saying what it holds (§23).
func (p *started) answerHoldings() {
p.mu.Lock()
reports := append([]Holdings(nil), p.holdings...)
p.mu.Unlock()
for _, r := range reports {
body, _ := json.Marshal(r)
p.mu.Lock()
p.next++
id := fmt.Sprintf("e-%d", p.next)
p.mu.Unlock()
p.send(map[string]any{"id": id, "method": "mesh/event", "params": map[string]any{"envelope": map[string]any{
"key": HoldingsChanged, "node": r.Node, "body": json.RawMessage(body)}}})
}
}
// asked answers what the manager asks of another part: the vault, a node's agent module, the operator channel.
func (p *started) asked(key string, body json.RawMessage) (any, error) {
var args map[string]any
_ = json.Unmarshal(body, &args)
p.mu.Lock()
defer p.mu.Unlock()
switch {
case key == "seat:mesh-vault.licence-put":
if call, _ := args["call"].(string); call != "" {
priv, ok := p.calls[call]
if !ok {
return nil, errors.New("no such call")
}
sealed, _ := base64.StdEncoding.DecodeString(fmt.Sprint(args["sealed"]))
var pub [32]byte
copy(pub[:], p.callArgs[call]["pub"].([]byte))
value, ok := box.OpenAnonymous(nil, sealed, &pub, &priv)
if !ok {
return nil, errors.New("the sealed value does not open")
}
a := p.callArgs[call]
p.secrets[SecretName(fmt.Sprint(a["licence"]), fmt.Sprint(a["part"]))] = string(value)
delete(p.calls, call)
return map[string]any{"put": true}, nil
}
pub, priv, _ := box.GenerateKey(rand.Reader)
call := fmt.Sprintf("call-%d", len(p.callArgs)+1)
p.calls[call] = *priv
args["pub"] = pub[:]
p.callArgs[call] = args
return map[string]any{"call": call, "seal_to": base64.StdEncoding.EncodeToString(pub[:])}, nil
case key == "seat:mesh-vault.get":
name, _ := args["name"].(string)
v, ok := p.secrets[name]
if !ok {
return nil, fmt.Errorf("the vault holds no %s", name)
}
sealed, err := Seal(v, fmt.Sprint(args["public_key"]))
return map[string]any{"sealed": sealed}, err
case strings.HasPrefix(key, "claude-code.claude_code_grant@"):
node := strings.TrimPrefix(key, "claude-code.claude_code_grant@")
g, ok := p.logins[node]
if !ok {
return GrantAnswer{}, nil
}
raw, _ := json.Marshal(g)
sealed, err := Seal(string(raw), fmt.Sprint(args["public_key"]))
return GrantAnswer{Sealed: &sealed, Fingerprint: Fingerprint(g.RefreshToken)}, err
case key == "seat:operator-channel.tell":
return map[string]any{"told": true}, nil
}
return nil, errors.New("nats: no responders available for request")
}
// keyMatches is a log's key against a pattern: `*` one name, `>` or `**` the rest, empty every key.
func keyMatches(pattern, key string) bool {
if pattern == "" {
return true
}
return namesMatch(strings.Split(pattern, "."), strings.Split(key, "."))
}
func namesMatch(p, k []string) bool {
if len(p) == 0 {
return len(k) == 0
}
if p[0] == ">" || p[0] == "**" {
return len(k) > 0
}
if len(k) == 0 || (p[0] != "*" && p[0] != k[0]) {
return false
}
return namesMatch(p[1:], k[1:])
}
// log answers the runtime's log verbs from the log's real stream, LOG_<module>_<name> on mesh.log.<module>.<name>.<key>.
func (p *started) log(w wire) {
var a struct {
Log string `json:"log"`
Key string `json:"key"`
Keys string `json:"keys"`
Value json.RawMessage `json:"value"`
From uint64 `json:"from"`
Since string `json:"since"`
Limit int `json:"limit"`
}
_ = json.Unmarshal(w.Params, &a)
subject := "mesh.log." + Publisher + "." + a.Log
s, err := p.js.Stream(p.ctx, "LOG_"+Publisher+"_"+a.Log)
if err != nil {
p.answer(w.ID, nil, err)
return
}
info, err := s.Info(p.ctx)
if err != nil {
p.answer(w.ID, nil, err)
return
}
entry := func(r *jetstream.RawStreamMsg) map[string]any {
return map[string]any{"sequence": r.Sequence, "key": strings.TrimPrefix(r.Subject, subject+"."),
"value": json.RawMessage(r.Data), "at": r.Time}
}
all := func(keys string, since time.Time) []map[string]any {
out := []map[string]any{}
for seq := max(a.From, info.State.FirstSeq, 1); seq <= info.State.LastSeq; seq++ {
r, err := s.GetMsg(p.ctx, seq)
if err != nil || !keyMatches(keys, strings.TrimPrefix(r.Subject, subject+".")) || r.Time.Before(since) {
continue
}
out = append(out, entry(r))
}
return out
}
switch w.Method {
case "mesh/log.append":
ack, err := p.js.Publish(p.ctx, subject+"."+a.Key, a.Value)
if err != nil {
p.answer(w.ID, nil, err)
return
}
p.answer(w.ID, map[string]any{"sequence": ack.Sequence}, nil)
case "mesh/log.last":
r, err := s.GetLastMsgForSubject(p.ctx, subject+"."+a.Key)
if errors.Is(err, jetstream.ErrMsgNotFound) {
p.answer(w.ID, nil, nil)
return
}
if err != nil {
p.answer(w.ID, nil, err)
return
}
p.answer(w.ID, entry(r), nil)
case "mesh/log.read":
var since time.Time
if a.Since != "" {
since, _ = time.Parse(time.RFC3339Nano, a.Since)
}
entries := all(a.Keys, since)
limit := a.Limit
if limit <= 0 {
limit = 100
}
next := uint64(0)
if len(entries) > limit {
next = entries[limit]["sequence"].(uint64)
entries = entries[:limit]
}
p.answer(w.ID, map[string]any{"entries": entries, "next": next, "last": info.State.LastSeq}, nil)
case "mesh/log.newest":
newest := map[string]int{}
var out []map[string]any
for _, e := range all(a.Keys, time.Time{}) {
k := e["key"].(string)
if i, ok := newest[k]; ok {
out[i] = e
continue
}
newest[k] = len(out)
out = append(out, e)
}
if out == nil {
out = []map[string]any{}
}
p.answer(w.ID, out, nil)
case "mesh/log.info":
p.answer(w.ID, map[string]any{"entries": info.State.Msgs, "bytes": info.State.Bytes,
"max_bytes": info.Config.MaxBytes, "first": info.State.FirstSeq, "last": info.State.LastSeq}, nil)
default:
p.answer(w.ID, nil, fmt.Errorf("no log verb %s", w.Method))
}
}
// call is a tools/call of the manager by a person, answered as the tool's JSON.
func (p *started) call(name string, args map[string]any) (json.RawMessage, error) {
p.mu.Lock()
p.next++
id := fmt.Sprintf("c-%d", p.next)
p.mu.Unlock()
ch := make(chan wire, 1)
p.pmu.Lock()
p.pending[id] = ch
p.pmu.Unlock()
p.send(map[string]any{"id": id, "method": "tools/call", "params": map[string]any{"name": name, "arguments": args,
"_meta": map[string]any{"mesh/caller": "person.operator"}}})
select {
case w := <-ch:
var r struct {
Content []struct {
Text string `json:"text"`
} `json:"content"`
IsError bool `json:"isError"`
}
if w.Error != nil {
return nil, errors.New(w.Error.Message)
}
if err := json.Unmarshal(w.Result, &r); err != nil || len(r.Content) != 1 {
return nil, fmt.Errorf("%s answered %s", name, w.Result)
}
if r.IsError {
return nil, errors.New(r.Content[0].Text)
}
return json.RawMessage(r.Content[0].Text), nil
case <-time.After(60 * time.Second):
return nil, fmt.Errorf("%s did not answer in 60s", name)
}
}
func (p *started) must(name string, args map[string]any) json.RawMessage {
p.t.Helper()
raw, err := p.call(name, args)
if err != nil {
p.t.Fatalf("%s: %v", name, err)
}
return raw
}
// bindings are the consumers' bindings, as the seat's verb answers them.
func (p *started) bindings() map[string]Binding {
p.t.Helper()
var list []Binding
if err := json.Unmarshal(p.must(Seat+".bindings", nil), &list); err != nil {
p.t.Fatal(err)
}
out := map[string]Binding{}
for _, b := range list {
out[b.Consumer] = b
}
return out
}
// ---- the tests -------------------------------------------------------------------------------------------------
// design 39 bus-and-switch §26/AC2, §28, §29/AC2, §9/AC3, B41: a reading of 99 % moves the four consumers bound to a
// licence to the one with the most room in one act, saying one binding.changed each, one licence.switched and one tell;
// with every licence at its threshold no-room is raised on the operator channel's subject, and a reading with room
// clears it.
func TestAReadingAtTheThresholdMovesEveryConsumer(t *testing.T) {
m := newWholeMesh(t)
m.seed()
p := m.start()
m.until("holdings.asked at the start", func() bool { return m.count(HoldingsAsked) > 0 })
m.mu.Lock()
carried := m.count("binding.changed")
m.mu.Unlock()
m.vendor.set("at-b", 20)
m.vendor.set("at-a", 99)
p.must("licences_read_usage", map[string]any{"licence": licenceB})
p.must("licences_read_usage", map[string]any{"licence": licenceA})
m.until("the four consumers moved", func() bool { return m.count("binding.changed") >= carried+4 })
m.mu.Lock()
switched, told := m.of("licence.switched"), m.of("ask seat:operator-channel.tell")
changed := m.of("binding.changed")[carried:]
m.mu.Unlock()
if len(switched) != 1 || switched[0]["from"] != licenceA || switched[0]["to"] != licenceB || switched[0]["by"] != "usage" ||
len(switched[0]["consumers"].([]any)) != 4 {
t.Errorf("licence.switched said %v", switched)
}
if len(told) != 1 {
t.Errorf("the operator was told %d times: %v", len(told), told)
}
moved := map[string]bool{}
for _, c := range changed {
if c["licence"] == licenceB && c["from"] == licenceA && c["by"] == "usage" {
moved[fmt.Sprint(c["consumer"])] = true
}
}
if len(moved) != 4 || len(changed) != 4 {
t.Errorf("binding.changed said %v", changed)
}
for c, b := range p.bindings() {
if b.Licence != licenceB || b.By != "usage" {
t.Errorf("%s is bound %+v", c, b)
}
}
// Every licence at its threshold: the consumers have nowhere to go.
noRoom := "licence." + KeyFor(licenceB) + ".no-room"
m.vendor.set("at-a", 99)
m.vendor.set("at-b", 99)
p.must("licences_read_usage", map[string]any{"licence": licenceA})
p.must("licences_read_usage", map[string]any{"licence": licenceB})
m.until("no-room is raised", func() bool { return len(m.conditionsOf(noRoom)) > 0 })
m.mu.Lock()
r := m.conditionsOf(noRoom)[0]
m.mu.Unlock()
if r.State != "raised" || r.Severity != "urgent" || r.Subject.ID != Publisher {
t.Errorf("no-room said %+v", r)
}
// A reading with room: the next reading of the full licence moves its consumers, and no-room is cleared.
m.vendor.set("at-a", 30)
p.must("licences_read_usage", map[string]any{"licence": licenceA})
p.must("licences_read_usage", map[string]any{"licence": licenceB})
m.until("no-room is cleared", func() bool {
c := m.conditionsOf(noRoom)
return len(c) > 1 && c[len(c)-1].State == "cleared"
})
m.mu.Lock()
defer m.mu.Unlock()
if c := m.conditionsOf(noRoom); len(c) != 2 {
t.Errorf("no-room was said %d times, not once raised and once cleared: %+v", len(c), c)
}
if n := m.count("licence.switched"); n != 2 {
t.Errorf("licence.switched was said %d times, not once per act", n)
}
}
// design 39 bus-and-switch §23/AC1, §46/AC1, design 39 parts §11: on a fresh install the manager waits for no carry-over
// and says holdings.asked; each node's agent module answers with one holdings-changed; a report carrying an
// unknown refresh token's fingerprint makes a candidate, which is adopted, listed by licences with its organisation,
// and chosen as a target at its first reading with room.
func TestANewLoginIsAdoptedListedAndATarget(t *testing.T) {
m := newWholeMesh(t)
changed := time.Now().UTC().Format(time.RFC3339Nano)
report := func(node, account, email, org, refresh string) Holdings {
h := Holdings{Node: node, Identity: &Identity{AccountUUID: account, EmailAddress: email, OrganizationUUID: org},
Kind: "subscription", ChangedAt: changed}
h.Refresh.Present, h.Refresh.Fingerprint = true, Fingerprint(refresh)
return h
}
m.holdings = []Holdings{report("laptop", "acct-old", licenceA, "", "rt-old"), report("workstation", "acct-team", "team@example.org", "org-1", "rt-team")}
m.logins["laptop"] = FullGrant{AccessToken: "at-old-0", RefreshToken: "rt-old"}
m.logins["workstation"] = FullGrant{AccessToken: "at-team-0", RefreshToken: "rt-team"}
m.vendor.logins["rt-old"] = [2]string{"at-old", "acct-old"}
m.vendor.logins["rt-team"] = [2]string{"at-team", "acct-team"}
p := m.start()
m.until("both logins adopted", func() bool { return m.count("licence.adopted") >= 2 })
m.mu.Lock()
asked := m.count("ask claude-code.claude_code_grant@laptop") + m.count("ask claude-code.claude_code_grant@workstation")
m.mu.Unlock()
if asked != 2 {
t.Errorf("the nodes were asked for their logins %d times, not once each", asked)
}
// The full licence is read first: nothing has room yet, so its consumer stays.
m.vendor.set("at-old", 99)
m.vendor.set("at-team", 5)
p.must("licences_read_usage", map[string]any{"licence": licenceA})
p.must("licences_read_usage", map[string]any{"licence": "team@example.org"})
var listed []map[string]any
if err := json.Unmarshal(p.must(Seat+".licences", nil), &listed); err != nil {
t.Fatal(err)
}
var team map[string]any
for _, l := range listed {
if l["name"] == "team@example.org" {
team = l
}
}
if team == nil || team["organisation"] != "org-1" || team["target"] != true || team["usage"] == nil {
t.Fatalf("licences lists the new login as %v (all: %v)", team, listed)
}
p.must("licences_read_usage", map[string]any{"licence": licenceA})
m.until("the full licence's consumer moved to the new one", func() bool {
for _, s := range m.of("licence.switched") {
if s["to"] == "team@example.org" && s["from"] == licenceA {
return true
}
}
return false
})
if b := p.bindings()["laptop"]; b.Licence != "team@example.org" {
t.Errorf("laptop is bound %+v", b)
}
}
// design 39 parts §3, §10, §18: with the manager bundle not loaded (as when it refuses to start), the tools bundle,
// loaded by the same runtime, answers licences_kept with every entry the module keeps and licences_conditions with
// each condition kept, and says, writes and asks nothing while it does.
func TestTheReadingToolsAnswerWithoutTheManager(t *testing.T) {
m := newWholeMesh(t)
m.seed()
carried, err := m.js.KeyValue(m.ctx, Publisher+"_carried")
if err != nil {
t.Fatal(err)
}
if _, err := carried.Put(m.ctx, "postgres", []byte(`{"at":"2026-11-12T09:44:59Z"}`)); err != nil {
t.Fatal(err)
}
seqs := func() map[string]uint64 {
out := map[string]uint64{}
for s := range m.own.States {
st, err := m.js.Stream(m.ctx, "KV_"+Publisher+"_"+s)
if err != nil {
t.Fatal(err)
}
i, _ := st.Info(m.ctx)
out[s] = i.State.LastSeq
}
for l := range m.own.Logs {
st, err := m.js.Stream(m.ctx, "LOG_"+Publisher+"_"+l)
if err != nil {
t.Fatal(err)
}
i, _ := st.Info(m.ctx)
out["log "+l] = i.State.LastSeq
}
return out
}
before := seqs()
tools := m.load(m.toolsBin)
var all map[string]map[string]any
if err := json.Unmarshal(tools.must("licences_kept", nil), &all); err != nil {
t.Fatal(err)
}
if len(all) != len(m.own.States)+len(m.own.Logs) || len(all) != 8 {
t.Fatalf("licences_kept answers %d entries without the manager, not 8: %v", len(all), all)
}
for name, e := range all {
if e["fill"] == nil {
t.Errorf("licences_kept answers %s without its fill: %v", name, e)
}
}
var one map[string]map[string]any
if err := json.Unmarshal(tools.must("licences_kept", map[string]any{"entry": "carried", "key": "postgres"}), &one); err != nil {
t.Fatal(err)
}
if v, _ := one["carried"]["value"].(map[string]any); v["at"] != "2026-11-12T09:44:59Z" {
t.Errorf("the carry-over's record is answered as %v", one)
}
if keys, _ := all["bindings"]["keys"].([]any); len(keys) != len(consumers) {
t.Errorf("bindings answers %v", all["bindings"])
}
tools.must("licences_conditions", nil)
if after := seqs(); fmt.Sprint(after) != fmt.Sprint(before) {
t.Errorf("the tools bundle wrote: before %v, after %v", before, after)
}
m.mu.Lock()
defer m.mu.Unlock()
if len(m.said) != 0 || len(m.conditions) != 0 {
t.Errorf("the tools bundle said or asked %v and %v", m.said, m.conditions)
}
}