mesh-issues: check every new issue for a duplicate; claude-code: one judgement with no tools (hq ADR 0278)
mesh/merge-gate pass: builds claude-code, mesh-issues → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 o…
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer head of the same pull request

The operator asked for duplicate issues to be consolidated as they are opened.
The tracker consumes its own opened event and asks the agent on its node, through
claude-code's new claude_code_judge, whether an older issue not resolved asks the
same question; it closes only the newer issue of a certain duplicate, keeping its
report on the older one, and fails loudly when it cannot judge. groom runs the
same judgement over the backlog as a dry run, applied on confirm.
This commit is contained in:
jochen
2026-10-10 17:11:54 +02:00
parent fb77be42ca
commit f58840b8a6
13 changed files with 1750 additions and 16 deletions
@@ -0,0 +1,168 @@
package main
import (
"context"
"encoding/json"
"errors"
"slices"
"strings"
"testing"
"time"
)
func testJudge(confined bool, licensed bool, exec func(ctx context.Context, argv []string, stdin []byte) ([]byte, error)) *Judge {
p := Paths{Node: "control", Operator: "op", Agent: "op"}
if confined {
p.Agent = "nox"
}
return &Judge{P: p, Licensed: func() bool { return licensed }, Exec: exec, Now: time.Now, turn: make(chan struct{}, 1)}
}
var verdictSchema = map[string]any{"type": "object", "properties": map[string]any{"verdict": map[string]any{"type": "string"}}}
// The session can do nothing but answer: built-in tools off, safe mode, no session kept, as the agent's account.
func TestAJudgementRunsTheAgentWithNoToolsAsItsAccount(t *testing.T) {
var got []string
var input string
j := testJudge(true, true, func(_ context.Context, argv []string, stdin []byte) ([]byte, error) {
got, input = argv, string(stdin)
return []byte(`{"is_error":false,"subtype":"success","structured_output":{"verdict":"none"}}`), nil
})
out, err := j.Judge(JudgeAsk{Question: "is 1 the same as 2?", Schema: verdictSchema})
if err != nil {
t.Fatal(err)
}
if string(out.Answer) != `{"verdict":"none"}` || out.Model != "sonnet" || out.Node != "control" {
t.Fatalf("%+v", out)
}
if input != "is 1 the same as 2?" {
t.Fatalf("the question goes on the input, never the command line: %q", input)
}
line := strings.Join(got, " ")
if !strings.HasPrefix(line, "sudo -n -H -u nox -- "+JudgeProgram+" -p ") {
t.Fatalf("not run as the agent's account: %s", line)
}
i := slices.Index(got, "--tools")
if i < 0 || got[i+1] != "" {
t.Fatalf("built-in tools are not off: %q", got)
}
for _, want := range []string{"--safe-mode", "--no-session-persistence", "--json-schema"} {
if !slices.Contains(got, want) {
t.Errorf("%s missing: %q", want, got)
}
}
for _, a := range got {
if strings.Contains(a, "is 1 the same") {
t.Fatal("the question is on the command line")
}
}
// Where agents run as the operator's account, no sudo.
j = testJudge(false, true, func(_ context.Context, argv []string, _ []byte) ([]byte, error) {
got = argv
return []byte(`{"structured_output":{"verdict":"none"}}`), nil
})
if _, err := j.Judge(JudgeAsk{Question: "q", Schema: verdictSchema, Model: "haiku"}); err != nil {
t.Fatal(err)
}
if got[0] != JudgeProgram || !slices.Contains(got, "haiku") {
t.Fatalf("%q", got)
}
}
func TestAJudgementRefusesWhatItCannotAnswer(t *testing.T) {
ran := false
ok := func(context.Context, []string, []byte) ([]byte, error) {
ran = true
return []byte(`{"structured_output":{}}`), nil
}
cases := map[string]struct {
j *Judge
ask JudgeAsk
say string
}{
"empty": {testJudge(true, true, ok), JudgeAsk{Question: " ", Schema: verdictSchema}, "needs a question"},
"too large": {testJudge(true, true, ok), JudgeAsk{Question: strings.Repeat("x", MostQuestion+1), Schema: verdictSchema}, "64 KiB"},
"no schema": {testJudge(true, true, ok), JudgeAsk{Question: "q"}, "needs schema"},
"not object": {testJudge(true, true, ok), JudgeAsk{Question: "q", Schema: map[string]any{"type": "string"}}, "object"},
"model": {testJudge(true, true, ok), JudgeAsk{Question: "q", Schema: verdictSchema, Model: "gpt"}, "not one of"},
"no licence": {testJudge(true, false, ok), JudgeAsk{Question: "q", Schema: verdictSchema}, "holds no licence"},
}
for name, c := range cases {
_, err := c.j.Judge(c.ask)
if err == nil || !strings.Contains(err.Error(), c.say) {
t.Errorf("%s: %v", name, err)
}
}
if ran {
t.Fatal("a refused judgement ran the agent")
}
}
func TestAJudgementThatFailsSaysWhy(t *testing.T) {
answers := map[string][]byte{
"an error": []byte(`{"is_error":true,"subtype":"error_during_execution","result":"rate limited"}`),
"no structure": []byte(`{"is_error":false,"result":"it is a duplicate"}`),
"not an object": []byte(`{"structured_output":[1,2]}`),
"not json": []byte(`Invalid API key`),
}
for name, out := range answers {
j := testJudge(true, true, func(context.Context, []string, []byte) ([]byte, error) { return out, nil })
if _, err := j.Judge(JudgeAsk{Question: "q", Schema: verdictSchema}); err == nil || !strings.Contains(err.Error(), "not in the shape") {
t.Errorf("%s: %v", name, err)
}
}
j := testJudge(true, true, func(context.Context, []string, []byte) ([]byte, error) {
return nil, errors.New("exit status 1: sudo: a password is required")
})
if _, err := j.Judge(JudgeAsk{Question: "q", Schema: verdictSchema}); err == nil || !strings.Contains(err.Error(), "could not judge") {
t.Errorf("%v", err)
}
}
// One at a time on a node, and never past the bound: a judgement still waiting at the bound is refused.
func TestAJudgementWaitsItsTurnWithinTheBound(t *testing.T) {
j := testJudge(true, true, func(ctx context.Context, _ []string, _ []byte) ([]byte, error) {
<-ctx.Done()
return nil, ctx.Err()
})
j.Bound = 300 * time.Millisecond
j.turn <- struct{}{} // another judgement holds the agent
start := time.Now()
_, err := j.Judge(JudgeAsk{Question: "q", Schema: verdictSchema})
if err == nil || !strings.Contains(err.Error(), "another judgement") {
t.Fatalf("%v", err)
}
if time.Since(start) > 2*time.Second {
t.Fatal("waited past the bound")
}
}
func TestAJudgementPastTheBoundIsEnded(t *testing.T) {
j := testJudge(true, true, func(ctx context.Context, _ []string, _ []byte) ([]byte, error) {
<-ctx.Done()
return nil, ctx.Err()
})
j.Bound = 200 * time.Millisecond
if _, err := j.Judge(JudgeAsk{Question: "q", Schema: verdictSchema}); err == nil || !strings.Contains(err.Error(), "did not answer within") {
t.Fatalf("%v", err)
}
}
func TestTheToolTakesOnlyItsArguments(t *testing.T) {
j := testJudge(true, true, func(context.Context, []string, []byte) ([]byte, error) {
return []byte(`{"structured_output":{"verdict":"none"}}`), nil
})
tool := judgeTool(j)
if _, err := tool.Run(map[string]any{"question": "q", "schema": verdictSchema, "by": "x"}); err == nil {
t.Fatal("an unknown argument was taken")
}
out, err := tool.Run(map[string]any{"question": "q", "schema": verdictSchema})
if err != nil {
t.Fatal(err)
}
raw, _ := json.Marshal(out)
if !strings.Contains(string(raw), `"answer":{"verdict":"none"}`) {
t.Fatalf("%s", raw)
}
}