Name no node in mesh-knowledge's fixtures (issue 1838)
This commit is contained in:
@@ -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}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user