Name the open walk a change is related to, own path related to all (issue 973)

This commit is contained in:
2026-10-17 00:45:00 +02:00
parent 6a62a7e552
commit a5ba47e23c
2 changed files with 78 additions and 1 deletions
+31 -1
View File
@@ -11,7 +11,9 @@ import (
// related when they share a repository, a module, a delivery group's head, or an edge of the module graph
// between their modules. A module is every one the walk builds or sends: the modules its merges moved and the
// modules that depend on them, not only the ones the merges touched. Unrelated changes may walk beside each
// other (ADR 0304 decision 2, ADR 0282 decision 3); nothing walks so yet, and nothing but tests reads this.
// other (ADR 0304 decision 2, ADR 0282 decision 3); a closed batch is cut beside an open walk it is
// not related to, and a walk about to ask its first tier waits only for a started walk it is related to (issue 973,
// ADR 0407 decision 4).
// footprint is what one change reaches: its repositories (lower case), its modules, and its delivery group
// heads (the head branch names of its merges). unknown says a merge of it was kept without the modules it
@@ -109,3 +111,31 @@ func firstShared(a, b map[string]bool) string {
sort.Strings(both)
return both[0]
}
// openWalk is a walk open beside a change: its id, what it reaches, and whether it is on the controller's own path.
type openWalk struct {
id string
fp footprint
own bool
}
// relatedOpen is the first open walk a change is related to, with the reason; empty when it is related to none
// and may walk beside them all (issue 973, ADR 0407 decision 4, ADR 0306 decision 3).
//
// **The controller's own path is related to everything** (decided for issue 973): a walk or batch that replaces
// the controller, the node-engine, the tool runner, the bus or mesh-delivery never runs beside another, and
// nothing runs beside it, whatever the footprints say.
func relatedOpen(cand footprint, candOwn bool, open []openWalk, edges []inventory.Edge) (behind, why string) {
for _, w := range open {
if candOwn {
return w.id, "it is on the controller's own path"
}
if w.own {
return w.id, w.id + " is on the controller's own path"
}
if ok, why := related(cand, w.fp, edges); ok {
return w.id, why
}
}
return "", ""
}
+47
View File
@@ -108,3 +108,50 @@ func TestABatchWhoseMovesAreNotKnownIsRelatedToEverything(t *testing.T) {
t.Fatalf("a known, unrelated batch read as related: %q", why)
}
}
// TestRelatedOpenNamesTheFirstOpenWalkAChangeIsRelatedTo: a change that shares nothing with any open walk is
// held behind none (issue 973, ADR 0407 decision 4); one that shares a repository, a module, a graph edge or a
// group head is held behind the first walk it shares it with, with the reason; one whose moves are not known
// is held behind the first; a walk or change on the controller's own path is related to every other.
func TestRelatedOpenNamesTheFirstOpenWalkAChangeIsRelatedTo(t *testing.T) {
edges := []inventory.Edge{{From: "nzbget", To: "base-image", Kind: inventory.EdgeStandsOn}}
walk := func(id, repo string, own bool, modules ...string) openWalk {
return openWalk{id: id, fp: footprintOfWalk(walkOf(repo, modules...), nil), own: own}
}
one, two := walk("plan-1", "novox/one", false, "notes"), walk("plan-2", "novox/two", false, "nzbget")
cand := func(repo, head string, moves ...string) footprint {
return footprintOfBatch([]inventory.BatchedMerge{heardMerge(repo, head, moves...)}, edges)
}
cases := []struct {
name string
fp footprint
own bool
open []openWalk
behind string
why string
}{
{"nothing open", cand("novox/x", "fix/a", "app"), false, nil, "", ""},
{"unrelated to every open walk", cand("novox/x", "fix/a", "app"), false, []openWalk{one, two}, "", ""},
{"a repository", cand("novox/ONE", "fix/a", "app"), false, []openWalk{two, one}, "plan-1", "both change novox/one"},
{"a module through its dependents", cand("novox/x", "fix/a", "base-image"), false, []openWalk{one, two},
"plan-2", "both move nzbget"},
{"a graph edge", cand("novox/x", "fix/a", "nzbget"),
false, []openWalk{one, walk("plan-3", "novox/y", false, "base-image")}, "plan-3",
"nzbget depends on base-image (stands-on)"},
{"moves not known", cand("novox/x", "fix/a"), false, []openWalk{one, two}, "plan-1",
"the modules a merge of novox/x moves are not known until its batch is cut"},
{"the candidate on the own path", cand("novox/x", "fix/a", "app"), true, []openWalk{one}, "plan-1",
"it is on the controller's own path"},
{"an open walk on the own path", cand("novox/x", "fix/a", "app"), false,
[]openWalk{one, walk("plan-4", "novox/mesh-controller", true, "mesh-controller")}, "plan-4",
"plan-4 is on the controller's own path"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
behind, why := relatedOpen(c.fp, c.own, c.open, edges)
if behind != c.behind || why != c.why {
t.Errorf("relatedOpen = %q, %q; want %q, %q", behind, why, c.behind, c.why)
}
})
}
}