Files
mesh-catalog/modules/mesh-knowledge/cmd/mesh-knowledge/import_test.go
T
jschoubben ba7b455719
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
Add mesh-knowledge, the knowledge base's first slice (hq issue 425, ADR 0290)
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.
2026-10-11 04:58:35 +02:00

183 lines
6.6 KiB
Go

package main
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
)
// to-be 55 §10: "The import changes nothing on a second run, and loses nothing — the module's test over a fixture
// repository." The fixture is real hq records copied at the commit testdata/hq/COMMIT names.
func TestTheImportWritesEveryRecordWholeAndASecondRunChangesNothing(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := newWorld(t, s, fixture())
ctx := context.Background()
dry, err := w.k.Import("import@test", ImportAsk{DryRun: true}, fixture())
if err != nil {
t.Fatal(err)
}
if all, _ := s.All(ctx); len(all) != 0 || dry.Created != 11 || !strings.Contains(dry.Said, "a dry run") {
t.Fatalf("the dry run wrote %d records, or would create %d: %s", len(all), dry.Created, dry.Said)
}
first, err := w.k.Import("import@test", ImportAsk{}, fixture())
if err != nil {
t.Fatal(err)
}
if first.Created != 11 || first.Refused != 0 || first.Held != 0 || first.ToDraft != 5 {
t.Fatalf("first run: %+v", first)
}
if len(w.said.of(EventImported)) != 11 {
t.Fatalf("%d imported events", len(w.said.of(EventImported)))
}
// Loses nothing: every file's record, whole.
commit := strings.TrimSpace(readFile(t, "testdata/hq/COMMIT"))
entries, _ := os.ReadDir("testdata/hq/02-DECISIONS")
for _, f := range entries {
if !adrFile.MatchString(f.Name()) {
continue
}
text := readFile(t, filepath.Join("testdata/hq/02-DECISIONS", f.Name()))
p, err := ParseDecision(f.Name(), text)
if err != nil {
t.Fatal(err)
}
e := mustGet(t, s, p.Record.Key())
r := e.Current
if r.Title != p.Record.Title || r.Status != p.Record.Status || r.Topic != p.Record.Topic || r.Date != p.Record.Date ||
len(r.Sections) != len(p.Record.Sections) || len(r.Clauses) != len(p.Record.Clauses) || e.Versions != 1 ||
r.Source != "hq@"+commit+":02-DECISIONS/"+f.Name() {
t.Errorf("%s is not held whole: %+v", f.Name(), r)
}
for i, sec := range p.Record.Sections {
if r.Sections[i] != sec {
t.Errorf("%s's section %s differs", f.Name(), sec.Name)
}
}
// Every section of the file, read back in order, is the file's body after its heading.
if body := sectionsText(r); !strings.Contains(text, strings.TrimSpace(r.Sections[len(r.Sections)-1].Text)) || body == "" {
t.Errorf("%s's last section is not the file's", f.Name())
}
}
// 0276 writes nine numbered clauses with a bold lead: written and in force. 0240 writes prose: none yet,
// waiting to be drafted. 0127 is superseded by 0131.
r276 := mustGet(t, s, Key{KindDecision, 276}).Current
if len(r276.Clauses) != 9 || r276.Clauses[0].Source != SourceWritten || r276.Clauses[0].Status != ClauseInForce ||
!strings.HasPrefix(r276.Clauses[0].Text, "**A rolling merge window.**") {
t.Fatalf("0276's clauses: %+v", r276.Clauses)
}
if r := mustGet(t, s, Key{KindDecision, 240}).Current; len(r.Clauses) != 0 || r.Drafting == nil || r.Drafting.State != DraftWaiting {
t.Fatalf("0240: %+v", r.Drafting)
}
if r := mustGet(t, s, Key{KindDecision, 127}).Current; r.Status != StatusSuperseded {
t.Fatalf("0127: %s", r.Status)
}
// 0282 supersedes part of 0276, as hq wrote it: the link is held, its clause waiting to be judged.
r282 := mustGet(t, s, Key{KindDecision, 282}).Current
var changes *Link
for i, l := range r282.Links {
if l.Kind == LinkChanges && l.To.Number == 276 {
changes = &r282.Links[i]
}
}
if changes == nil || changes.Source != LinkPending || changes.To.Clause != 0 {
t.Fatalf("0282's change of 0276: %+v", r282.Links)
}
in, _ := s.Inbound(ctx, Key{KindDecision, 276})
if len(in) == 0 {
t.Fatal("0276 reads no link from its end")
}
// Research: 045 and 042, every document a section.
r45 := mustGet(t, s, Key{KindResearch, 45}).Current
if r45.Status != StatusGraduated || len(r45.Sections) != 2 || r45.Sections[0].Name != "00-overview.md" {
t.Fatalf("research 045: %s %v", r45.Status, r45.Sections)
}
// A second run changes nothing, and says so.
before := countVersions(t, s)
second, err := w.k.Import("import@test", ImportAsk{}, fixture())
if err != nil {
t.Fatal(err)
}
if second.Created != 0 || second.Held != 11 || !strings.Contains(second.Said, "Nothing changed") || countVersions(t, s) != before {
t.Fatalf("second run: %+v", second)
}
if len(w.said.of(EventImported)) != 11 {
t.Fatal("the second run said an import")
}
})
}
// The import never overwrites: a record changed here keeps its change through a later import.
func TestTheImportNeverOverwrites(t *testing.T) {
w := imported(t, newMemStore())
ctx := context.Background()
e := mustGet(t, w.k.Store, Key{KindDecision, 11})
r := e.Current.Clone()
r.Title = "changed here"
if err := w.k.Store.Save(ctx, Version{By: "test", Why: "changed", Record: r}, true, false, e.Revision); err != nil {
t.Fatal(err)
}
if _, err := w.k.Import("import@test", ImportAsk{}, fixture()); err != nil {
t.Fatal(err)
}
if got := mustGet(t, w.k.Store, Key{KindDecision, 11}).Current.Title; got != "changed here" {
t.Fatalf("overwritten: %q", got)
}
}
func TestTheImportRefusesACommitTheRecordDoesNotStandAt(t *testing.T) {
w := newWorld(t, newMemStore(), fixture())
if _, err := w.k.Import("import@test", ImportAsk{Commit: "0000000"}, fixture()); err == nil || !strings.Contains(err.Error(), "not 0000000") {
t.Fatalf("%v", err)
}
commit := strings.TrimSpace(readFile(t, "testdata/hq/COMMIT"))
if out, err := w.k.Import("import@test", ImportAsk{Commit: commit[:9]}, fixture()); err != nil || out.Created != 11 {
t.Fatalf("%v %+v", err, out)
}
if _, err := w.k.Import("import@test", ImportAsk{Commit: "not-hex"}, fixture()); err == nil {
t.Fatal("a commit that is not one was taken")
}
}
// The whole of main at a recorded commit is imported without a refusal, and leaves the whole set consistent.
func TestTheWholeOfMainImports(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := newWorld(t, s, hqMain(t))
out, err := w.k.Import("import@test", ImportAsk{}, hqMain(t))
if err != nil {
t.Fatal(err)
}
if out.Refused != 0 || out.Created < 300 {
t.Fatalf("%s; rows %+v", out.Said, out.Rows)
}
if len(out.Findings) != 0 {
t.Fatalf("the whole set of main fails: %+v", out.Findings)
}
t.Log(out.Said)
})
}
func readFile(t *testing.T, path string) string {
t.Helper()
raw, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
return string(raw)
}
func countVersions(t *testing.T, s Store) int {
t.Helper()
all, err := s.All(context.Background())
if err != nil {
t.Fatal(err)
}
n := 0
for _, e := range all {
n += e.Versions
}
return n
}