diff --git a/internal/compose/frombus/frombus.go b/internal/compose/frombus/frombus.go index c17e0f2..3478df6 100644 --- a/internal/compose/frombus/frombus.go +++ b/internal/compose/frombus/frombus.go @@ -607,11 +607,13 @@ func ComposeSent(in compose.Input, node string) (map[string]delivery.Composed, b if err != nil { return nil, true, err } - // A module the sandbox held that the node-engine did not is the change refusing it: the node does not compose, said - // in that module's words, never passed with the rest composed (issue 774, review of the sandbox input). + // A module the sandbox held that the node-engine held neither in the read nor composing without the change is the change + // refusing it: the node does not compose, said in that module's words, never passed with the rest composed (issue 774, + // review of the sandbox input). var refused []string for _, m := range sortedKeys(held) { - if _, was := c.Held[m]; !was { + _, was := c.Held[m] + if _, before := c.HeldBefore[m]; !was && !before { refused = append(refused, m+": "+held[m]) } } diff --git a/internal/compose/input.go b/internal/compose/input.go index 4471e5e..d8eae82 100644 --- a/internal/compose/input.go +++ b/internal/compose/input.go @@ -249,6 +249,9 @@ type ComposedHow struct { Held map[string]string // Running is what runs of each held module, its own composition, by which it is carried as it runs. Running []delivery.Composed + // HeldBefore is each module the node holds composing without the change (the candidate's base), held by the read or + // blamed later for a refusal: the change refuses none of them (issue 774, review round 1). + HeldBefore map[string]string } // Place is where a node is, as its placement says (inv.Overlay). diff --git a/internal/composer/composer_test.go b/internal/composer/composer_test.go index 7ae1e90..3e669aa 100644 --- a/internal/composer/composer_test.go +++ b/internal/composer/composer_test.go @@ -159,6 +159,17 @@ func TestARequestItCannotRunIsRefused(t *testing.T) { if m := refused.Cases[0].Machines["a"]; m.Composes || !strings.Contains(m.Reason, "app: ") || !strings.Contains(m.Reason, "repository") { t.Errorf("a module the change refuses on a node composed as its node-engine does: %+v", m) } + // Held composing without the change, blamed for a refusal beyond the read (issue 1960's unset names): no refusal of + // the change either (review round 1). + in.ComposedHow.HeldBefore = map[string]string{"app": "its route names are unset"} + before, err := Run(request(in)) + if err != nil { + t.Fatal(err) + } + if m := before.Cases[0].Machines["a"]; !m.Composes { + t.Errorf("a module the node holds composing without the change: %+v", m) + } + in.ComposedHow.HeldBefore = nil in.ComposedHow.Held = map[string]string{"app": "held on the node"} held, err := Run(request(in)) if err != nil { diff --git a/internal/selfcompose/candidate.go b/internal/selfcompose/candidate.go index 4e00674..1176808 100644 --- a/internal/selfcompose/candidate.go +++ b/internal/selfcompose/candidate.go @@ -191,6 +191,9 @@ func (s *Shadow) composeCandidate(ctx context.Context, c *Composer, ask delivery if err != nil { return } + // What the node holds composing without the candidate, a module blamed for a refusal among them, is no refusal of + // the change (review round 1). + in.ComposedHow.HeldBefore = maps.Clone(baseHeld) // As the sandbox reads it (composer.SentInput, the one shape): this node's own modules as taken in from their // builds, every other module's manifest left to the cases. if body, err := json.Marshal(composer.SentInput(in, laid.env.Node)); err == nil {