Judge a group's controller by itself with the validator it vendors, and copy nothing of mesh-host's (issue 1391, 3 of 3)

judgeFromTheGroup copies nothing into the judge's vendor tree: a mesh-host member whose tree holds no validate/ does not fail the judge, and the verdict names the validator as mesh-sdk's at the pin of the controller that judges. replaceGoFiles and its test are gone.
This commit is contained in:
2026-10-20 09:35:38 +00:00
parent 52d5e38729
commit 0fc455aa65
2 changed files with 11 additions and 93 deletions
+11 -72
View File
@@ -1446,42 +1446,6 @@ func refWords(ref string) string {
// commitLike is a ref that names a commit.
var commitLike = regexp.MustCompile(`^[0-9a-f]{7,40}$`)
// replaceGoFiles puts a package's Go files — never its tests — in place of another copy's.
func replaceGoFiles(from, into string) error {
old, err := filepath.Glob(filepath.Join(into, "*.go"))
if err != nil {
return err
}
for _, f := range old {
if err := os.Remove(f); err != nil {
return err
}
}
if err := os.MkdirAll(into, 0o755); err != nil {
return err
}
files, err := filepath.Glob(filepath.Join(from, "*.go"))
if err != nil {
return err
}
if len(files) == 0 {
return fmt.Errorf("%s holds no Go files", from)
}
for _, f := range files {
if strings.HasSuffix(f, "_test.go") {
continue
}
body, err := os.ReadFile(f)
if err != nil {
return err
}
if err := os.WriteFile(filepath.Join(into, filepath.Base(f)), body, 0o644); err != nil {
return err
}
}
return nil
}
// problemLines are the lines of a module check's output that name a problem: not a manifest found ok, not
// the count, not the closing note.
func problemLines(s string) []string {
@@ -1794,20 +1758,20 @@ func groupDir(spec CheckSpec, root, tree, repo string) string {
// to), and false leaves the judge to the rules before it.
//
// - A member with a mesh-controller sibling is judged by the controller built from that sibling's merge (read beside
// the check), with the node-engine's validator from the member's own change when it is mesh-host's, else from a
// mesh-host sibling's merge, else the one that controller vendors.
// - A mesh-controller member is judged by itself, with a mesh-host sibling's validator in place of the one it vendors.
// the check), with the validator that controller takes from mesh-sdk at its pin.
// - A mesh-controller member is judged by itself, and a mesh-host sibling changes nothing of it: the node-engine holds
// no validator any more (issue 1391, novox/hq ADR 0446 clause 5).
//
// **The judge is unreviewed code** and is built where nothing the change's script does can reach it: from a copy of the
// merge made apart from the workspace's tree, with the judge-build environment (JudgeBuildEnv) — a home and Go cache of
// its own, no global or system git configuration, no version stamping from git — and kept in the judge cache, which no
// check's container mounts, only for the same inputs: the controller merge and the base commits it was merged onto, the
// validator's source and commit.
// controller's pin of the validator.
func judgeFromTheGroup(ctx context.Context, labelled, run Runner, spec CheckSpec, root, tree string, judged CheckVerdict,
said *siblingJudgement, inToolchain func(string, []string, ...string) []string,
say func(step, format string, args ...any)) (string, string, bool, error) {
controller, host := siblingIn(spec, "mesh-controller"), siblingIn(spec, "mesh-host")
var source, validatorDir, from, validator string
controller := siblingIn(spec, "mesh-controller")
var source, from, validator string
var inputs []string
merge := func(dir string, s *Sibling) string {
return fmt.Sprintf("sibling %s#%d merge %s", s.Repository, s.Number, judged.Beside[dir])
@@ -1815,33 +1779,19 @@ func judgeFromTheGroup(ctx context.Context, labelled, run Runner, spec CheckSpec
switch {
case len(spec.Group) > 0 && groupDir(spec, root, tree, "mesh-controller") != "":
// **A delivery group's composed check is judged by the group's own controller** (novox/hq ADR 0239 §14), whatever
// base it merges into: the member that moves mesh-controller, as merged, with the validator of the group's mesh-host member's
// merge when it has one, else the one that controller vendors.
source, validatorDir = groupDir(spec, root, tree, "mesh-controller"), groupDir(spec, root, tree, "mesh-host")
// base it merges into: the member that moves mesh-controller, as merged, with the validator it takes from mesh-sdk at
// its pin. A mesh-host member brings no validator (issue 1391), and its tree need hold none.
source = groupDir(spec, root, tree, "mesh-controller")
from = "the group's own controller, merge " + headAt(ctx, run, source)
validator = "the validator the group's controller vendors"
if validatorDir != "" {
validator = "the group's mesh-host merge " + headAt(ctx, run, validatorDir) + "'s validator"
}
validator = "mesh-sdk's validator at the pin of the group's controller"
inputs = append(inputs, "group member "+spec.Repo+" "+judged.Head+" onto "+judged.Trunk)
for _, m := range judged.Members {
inputs = append(inputs, "group member "+m.Repo+" "+m.Head+" onto "+m.Trunk)
}
case spec.Judge == "self" && host != nil:
source, validatorDir = tree, filepath.Join(root, "mesh-host")
from = "this change's own merge " + judged.Head
validator = merge("mesh-host", host) + "'s validator"
case spec.Judge != "self" && controller != nil:
source = filepath.Join(root, "mesh-controller")
from = merge("mesh-controller", controller)
switch {
case spec.Judge == "validator":
validatorDir, validator = tree, "the change's own validator"
case host != nil:
validatorDir, validator = filepath.Join(root, "mesh-host"), merge("mesh-host", host)+"'s validator"
default:
validator = "the validator " + merge("mesh-controller", controller) + " vendors"
}
validator = "mesh-sdk's validator at the pin of " + merge("mesh-controller", controller)
default:
return "", "", false, nil
}
@@ -1851,9 +1801,6 @@ func judgeFromTheGroup(ctx context.Context, labelled, run Runner, spec CheckSpec
// A merge made for a check is a new commit each time (its time is in it); what it holds is the same for the same
// heads and bases, so the key names those and the trees the judge is built from.
inputs = append(inputs, "member "+judged.Head+" onto "+judged.Trunk, "controller tree "+treeAt(ctx, run, source))
if validatorDir != "" {
inputs = append(inputs, "validator tree "+treeAt(ctx, run, validatorDir))
}
sum := sha256.Sum256([]byte(strings.Join(inputs, "\n")))
key := "siblings-" + hex.EncodeToString(sum[:16])
bin := filepath.Join(root, "bin", "judge-of-the-group")
@@ -1867,14 +1814,6 @@ func judgeFromTheGroup(ctx context.Context, labelled, run Runner, spec CheckSpec
if err := copyCheckout(ctx, run, source, src); err != nil {
return "", "", true, fmt.Errorf("the controller that judges (%s) could not be copied: %w", from, err)
}
if validatorDir != "" {
vendored := filepath.Join(src, "vendor", "github.com", "novox", "mesh-host")
for _, pkg := range []string{"validate", filepath.Join("internal", "declaration")} {
if err := replaceGoFiles(filepath.Join(validatorDir, pkg), filepath.Join(vendored, pkg)); err != nil {
return "", "the validator (" + validator + ") could not be put in the judge: " + err.Error(), true, nil
}
}
}
if _, err := labelled(ctx, root, "docker", inToolchain(src, nil,
"go", "build", "-o", bin, "./cmd/mesh-controller")...); err != nil {
return "", "the controller that judges (" + from + ") does not build with " + validator + ": " + firstLine(err.Error()),
-21
View File
@@ -3,7 +3,6 @@ package builder
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"time"
@@ -82,26 +81,6 @@ func TestAScriptDeclaresItsToolchain(t *testing.T) {
}
}
// A node-engine change's validator is put in place of the one the judge vendors: its Go files, never its tests.
func TestTheChangesValidatorReplacesTheVendoredOne(t *testing.T) {
from, into := t.TempDir(), t.TempDir()
for name, body := range map[string]string{"v.go": "package validate // new", "v_test.go": "package validate"} {
if err := os.WriteFile(filepath.Join(from, name), []byte(body), 0o644); err != nil {
t.Fatal(err)
}
}
if err := os.WriteFile(filepath.Join(into, "old.go"), []byte("package validate // old"), 0o644); err != nil {
t.Fatal(err)
}
if err := replaceGoFiles(from, into); err != nil {
t.Fatal(err)
}
got, _ := filepath.Glob(filepath.Join(into, "*.go"))
if len(got) != 1 || filepath.Base(got[0]) != "v.go" {
t.Fatalf("the vendored validator holds %v", got)
}
}
// aJudge is a controller that judges as told: `merge-gate` answers a warning, `module check` refuses a
// manifest that says it is broken. What the gate layer is tested against without building the real one.
var aJudge = map[string]string{