Node agent: count a module running a build of the old form as held today, so the seed keeps it as the controller does (issue 1126)

This commit is contained in:
2026-10-28 23:45:28 +01:00
parent d2a868f99f
commit 91686fdb81
2 changed files with 12 additions and 3 deletions
+5 -1
View File
@@ -1407,7 +1407,11 @@ func TestAHaveSaysWhetherItsModuleRunsInsideTheNodesOwn(t *testing.T) {
{"failed, naming nothing it runs", delivery.Have{Phase: delivery.PhaseFailed, Health: delivery.HealthFailed,
Detail: "the node cannot compose it, and keeps running what it ran: no build"}, false, false},
{"failed at a build fingerprint", delivery.Have{FP: "build-0123abcd", Composed: "sha256:" + strings.Repeat("c", 64), Phase: delivery.PhaseFailed,
Health: delivery.HealthFailed, Detail: "the node cannot compose it, and keeps running what it ran: no build"}, true, false},
Health: delivery.HealthFailed, Detail: "the node cannot compose it, and keeps running what it ran: no build"}, true, true},
{"running a build of the old form", delivery.Have{FP: "build-1790368817085312877", Composed: "sha256:" + strings.Repeat("c", 64),
Phase: delivery.PhaseRunning, Health: delivery.HealthOK}, true, true},
{"running a build of the new form", delivery.Have{FP: delivery.SourcePrefix2 + strings.Repeat("a", 64), Composed: "sha256:" + strings.Repeat("c", 64),
Phase: delivery.PhaseRunning, Health: delivery.HealthOK}, false, false},
{"running with no fingerprint (mesh-wireguard)", delivery.Have{Phase: delivery.PhaseRunning, Health: delivery.HealthOK}, true, false},
{"held today", delivery.Have{FP: "build-0123abcd", Composed: "sha256:" + strings.Repeat("c", 64), Phase: delivery.PhaseHeld,
Health: delivery.HealthWaits, Detail: "held: a required config value is unset"}, true, true},
+7 -2
View File
@@ -40,7 +40,8 @@ type Shadow struct {
// ran is, by module, the digest the module's have says runs: what runs, where the agent's list holds only the copy
// from the declaration kept before the switch (issue 1126, probe #532 on shanks).
ran map[string]string
// heldNow is, by module, whether its have says the node holds it today (phase held): a candidate holding it too holds
// heldNow is, by module, whether its have says the node holds it today (phase held, or a build of the old form it runs
// as the controller keeps it): a candidate holding it too holds
// it as today (frombus.Scope.HeldToday, issue 1126).
heldNow map[string]bool
// answered is, by proposal, the candidate revisions and the input changes (moved) each answer was composed at: a proposal
@@ -664,7 +665,11 @@ func (s *Shadow) takeRan(u agent.Update) bool {
s.heldNow = map[string]bool{}
}
wasHeld := s.heldNow[module]
s.heldNow[module] = !u.Deleted && err == nil && h.Phase == delivery.PhaseHeld
// Held today: its have's phase is held, or it runs a build of the old form (not src2:), which no registered build of
// the trunk names, so the controller keeps it as it runs (issue 1126: novox's de-spiegel at build-…, its newer build
// not registered); a seed keeps it so too.
s.heldNow[module] = !u.Deleted && err == nil && h.Phase != delivery.PhaseRemoved &&
(h.Phase == delivery.PhaseHeld || (h.FP != "" && !strings.HasPrefix(h.FP, delivery.SourcePrefix2)))
holdMoved := wasHeld != s.heldNow[module] // a hold's start or end changes the answer too
if u.Deleted || err != nil || h.Composed == "" || h.Phase == delivery.PhaseRemoved {
delete(s.ran, module)