Say once after a restart that nothing waits, so an old retirement condition clears (issue 937)
mesh/merge-gate head d7a880a60878 merged into trunk 3ee754eb3b0c — pass: builds keycloak, postgres, sent nowhere; no bus step; 3 wait(s) for a person; ever…
mesh/repo-check head d7a880a60878 merged into trunk 3ee754eb3b0c — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered

The controller clears a provider's retire-waiting condition only on its
settled word, and a provider says settled only for a set its own memory
held. A provider restarted after the set stopped waiting (here: the
delivery of the grant-file fix) never says it, so the condition kept
asking the operator to approve retiring what nobody waits on. The first
pass of a process that finds every consumer asked now says settled once,
with no set; the controller clears both conditions on it.
This commit is contained in:
2026-10-16 16:42:39 +00:00
parent 3ee754eb3b
commit d7a880a608
6 changed files with 136 additions and 6 deletions
@@ -121,6 +121,11 @@ func retirements(said []announced) []string {
return out
}
func noneWaits(a announced) bool {
c, _ := a.body["consumers"].([]map[string]any)
return a.body["change"] == ChangeSettled && len(c) == 0
}
func lastRetirement(t *testing.T, said []announced) map[string]any {
t.Helper()
for i := len(said) - 1; i >= 0; i-- {
@@ -521,3 +526,46 @@ func TestAFailingConsumerRetiredIsSaidRecovered(t *testing.T) {
t.Fatalf("%v", *said)
}
}
// everyWord is a world that keeps every word the provider announces.
func everyWord(t *testing.T) (*world, *[]announced) {
w := newWorld(t)
var said []announced
w.h.Announce = func(e string, b map[string]any) { said = append(said, announced{e, b}) }
w.h.Node = "anchor"
return w, &said
}
// A restarted provider that finds every consumer it holds asked for says once that nothing waits, so the controller
// clears a waiting condition an earlier process raised and this one never knew (issue 937); it says it no more.
func TestARestartedProviderSaysOnceThatNothingWaits(t *testing.T) {
w, said := everyWord(t)
holding(w, 2)
w.pass()
w.pass()
var words []announced
for _, a := range *said {
if a.event == EventRetirement {
words = append(words, a)
}
}
if len(words) != 1 || !noneWaits(words[0]) || words[0].body["provider-node"] != w.h.Node {
t.Fatalf("said %+v, want one settled with no set", words)
}
}
// A provider whose own set waits does not say that nothing waits.
func TestAProviderThatWaitsDoesNotSayNothingWaits(t *testing.T) {
w, said := everyWord(t)
w.a.inv.Active = []string{"c1", "c2", "c3", "c4", "c5"}
w.give(map[string]any{"as": "c1", "node": "anchor"})
w.settle()
for _, a := range *said {
if a.event == EventRetirement && noneWaits(a) {
t.Fatalf("said nothing waits while %v waited", w.h.r.waiting)
}
}
if w.h.r.waiting == nil {
t.Fatal("nothing waited: the test does not hold the case")
}
}