diff --git a/cmd/artwork.go b/cmd/artwork.go index 1ff2b8f85..0757c0e52 100644 --- a/cmd/artwork.go +++ b/cmd/artwork.go @@ -540,7 +540,9 @@ func explainResult(source string, steps []artwork.TraceStep) string { return "resolved from " + source + " (offline: a higher-priority external candidate was not tried; re-run with --live)" } - if s.Outcome == artwork.OutcomeError && strings.HasPrefix(s.Candidate, artwork.ExternalPrefix) { + // An external winner discards the earlier error, so the resolver settles it with no retry. + if s.Outcome == artwork.OutcomeError && strings.HasPrefix(s.Candidate, artwork.ExternalPrefix) && + !strings.HasPrefix(source, artwork.ExternalPrefix) { return "resolved from " + source + " (indeterminate: a higher-priority external lookup failed; this may resolve differently on a retry)" } diff --git a/cmd/artwork_test.go b/cmd/artwork_test.go index c89c63ab0..cc8b12e07 100644 --- a/cmd/artwork_test.go +++ b/cmd/artwork_test.go @@ -99,6 +99,15 @@ var _ = Describe("explainResult", func() { "the resolver serves this hit but retries later, so the winner is provisional") }) + It("does not qualify an external win that followed a failed external lookup", func() { + steps := []artwork.TraceStep{ + {Candidate: "external:deezer", Outcome: "error", Detail: "context deadline exceeded"}, + {Candidate: "external:lastfm", Outcome: "hit", Detail: "http://img"}, + } + Expect(explainResult("external:lastfm", steps)).To(Equal("resolved from external:lastfm"), + "a later agent supplying the image discards the earlier error, so there is no retry to warn about") + }) + It("does not qualify a win that outranked the failed external lookup", func() { steps := []artwork.TraceStep{ {Candidate: "artist.*", Outcome: "hit"},