Let claude-code read its tools and machines from the bus, not the controller

The controller is not placed (ADR 0590), so its tools, modules, nodes and
node verbs answer nothing. claude-code now reads the seats' verbs from the
seats' contract, the placed modules' replaces from the indexer's manifests,
and the machines and where modules run from mesh-placement's placement; the
rendered instructions name the seats that own each job (issue 1126 B13).

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 12:29:56 +01:00
parent b44e600e87
commit f723d4372f
8 changed files with 311 additions and 226 deletions
@@ -1,43 +1,82 @@
package main
import (
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"os"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// askingAController answers the controller's verbs as the seat does: `tools` in-process, the rest as the
// command's output and its JSON.
func askingAController(t *testing.T) Ask {
// aBus is the states claude-code reads, as a test holds them: by read, key and value.
type aBus map[string]map[string][]byte
func (b aBus) Keys(read string) ([]string, error) {
if b[read] == nil {
return nil, errors.New("no such state")
}
var keys []string
for k := range b[read] {
keys = append(keys, k)
}
return keys, nil
}
func (b aBus) Get(read, key string) ([]byte, bool, error) {
v, ok := b[read][key]
return v, ok, nil
}
// someSeats are two seats as the seats' contract says them: one held once for the mesh, one on every machine.
func someSeats() []catalogue.Seat {
return []catalogue.Seat{
{Name: "mesh-placement", Scope: catalogue.ScopeMesh, Serves: []catalogue.Verb{
{Name: "placement", Description: "Read placement: one node's key.", Replaces: []string{"hostnamectl", "uptime"}},
{Name: "propose", Description: "Propose a change."}}},
{Name: "node-service-manager", Scope: catalogue.ScopeNode, Serves: []catalogue.Verb{
{Name: "status", Description: "One unit as the service manager sees it now: its states, whether it starts at boot.", Replaces: []string{"systemctl status", "systemctl is-active"}},
{Name: "journal", Description: "The last lines of one unit's journal.", Replaces: []string{"journalctl"}}}},
}
}
// aMesh is two machines, anchor (with a public domain) and laptop, docker and zsh placed on anchor, docker's manifest
// saying what its tool replaces, as the seat mesh-placement and the indexer keep them on the bus.
func aMesh(t *testing.T) aBus {
t.Helper()
wrap := func(output string, answer any) json.RawMessage {
raw, _ := json.Marshal(map[string]any{"ok": true, "output": output, "answer": answer})
return raw
}
return func(address string, args any) (json.RawMessage, error) {
switch address {
case "seat:mesh-controller.tools":
return json.RawMessage(`{"seats":[
{"seat":"mesh-controller","scope":"mesh","tools":[{"name":"node","description":"What one machine reported it can do, what it is assigned, and why.","replaces":["hostnamectl","uptime"]},{"name":"nodes","description":"Every machine."}]},
{"seat":"node-service-manager","scope":"node","tools":[
{"name":"status","description":"One unit as the service manager sees it now: its states, whether it starts at boot.","replaces":["systemctl status","systemctl is-active"]},
{"name":"journal","description":"The last lines of one unit's journal.","replaces":["journalctl"]}]}]}`), nil
case "seat:mesh-controller.modules":
return wrap("[...]", []any{map[string]any{"module": "docker", "on": []string{"anchor"},
"replaces": map[string][]string{"docker_logs": {"docker logs"}}}, map[string]any{"module": "zsh", "on": []string{"anchor"}}}), nil
case "seat:mesh-controller.nodes":
return wrap("", []any{map[string]any{"name": "anchor"}, map[string]any{"name": "laptop"}}), nil
case "seat:mesh-controller.node":
node, _ := args.(map[string]any)["node"].(string)
if node == "anchor" {
return wrap("anchor\n mode converged\n public domain Anchor.Example\n\n what it runs\n", nil), nil
}
return wrap("laptop\n mode converged\n", nil), nil
b := aBus{PlacementRead: {}, ModulesRead: {}, ManifestsRead: {}}
for _, p := range []delivery.Placement{
{V: 1, Node: "anchor", Decided: delivery.NodeDecided{PublicDomain: "Anchor.Example"},
Modules: []delivery.PlacedModule{{Module: "docker"}, {Module: "zsh"}}},
{V: 1, Node: "laptop"},
} {
values, err := delivery.PlacementValues(p)
if err != nil {
t.Fatal(err)
}
for k, v := range values {
b[PlacementRead][k] = v
}
return nil, errors.New("no such verb")
}
for module, manifest := range map[string]string{
"docker": `{"module":"docker","replaces":{"docker_logs":["docker logs"]}}`,
"zsh": `{"module":"zsh"}`,
} {
digest := fmt.Sprintf("%x", sha256.Sum256([]byte(manifest)))
mkey, _ := delivery.ManifestsKey(digest)
raw, err := json.Marshal(delivery.Manifest{V: 1, Module: module, JSON: manifest})
if err != nil {
t.Fatal(err)
}
b[ManifestsRead][mkey] = raw
key, _ := delivery.ModulesKey(module)
b[ModulesRead][key], _ = json.Marshal(delivery.Module{V: 1, None: "nothing is built of it", Manifest: digest, Repository: "novox/mesh-catalog", Commit: "c"})
}
return b
}
func resolving(name string) []string {
@@ -45,10 +84,11 @@ func resolving(name string) []string {
"laptop": {"127.0.0.1", "10.10.0.4"}}[name]
}
// What the controller says of its tools and machines is read whole: the seats' verbs, the modules' own tools,
// every machine with its domains and addresses — a loopback address never one of them.
func TestTheMeshsToolsAreAskedOfTheController(t *testing.T) {
m, err := AskMeshTools(askingAController(t), resolving)
// Issue 1126 B13: what the mesh says of its tools and machines is read from the bus whole, never asked of the
// controller: the seats' verbs, the placed modules' own tools, every machine with its domains and addresses — a
// loopback address never one of them.
func TestTheMeshsToolsAreReadFromTheBus(t *testing.T) {
m, err := ReadMeshToolsFrom(aMesh(t), someSeats(), resolving)
if err != nil {
t.Fatal(err)
}
@@ -56,7 +96,7 @@ func TestTheMeshsToolsAreAskedOfTheController(t *testing.T) {
for _, r := range m.Replacements {
addresses = append(addresses, r.Address)
}
if got := strings.Join(addresses, ","); got != "mesh-controller.node,node-service-manager.status,node-service-manager.journal,docker.docker_logs" {
if got := strings.Join(addresses, ","); got != "mesh-placement.placement,node-service-manager.status,node-service-manager.journal,docker.docker_logs" {
t.Errorf("replacements: %s", got)
}
if len(m.Machines) != 2 || strings.Join(m.Machines[0].Domains, ",") != "anchor.internal,anchor.example" ||
@@ -71,12 +111,12 @@ func TestTheMeshsToolsAreAskedOfTheController(t *testing.T) {
// **The table is generated, not written** (novox/hq ADR 0245): what the records say a verb replaces is a row,
// the machines' seats first, and nothing is rendered where the records say nothing.
func TestTheInsteadOfTableIsGeneratedFromTheRecords(t *testing.T) {
m, _ := AskMeshTools(askingAController(t), resolving)
m, _ := ReadMeshToolsFrom(aMesh(t), someSeats(), resolving)
table := InsteadOf(&m)
for _, want := range []string{
"| `<node>/node-service-manager.` | `status` — `systemctl status`, `systemctl is-active` · `journal` — `journalctl` |",
"| `<node>/docker.` | `docker_logs` — `docker logs` |",
"| `mesh-controller.` | `node` — `hostnamectl`, `uptime` |",
"| `mesh-placement.` | `placement` — `hostnamectl`, `uptime` |",
"Never `ssh` to a mesh machine",
} {
if !strings.Contains(table, want) {
@@ -84,14 +124,14 @@ func TestTheInsteadOfTableIsGeneratedFromTheRecords(t *testing.T) {
}
}
if strings.Index(table, "node-service-manager.") > strings.Index(table, "docker.") ||
strings.Index(table, "docker.") > strings.Index(table, "`mesh-controller.`") {
strings.Index(table, "docker.") > strings.Index(table, "`mesh-placement.`") {
t.Errorf("not the machines' seats, then modules, then the mesh's:\n%s", table)
}
// What the guard here named most comes first: its row, and in its row its verb.
m.Refused = map[string]int{"node-service-manager.journal": 3, "mesh-controller.node": 1}
m.Refused = map[string]int{"node-service-manager.journal": 3, "mesh-placement.placement": 1}
ranked := InsteadOf(&m)
if !strings.Contains(ranked, "| `<node>/node-service-manager.` | `journal` — `journalctl` · `status`") ||
strings.Index(ranked, "`mesh-controller.`") > strings.Index(ranked, "`<node>/docker.`") {
strings.Index(ranked, "`mesh-placement.`") > strings.Index(ranked, "`<node>/docker.`") {
t.Errorf("not ranked by the guard's record:\n%s", ranked)
}
m.Refused = nil
@@ -121,7 +161,7 @@ func TestTheInsteadOfTableIsGeneratedFromTheRecords(t *testing.T) {
// Asked again with the same answer, nothing is written and nothing renders.
func TestTheMeshsToolsAreKeptOnlyWhenTheyChange(t *testing.T) {
p := Paths{State: t.TempDir()}
m, _ := AskMeshTools(askingAController(t), resolving)
m, _ := ReadMeshToolsFrom(aMesh(t), someSeats(), resolving)
if !KeepMeshTools(p, m) {
t.Fatal("the first answer was not kept")
}
@@ -138,18 +178,32 @@ func TestTheMeshsToolsAreKeptOnlyWhenTheyChange(t *testing.T) {
}
}
// Where claude-code runs is read from the controller's `modules` answer as it comes — JSON, from `module list
// --json` — and from the printed list too.
func TestTheMachinesRunningTheModuleAreReadFromTheControllersAnswer(t *testing.T) {
asJSON := json.RawMessage(`{"ok":true,"output":"[...]","answer":[{"module":"zsh","on":["a"]},{"module":"claude-code","on":["a","b"]}]}`)
if got := strings.Join(NodesRunning(asJSON, "claude-code"), ","); got != "a,b" {
t.Errorf("from JSON: %q", got)
// Where a module runs is read from the seat mesh-placement's placement (issue 1126 B13), never the controller's answer.
func TestTheMachinesRunningAModuleAreReadFromPlacement(t *testing.T) {
b := aMesh(t)
if got, err := NodesRunning(b, "zsh"); err != nil || strings.Join(got, ",") != "anchor" {
t.Errorf("zsh runs on %v (%v)", got, err)
}
printed := json.RawMessage(`{"ok":true,"output":"zsh 1 built x on a\nclaude-code 1 built y on a, b\n"}`)
if got := strings.Join(NodesRunning(printed, "claude-code"), ","); got != "a,b" {
t.Errorf("from the printed list: %q", got)
if got, err := NodesRunning(b, "claude-code"); err != nil || got != nil {
t.Errorf("a module that runs nowhere: %v (%v)", got, err)
}
if got := NodesRunning(json.RawMessage(`{"ok":true,"answer":[{"module":"zsh","on":["a"]}]}`), "claude-code"); got != nil {
t.Errorf("a module that runs nowhere: %v", got)
if _, err := NodesRunning(aBus{}, "zsh"); err == nil {
t.Error("an unreadable placement was read as no machine")
}
}
// Issue 1126 B13 AC1 (ADR 0590): over the seats the mesh defines, the rendered instructions, their table among them,
// name no address of the controller, which is not placed: each job is named by the seat that owns it now.
func TestTheRenderedInstructionsNameNoControllerAddress(t *testing.T) {
m, err := ReadMeshToolsFrom(aMesh(t), catalogue.Seats(), resolving)
if err != nil {
t.Fatal(err)
}
md := RenderWithMesh(Facts{Node: "w", Console: "x"}, Settings{}, nil, "/h", nil, Config{}, &m)["CLAUDE.md"]
if !strings.Contains(md, "## Instead of a shell command") {
t.Fatalf("no table rendered:\n%s", md)
}
if strings.Contains(md, "mesh-controller") {
t.Errorf("the instructions name the controller:\n%s", md)
}
}