Name no node in mesh-knowledge's fixtures (issue 1838)

This commit is contained in:
jochen
2026-10-22 21:36:26 +02:00
parent 7c4891cd13
commit 4909c9c8c7
21 changed files with 125 additions and 125 deletions
@@ -16,17 +16,17 @@ func effortAsk(n int, status string, docs ...Section) ProposeAsk {
// novox/hq issue 844: an active research effort takes new versions freely, each reviewed as a proposal.
func TestAnActiveEffortTakesANewVersionWithANewDocument(t *testing.T) {
w := imported(t, newMemStore())
r, err := w.k.ReserveNumber("author@g14", KindResearch, "an effort")
r, err := w.k.ReserveNumber("author@node-b", KindResearch, "an effort")
if err != nil {
t.Fatal(err)
}
overview := Section{Name: "00-overview.md", Text: "What an inference layer would be."}
w.accepted(t, "author@g14", effortAsk(r.Number, StatusActive, overview))
w.accepted(t, "author@node-b", effortAsk(r.Number, StatusActive, overview))
key := Key{KindResearch, r.Number}
reviews := len(w.judge.reviews)
next := effortAsk(r.Number, StatusActive, overview, Section{Name: "01-findings.md", Text: "A new finding."})
next.Why = "findings added"
if _, err := w.k.Propose("author@g14", next); err != nil {
if _, err := w.k.Propose("author@node-b", next); err != nil {
t.Fatalf("an active effort refused a new version: %v", err)
}
e := mustGet(t, w.k.Store, key)
@@ -56,24 +56,24 @@ func TestAnActiveEffortTakesANewVersionWithANewDocument(t *testing.T) {
func TestAGraduatedEffortAndADecisionStillTakeOnlyAnInsight(t *testing.T) {
w := imported(t, newMemStore())
r, err := w.k.ReserveNumber("author@g14", KindResearch, "an effort")
r, err := w.k.ReserveNumber("author@node-b", KindResearch, "an effort")
if err != nil {
t.Fatal(err)
}
overview := Section{Name: "00-overview.md", Text: "What an inference layer would be."}
grad := effortAsk(r.Number, StatusGraduated, overview)
grad.Links = append(grad.Links, LinkAsk{Kind: LinkBecame, To: "0290"})
w.accepted(t, "author@g14", grad)
w.accepted(t, "author@node-b", grad)
next := effortAsk(r.Number, StatusGraduated, overview, Section{Name: "01-findings.md", Text: "More."})
next.Links = grad.Links
if _, err := w.k.Propose("author@g14", next); err == nil || !strings.Contains(err.Error(), "progressive insight") {
if _, err := w.k.Propose("author@node-b", next); err == nil || !strings.Contains(err.Error(), "progressive insight") {
t.Fatalf("a graduated effort took a plain version: %v", err)
}
n := w.reserved(t, "author@g14")
w.accepted(t, "author@g14", valid(n))
n := w.reserved(t, "author@node-b")
w.accepted(t, "author@node-b", valid(n))
p := valid(n)
p.Sections[2].Text = "Changed."
if _, err := w.k.Propose("author@g14", p); err == nil || !strings.Contains(err.Error(), "progressive insight") {
if _, err := w.k.Propose("author@node-b", p); err == nil || !strings.Contains(err.Error(), "progressive insight") {
t.Fatalf("a decision took a plain version: %v", err)
}
}
@@ -82,34 +82,34 @@ func TestAGraduatedEffortAndADecisionStillTakeOnlyAnInsight(t *testing.T) {
func TestANewVersionOfAnOldActiveEffortIsHeldToTodaysRules(t *testing.T) {
w := imported(t, newMemStore())
w.clock = time.Date(2026, 10, 1, 9, 0, 0, 0, time.UTC)
r, err := w.k.ReserveNumber("author@g14", KindResearch, "an old effort")
r, err := w.k.ReserveNumber("author@node-b", KindResearch, "an old effort")
if err != nil {
t.Fatal(err)
}
overview := Section{Name: "00-overview.md", Text: "What an inference layer would be."}
first := effortAsk(r.Number, StatusActive, overview)
first.Date = "2026-10-01"
w.accepted(t, "author@g14", first)
w.accepted(t, "author@node-b", first)
w.clock = time.Date(2026, 10, 15, 9, 0, 0, 0, time.UTC)
next := effortAsk(r.Number, StatusActive, overview, Section{Name: "01-findings.md", Text: "The control plane wrote them."})
next.Date = "2026-10-01"
if _, err := w.k.Propose("author@g14", next); err == nil || !strings.Contains(err.Error(), "retired-word") {
if _, err := w.k.Propose("author@node-b", next); err == nil || !strings.Contains(err.Error(), "retired-word") {
t.Fatalf("a retired word in new text of an old effort: %v", err)
}
}
func TestAChangesVerdictLeavesTheServedVersionServedAndGraduatingNeedsABecameLink(t *testing.T) {
w := imported(t, newMemStore())
r, err := w.k.ReserveNumber("author@g14", KindResearch, "an effort")
r, err := w.k.ReserveNumber("author@node-b", KindResearch, "an effort")
if err != nil {
t.Fatal(err)
}
overview := Section{Name: "00-overview.md", Text: "What an inference layer would be."}
w.accepted(t, "author@g14", effortAsk(r.Number, StatusActive, overview))
w.accepted(t, "author@node-b", effortAsk(r.Number, StatusActive, overview))
key := Key{KindResearch, r.Number}
w.judge.review = `{"verdict":"changes","findings":["01-findings.md: say where the finding comes from"]}`
next := effortAsk(r.Number, StatusActive, overview, Section{Name: "01-findings.md", Text: "A new finding."})
if _, err := w.k.Propose("author@g14", next); err != nil {
if _, err := w.k.Propose("author@node-b", next); err != nil {
t.Fatal(err)
}
w.reviewAll(t)
@@ -119,7 +119,7 @@ func TestAChangesVerdictLeavesTheServedVersionServedAndGraduatingNeedsABecameLin
t.Fatalf("after changes: pending %v, current %+v", e.Pending != nil, e.Current.Sections)
}
grad := effortAsk(r.Number, StatusGraduated, overview)
if _, err := w.k.Propose("author@g14", grad); err == nil || !strings.Contains(err.Error(), "became") {
if _, err := w.k.Propose("author@node-b", grad); err == nil || !strings.Contains(err.Error(), "became") {
t.Fatalf("graduated without a became link: %v", err)
}
}
@@ -128,18 +128,18 @@ func TestAChangesVerdictLeavesTheServedVersionServedAndGraduatingNeedsABecameLin
func TestAnOldActiveEffortWithAMarkedInsightTakesANewVersion(t *testing.T) {
w := imported(t, newMemStore())
w.clock = time.Date(2026, 10, 1, 9, 0, 0, 0, time.UTC)
r, err := w.k.ReserveNumber("author@g14", KindResearch, "an old effort")
r, err := w.k.ReserveNumber("author@node-b", KindResearch, "an old effort")
if err != nil {
t.Fatal(err)
}
overview := Section{Name: "00-overview.md", Text: "What an inference layer would be.\n\n**Progressive insight — 2026-10-05.** A fact was corrected."}
first := effortAsk(r.Number, StatusActive, overview)
first.Date = "2026-10-01"
w.accepted(t, "author@g14", first)
w.accepted(t, "author@node-b", first)
w.clock = time.Date(2026, 10, 15, 9, 0, 0, 0, time.UTC)
next := effortAsk(r.Number, StatusActive, overview, Section{Name: "01-findings.md", Text: "A new finding."})
next.Date = "2026-10-01"
if _, err := w.k.Propose("author@g14", next); err != nil {
if _, err := w.k.Propose("author@node-b", next); err != nil {
t.Fatalf("a new version with an earlier marked insight: %v", err)
}
w.reviewAll(t)
@@ -55,11 +55,11 @@ func whoCalled(t *testing.T, params map[string]any) string {
// **Who called is the caller the runtime proved** (hq issue 365): read from the call's runtime-written `_meta`,
// never from its arguments; Unproven where the runtime named none.
func TestTheCallerIsTheOneTheRuntimeProved(t *testing.T) {
if got := whoCalled(t, map[string]any{"name": "who", "arguments": map[string]any{"caller": "novox.node-tools"},
"_meta": map[string]any{stdio.MetaCaller: "shanks.node-tools"}}); got != "shanks.node-tools" {
if got := whoCalled(t, map[string]any{"name": "who", "arguments": map[string]any{"caller": "node-c.node-tools"},
"_meta": map[string]any{stdio.MetaCaller: "node-d.node-tools"}}); got != "node-d.node-tools" {
t.Errorf("callerOf answered %q, want the runtime's caller", got)
}
if got := whoCalled(t, map[string]any{"name": "who", "arguments": map[string]any{"caller": "novox.node-tools"}}); got != Unproven {
if got := whoCalled(t, map[string]any{"name": "who", "arguments": map[string]any{"caller": "node-c.node-tools"}}); got != Unproven {
t.Errorf("a call the runtime named no caller for answered %q, want %s", got, Unproven)
}
}
@@ -33,14 +33,14 @@ func TestAnInsightToAnOlderRecordIsJudgedByTheRulesThatHeldIt(t *testing.T) {
}
p := insightTo(t, w, Key{KindDecision, 11})
p.Sections[0].Text += "\n\nThe control plane wrote them."
if _, err := w.k.Propose("corrector@ace", p); err != nil {
if _, err := w.k.Propose("corrector@node-a", p); err != nil {
t.Fatalf("an insight to ADR 0011 was refused by rules that never held it: %v", err)
}
// The same words in a record of today are refused.
n := w.reserved(t, "author@g14")
n := w.reserved(t, "author@node-b")
q := valid(n)
q.Sections[2].Text = "The control plane wrote them."
if _, err := w.k.Propose("author@g14", q); err == nil || !strings.Contains(err.Error(), "- retired-word:") {
if _, err := w.k.Propose("author@node-b", q); err == nil || !strings.Contains(err.Error(), "- retired-word:") {
t.Fatalf("a retired word in a record of today: %v", err)
}
}
@@ -73,11 +73,11 @@ func TestEachDatedRuleHoldsFromItsDay(t *testing.T) {
// A new record cannot be dated back past the rules: it is of the day its number was reserved, or later.
func TestANewRecordIsNotDatedBeforeItsReservation(t *testing.T) {
w := imported(t, newMemStore())
n := w.reserved(t, "author@g14")
n := w.reserved(t, "author@node-b")
p := valid(n)
p.Date = "2026-01-01"
p.Sections[2].Text = "The control plane wrote them."
_, err := w.k.Propose("author@g14", p)
_, err := w.k.Propose("author@node-b", p)
if err == nil || !strings.Contains(err.Error(), "- date:") {
t.Fatalf("a new record dated before its reservation: %v", err)
}
@@ -91,7 +91,7 @@ func TestAnInsightToADecisionOfOctoberKeepsItsWords(t *testing.T) {
t.Fatal(err)
}
for _, n := range []int{276, 240, 244, 272} {
if _, err := w.k.Propose("corrector@ace", insightTo(t, w, Key{KindDecision, n})); err != nil {
if _, err := w.k.Propose("corrector@node-a", insightTo(t, w, Key{KindDecision, n})); err != nil {
t.Errorf("an insight to ADR %04d was refused: %v", n, err)
}
}
@@ -178,10 +178,10 @@ func TestTheOperatorIsToldOncePerTopicAndReturnDraftsAgain(t *testing.T) {
}
told := len(w.told)
k := Key{KindDecision, 240}
if _, err := w.k.Return("operator@shanks", Key{KindDecision, 276}, "x"); err == nil {
if _, err := w.k.Return("operator@node-d", Key{KindDecision, 276}, "x"); err == nil {
t.Fatal("a record whose author wrote its clauses was returned")
}
if _, err := w.k.Return("operator@shanks", k, "clause 2 says more than the section"); err != nil {
if _, err := w.k.Return("operator@node-d", k, "clause 2 says more than the section"); err != nil {
t.Fatal(err)
}
r := mustGet(t, w.k.Store, k).Current
@@ -258,7 +258,7 @@ func TestARefreshRepairsOnlyRecordsNobodyChangedSinceTheImportAndChangesNothingT
e85 := mustGet(t, s, Key{KindDecision, 85})
d := e85.Current.Clone()
d.Title = "A secret is a provision, corrected"
if err := s.Save(ctx, Version{By: "someone@g14", At: at, Why: "a correction by hand", Record: d}, true, false, e85.Revision); err != nil {
if err := s.Save(ctx, Version{By: "someone@node-b", At: at, Why: "a correction by hand", Record: d}, true, false, e85.Revision); err != nil {
t.Fatal(err)
}
before := countVersions(t, s)
@@ -381,7 +381,7 @@ func TestARefreshRepairsARecordTheKnowledgeBaseDraftedAndKeepsItsClauses(t *test
t.Fatalf("0004 after the refresh: %+v %+v", e4.Clauses, e4.Drafting)
}
// A record someone returned is someone's change: left alone.
if _, err := w.k.Return("operator@shanks", Key{KindDecision, 2}, "clause 2 says more than the record"); err != nil {
if _, err := w.k.Return("operator@node-d", Key{KindDecision, 2}, "clause 2 says more than the record"); err != nil {
t.Fatal(err)
}
again, _ := w.k.Import("import@test", ImportAsk{Refresh: true}, at487())
@@ -17,7 +17,7 @@ import (
func adr0343() *Record {
r := &Record{Kind: KindDecision, Number: 343, Status: StatusProposed, Date: "2026-10-13", NeedsOperator: true,
Title: "A session's memory follows the operator: the agent module carries each project's memory folder to every node, and a file changed on two keeps both",
Author: "fix-367@g14",
Author: "fix-367@node-b",
Brief: &Brief{Headline: "Your agents' memory follows you to every machine",
Summary: "What an agent learns in a project's memory is copied to every machine that runs the agent, so a session " +
"anywhere starts with it. A file changed on two machines keeps both versions and warns you; secrets in memory " +
@@ -62,7 +62,7 @@ func TestADecisionAskReadsAtAGlance(t *testing.T) {
}
}
details := strings.Split(a.Details, "\n")
if len(details) != 2 || !strings.Contains(details[0], "ADR 0343, proposed by fix-367@g14; the knowledge base's own review approved it.") ||
if len(details) != 2 || !strings.Contains(details[0], "ADR 0343, proposed by fix-367@node-b; the knowledge base's own review approved it.") ||
!strings.Contains(details[0], "Fingerprint "+fingerprint(r.Digest())+".") ||
details[1] != "Read its 13 clauses with the knowledge base's get, number 343." {
t.Errorf("the details:\n%s", a.Details)
@@ -35,7 +35,7 @@ func TestTheHighestToolAnswersTheHighestNumberHeldPerKind(t *testing.T) {
t.Fatalf("%+v", h)
}
// A number reserved, and later withdrawn, is spent: it is the highest.
w.reserved(t, "author@g14") // 300
w.reserved(t, "author@node-b") // 300
w.clock = w.clock.Add(DefaultReservedFor + time.Hour)
if _, err := w.k.WithdrawStale(); err != nil {
t.Fatal(err)
@@ -12,14 +12,14 @@ import (
func TestThreeVersionsAreKeptAndTheFirstAndThirdCompareExactly(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@g14") // version 1: the reservation
n := w.reserved(t, "author@node-b") // version 1: the reservation
p := valid(n)
if _, err := w.k.Propose("author@g14", p); err != nil { // version 2
if _, err := w.k.Propose("author@node-b", p); err != nil { // version 2
t.Fatal(err)
}
p.Clauses[1] = "**A batch is delivered by one walk.** At most one commit per repository."
p.Why = "the bound named"
if _, err := w.k.Propose("author@g14", p); err != nil { // version 3
if _, err := w.k.Propose("author@node-b", p); err != nil { // version 3
t.Fatal(err)
}
h, err := w.k.History(Key{KindDecision, n}, 0, 0, 0)
@@ -27,7 +27,7 @@ func TestThreeVersionsAreKeptAndTheFirstAndThirdCompareExactly(t *testing.T) {
t.Fatal(err)
}
if len(h.Versions) != 3 || h.Versions[0].Status != StatusReserved || h.Versions[1].Why != "proposed" ||
h.Versions[2].Why != "the bound named" || !h.Versions[2].Served || h.Versions[0].By != "author@g14" {
h.Versions[2].Why != "the bound named" || !h.Versions[2].Served || h.Versions[0].By != "author@node-b" {
t.Fatalf("history: %+v", h.Versions)
}
d, err := w.k.History(Key{KindDecision, n}, 1, 3, 0)
@@ -114,15 +114,15 @@ func TestDiffIsExactOnSmallTexts(t *testing.T) {
// history is bounded like the other answers: its work, and its answer, with a cut notice (the review of #206).
func TestHistoryIsBounded(t *testing.T) {
w := imported(t, newMemStore())
n := w.reserved(t, "author@g14")
n := w.reserved(t, "author@node-b")
p := valid(n)
big := strings.Repeat("A line of reasoning that is long enough to count.\n", 3000)
p.Sections[0].Text = big
if _, err := w.k.Propose("author@g14", p); err != nil {
if _, err := w.k.Propose("author@node-b", p); err != nil {
t.Fatal(err)
}
p.Sections[0].Text = strings.ReplaceAll(big, "long enough", "longer than")
if _, err := w.k.Propose("author@g14", p); err != nil {
if _, err := w.k.Propose("author@node-b", p); err != nil {
t.Fatal(err)
}
h, err := w.k.History(Key{KindDecision, n}, 2, 3, 0)
@@ -82,7 +82,7 @@ func TestARecordWhoseClausesAreLinkedByNumberIsNeverReturned(t *testing.T) {
}
w.reviewAll(t)
before := mustGet(t, s, k)
_, err := w.k.Return("operator@shanks", k, "clause 1 says more than the section")
_, err := w.k.Return("operator@node-d", k, "clause 1 says more than the section")
if err == nil {
t.Fatal("a record a proposed record links by clause was returned")
}
@@ -101,7 +101,7 @@ func TestARecordWhoseClausesAreLinkedByNumberIsNeverReturned(t *testing.T) {
p2 := valid(n2)
p2.Links = append(p2.Links, LinkAsk{Kind: LinkChanges, To: "0240 §1", From: 2})
w2.accepted(t, "author@test", p2)
if _, err := w2.k.Return("operator@shanks", k2, "again"); err == nil || !strings.Contains(err.Error(), "§1 is changed by ADR "+itoa4(n2)+" §2") {
if _, err := w2.k.Return("operator@node-d", k2, "again"); err == nil || !strings.Contains(err.Error(), "§1 is changed by ADR "+itoa4(n2)+" §2") {
t.Fatalf("a record with a changed clause was returned, or the refusal does not name the change: %v", err)
}
})
@@ -39,15 +39,15 @@ func (a *asked) ask(key string, body any) (json.RawMessage, error) {
return nil, errors.New("claude_code_judge takes question, schema and model; not within")
}
if _, long := b["within"]; long && a.pending > 0 {
return json.RawMessage(`{"node":"novox","ticket":"t1","pending":true}`), nil
return json.RawMessage(`{"node":"node-c","ticket":"t1","pending":true}`), nil
}
return json.RawMessage(`{"answer":{"verdict":"approve","findings":[]},"model":"sonnet","node":"novox"}`), nil
return json.RawMessage(`{"answer":{"verdict":"approve","findings":[]},"model":"sonnet","node":"node-c"}`), nil
}
if key == "claude-code.claude_code_judged@novox" && b["ticket"] == "t1" {
if key == "claude-code.claude_code_judged@node-c" && b["ticket"] == "t1" {
if a.pending--; a.pending > 0 {
return json.RawMessage(`{"node":"novox","ticket":"t1","pending":true}`), nil
return json.RawMessage(`{"node":"node-c","ticket":"t1","pending":true}`), nil
}
return json.RawMessage(`{"answer":{"verdict":"approve","findings":[]},"model":"sonnet","node":"novox","ticket":"t1"}`), nil
return json.RawMessage(`{"answer":{"verdict":"approve","findings":[]},"model":"sonnet","node":"node-c","ticket":"t1"}`), nil
}
return nil, fmt.Errorf("nothing answers %s", key)
}
@@ -68,7 +68,7 @@ func withinOf(t *testing.T, b map[string]any) time.Duration {
func TestALongRecordsReviewGetsTheLargerBound(t *testing.T) {
short, long := ReviewQuestion(aRecord(2, 200), nil), ReviewQuestion(aRecord(12, 2000), nil)
a := &asked{}
j := judgementOver(a.ask, "novox")
j := judgementOver(a.ask, "node-c")
for _, q := range []string{short, long} {
if _, _, err := j(q, reviewSchema, "sonnet"); err != nil {
t.Fatal(err)
@@ -88,14 +88,14 @@ func TestALongRecordsReviewGetsTheLargerBound(t *testing.T) {
// judgement's.
func TestAPendingJudgementIsCollectedByItsTicket(t *testing.T) {
a := &asked{pending: 3}
answer, by, err := judgementOver(a.ask, "novox")(ReviewQuestion(aRecord(12, 2000), nil), reviewSchema, "sonnet")
answer, by, err := judgementOver(a.ask, "node-c")(ReviewQuestion(aRecord(12, 2000), nil), reviewSchema, "sonnet")
if err != nil {
t.Fatal(err)
}
if string(answer) != `{"verdict":"approve","findings":[]}` || by != "the agent on novox (sonnet)" {
if string(answer) != `{"verdict":"approve","findings":[]}` || by != "the agent on node-c (sonnet)" {
t.Fatalf("%s by %s", answer, by)
}
if strings.Join(a.keys, " ") != "claude-code.claude_code_judge@novox claude-code.claude_code_judged@novox claude-code.claude_code_judged@novox claude-code.claude_code_judged@novox" {
if strings.Join(a.keys, " ") != "claude-code.claude_code_judge@node-c claude-code.claude_code_judged@node-c claude-code.claude_code_judged@node-c claude-code.claude_code_judged@node-c" {
t.Fatalf("asked %q", a.keys)
}
}
@@ -104,7 +104,7 @@ func TestAPendingJudgementIsCollectedByItsTicket(t *testing.T) {
// it fits the old bound, and fails as before when it does not.
func TestAnAgentModuleThatTakesNoWithinIsAskedWithoutIt(t *testing.T) {
a := &asked{refuse: true}
if _, _, err := judgementOver(a.ask, "novox")(ReviewQuestion(aRecord(12, 2000), nil), reviewSchema, "sonnet"); err != nil {
if _, _, err := judgementOver(a.ask, "node-c")(ReviewQuestion(aRecord(12, 2000), nil), reviewSchema, "sonnet"); err != nil {
t.Fatal(err)
}
if len(a.bodies) != 2 || withinOf(t, a.bodies[1]) != 0 {
@@ -95,7 +95,7 @@ func TestItDeclaresAndHoldsTheKnowledgeBaseSeatOnceForTheMesh(t *testing.T) {
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"} {
for _, never := range []string{"/home/", "jochen", "node-d", "node-c.be"} {
if strings.Contains(strings.ToLower(raw), never) {
t.Errorf("module.json names %q", never)
}
@@ -15,7 +15,7 @@ import (
func TestAnAskThatCannotBeMadeIsTriedABoundedNumberOfTimes(t *testing.T) {
w := imported(t, newMemStore())
w.k.Asks = nil
n := proposed(t, w, "author@g14", true)
n := proposed(t, w, "author@node-b", true)
for i := 0; i < 6*48; i++ { // two days, every ten minutes
w.reviewAll(t)
w.clock = w.clock.Add(10 * time.Minute)
@@ -45,8 +45,8 @@ func (f *failingSaves) Save(ctx context.Context, v Version, current, clearPendin
func TestARecordWhoseReviewCannotBeKeptBlocksNoOtherAndIsTriedBoundedly(t *testing.T) {
s := &failingSaves{memStore: newMemStore()}
w := imported(t, s)
a := proposed(t, w, "author@g14", false)
b := proposed(t, w, "author@g14", false)
a := proposed(t, w, "author@node-b", false)
b := proposed(t, w, "author@node-b", false)
s.key, s.fail = Key{KindDecision, a}, true
errs := 0
for i := 0; i < 6*48; i++ {
@@ -78,7 +78,7 @@ func TestARecordWhoseReviewCannotBeKeptBlocksNoOtherAndIsTriedBoundedly(t *testi
// sent is sent again at the next step, since health no longer stands for it.
func TestARecordThatCouldNotBeReviewedLeavesTheModuleHealthyAndIsTold(t *testing.T) {
w := imported(t, newMemStore())
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
w.judge.reviewFail = true
notify := w.k.Notify
failing := true
@@ -109,18 +109,18 @@ func TestARecordThatCouldNotBeReviewedLeavesTheModuleHealthyAndIsTold(t *testing
// A progressive insight waiting for its review is replaced only by its author, proven.
func TestAPendingInsightIsReplacedOnlyByItsAuthor(t *testing.T) {
w := imported(t, newMemStore())
n := w.reserved(t, "author@g14")
w.accepted(t, "author@g14", valid(n))
n := w.reserved(t, "author@node-b")
w.accepted(t, "author@node-b", valid(n))
p := valid(n)
p.Sections[2].Text = "Merges land sooner, by about a minute."
p.Insight = "it said only that merges land sooner"
if _, err := w.k.Propose("corrector@ace", p); err != nil {
if _, err := w.k.Propose("corrector@node-a", p); err != nil {
t.Fatal(err)
}
q := valid(n)
q.Sections[2].Text = "Merges land later."
q.Insight = "it said merges land sooner"
for _, other := range []string{"author@g14", "other@novox", Unproven} {
for _, other := range []string{"author@node-b", "other@node-c", Unproven} {
if _, err := w.k.Propose(other, q); err == nil || !strings.Contains(err.Error(), "only its author") {
t.Fatalf("a pending insight replaced by %s: %v", other, err)
}
@@ -128,7 +128,7 @@ func TestAPendingInsightIsReplacedOnlyByItsAuthor(t *testing.T) {
if e := mustGet(t, w.k.Store, Key{KindDecision, n}); e.Pending.Section("Consequences") != p.Sections[2].Text {
t.Fatalf("the pending insight was replaced: %q", e.Pending.Section("Consequences"))
}
if _, err := w.k.Propose("corrector@ace", q); err != nil {
if _, err := w.k.Propose("corrector@node-a", q); err != nil {
t.Fatalf("its author's revision: %v", err)
}
}
@@ -17,7 +17,7 @@ func TestAReviewOwedOutlivesARestartAndItsLastTryIsSaid(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
inZone(t)
w := imported(t, s)
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
key := Key{KindDecision, n}
lastWhy := func() string {
vs, err := s.Versions(context.Background(), key)
@@ -97,7 +97,7 @@ func TestAReviewOwedOutlivesARestartAndItsLastTryIsSaid(t *testing.T) {
func TestProposedAgainAfterTheLastTryClearsTheNotice(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
key := Key{KindDecision, n}
runOut := func(from int) {
t.Helper()
@@ -125,7 +125,7 @@ func TestProposedAgainAfterTheLastTryClearsTheNotice(t *testing.T) {
t.Fatalf("a version written while it waits: told %v, cleared %v", w.toldKeys, w.cleared)
}
// Proposed again: the notice is cleared, saying so.
if _, err := w.k.Propose("author@g14", valid(n)); err != nil {
if _, err := w.k.Propose("author@node-b", valid(n)); err != nil {
t.Fatal(err)
}
w.clock = w.clock.Add(time.Second)
@@ -142,7 +142,7 @@ func TestProposedAgainAfterTheLastTryClearsTheNotice(t *testing.T) {
// Proposed again and accepted at last: that notice is cleared too, and nothing is cleared twice, also after
// a restart.
w.judge.reviewFail = false
w.accepted(t, "author@g14", valid(n))
w.accepted(t, "author@node-b", valid(n))
if len(w.cleared) != 2 || w.cleared[1][0] != w.toldKeys[1] || !strings.Contains(w.cleared[1][1], "proposed again") {
t.Fatalf("accepted: cleared %v", w.cleared)
}
@@ -172,7 +172,7 @@ func inZone(t *testing.T) {
func TestAClearThatFailsIsSentAgain(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
w.judge.reviewFail = true
for try := 1; try <= MostReviewTries; try++ {
w.reviewAll(t)
@@ -184,7 +184,7 @@ func TestAClearThatFailsIsSentAgain(t *testing.T) {
prefix := fmt.Sprintf("knowledge.unreviewed.decision-%d.", n)
refused := 0
w.k.Clear = func(key, resolved string) error { refused++; return errors.New("the channel is down") }
if _, err := w.k.Propose("author@g14", valid(n)); err != nil {
if _, err := w.k.Propose("author@node-b", valid(n)); err != nil {
t.Fatal(err)
}
w.reviewAll(t)
@@ -30,11 +30,11 @@ func TestTheReviewIsShownEveryLinkKindProposeAccepts(t *testing.T) {
// A research effort's own status is shown apart from its state in the knowledge base.
func TestTheReviewIsShownAResearchEffortsStatusApartFromItsState(t *testing.T) {
w := imported(t, newMemStore())
r, err := w.k.ReserveNumber("author@g14", KindResearch, "a vendor-neutral inference layer")
r, err := w.k.ReserveNumber("author@node-b", KindResearch, "a vendor-neutral inference layer")
if err != nil {
t.Fatal(err)
}
if _, err := w.k.Propose("author@g14", ProposeAsk{Kind: KindResearch, Number: r.Number, Title: "A vendor-neutral inference layer",
if _, err := w.k.Propose("author@node-b", ProposeAsk{Kind: KindResearch, Number: r.Number, Title: "A vendor-neutral inference layer",
Date: "2026-10-11", Deciders: []string{"jochen"}, Status: StatusActive,
Sections: []Section{{Name: "00-overview.md", Text: "What an inference layer the mesh controls would be."}},
Links: []LinkAsk{{Kind: LinkTouches, To: "0290"}, {Kind: LinkTouches, To: "issue 365"}}}); err != nil {
@@ -31,7 +31,7 @@ func proposed(t *testing.T, w *world, author string, needsOperator bool) int {
func TestAProposalIsReviewedByTheKnowledgeBaseItselfAndAcceptedOnApprove(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
// Proposed, waiting for its review: nothing of it holds yet.
e := mustGet(t, s, Key{KindDecision, n})
if e.Current.Status != StatusProposed || e.Current.Judging == nil || e.Current.Judging.State != JudgingDue || len(w.judge.reviews) != 0 {
@@ -49,7 +49,7 @@ func TestAProposalIsReviewedByTheKnowledgeBaseItselfAndAcceptedOnApprove(t *test
t.Errorf("the review's question lacks %q", want)
}
}
for _, never := range []string{"ADR 0131", "ADR 0011", "author@g14"} {
for _, never := range []string{"ADR 0131", "ADR 0011", "author@node-b"} {
if strings.Contains(q, never) {
t.Errorf("the review's question holds %q, which the record does not link", never)
}
@@ -89,7 +89,7 @@ func itoaKey(n int) string { return Key{KindDecision, n}.String() }
func TestOnChangesTheRecordStaysProposedAndItsAuthorsRevisionIsReviewedAgain(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
w.judge.review = `{"verdict":"changes","findings":["§2: name the bound","Consequences: say who waits"]}`
w.reviewAll(t)
e := mustGet(t, s, Key{KindDecision, n})
@@ -108,11 +108,11 @@ func TestOnChangesTheRecordStaysProposedAndItsAuthorsRevisionIsReviewedAgain(t *
}
p := valid(n)
p.Sections[2].Text = "Merges land sooner; nobody waits longer than ninety seconds."
if _, err := w.k.Propose("reviewer@novox", p); err == nil || !strings.Contains(err.Error(), "only its author") {
if _, err := w.k.Propose("reviewer@node-c", p); err == nil || !strings.Contains(err.Error(), "only its author") {
t.Fatalf("a revision by someone else: %v", err)
}
w.judge.review = ""
if _, err := w.k.Propose("author@g14", p); err != nil {
if _, err := w.k.Propose("author@node-b", p); err != nil {
t.Fatal(err)
}
w.reviewAll(t)
@@ -137,7 +137,7 @@ func TestAJudgementThatCannotBeHadNeverApproves(t *testing.T) {
} {
t.Run(c.name, func(t *testing.T) {
w := imported(t, newMemStore())
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
w.judge.review, w.judge.reviewFail = c.answer, c.answer == ""
for try := 1; try <= MostReviewTries; try++ {
if said := w.reviewAll(t); len(said) != 1 || !strings.Contains(said[0], "not reviewed") {
@@ -174,7 +174,7 @@ func TestAJudgementThatCannotBeHadNeverApproves(t *testing.T) {
}
// Its author proposes it again, and that version is reviewed.
w.judge.review, w.judge.reviewFail = "", false
w.accepted(t, "author@g14", valid(n))
w.accepted(t, "author@node-b", valid(n))
})
}
}
@@ -182,11 +182,11 @@ func TestAJudgementThatCannotBeHadNeverApproves(t *testing.T) {
// A record revised while its judgement was asked is not decided on the version judged: the newest is judged next.
func TestARecordRevisedWhileItIsJudgedIsJudgedAgain(t *testing.T) {
w := imported(t, newMemStore())
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
p := valid(n)
p.Sections[2].Text = "Merges land sooner, and the walk is shorter."
w.judge.during = func() {
if _, err := w.k.Propose("author@g14", p); err != nil {
if _, err := w.k.Propose("author@node-b", p); err != nil {
t.Error(err)
}
}
@@ -224,11 +224,11 @@ func TestARecordProposedUnprovenIsNeverReviewed(t *testing.T) {
// A record that supersedes another moves it and every clause of it to superseded.
func TestASupersedingRecordSupersedesTheOlderOnAcceptance(t *testing.T) {
w := imported(t, newMemStore())
n := w.reserved(t, "author@g14")
n := w.reserved(t, "author@node-b")
p := valid(n)
p.Links = []LinkAsk{{Kind: LinkSupersedes, To: "0276"}}
p.Sections[0].Text = "The merge window is replaced."
w.accepted(t, "author@g14", p)
w.accepted(t, "author@node-b", p)
old := mustGet(t, w.k.Store, Key{KindDecision, 276}).Current
if old.Status != StatusSuperseded || old.Clause(4).Status != ClauseSuperseded || old.Extra["superseded-by"] != itoaKey(n) {
t.Fatalf("0276: %s, §4 %+v", old.Status, old.Clause(4))
@@ -242,7 +242,7 @@ func TestASupersedingRecordSupersedesTheOlderOnAcceptance(t *testing.T) {
func TestARecordThatNeedsTheOperatorIsAcceptedOnlyOnTheWarrant(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := proposed(t, w, "author@g14", true)
n := proposed(t, w, "author@node-b", true)
w.reviewAll(t)
if e := mustGet(t, s, Key{KindDecision, n}); e.Current.Status != StatusProposed || len(w.router.asked) != 1 {
t.Fatalf("after the review: %s, asks %d", e.Current.Status, len(w.router.asked))
@@ -293,7 +293,7 @@ func TestARecordThatNeedsTheOperatorIsAcceptedOnlyOnTheWarrant(t *testing.T) {
func TestAnAskThatCannotBePublishedLeavesTheRecordProposed(t *testing.T) {
w := imported(t, newMemStore())
w.k.Asks = nil
n := proposed(t, w, "author@g14", true)
n := proposed(t, w, "author@node-b", true)
said := w.reviewAll(t)
e := mustGet(t, w.k.Store, Key{KindDecision, n})
if len(said) != 1 || !strings.Contains(said[0], "cannot be asked") || e.Current.Status != StatusProposed || e.Current.Ask != nil ||
@@ -305,7 +305,7 @@ func TestAnAskThatCannotBePublishedLeavesTheRecordProposed(t *testing.T) {
// A warrant for an ask whose record changed after it was asked does not hold: the act it bound is another version.
func TestAWarrantForAnotherVersionDoesNotAccept(t *testing.T) {
w := imported(t, newMemStore())
n := proposed(t, w, "author@g14", true)
n := proposed(t, w, "author@node-b", true)
w.reviewAll(t)
// The record is changed behind the ask, keeping the ask: what the operator was shown is not what is held.
ctx := context.Background()
@@ -327,7 +327,7 @@ func TestAWarrantForAnotherVersionDoesNotAccept(t *testing.T) {
func TestTheOperatorsDeclineLeavesTheRecordProposed(t *testing.T) {
w := imported(t, newMemStore())
n := proposed(t, w, "author@g14", true)
n := proposed(t, w, "author@node-b", true)
w.reviewAll(t)
w.router.answer(w.router.asked[0].ID, OptionDecline, w.clock.Add(time.Minute))
if _, err := w.k.Reconcile(); err != nil {
@@ -343,16 +343,16 @@ func TestTheOperatorsDeclineLeavesTheRecordProposed(t *testing.T) {
// version is served.
func TestAnAcceptedRecordChangesOnlyByAnInsightReviewedLikeAProposal(t *testing.T) {
w := imported(t, newMemStore())
n := w.reserved(t, "author@g14")
w.accepted(t, "author@g14", valid(n))
n := w.reserved(t, "author@node-b")
w.accepted(t, "author@node-b", valid(n))
p := valid(n)
p.Sections[2].Text = "Merges land sooner, by about a minute."
if _, err := w.k.Propose("author@g14", p); err == nil || !strings.Contains(err.Error(), "progressive insight") {
if _, err := w.k.Propose("author@node-b", p); err == nil || !strings.Contains(err.Error(), "progressive insight") {
t.Fatalf("an accepted record rewritten: %v", err)
}
p.Insight = "it said only that merges land sooner"
w.judge.review = `{"verdict":"changes","findings":["Consequences: say what a minute is measured from"]}`
if _, err := w.k.Propose("author@g14", p); err != nil {
if _, err := w.k.Propose("author@node-b", p); err != nil {
t.Fatal(err)
}
w.reviewAll(t)
@@ -363,7 +363,7 @@ func TestAnAcceptedRecordChangesOnlyByAnInsightReviewedLikeAProposal(t *testing.
}
w.judge.review = ""
p.Sections[2].Text = "Merges land sooner, by about a minute from the last merge."
if _, err := w.k.Propose("author@g14", p); err != nil {
if _, err := w.k.Propose("author@node-b", p); err != nil {
t.Fatal(err)
}
w.reviewAll(t)
@@ -394,7 +394,7 @@ func TestNoVerbTakesAReview(t *testing.T) {
func TestReserveAsksTheTrackerAndANumberNeverProposedIsWithdrawn(t *testing.T) {
w := newWorld(t, newMemStore(), fixture())
r, err := w.k.ReserveNumber("author@g14", KindResearch, "how a knowledge base is asked")
r, err := w.k.ReserveNumber("author@node-b", KindResearch, "how a knowledge base is asked")
if err != nil {
t.Fatal(err)
}
@@ -402,7 +402,7 @@ func TestReserveAsksTheTrackerAndANumberNeverProposedIsWithdrawn(t *testing.T) {
w.tracker.asked[0]["for"] != "how a knowledge base is asked" {
t.Fatalf("%+v %v", r, w.tracker.asked)
}
if _, err := w.k.ReserveNumber("author@g14", "design", "x"); err == nil {
if _, err := w.k.ReserveNumber("author@node-b", "design", "x"); err == nil {
t.Fatal("a design number reserved")
}
w.clock = w.clock.Add(DefaultReservedFor + time.Hour)
@@ -410,10 +410,10 @@ func TestReserveAsksTheTrackerAndANumberNeverProposedIsWithdrawn(t *testing.T) {
t.Fatalf("withdrew %d (%v)", n, err)
}
e := mustGet(t, w.k.Store, Key{KindResearch, 50})
if e.Current.Status != StatusWithdrawn || e.Current.ReservedBy != "author@g14" {
if e.Current.Status != StatusWithdrawn || e.Current.ReservedBy != "author@node-b" {
t.Fatalf("%+v", e.Current)
}
if _, err := w.k.Propose("author@g14", ProposeAsk{Kind: KindResearch, Number: 50, Title: "late", Status: StatusActive,
if _, err := w.k.Propose("author@node-b", ProposeAsk{Kind: KindResearch, Number: 50, Title: "late", Status: StatusActive,
Sections: []Section{{Name: "00-overview.md", Text: "x"}}}); err == nil {
t.Fatal("a withdrawn number took a proposal")
}
@@ -423,7 +423,7 @@ func TestReserveAsksTheTrackerAndANumberNeverProposedIsWithdrawn(t *testing.T) {
// for an answer nobody was shown (ADR 0397, issue 926); offered, it waits again; answered, it is decided as ever.
func TestAnAskTheRouterHoldsIsShownHeldWithTheReason(t *testing.T) {
w := imported(t, newMemStore())
n := proposed(t, w, "author@g14", true)
n := proposed(t, w, "author@node-b", true)
w.reviewAll(t)
id := w.router.asked[0].ID
key := Key{KindDecision, n}
@@ -39,7 +39,7 @@ would receive them whole.
1. **Keep the flat list; rely on the client to defer it.** Rejected: a property of one client, and it
leaves the ambiguity and the stale list.
2. **One flat tool per assignment** (`ace_postgres_list_databases`). Removes the ambiguity, multiplies
2. **One flat tool per assignment** (`node-a_postgres_list_databases`). Removes the ambiguity, multiplies
the list, and runs into the API's tool-name limit (letters, digits, `_`, `-`, 64 characters).
3. **A small fixed set of tools that walk the mesh's own structure**, with the full address as an
argument: the mesh's seats; a machine's node seats and assignments; a search; a description; a
@@ -27,7 +27,7 @@ connections lasted, and then the public name went down
**The same fault, four days later, undetected for five days.** One container had restarted 2286 times
against a database it could no longer find, while the mesh reported the machine as doing what it was
told. Inside it, `novox.internal` was an address that had not existed for five days
told. Inside it, `node-c.internal` was an address that had not existed for five days
([issue 135](../04-ISSUES/135-a-containers-mesh-names-are-not-compared/00-report.md)). Forty-eight
other containers were current, none of them corrected — each had been recreated for some other
reason and picked up the roster on the way.
@@ -128,7 +128,7 @@ catalogue along for a controller change; `plans stop`), 200. The first merge han
machinery, at 18:56Z, was a controller change and produced the plan this record describes: tier 0
the build machine; tier 1 the controller and the proxy that packages its source. The handler
returned at once; the build machine was built, rolled, and the plan read *tier 0 built; waiting for
builder on novox to be applied* until the machine reported; then tier 1 was asked, both built, and
builder on node-c to be applied* until the machine reported; then tier 1 was asked, both built, and
the plan read done — three minutes, read through the console with `plans`, the receive loop taking
reports throughout. What the day between decision and proof taught is in issues
[184](../04-ISSUES/184-a-merge-announcement-blocks-the-controllers-receive-loop/00-report.md),
@@ -13,10 +13,10 @@ import (
func TestADecisionNothingWouldCiteIsNotAccepted(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@g14")
n := w.reserved(t, "author@node-b")
p := valid(n)
p.Homes = nil
if _, err := w.k.Propose("author@g14", p); err != nil {
if _, err := w.k.Propose("author@node-b", p); err != nil {
t.Fatal(err)
}
judged := len(w.judge.reviews)
@@ -38,7 +38,7 @@ func TestADecisionNothingWouldCiteIsNotAccepted(t *testing.T) {
}
// Named with its home, it is accepted, and the module stays healthy.
p.Homes = []string{testHome}
w.accepted(t, "author@g14", p)
w.accepted(t, "author@node-b", p)
if h := w.k.Health(nil); !h.Healthy {
t.Fatalf("unhealthy after a decision with its home was accepted: %s", h.Why)
}
@@ -53,18 +53,18 @@ func TestADecisionNothingWouldCiteIsNotAccepted(t *testing.T) {
func TestARecordAcceptedCitingANewDecisionLetsItBeAcceptedAndDroppingTheLinkIsLoud(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@g14")
n := w.reserved(t, "author@node-b")
a := valid(n)
a.Homes = nil
if _, err := w.k.Propose("author@g14", a); err != nil {
if _, err := w.k.Propose("author@node-b", a); err != nil {
t.Fatal(err)
}
w.reviewAll(t)
m := w.reserved(t, "author@g14")
m := w.reserved(t, "author@node-b")
b := valid(m)
b.Links = append(b.Links, LinkAsk{Kind: LinkCites, To: itoa4(n)})
w.accepted(t, "author@g14", b)
w.accepted(t, "author@g14", a) // its revision: an accepted record links it now
w.accepted(t, "author@node-b", b)
w.accepted(t, "author@node-b", a) // its revision: an accepted record links it now
if h := w.k.Health(nil); !h.Healthy {
t.Fatalf("unhealthy with both accepted, one citing the other: %s", h.Why)
}
@@ -75,7 +75,7 @@ func TestARecordAcceptedCitingANewDecisionLetsItBeAcceptedAndDroppingTheLinkIsLo
// A correction of the citing record drops its link: the rule, run after the acceptance, says so.
b.Links = b.Links[:len(b.Links)-1]
b.Insight = "it cited " + itoaKey(n)
w.accepted(t, "author@g14", b)
w.accepted(t, "author@node-b", b)
h := w.k.Health(nil)
if !h.Healthy || !strings.Contains(h.Why, "the rule cited") || !strings.Contains(h.Why, itoaKey(n)) {
t.Fatalf("a decision left cited by nothing: the health should stay healthy and name it, not %+v", h)
@@ -99,10 +99,10 @@ func TestARecordAcceptedCitingANewDecisionLetsItBeAcceptedAndDroppingTheLinkIsLo
t.Fatal("the acceptance was undone")
}
// A record that cites it heals it.
k := w.reserved(t, "author@g14")
k := w.reserved(t, "author@node-b")
c := valid(k)
c.Links = append(c.Links, LinkAsk{Kind: LinkCites, To: itoa4(n)})
w.accepted(t, "author@g14", c)
w.accepted(t, "author@node-b", c)
if h := w.k.Health(nil); strings.Contains(h.Why, itoaKey(n)+" is accepted and nothing cites it") {
t.Fatalf("still said after a record cited it: %s", h.Why)
}
@@ -14,7 +14,7 @@ func TestAReservedRecordIsWithdrawnAtOnce(t *testing.T) {
w := imported(t, s)
n := w.reserved(t, "author@test")
key := Key{KindDecision, n}
out, err := w.k.WithdrawRecord("operator@shanks", key, "never proposed")
out, err := w.k.WithdrawRecord("operator@node-d", key, "never proposed")
if err != nil {
t.Fatal(err)
}
@@ -45,7 +45,7 @@ func TestAProposedRecordNeedingTheOperatorIsWithdrawnWithItsAskEndedAndItsReview
t.Fatalf("not waiting for the operator: %+v", before.Current)
}
why := "replaced by research on moving designs into the knowledge base"
out, err := w.k.WithdrawRecord("operator@shanks", key, why)
out, err := w.k.WithdrawRecord("operator@node-d", key, why)
if err != nil {
t.Fatal(err)
}
@@ -73,7 +73,7 @@ func TestAProposedRecordNeedingTheOperatorIsWithdrawnWithItsAskEndedAndItsReview
t.Fatal(err)
}
last := vs[len(vs)-1]
if last.By != "operator@shanks" || !strings.Contains(last.Why, why) {
if last.By != "operator@node-d" || !strings.Contains(last.Why, why) {
t.Fatalf("the new version is not by the caller with the why: %+v", last)
}
})
@@ -85,7 +85,7 @@ func TestAnAcceptedRecordRefusesWithdrawNamingWhy(t *testing.T) {
n := w.reserved(t, "author@test")
key := Key{KindDecision, n}
w.accepted(t, "author@test", valid(n))
if _, err := w.k.WithdrawRecord("operator@shanks", key, "no longer wanted"); err == nil || !strings.Contains(err.Error(), "accepted") {
if _, err := w.k.WithdrawRecord("operator@node-d", key, "no longer wanted"); err == nil || !strings.Contains(err.Error(), "accepted") {
t.Fatalf("err %v", err)
}
e := mustGet(t, w.k.Store, key)
@@ -100,10 +100,10 @@ func TestAWithdrawnRecordRefusesWithdrawAgain(t *testing.T) {
w := imported(t, s)
n := w.reserved(t, "author@test")
key := Key{KindDecision, n}
if _, err := w.k.WithdrawRecord("operator@shanks", key, "first"); err != nil {
if _, err := w.k.WithdrawRecord("operator@node-d", key, "first"); err != nil {
t.Fatal(err)
}
if _, err := w.k.WithdrawRecord("operator@shanks", key, "again"); err == nil || !strings.Contains(err.Error(), "withdrawn") {
if _, err := w.k.WithdrawRecord("operator@node-d", key, "again"); err == nil || !strings.Contains(err.Error(), "withdrawn") {
t.Fatalf("err %v", err)
}
})
@@ -113,10 +113,10 @@ func TestWithdrawNeedsWhyAndRefusesARecordItHoldsNoneOf(t *testing.T) {
eachStore(t, func(t *testing.T, s Store) {
w := imported(t, s)
n := w.reserved(t, "author@test")
if _, err := w.k.WithdrawRecord("operator@shanks", Key{KindDecision, n}, " "); err == nil {
if _, err := w.k.WithdrawRecord("operator@node-d", Key{KindDecision, n}, " "); err == nil {
t.Fatal("an empty why was accepted")
}
if _, err := w.k.WithdrawRecord("operator@shanks", Key{KindDecision, 999999}, "why"); err == nil {
if _, err := w.k.WithdrawRecord("operator@node-d", Key{KindDecision, 999999}, "why"); err == nil {
t.Fatal("a record it holds none of was accepted")
}
})
@@ -11,10 +11,10 @@ import (
func TestARevisionIsTakenOnlyFromTheRecordsAuthor(t *testing.T) {
w := imported(t, newMemStore())
n := proposed(t, w, "author@g14", false)
n := proposed(t, w, "author@node-b", false)
p := valid(n)
p.Sections[2].Text = "Merges land a little sooner."
if _, err := w.k.Propose("other@novox", p); err == nil || !strings.Contains(err.Error(), "only its author") {
if _, err := w.k.Propose("other@node-c", p); err == nil || !strings.Contains(err.Error(), "only its author") {
t.Fatalf("a revision by someone else: %v", err)
}
if _, err := w.k.Propose(Unproven, p); err == nil || !strings.Contains(err.Error(), "only its author") {
@@ -23,18 +23,18 @@ func TestARevisionIsTakenOnlyFromTheRecordsAuthor(t *testing.T) {
if mustGet(t, w.k.Store, Key{KindDecision, n}).Versions != 2 {
t.Fatal("a refused revision wrote a version")
}
if _, err := w.k.Propose("author@g14", p); err != nil {
if _, err := w.k.Propose("author@node-b", p); err != nil {
t.Fatalf("the author's revision: %v", err)
}
}
func TestAReservedNumberIsProposedOnlyByWhoReservedIt(t *testing.T) {
w := imported(t, newMemStore())
n := w.reserved(t, "author@g14")
if _, err := w.k.Propose("other@novox", valid(n)); err == nil || !strings.Contains(err.Error(), "reserved by author@g14") {
n := w.reserved(t, "author@node-b")
if _, err := w.k.Propose("other@node-c", valid(n)); err == nil || !strings.Contains(err.Error(), "reserved by author@node-b") {
t.Fatalf("a proposal under another's number: %v", err)
}
if _, err := w.k.Propose("author@g14", valid(n)); err != nil {
if _, err := w.k.Propose("author@node-b", valid(n)); err != nil {
t.Fatal(err)
}
}