Every check is judged by the checking program built from its heads (issue 1921)

The running checker asks the checking program twice on the build seat's job run: first the
heads' seat list, which the manifest validator's requests (change and trunk) and the
node-engine composer's carry; then the verdict of the facts it gathered. The program is built
at the group's mesh-delivery head, else at mesh-delivery's trunk, and its input is kept in the
checker's new state inputs as the exact bytes of its digest, read with checker_inputs. A run
ask no build node begins within 5 minutes is put once more, then fails the check naming the
job; a program that does not build or answer fails the check naming it, and the verdict
records who judged it (JudgedBy). A second step-seen hook on a context is added to the
first, so a try still sees its steps.

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-06 22:58:15 +01:00
parent 043e3fb979
commit 63bbabacbf
24 changed files with 588 additions and 72 deletions
@@ -149,8 +149,13 @@ type stepSeenKey struct{}
// WithStepSeen is ctx carrying seen, which Asker.Wait hands every value the ask's step key takes while it waits: the node
// that took it, each phase it says while running (delivery.Step.Phase), and its end. A try names its asks' progress so
// (issue 1890). seen runs in the waiting goroutine and must not block.
// (issue 1890). seen runs in the waiting goroutine and must not block. A seen ctx already carries is kept: both are handed
// every value, the earlier first (a check's begin bound watches the steps of a try that names them).
func WithStepSeen(ctx context.Context, seen func(delivery.Step)) context.Context {
if before := stepSeenOf(ctx); before != nil {
later := seen
seen = func(s delivery.Step) { before(s); later(s) }
}
return context.WithValue(ctx, stepSeenKey{}, seen)
}
@@ -26,10 +26,13 @@ func TestAnAskerPutsOnceAndReadsTheStep(t *testing.T) {
return delivery.Step{ID: a.ID, Node: "ace", State: delivery.StepPassed, Result: []byte(`{"artifacts":[]}`)}
}}
k := Asker{Publisher: f, Waiter: f}
var seen []delivery.Step // issue 1890: a waiter that asks to see each value of the step sees it
step, err := k.Ask(WithStepSeen(context.Background(), func(s delivery.Step) { seen = append(seen, s) }), goAsk("mvl0frv18d1957"))
if err != nil || step.Node != "ace" || len(f.Asks()) != 1 || len(seen) != 1 || seen[0].Node != "ace" {
t.Fatalf("step %+v, %v, asks %d, seen %+v", step, err, len(f.Asks()), seen)
var seen, also []delivery.Step // issue 1890: a waiter that asks to see each value of the step sees it
// Issue 1921: a second seen on the same context (a check's begin bound inside a try) is added, never in place of the first.
both := WithStepSeen(WithStepSeen(context.Background(), func(s delivery.Step) { seen = append(seen, s) }),
func(s delivery.Step) { also = append(also, s) })
step, err := k.Ask(both, goAsk("mvl0frv18d1957"))
if err != nil || step.Node != "ace" || len(f.Asks()) != 1 || len(seen) != 1 || seen[0].Node != "ace" || len(also) != 1 {
t.Fatalf("step %+v, %v, asks %d, seen %+v and %+v", step, err, len(f.Asks()), seen, also)
}
f.Answer = func(a delivery.StepAsk) delivery.Step {
return delivery.Step{ID: a.ID, Node: "shanks", State: delivery.StepRefused, Reason: "go 1.27 installed"}