Leave a record the node's own carried for a module that composes its own, and let that module's apply remove it, so the node's own is not refused for ever (issue 774)
mesh/delivery merged: source.main moved to novox/mesh-host@62b211bb6040
mesh/check checking 1d8d7267584e on 62b211bb6040

On the bus node restic's manifest replaced its process measure by awake (mesh-catalog 35ff67bd). The record of restic.measure was the node's, made while restic was folded, so restic's own apply never saw it, and the guard against removing a placed module's resources refused the node's own apply whole every two minutes from 2026-10-30 19:42: nothing of the node's own applied.

Quick fix considered: forget the one record by hand (a hand act on the node; refused). Thorough fix (this): the node's own apply keeps such a record and says so, never refusing or removing it; a module's own apply owns a node record whose id names it, so it alone removes it once neither composition declares it.
This commit is contained in:
2026-10-31 01:13:11 +01:00
parent 91fb323ce0
commit 1d8d726758
2 changed files with 83 additions and 7 deletions
+35 -6
View File
@@ -125,12 +125,15 @@ func TestARecordWithoutAnOwnerBelongsToTheModuleItsIdNames(t *testing.T) {
// want's removal lets it go.
func TestAResourceThatMovedToItsModulesCompositionIsLeftByTheNodesOwnApply(t *testing.T) {
for _, tc := range []struct {
name string
id string // the resource the node's own composition carried, and no longer does
moved bool // its module's own composition now declares it (Others)
placed bool // a want still places its module here
refused bool // the node's own apply is refused whole
stays bool // the resource is still on the machine and recorded
name string
id string // the resource the node's own composition carried, and no longer does
moved bool // its module's own composition now declares it (Others)
// dropped: its module has a composition of its own here that no longer declares it (Others holds another of its
// resources); the node's own apply leaves it, and the module's own apply removes it.
dropped bool
placed bool // a want still places its module here
refused bool // the node's own apply is refused whole
stays bool // the resource is still on the machine and recorded
// wants names the modules whose want says removed (Scope.RemovedByWant); nil leaves the guard to Placed alone.
wants []string
}{
@@ -141,6 +144,11 @@ func TestAResourceThatMovedToItsModulesCompositionIsLeftByTheNodesOwnApply(t *te
// it; in the node's own apply only a module a want removed loses its resources.
{name: "a folded module with no want", id: "nats.server-conf", wants: []string{}, refused: true, stays: true},
{name: "a folded module a want removed", id: "nats.server-conf", wants: []string{"nats", "old"}},
// 2026-10-30 19:42 on the bus node: restic's manifest replaced its process measure by awake. Its record was the
// node's, carried when restic was folded, so restic's own apply never saw it and the node's own was refused
// whole every two minutes, applying nothing of the node's own.
{name: "its module's own composition dropped it", id: "restic.measure", dropped: true, placed: true,
wants: []string{"old"}, stays: true},
} {
t.Run(tc.name, func(t *testing.T) {
dir := t.TempDir()
@@ -159,6 +167,11 @@ func TestAResourceThatMovedToItsModulesCompositionIsLeftByTheNodesOwnApply(t *te
moved := declare(t, `{"id":"`+tc.id+`","type":"file","path":"`+fact+`","content":"mesh\n","module":"`+module+`"}`)
scope.Others = moved.Resources
}
if tc.dropped {
later := declare(t, `{"id":"`+module+`.awake","type":"file","path":"`+filepath.Join(dir, "awake")+
`","content":"a\n","module":"`+module+`"}`)
scope.Others = later.Resources
}
if tc.placed {
scope.Placed = map[string]bool{module: true}
}
@@ -188,6 +201,22 @@ func TestAResourceThatMovedToItsModulesCompositionIsLeftByTheNodesOwnApply(t *te
if exists(gone) == !tc.refused {
t.Fatalf("a resource no composition holds any more exists %v, with the apply refused %v", exists(gone), tc.refused)
}
if tc.dropped {
if o := outcomeOf(report, tc.id); o.Action != "kept" {
t.Fatalf("the node's own apply did not say it left it: %+v", o)
}
later := declare(t, `{"id":"`+module+`.awake","type":"file","path":"`+filepath.Join(dir, "awake")+
`","content":"a\n","module":"`+module+`"}`)
_, last, err := ApplyModule(context.Background(), archHost(t), later, Scope{Module: module}, after,
store.OriginDeclared, noServices, nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
if _, still := last.Find(tc.id); still || exists(fact) {
t.Fatalf("the module's own apply left what it no longer declares: recorded %v, on the machine %v",
still, exists(fact))
}
}
})
}
}