Say an unanswered merge check's time in the operator's zone, from the checks given as data (novox/hq issue 443)
mesh/merge-gate pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without …
mesh/repo-check fail: its merge-check.sh failed: FAIL github.com/novox/mesh-controller/cmd/mesh-controller 268.072s
mesh/delivery-group group fix/443-a-stalled-lines-times-are-local rejected: a member's own check failed
mesh/delivery superseded: a newer head of the same pull request

This commit is contained in:
2026-10-11 03:10:30 +02:00
parent 47c7877e8d
commit 926fde2fda
3 changed files with 105 additions and 6 deletions
+38 -2
View File
@@ -879,8 +879,8 @@ func unansweredWords(l stalledLine, o conditions.Observation) (headline, explana
limit = ", past its limit of " + humanDuration(d)
}
which := "Its merge check"
if len(l.Waiting) > 0 {
which = "Its merge check (" + strings.Join(l.Waiting, ", ") + ")"
if said := uncheckedWaitWords(l); len(said) > 0 {
which = "Its merge check (" + strings.Join(said, ", ") + ")"
}
if o.Resolver == conditions.ResolverOperator {
needs = "push a new commit to its branch, which asks the check again, or see whether its check still waits " +
@@ -892,6 +892,42 @@ func unansweredWords(l stalledLine, o conditions.Observation) (headline, explana
fmt.Sprintf("%s has an answer from its merge check, or is closed", pull), needs, nil
}
// uncheckedWaitWords are the merge checks an unanswered line waits on, as the operator reads them: from the checks
// given as data, each time in the controller's local zone, as every other time in a message — "mesh/merge-gate
// pending since 02:11" — never the UTC time inside mesh-delivery's finished words, which cannot be said again in
// another zone (novox/hq issue 443). A line from a mesh-delivery that gives no such data is said by its words.
func uncheckedWaitWords(l stalledLine) []string {
if len(l.Checks) == 0 {
return l.Waiting
}
out := make([]string, 0, len(l.Checks))
for _, c := range l.Checks {
switch c.State {
case "never-set":
out = append(out, c.Context+" never set")
case "pending":
out = append(out, c.Context+" pending"+sinceWords(c.Since))
default:
out = append(out, c.Context+" not answered")
}
}
return out
}
// sinceWords is " since 02:11" in the controller's local zone, with its day when that is not today ("since 23:05 on
// 9 Oct"), so the time stays absolute; a time not given, or not readable, is said so and never made up.
func sinceWords(since string) string {
at, err := time.Parse(time.RFC3339, since)
if err != nil {
return ", since a time the forge did not say"
}
local, today := at.Local(), wordsNow().Local()
if local.YearDay() == today.YearDay() && local.Year() == today.Year() {
return " since " + local.Format("15:04")
}
return " since " + local.Format("15:04 on 2 Jan")
}
// causeWords is a hand-act's cause as a person says it.
func causeWords(cause string) string {
return strings.NewReplacer(".", " ", "_", " ").Replace(cause)