diff --git a/modules/mesh-delivery-checker/internal/check/engines.go b/modules/mesh-delivery-checker/internal/check/engines.go index ae38d8e..aef0ef1 100644 --- a/modules/mesh-delivery-checker/internal/check/engines.go +++ b/modules/mesh-delivery-checker/internal/check/engines.go @@ -91,8 +91,15 @@ func (e EngineCompositions) Compose(ctx context.Context, c *Case) (delivery.Comp defer cancel() a, err := e.Asker.ComposeCandidate(at, node, delivery.ComposeCandidateAsk{Candidate: key, Input: sandboxed}) if err == nil && sandboxed && a.Verdict != delivery.ComposeCandidateUnready { - // The composer's build and run are the check's to bound, not the engine's answer bound. - a, err = e.inSandbox(ctx, c, head, node, a) + // The composer's build and run are the check's to bound, not the engine's answer bound. A composer that + // cannot run is no silent node (ADR 0593 §9 lets only that pass): the node's composition fails, naming + // the head. + if composed, serr := e.inSandbox(ctx, c, head, node, a); serr != nil { + a = delivery.ComposeCandidateAnswer{V: a.V, Node: node, Candidate: a.Candidate, Verdict: delivery.ComposeCandidateRefused, + Refused: "the composer at the node-engine's head " + head + " could not compose it: " + serr.Error()} + } else { + a = composed + } } mu.Lock() defer mu.Unlock() diff --git a/modules/mesh-delivery-checker/internal/check/engines_test.go b/modules/mesh-delivery-checker/internal/check/engines_test.go index 76f7149..29cee46 100644 --- a/modules/mesh-delivery-checker/internal/check/engines_test.go +++ b/modules/mesh-delivery-checker/internal/check/engines_test.go @@ -45,6 +45,7 @@ type fakeSandbox struct { mu sync.Mutex jobs []delivery.ComposeJob v func(node string) composer.Verdict + err error } func (f *fakeSandbox) Compose(_ context.Context, job delivery.ComposeJob) (composer.Verdict, error) { @@ -55,6 +56,9 @@ func (f *fakeSandbox) Compose(_ context.Context, job delivery.ComposeJob) (compo f.mu.Lock() f.jobs = append(f.jobs, job) f.mu.Unlock() + if f.err != nil { + return composer.Verdict{}, f.err + } return f.v(req.Machines[0]), nil } @@ -164,5 +168,14 @@ func TestTheCompositionIsMadeFromTheEnginesAnswers(t *testing.T) { if v.State != delivery.CompositionFail || v.SDK != head2 || !strings.Contains(v.Words, "the new composer refuses it") { t.Errorf("verdict = %+v", v) } + // Review finding 3 (ADR 0593 §9 lets only a node that does not answer pass): a composer at the head that cannot + // run fails the composition, naming the head, never passing as a silent node. + sb.err = errors.New("the build of mesh-compose failed") + v, err = ec.Compose(context.Background(), host) + if err != nil || v.State != delivery.CompositionFail || !strings.Contains(v.Words, head2) || + !strings.Contains(v.Words, "the build of mesh-compose failed") || len(v.Warnings) != 0 { + t.Errorf("a composer that cannot run: %+v, %v", v, err) + } }) + }