mesh/merge-gate pass: builds claude-code, mesh-knowledge → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (…
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
A judgement over one bus call's 30 seconds is collected by its ticket from claude-code, so an eleven-clause record can be reviewed; a proposal out of review tries is told to the operator, not raised as the module's fault, so it no longer holds the module's own rollouts.
205 lines
8.4 KiB
Go
205 lines
8.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// The manifest says what the code does (novox/hq to-be 55 §1): the seat it declares and holds once for the mesh
|
|
// with the verbs it serves, the events it says, what it uses and invokes, the database it requires, its two
|
|
// long-running processes with their health, and its settings.
|
|
|
|
type manifest struct {
|
|
Module string `json:"module"`
|
|
Requires []string `json:"requires"`
|
|
Contributes map[string]map[string]any `json:"contributes"`
|
|
Seats []seat `json:"seats"`
|
|
Claims []seat `json:"claims"`
|
|
Tools []string `json:"tools"`
|
|
Emits []string `json:"emits"`
|
|
Consumes []string `json:"consumes"`
|
|
Uses []string `json:"uses"`
|
|
Invokes []string `json:"invokes"`
|
|
State []json.RawMessage `json:"state"`
|
|
Resources []map[string]any `json:"resources"`
|
|
Build struct {
|
|
Artifacts []struct {
|
|
From string `json:"from"`
|
|
Binary string `json:"binary"`
|
|
Loads []string `json:"loads"`
|
|
Env map[string]string `json:"env"`
|
|
} `json:"artifacts"`
|
|
} `json:"build"`
|
|
}
|
|
|
|
type seat struct {
|
|
Name string `json:"name"`
|
|
Scope string `json:"scope"`
|
|
Serves []string `json:"serves"`
|
|
}
|
|
|
|
func readManifest(t *testing.T) (manifest, string) {
|
|
t.Helper()
|
|
raw, err := os.ReadFile(filepath.Join("..", "..", "module.json"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var m manifest
|
|
if err := json.Unmarshal(raw, &m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return m, string(raw)
|
|
}
|
|
|
|
func TestItDeclaresAndHoldsTheKnowledgeBaseSeatOnceForTheMesh(t *testing.T) {
|
|
m, raw := readManifest(t)
|
|
want := []seat{{Name: Seat, Scope: "mesh", Serves: Verbs}}
|
|
if m.Module != Module || !reflect.DeepEqual(m.Seats, want) || !reflect.DeepEqual(m.Claims, want) {
|
|
t.Fatalf("module %q, seats %+v, claims %+v", m.Module, m.Seats, m.Claims)
|
|
}
|
|
if !reflect.DeepEqual(Verbs, []string{"ask", "get", "holds", "links", "history", "reserve", "propose", "import", "return"}) {
|
|
t.Fatalf("the verbs are not ADR 0290 rule 6's: %v", Verbs)
|
|
}
|
|
if !reflect.DeepEqual(m.Emits, Events) {
|
|
t.Fatalf("emits %v, the code says %v", m.Emits, Events)
|
|
}
|
|
// Its records are in a database in the store (ADR 0290 rule 7), not in buckets.
|
|
if !reflect.DeepEqual(m.Requires, []string{"postgres-database"}) || m.Contributes["postgres-database"]["name"] != "knowledge" || len(m.State) != 0 {
|
|
t.Fatalf("requires %v, contributes %v, state %v", m.Requires, m.Contributes, m.State)
|
|
}
|
|
// It asks the operator on the router, hears the router's word, and calls exactly what it calls.
|
|
if !reflect.DeepEqual(m.Uses, []string{"operator-channel"}) || len(m.Consumes) != 0 {
|
|
t.Fatalf("uses %v, consumes %v", m.Uses, m.Consumes)
|
|
}
|
|
if !reflect.DeepEqual(m.Invokes, []string{"seat:issue-tracker.reserve", "claude-code.claude_code_judge", "claude-code.claude_code_judged", "records.records_status",
|
|
"records.records_list", "records.records_read", "seat:operator-channel.notify"}) {
|
|
t.Fatalf("invokes %v", m.Invokes)
|
|
}
|
|
src := ""
|
|
for _, f := range []string{"main.go", "hq.go"} {
|
|
src += readFile(t, f)
|
|
}
|
|
for _, inv := range m.Invokes {
|
|
if !strings.Contains(src, `"`+inv) {
|
|
t.Errorf("the manifest invokes %s, which the code never calls", inv)
|
|
}
|
|
}
|
|
if len(m.Build.Artifacts) != 1 || m.Build.Artifacts[0].From != "cmd/mesh-knowledge" || m.Build.Artifacts[0].Binary != Module ||
|
|
m.Build.Artifacts[0].Env["DATABASE_URL_FILE"] == "" || m.Build.Artifacts[0].Env["MESH_KNOWLEDGE_SETTINGS"] == "" ||
|
|
m.Build.Artifacts[0].Env["MESH_KNOWLEDGE_STATUS"] == "" || !reflect.DeepEqual(m.Build.Artifacts[0].Loads, []string{Module}) {
|
|
t.Fatalf("build %+v", m.Build)
|
|
}
|
|
for _, never := range []string{"/home/", "jochen", "shanks", "novox.be"} {
|
|
if strings.Contains(strings.ToLower(raw), never) {
|
|
t.Errorf("module.json names %q", never)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Its processes: the preparation step once, keep judged by its unit, watch by the health tool, which the module
|
|
// serves; the status file watch writes is the one the bundle's health tool reads.
|
|
func TestItsProcessesAreThePreparationTheActAndTheJudge(t *testing.T) {
|
|
m, _ := readManifest(t)
|
|
byID := map[string]map[string]any{}
|
|
for _, r := range m.Resources {
|
|
byID[r["id"].(string)] = r
|
|
}
|
|
prep, keep, watch := byID["prepare"], byID["keep"], byID["watch"]
|
|
if prep == nil || prep["run-once"] != true || prep["run"].([]any)[1] != "prepare" {
|
|
t.Fatalf("prepare %v", prep)
|
|
}
|
|
if keep == nil || keep["run"].([]any)[1] != "keep" || keep["health"].(map[string]any)["kind"] != "unit" {
|
|
t.Fatalf("keep %v", keep)
|
|
}
|
|
h, _ := watch["health"].(map[string]any)
|
|
if watch == nil || watch["run"].([]any)[1] != "watch" || h["kind"] != "tool" || h["tool"] != HealthTool ||
|
|
!reflect.DeepEqual(m.Tools, []string{HealthTool, HighestTool}) {
|
|
t.Fatalf("watch %v, tools %v", watch, m.Tools)
|
|
}
|
|
if watch["env"].(map[string]any)["MESH_KNOWLEDGE_STATUS"] != m.Build.Artifacts[0].Env["MESH_KNOWLEDGE_STATUS"] {
|
|
t.Fatal("watch writes another status file than the health tool reads")
|
|
}
|
|
// The health tool reads the status file as the account the runtime runs the bundle as, and the mesh gives that
|
|
// account the state directory (and nothing a process writes there later). A watch running as root wrote the
|
|
// file root's, 0600, and the tool could not open it (hq issue 479): watch runs as that account, as zfs's does.
|
|
if watch["user"] != "${machine:account}" {
|
|
t.Fatalf("watch runs as %v, not as the account the health tool reads its verdict as", watch["user"])
|
|
}
|
|
settings := byID["settings"]
|
|
var s Settings
|
|
if err := json.Unmarshal([]byte(settings["content"].(string)), &s); err != nil || s.JudgeModel == "" || s.ReservedFor != "168h" {
|
|
t.Fatalf("the settings the manifest writes are not the module's: %v %+v", err, s)
|
|
}
|
|
if d, err := time.ParseDuration(s.ReservedFor); err != nil || d != DefaultReservedFor {
|
|
t.Fatalf("reserved-for %q is not the default the code holds", s.ReservedFor)
|
|
}
|
|
}
|
|
|
|
// The tools are the seat's verbs and the health tool, each said in plain words with what it refuses.
|
|
func TestTheToolsAreTheSeatsVerbsAndSayWhatTheyDo(t *testing.T) {
|
|
m, _ := readManifest(t)
|
|
var verbs []string
|
|
for _, tool := range Tools(&KB{}, callerOf) {
|
|
s, verb, ok := strings.Cut(tool.Name, ".")
|
|
if !ok || s != Seat {
|
|
t.Errorf("%s is not a verb of %s", tool.Name, Seat)
|
|
}
|
|
verbs = append(verbs, verb)
|
|
if len(tool.Description) < 120 {
|
|
t.Errorf("%s says too little of what it does", tool.Name)
|
|
}
|
|
for _, internal := range []string{"ADR", "to-be", "bucket", "postgres", "KV"} {
|
|
if strings.Contains(tool.Description, internal) {
|
|
t.Errorf("%s's description uses the internal name %q", tool.Name, internal)
|
|
}
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(verbs, m.Claims[0].Serves) {
|
|
t.Fatalf("verbs %v, claim %v", verbs, m.Claims[0].Serves)
|
|
}
|
|
}
|
|
|
|
// No argument can name the caller: who acted is the runtime's word, unproven until it gives one.
|
|
func TestNoArgumentNamesTheCaller(t *testing.T) {
|
|
for _, tool := range Tools(&KB{}, callerOf) {
|
|
props := tool.Input["properties"].(map[string]any)
|
|
for _, who := range []string{"by", "caller", "author", "reviewer", "who"} {
|
|
if _, ok := props[who]; ok {
|
|
t.Errorf("%s takes %s", tool.Name, who)
|
|
}
|
|
}
|
|
if tool.Input["additionalProperties"] != false {
|
|
t.Errorf("%s takes arguments it does not name", tool.Name)
|
|
}
|
|
}
|
|
if callerOf(map[string]any{"by": "someone@else"}) != Unproven {
|
|
t.Fatal("the caller was read from an argument")
|
|
}
|
|
}
|
|
|
|
func TestTheHealthToolReadsTheWatchsVerdictAndSaysWhenItIsStale(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "health.json")
|
|
now := time.Date(2026, 10, 11, 9, 0, 0, 0, time.UTC)
|
|
if a := ReadStatus(path, now); a.Healthy {
|
|
t.Fatal("healthy with no verdict")
|
|
}
|
|
if err := writeStatus(path, HealthAnswer{State: "unhealthy", Why: "the rule cited: ADR 0300 is accepted and nothing cites it", At: now}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a := ReadStatus(path, now.Add(time.Minute)); a.Healthy || !strings.Contains(a.Why, "ADR 0300") {
|
|
t.Fatalf("%+v", a)
|
|
}
|
|
_ = writeStatus(path, HealthAnswer{State: "healthy", Why: "fine", At: now})
|
|
if a := ReadStatus(path, now.Add(time.Minute)); !a.Healthy {
|
|
t.Fatalf("%+v", a)
|
|
}
|
|
if a := ReadStatus(path, now.Add(StatusStale+time.Second)); a.Healthy || !strings.Contains(a.Why, "has not looked") {
|
|
t.Fatalf("a stale verdict: %+v", a)
|
|
}
|
|
}
|