From e962279f1d83b72bc4d1ca480a13a41d7a234907 Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Wed, 21 Oct 2026 08:29:57 +0000 Subject: [PATCH 1/3] Do not ask the operator to stop a delivery that is already stopped; say what ends it (issue 1581) --- cmd/mesh-controller/plain_words.go | 15 +++++++++++++++ cmd/mesh-controller/plain_words_test.go | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/cmd/mesh-controller/plain_words.go b/cmd/mesh-controller/plain_words.go index 965b8892..285d05cc 100644 --- a/cmd/mesh-controller/plain_words.go +++ b/cmd/mesh-controller/plain_words.go @@ -951,6 +951,10 @@ func stalledWords(l stalledLine, o conditions.Observation) (headline, explanatio needs, actions = "release it, or stop it, "+FromMeshMCPServer, []conditions.Action{release, stop} case "ready", "checked": needs = "merge its pull request, or close it." + case "stopped": + // Already stopped: mesh-delivery.stop refuses it, so neither offer nor ask it (novox/hq issue 1581). + // What ends it is the stalled line's own word, such as a later merge that delivers its modules. + needs = stoppedNeeds(l) default: needs, actions = "stop it "+FromMeshMCPServer, []conditions.Action{stop} } @@ -960,6 +964,17 @@ func stalledWords(l stalledLine, o conditions.Observation) (headline, explanatio fmt.Sprintf("Delivery of %s is no longer %s", name, held), needs, actions } +// stoppedNeeds is what ends a delivery that is already stopped, from the stalled line's healer words ("none: a +// merge that delivers its modules ends it — the operator's"): the part that says what ends it. +func stoppedNeeds(l stalledLine) string { + ends := strings.TrimSpace(strings.TrimPrefix(l.H2, "none:")) + ends, _, _ = strings.Cut(ends, " — ") + if ends == "" { + ends = "a later merge that delivers its modules ends it" + } + return "nothing to stop, it is stopped already: " + ends + "." +} + // unansweredWords are the plain words of a pull request's head whose merge check was asked and has not answered // within its bound (novox/hq issue 438): mesh-delivery holds no delivery of it, so there is nothing to stop, release // or close, and no action is offered. The operator's acts are a new commit, which asks the check again, or a look diff --git a/cmd/mesh-controller/plain_words_test.go b/cmd/mesh-controller/plain_words_test.go index f832f479..97a9dc5d 100644 --- a/cmd/mesh-controller/plain_words_test.go +++ b/cmd/mesh-controller/plain_words_test.go @@ -498,3 +498,24 @@ func TestAnUnansweredMergeCheckOnAReadyOrRejectedDeliveryOffersARecheck(t *testi t.Fatalf("a line with no delivery held says to %q", o.Needs) } } + +// **A delivery already stopped is not asked to be stopped** (novox/hq issue 1581): mesh-delivery.stop refuses a +// stopped delivery, so the condition offers no Stop and says what ends it, in the stalled line's own words. Any +// other held state keeps its Stop. +func TestAStoppedDeliveryIsNotAskedToBeStopped(t *testing.T) { + l := stalledLine{ID: "novox/mesh-catalog@2f6086120c46", State: "stopped", For: "12h19m36s", + H2: "none: a merge that delivers its modules ends it — the operator's", + Says: "a merged change never reached the machines"} + _, _, _, needs, actions := stalledWords(l, conditions.Observation{Resolver: conditions.ResolverOperator}) + if len(actions) != 0 { + t.Fatalf("a stopped delivery offers %v, want no action", actions) + } + if strings.Contains(needs, "stop it") || !strings.Contains(needs, "a merge that delivers its modules ends it") { + t.Fatalf("needs = %q, want what ends it and no ask to stop", needs) + } + l.State = "failing" + _, _, _, needs, actions = stalledWords(l, conditions.Observation{Resolver: conditions.ResolverOperator}) + if len(actions) != 1 || actions[0].Label != "Stop" || !strings.HasPrefix(needs, "stop it") { + t.Fatalf("another held state changed: needs %q, actions %v", needs, actions) + } +} From ef29adbc1afe0329e2eeb2dceea83c875146c684 Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Wed, 21 Oct 2026 08:30:12 +0000 Subject: [PATCH 2/3] Spell the dash in stoppedNeeds as an escape, as the reviewed source has it (issue 1581) --- cmd/mesh-controller/plain_words.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/mesh-controller/plain_words.go b/cmd/mesh-controller/plain_words.go index 285d05cc..450df265 100644 --- a/cmd/mesh-controller/plain_words.go +++ b/cmd/mesh-controller/plain_words.go @@ -968,7 +968,7 @@ func stalledWords(l stalledLine, o conditions.Observation) (headline, explanatio // merge that delivers its modules ends it — the operator's"): the part that says what ends it. func stoppedNeeds(l stalledLine) string { ends := strings.TrimSpace(strings.TrimPrefix(l.H2, "none:")) - ends, _, _ = strings.Cut(ends, " — ") + ends, _, _ = strings.Cut(ends, " \\u2014 ") if ends == "" { ends = "a later merge that delivers its modules ends it" } From cddf1508717816f70730cbc5eff0e8718e2c09e6 Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Wed, 21 Oct 2026 08:30:27 +0000 Subject: [PATCH 3/3] Spell the dash escape with one backslash, as the reviewed source has it (issue 1581) --- cmd/mesh-controller/plain_words.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/mesh-controller/plain_words.go b/cmd/mesh-controller/plain_words.go index 450df265..285d05cc 100644 --- a/cmd/mesh-controller/plain_words.go +++ b/cmd/mesh-controller/plain_words.go @@ -968,7 +968,7 @@ func stalledWords(l stalledLine, o conditions.Observation) (headline, explanatio // merge that delivers its modules ends it — the operator's"): the part that says what ends it. func stoppedNeeds(l stalledLine) string { ends := strings.TrimSpace(strings.TrimPrefix(l.H2, "none:")) - ends, _, _ = strings.Cut(ends, " \\u2014 ") + ends, _, _ = strings.Cut(ends, " — ") if ends == "" { ends = "a later merge that delivers its modules ends it" }