B-D14b (judge half): a build seat's toolchain stream is kept by the seat its module claims, not by its name

Design 47 at b229f5c4, *A module's registration*, lines 482-485 ("No part fixes a name": every module name a
part needs is read from the catalog graph; ADR 0666 §5): the validator kept the build modules' toolchain streams
(toolchains-go, toolchains-node) until they move by the modules' names. It now keeps them for the module that
claims node-build-go or node-build-node, whichever module that is. The other entries of the list, the node-engine's
module (engineModule) and the indexer's own toolchain watch are not in this commit. Rows in
TestRulesBus/TwoModulesCannotDeclareOneStream (fail without it). Issue 1966.

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ

Builds: design 47 G §364, §428, §535
This commit is contained in:
2026-11-11 14:37:18 +01:00
parent c16e07ba0e
commit 5d3c2c680e
2 changed files with 34 additions and 4 deletions
+24 -4
View File
@@ -5557,20 +5557,40 @@ func StateProblems(m catalogue.Manifest) []string {
// which names no module (issue 774, the operator 2026-11-03).
var streamsKeptUntilMoved = map[string][]string{
"brother": {"device-asks"},
"mesh-build-go": {"toolchains-go"},
"mesh-build-node": {"toolchains-node"},
"mesh-mail": {"mail", "mail-sends"},
"only-office": {"convert-asks"},
"mesh-delivery-checker": {"checks"},
"mesh-delivery-forge-bridge": {"forge"},
}
// PredefinedFormProblems refuses each stream a module declares that streamsKeptUntilMoved does not name for it.
// seatStreamsKeptUntilMoved are the streams kept the same way by the seat their module claims, not by its name: a build
// seat's holder keeps its toolchain reports (`toolchains-go`, `toolchains-node`) whichever module holds the seat, since no
// part fixes a module's name (novox/hq ADR 0666 §5; design 47 *A module's registration*, "No part fixes a name").
var seatStreamsKeptUntilMoved = map[string][]string{
"node-build-go": {"toolchains-go"},
"node-build-node": {"toolchains-node"},
}
// keptUntilMoved is whether a stream of a manifest is one kept until its module moves it: by the module's name, or by a
// seat it claims.
func keptUntilMoved(m catalogue.Manifest, stream string) bool {
if slices.Contains(streamsKeptUntilMoved[m.Module], stream) {
return true
}
for _, c := range m.Claims {
if slices.Contains(seatStreamsKeptUntilMoved[c.Name], stream) {
return true
}
}
return false
}
// PredefinedFormProblems refuses each stream a module declares that is not kept until it moves (keptUntilMoved).
func PredefinedFormProblems(m catalogue.Manifest) []string {
var out []string
for _, s := range m.Streams {
// A stream that keeps its history is one of the bus's predefined forms (novox/hq ADR 0592 §6).
if !s.KeepsHistory() && !slices.Contains(streamsKeptUntilMoved[m.Module], s.Name) {
if !s.KeepsHistory() && !keptUntilMoved(m, s.Name) {
out = append(out, fmt.Sprintf("%s keeps the stream %q, outside the bus's predefined forms: keep it as a state, "+
"a log or an object store, which the runtime reads for the module's tools and others read by `reads`", m.Module, s.Name))
}
@@ -5111,6 +5111,16 @@ func caseTwoModulesCannotDeclareOneStream(t *testing.T) {
if got := PredefinedFormProblems(catalogue.Manifest{Module: "mesh-mail", Streams: a.Streams}); len(got) != 0 {
t.Fatalf("a stream kept until it moves was refused: %v", got)
}
// A build seat's toolchain stream is kept by the seat its module claims, whatever the module's name (ADR 0666 §5): the
// holder of node-build-go keeps toolchains-go; a module of the old holder's name claiming no build seat does not.
toolchains := []catalogue.StreamDeclaration{{Name: "toolchains-go", Events: []string{"toolchain.**"}}}
if got := PredefinedFormProblems(catalogue.Manifest{Module: "a-go-builder", Streams: toolchains,
Claims: []catalogue.Claim{{Name: "node-build-go", Scope: catalogue.ScopeNode}}}); len(got) != 0 {
t.Fatalf("the build seat's holder's toolchain stream was refused: %v", got)
}
if got := PredefinedFormProblems(catalogue.Manifest{Module: "mesh-build-go", Streams: toolchains}); len(got) != 1 {
t.Fatalf("a toolchain stream of a module claiming no build seat was kept by its name: %v", got)
}
}
// A seat name meaning two protocols is the failure nobody could diagnose afterwards.