mesh/merge-gate pass: builds new: modules/mesh-knowledge, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compo…
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 superseded: a newer head of the same pull request
An agent learns what a decision says only by reading whole records. This module holds every decision record and research effort whole in a database in the store, with clauses that carry their own status and source, typed links read from both ends, and every version. It answers ask, get and holds within a stated bound, and takes a record through reserve, propose (refused on any of the 29 per-record rules), review by someone other than the author, and acceptance, on the operator's proven warrant when the record needs it. The 4 whole-set rules make the module unhealthy when they fail. The import reads hq at a commit through the records module, never overwrites, and changes nothing when run again. Prose decisions get drafted clauses that a second judgement must confirm before they are served.
199 lines
7.9 KiB
Go
199 lines
7.9 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", "review", "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", "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}) {
|
|
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")
|
|
}
|
|
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)
|
|
}
|
|
}
|