diff --git a/internal/selfcompose/selfcompose_test.go b/internal/selfcompose/selfcompose_test.go index 155efc8..09db36f 100644 --- a/internal/selfcompose/selfcompose_test.go +++ b/internal/selfcompose/selfcompose_test.go @@ -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}, diff --git a/internal/selfcompose/shadow.go b/internal/selfcompose/shadow.go index bdc7422..91bf349 100644 --- a/internal/selfcompose/shadow.go +++ b/internal/selfcompose/shadow.go @@ -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)