Files
mesh-catalog/modules/mesh-knowledge/cmd/mesh-knowledge/form_test.go
T
jschoubben 47b3ae7528 CAT-K11: form-only versions: plain titles and links of the one form, proven to change form alone
A record imported with file-named sections gets plain titles, and its links to files become references of the one form, in one
version written after the move by the tool knowledge_form_only: marked form, listing the names changed, accepted without a
judgement because a check proves each section's text with its links replaced by their labels is the same and each new link names
the record the old one named. The old names stay as aliases get takes; the parts' reviews carry over; a record waiting for its
review is skipped.

Issue 1966.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 12:20:19 +01:00

84 lines
3.9 KiB
Go

package main
import (
"strings"
"testing"
)
// A form-only version (to-be 55 §2.2, AC55): file-named sections get plain titles and links to files become references of
// the one form, in one version a check proves changes only form; the old names stay as aliases; a part's review carries over;
// nothing is written without commit, and a record waiting for its review is skipped.
func TestAFormOnlyVersionChangesTheNamesAndTheLinksAndNothingElse(t *testing.T) {
w, _ := ledgerWorld(t)
r, _ := w.k.ReserveNumber("author@g14", KindResearch, "an effort")
old := effortAsk(r.Number, StatusActive,
Section{Name: "00-overview.md", Text: "What it is. See [the window](0276-merges-are-assembled-in-a-rolling-window-and-each-batch-is-delivered-by-one-walk-with-one-commit-per-repository.md) and [the plan](https://example.org/plan.md)."},
Section{Name: "01-open-questions.md", Text: "Is it [ready](../../01-RESEARCH/045-a-knowledge-base-the-mesh-writes/01-findings.md)?"})
w.accepted(t, "author@g14", old)
key := Key{KindResearch, r.Number}
before := mustGet(t, w.k.Store, key)
w.k.Store.(*ledgerStore).mu.Lock()
versions := before.Versions
w.k.Store.(*ledgerStore).mu.Unlock()
dry, err := w.k.FormOnly("lead@g14", &key, false)
if err != nil || len(dry) != 1 || dry[0].Renamed["00-overview.md"] != "Overview" || dry[0].Renamed["01-open-questions.md"] != "Open questions" || dry[0].Relinked != 2 {
t.Fatalf("%v %+v", err, dry)
}
if e := mustGet(t, w.k.Store, key); e.Versions != versions {
t.Fatal("a dry run wrote a version")
}
if _, err := w.k.FormOnly("", &key, true); err == nil {
t.Fatal("an unproven caller wrote a form-only version")
}
done, err := w.k.FormOnly("lead@g14", &key, true)
if err != nil || len(done) != 1 || done[0].Skipped != "" {
t.Fatalf("%v %+v", err, done)
}
e := mustGet(t, w.k.Store, key)
if e.Versions != versions+1 || e.Current.Status != StatusActive || e.Pending != nil || e.Current.Judging != nil {
t.Fatalf("%d versions, %s", e.Versions, e.Current.Status)
}
got := e.Current
if got.Sections[0].Name != "Overview" || got.Sections[1].Name != "Open questions" ||
!strings.Contains(got.Sections[0].Text, "[the window](ref:ADR%200276)") || !strings.Contains(got.Sections[0].Text, "(https://example.org/plan.md)") ||
!strings.Contains(got.Sections[1].Text, "[ready](ref:research%20045)") {
t.Fatalf("%+v", got.Sections)
}
// get takes the old name as an alias, and the review of the parts carries over to the renamed parts.
if got.Section("00-overview.md") != got.Sections[0].Text || got.Aliases["01-open-questions.md"] != "Open questions" {
t.Fatalf("aliases %v", got.Aliases)
}
if len(got.Parts) != 3 || got.Parts[1].Part != "Overview" {
t.Fatalf("parts %+v", got.Parts)
}
for _, p := range partsOf(got, w.k.linkedOf(t.Context(), got)) {
if keptPart(got, p) == nil {
t.Errorf("the part %q is judged again after a change of form", p.name)
}
}
h, _ := w.k.History(key, 0, 0, 0)
if last := h.Versions[len(h.Versions)-1]; !strings.HasPrefix(last.Why, "form only:") {
t.Fatalf("%+v", last)
}
if len(w.said.of(EventFormed)) != 1 {
t.Fatalf("events %v", w.said.events)
}
// Done: another run has nothing left to do; and the check refuses a change that is more than form.
if again, _ := w.k.FormOnly("lead@g14", &key, true); len(again) != 0 {
t.Fatalf("%+v", again)
}
more := e.Current.Clone()
more.Sections[0].Text += " And more."
if err := checkForm(e.Current, more, &FormChange{Relinked: 1}); err == nil {
t.Fatal("a change of text passed as form")
}
moreLinks := old
_ = moreLinks
wrong, ch := formOf(&Record{Kind: KindResearch, Number: 1, Sections: []Section{{Name: "a.md", Text: "[x](0276-a.md)"}}})
wrong.Sections[0].Text = "[x](ref:ADR%200131)"
if err := checkForm(&Record{Kind: KindResearch, Number: 1, Sections: []Section{{Name: "a.md", Text: "[x](0276-a.md)"}}}, wrong, ch); err == nil {
t.Fatal("a link to another record passed as form")
}
}