Carry every node's name on a check ask to the names check, so no repository lists them (ADR 0567 §12, issue 1126)

This commit is contained in:
2026-10-28 18:13:57 +01:00
parent fed64292f0
commit 004bbc2ce2
4 changed files with 39 additions and 1 deletions
+3
View File
@@ -200,6 +200,9 @@ func (s AskSteps) level(ctx context.Context, job delivery.CheckJob, level string
if runner != "" {
args["runner"] = runner
}
if len(job.NodeNames) > 0 {
args[delivery.NodeNamesArg] = job.NodeNames // the names check's (ADR 0567 §12)
}
return args
}
test := func(args map[string]any) (bool, error) {
+7
View File
@@ -143,6 +143,13 @@ test {"level":"unit","packages":["x/pkg/a"],"workspace":"/w"}`
t.Fatalf("the unit level %+v", u)
}
// ADR 0567 §12: a check's node names reach the test tool, for the names check.
r.calls = nil
if _, err := RunAsk(context.Background(), r.steps(), ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, NodeNames: []string{"anchor"},
Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})); err != nil || !strings.Contains(strings.Join(r.calls, "\n"), `"node-names":["anchor"]`) {
t.Fatalf("the node names are not handed to the test tool: %v, %v", r.calls, err)
}
// Issue 890/AC2: a package declaring node-build-node is not tested on a node that lacks it but named unmet, and is
// tested on a node that has it.
for _, has := range []bool{false, true} {
+19
View File
@@ -340,8 +340,20 @@ type CheckJob struct {
// Packages, when set, are the only packages each level tests (issue 890, ADR 0552 §4): a placed ask names the
// packages the first ask left unmet, and the others are neither tested nor taken kept, so nothing is judged twice.
Packages []string `json:"packages,omitempty"`
// NodeNames are the names of every node with a record (novox/hq ADR 0567 §12), read by the checker from each
// `<node>.node` of node-engine's have: the names check of ADR 0507 §9 looks for them in the tree, so no repository
// has to list them. The build step hands them to its test tool as the argument NodeNamesArg, and the build module
// gives them to the tests in NodeNamesEnv.
NodeNames []string `json:"node-names,omitempty"`
}
// NodeNamesArg is the test tool's argument that carries a check's node names, and NodeNamesEnv the environment
// variable a build module sets for the tests it runs from it, the names separated by commas.
const (
NodeNamesArg = "node-names"
NodeNamesEnv = "MESH_NODE_NAMES"
)
func (a StepAsk) check() error {
if err := checkAskID(a.ID); err != nil {
return err
@@ -447,6 +459,13 @@ func (c CheckJob) check(id string) error {
return fmt.Errorf("delivery: the check ask %s names a package %q that is no import path", id, p)
}
}
seen := map[string]bool{}
for _, n := range c.NodeNames {
if err := checkName("node", n); err != nil || strings.Contains(n, ",") || seen[n] {
return fmt.Errorf("delivery: the check ask %s names the node %q, which is no node name or named twice", id, n)
}
seen[n] = true
}
return checkFetchArgs(id, c.Fetch)
}
+10 -1
View File
@@ -24,7 +24,8 @@ func checkAsk() StepAsk {
return StepAsk{ID: "mh3k2x9qa1b2c4", Kind: AskCheck, Language: AskNode, Asker: "mesh-delivery-checker",
At: time.Date(2026, 10, 23, 13, 0, 0, 0, time.UTC),
Check: &CheckJob{Fetch: map[string]any{"repository": "novox/mesh-catalog", "commit": askCommit, "ref": "refs/pull/3/head", "base": askCommit},
Levels: []string{LevelUnit, LevelIntegration}, Kept: true, Runner: "workspace", RunnerWhen: "modules/mesh-build-go/", Run: ""}}
Levels: []string{LevelUnit, LevelIntegration}, Kept: true, Runner: "workspace", RunnerWhen: "modules/mesh-build-go/", Run: "",
NodeNames: []string{"anchor", "laptop"}}}
}
// 1887/A1a: an ask encodes and decodes with every field.
@@ -65,6 +66,14 @@ func TestAskRefusesUnknownKindAndLanguage(t *testing.T) {
t.Errorf("%s: encoded", name)
}
}
// ADR 0567 §12: a check's node names are each a node name, once.
for _, names := range [][]string{{"anchor", "anchor"}, {"a.b"}, {""}, {"a,b"}} {
c := checkAsk()
c.Check.NodeNames = names
if _, err := EncodeStepAsk(c); err == nil {
t.Errorf("the node names %q: encoded", names)
}
}
// A copy alone fetches nothing and needs no path.
a := buildAsk()
a.Build.Fetch, a.Build.Path, a.Build.Artifacts = nil, "", []AskArtifact{{Artifact: "base", From: "registry/x@sha256:00"}}