CAT-CC3: claude-code reads the indexer's modules and manifests and the assigner's placement from their first views and views events, never their state (ADR 0615 §1)

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 12:45:58 +01:00
parent e6806d5698
commit 313c1997a4
6 changed files with 131 additions and 27 deletions
+43 -13
View File
@@ -12,6 +12,7 @@ package main
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
@@ -24,6 +25,9 @@ import (
"git.novox.be/novox/mesh-contracts/go/seats"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/asks"
"git.novox.be/novox/mesh-sdk/go/delivery"
"git.novox.be/novox/mesh-sdk/go/handacts"
"git.novox.be/novox/mesh-sdk/go/views"
)
func say(format string, args ...any) {
@@ -205,23 +209,46 @@ func (s stateOf) Get(key string) (json.RawMessage, bool, error) {
return e.Value, true, nil
}
// nodesRunningMe is the nodes claude-code runs on, from the seat mesh-placement's placement — for the register
// tool's question.
func nodesRunningMe() ([]string, error) { return NodesRunning(busStates{}, "claude-code") }
// nodesRunningMe is the nodes claude-code runs on, from the assigner's placement — for the register tool's question.
func nodesRunningMe() ([]string, error) { return NodesRunning(viewStates{meshViews}, "claude-code") }
// busStates reads the states the manifest declares in its reads through the runtime.
type busStates struct{}
// The owners' read tools of the states this module follows, which the manifest invokes (novox/hq ADR 0615 §1).
const (
ModulesTool = delivery.IndexerModule + ".indexer_read_modules"
ManifestsTool = delivery.IndexerModule + ".indexer_read_manifests"
PlacementTool = delivery.AssignerModule + ".assigner_read_placement"
)
func (busStates) Keys(read string) ([]string, error) { return stdio.State(read).Keys() }
// meshViews is this module's picture of the indexer's modules and manifests and the assigner's placement: each asked
// once of the owner's read tool, then followed on the owner's views family. It reads none of their state.
var meshViews *views.Reader
func (busStates) Get(read, key string) ([]byte, bool, error) {
e, err := stdio.State(read).Get(key)
if err != nil || e == nil {
return nil, false, err
}
return e.Value, true, nil
// meshChanged is told, without waiting, that a followed state changed: the instructions' table is read again.
var meshChanged = make(chan struct{}, 1)
// newMeshViews builds the reader of those three states; Start asks them.
func newMeshViews() *views.Reader {
v := &views.Reader{Module: Module, Logf: func(f string, a ...any) { say(f, a...) }, Findings: views.OwnFindings{},
Acts: handacts.Recorder{Ask: stdio.Ask},
Changed: func(string, string, json.RawMessage, bool) {
select {
case meshChanged <- struct{}{}:
default:
}
}}
v.Follow(delivery.IndexerModule, "modules", ModulesTool)
v.Follow(delivery.IndexerModule, "manifests", ManifestsTool)
v.Follow(delivery.AssignerModule, "placement", PlacementTool)
return v
}
// viewStates reads the followed states from the reader's pictures, never from the owners' state.
type viewStates struct{ v *views.Reader }
func (s viewStates) Keys(read string) ([]string, error) { return s.v.Keys(read) }
func (s viewStates) Get(read, key string) ([]byte, bool, error) { return s.v.Get(read, key) }
func fingerprintOfFile(path string) any {
raw, err := os.ReadFile(path)
if err != nil {
@@ -291,7 +318,7 @@ func tools(p Paths, servers ServerState, view *ServerView, config ConfigState, c
Description: "Write Claude Code's managed directory now, from the mesh's facts, this module's settings and the servers registered here — after reading the bus again for what each tool replaces and which machines the mesh has (the instructions' table and the shell's guard).",
Run: func(map[string]any) (any, error) {
answer := map[string]any{}
if m, err := ReadMeshToolsFrom(busStates{}, seats.List(), lookup); err != nil {
if m, err := ReadMeshToolsFrom(viewStates{meshViews}, seats.List(), lookup); err != nil {
answer["asked"] = "the bus could not be read in full (" + err.Error() + "); what was kept is rendered"
} else {
KeepMeshTools(p, m)
@@ -377,6 +404,7 @@ func tools(p Paths, servers ServerState, view *ServerView, config ConfigState, c
return stdio.Emit("judged", e, stdio.EmitOptions{MessageID: id})
}
out = append(out, judgeTool(judge), judgedTool(judge))
out = append(out, meshViews.Tools("claude_code")...)
return append(out, configTools(p, config, configView)...)
}
@@ -422,6 +450,7 @@ func main() {
return
}
p, launched := PathsFrom(os.Getenv)
meshViews = newMeshViews()
if launched {
fsys = FilesFor(p)
}
@@ -451,6 +480,7 @@ func main() {
}
}
}
meshViews.Start(context.Background())
go refreshMeshTools(p)
servers := stateOf{stdio.State("servers")}
view := NewServerView(p)