disk-load retires the readings of a module whose key went while its watch was down (review round 2)
mesh/delivery merged: source.main moved to novox/mesh-catalog@4b16c193f0fb
mesh/delivery-group group feat/data-items merged: every member is merged
mesh/check pass 0c46f47ae57e on 444c2903af7b | unit 4510 run, 4259 kept, 49 skipped | integration 4589 run, 4361 kept, 51 skipped | over bound: unit, …

A key deleted while disk-load was not watching (a restart, a reboot, a machine asleep) never
arrives as a delete. Once the watch has handed over every current key, the readings of modules
with no key are retired once; an empty set is skipped and said, since the engine has not written.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-01 00:30:39 +01:00
parent 6fe0ef321d
commit 0c46f47ae5
3 changed files with 70 additions and 2 deletions
@@ -134,6 +134,37 @@ func TestTheItemsComeFromTheEnginesKeysAndARoundSaysHowFarItGot(t *testing.T) {
if measured["/srv/web2"] != before || round().Items != 2 {
t.Errorf("an item whose key was deleted was measured again: %d times, round %+v", measured["/srv/web2"]-before, round())
}
// A restart: oldie's key was deleted while the watch was down, so no delete arrives. Once the watch handed over its
// keys, oldie's reading is retired and pg's kept; an empty set retires nothing (the engine has not written yet).
_ = readings.Put("ace.oldie.x", health.Reading{V: health.ReadingVersion, Node: "ace",
PlacedDataItem: catalogue.PlacedDataItem{Module: "oldie", ID: "x", Path: "/srv/oldie"}})
for _, restart := range []struct {
name string
keys []stdio.StateChange
retired bool
}{
{"no key yet", nil, false},
{"pg's key alone", []stdio.StateChange{{Key: key("pg"), Op: stdio.OpPut, Value: value("pg", pg, gone), Current: true}}, true},
} {
w2 := &Watched{Node: "ace"}
said = nil
k2 := &Keeper{Node: "ace", Items: w2.All, Store: readings, Say: k.Say, Measurer: k.Measurer}
for _, ch := range restart.keys {
if _, _, err := w2.Take(ch); err != nil {
t.Fatal(err)
}
}
w2.Ready()
k2.RetireUnkeyed(context.Background())
oldie, pgData := readingOf(readings, "ace.oldie.x"), readingOf(readings, "ace.pg.data")
if oldie == nil || pgData == nil || oldie.RetiredAt.IsZero() == restart.retired || !pgData.RetiredAt.IsZero() {
t.Errorf("%s: oldie %+v, pg %+v; oldie retired: want %v, pg never", restart.name, oldie, pgData, restart.retired)
}
if !restart.retired && !strings.Contains(strings.Join(said, "\n"), "holds no key") {
t.Errorf("%s: the skip was not said: %v", restart.name, said)
}
}
}
func readingOf(s *memStore, key string) *health.Reading {