From fc921c13d000b390aab2be079329758a321f1efc Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 6 Nov 2026 23:07:06 +0100 Subject: [PATCH] checker_verdicts and checker_pull say which checking program judged a verdict, its build and the heads it read (issue 1921) Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- .../cmd/mesh-delivery-checker-tools/main.go | 4 ++-- .../internal/check/read.go | 23 ++++++++++++++++++- .../internal/check/read_test.go | 14 ++++++++--- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main.go index 2e29ae40..81101036 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main.go @@ -233,7 +233,7 @@ func SeatTryTools(tr Trying) []stdio.Tool { func Tools(r check.Reader) []stdio.Tool { return []stdio.Tool{ {Name: check.VerdictsReadTool, - Description: "The verdicts the checker holds, each as stored under verdicts..: its state, every failure it names one line each (every member's failed tests, refused steps and conflicts, the manifests' refusals and the composition), the tests run, kept and skipped per level, the time of each part, the trunk heads it judged against and the composition, with the full " + + Description: "The verdicts the checker holds, each as stored under verdicts..: its state, every failure it names one line each (every member's failed tests, refused steps and conflicts, the manifests' refusals and the composition), the tests run, kept and skipped per level, the time of each part, the trunk heads it judged against, the composition and which checking program judged it (judged: its build and the heads it read), with the full " + "report of the status each pull request carries (the line the forge shows is cut at 140 characters, this is not). With a group, that group's only. Read-only.", Input: map[string]any{"type": "object", "properties": map[string]any{ "group": map[string]any{"type": "string", "description": "the delivery group's branch name"}}}, @@ -243,7 +243,7 @@ func Tools(r check.Reader) []stdio.Tool { return cutAnswer(map[string]any{"verdicts": vs}, cut), err }}, {Name: check.PullReadTool, - Description: "The verdict that judges one pull request, every failure it names one line each (all of them, not only the first the status line shows), and the full report of its status mesh/check. Read-only.", + Description: "The verdict that judges one pull request, every failure it names one line each (all of them, not only the first the status line shows), which checking program judged it (judged: its build, its key and the heads it read), and the full report of its status mesh/check. Read-only.", Input: map[string]any{"type": "object", "required": []string{"repository", "number"}, "properties": map[string]any{ "repository": map[string]any{"type": "string", "description": "/"}, "number": map[string]any{"type": "integer", "description": "the pull request's number"}}}, diff --git a/modules/mesh-delivery-checker/internal/check/read.go b/modules/mesh-delivery-checker/internal/check/read.go index 3457cd47..39c6f61e 100644 --- a/modules/mesh-delivery-checker/internal/check/read.go +++ b/modules/mesh-delivery-checker/internal/check/read.go @@ -65,7 +65,10 @@ type VerdictRead struct { Verdict json.RawMessage `json:"verdict"` // Failed is everything the verdict names as failed, one line each, in the order judged (failedLines): every member's // failed tests, refused steps and conflicts, the manifests' refusals and the composition (the operator, 2026-11-02). - Failed []string `json:"failed,omitempty"` + Failed []string `json:"failed,omitempty"` + // Judged says which checking program judged the verdict, in one line (judgedLine): where it was built, the key its build + // is kept under, whether this check built it, and the heads it read (issue 1921); empty for a verdict written before. + Judged string `json:"judged,omitempty"` Reports map[string]string `json:"reports,omitempty"` Note string `json:"note,omitempty"` } @@ -90,6 +93,7 @@ func (r Reader) read(key string, raw json.RawMessage) (VerdictRead, error) { return out, fmt.Errorf("%s holds what is not a verdict: %w", key, err) } out.Failed = failedLines(v) + out.Judged = judgedLine(v.JudgedBy) c, ok := r.candidate(v.Group) if !ok || (c.HeadsHash != v.Heads && GateHeads(c) != v.Heads) { out.Note = "the candidate no longer holds these heads" @@ -752,3 +756,20 @@ func (r Reader) buildsNotEnded(c delivery.Candidate) string { sort.Strings(out) return strings.Join(slices.Compact(out), ", ") } + +// judgedLine is a verdict's JudgedBy in one line, as the verdict tools answer it. +func judgedLine(by *delivery.JudgedBy) string { + if by == nil { + return "" + } + built := "kept" + if by.Built { + built = "built for this check" + } + heads := make([]string, len(by.Heads)) + for i, h := range by.Heads { + heads[i] = h.Repository + " " + h.Commit + } + return fmt.Sprintf("by the checking program %s of %s at %s (%s), %s as %s, over %s", by.Program.Package, by.Program.Repository, + by.Program.Commit, by.Program.Dir, built, by.Key, strings.Join(heads, ", ")) +} diff --git a/modules/mesh-delivery-checker/internal/check/read_test.go b/modules/mesh-delivery-checker/internal/check/read_test.go index c01589be..4da7a1ec 100644 --- a/modules/mesh-delivery-checker/internal/check/read_test.go +++ b/modules/mesh-delivery-checker/internal/check/read_test.go @@ -64,15 +64,23 @@ func TestTheVerdictToolsAnswerTheStoredVerdictWithTheFullReportOfEachPullRequest if got := vs[0].Reports["novox/mesh-delivery#7"]; !strings.HasPrefix(got, "pass 111111111111 on aaaaaaaaaaaa") || !strings.Contains(got, "composition not yet run") { t.Errorf("reports = %v", vs[0].Reports) } + if vs[0].Judged != "" { + t.Errorf("judged = %q of a verdict with no JudgedBy", vs[0].Judged) + } if only, _, _ := rd.Verdicts("feat/other"); len(only) != 0 { t.Errorf("another group's verdicts = %+v", only) } // A failed verdict is answered with every failure it names, one line each (the operator, 2026-11-02). raw, _ := delivery.EncodeVerdict(delivery.Verdict{Group: "feat/x", Heads: "0123456789ab", State: delivery.VerdictFail, Failed: delivery.FailedFirst{Test: "unit: m/a.TestA", Words: "a_test.go:3: boom\nmore"}, - Failures: []delivery.FailedFirst{{Test: "unit: m/a.TestA", Words: "a_test.go:3: boom"}, {Machine: "g14", Words: "route-proxy is defined twice"}}}) - if got, _ := rd.read(key, raw); strings.Join(got.Failed, " | ") != "unit: m/a.TestA: a_test.go:3: boom | g14: route-proxy is defined twice" { - t.Errorf("failed = %q", got.Failed) + Failures: []delivery.FailedFirst{{Test: "unit: m/a.TestA", Words: "a_test.go:3: boom"}, {Machine: "g14", Words: "route-proxy is defined twice"}}, + // Issue 1921: it names the checking program that judged it, its build and the heads it read. + JudgedBy: &delivery.JudgedBy{Program: delivery.RunProgram{Repository: repoA, Commit: head1, Dir: CheckingProgramDir, Package: CheckingProgramPackage}, + Key: "program-0123456789abcdef", Built: true, Heads: []delivery.RunHead{{Repository: repoA, Commit: head1}}}}) + want := "by the checking program " + CheckingProgramPackage + " of " + repoA + " at " + head1 + " (" + CheckingProgramDir + + "), built for this check as program-0123456789abcdef, over " + repoA + " " + head1 + if got, _ := rd.read(key, raw); strings.Join(got.Failed, " | ") != "unit: m/a.TestA: a_test.go:3: boom | g14: route-proxy is defined twice" || got.Judged != want { + t.Errorf("failed = %q, judged %q, want %q", got.Failed, got.Judged, want) } }