From bc8126efefa9188a6c54e1bab126ba304a451de3 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 13 Nov 2026 13:11:28 +0100 Subject: [PATCH] =?UTF-8?q?Count=20a=20bus=20module's=20running=20build=20?= =?UTF-8?q?as=20offering=20bus-state=20while=20its=20newer=20build=20waits?= =?UTF-8?q?=20for=20a=20yes=20(ADR=200614=20=C2=A75,=20A-352)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A have in phase waiting-yes keeps the build that still runs and that build's health (the node-engine writes the running fingerprint and composition, and its check's health), and that build serves the bus state. So the bus-state rule no longer holds a consumer that needs none of the newer build's forms: live, zfs on ace waited while nats on novox waited for a yes with its old build running. A consumer of a form only the newer build reads still waits by its kind-4 edge (§50), unchanged. Builds: ADR 0614 §5 and §2, A-352 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- .../cmd/mesh-delivery-assigner/pass_test.go | 15 ++++++++++----- .../cmd/mesh-delivery-assigner/verbs.go | 6 ++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/pass_test.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/pass_test.go index f29693ec..97d0d04c 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/pass_test.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/pass_test.go @@ -1391,13 +1391,18 @@ func aWantWaitsOnTheVerbEdgesTheGraphKeeps(t *testing.T) { } } // ADR 0614 §5: bus-state counts as offered only from a healthy build on a node present; the bus module's build on an - // offline node offers nothing, and one whose manifest is not read counts its trunk manifest's offer. + // offline node offers nothing, and one whose manifest is not read counts its trunk manifest's offer. A-352: a have waiting + // for a person's yes on a newer build names the build that still runs, healthy, and it offers bus-state too. bus := map[string]catalogue.Manifest{"bus": {Module: "bus", Provides: []catalogue.Offer{{Name: graph.BusState, Scope: catalogue.ScopeMesh}}}} for _, online := range []bool{false, true} { - offering := p.offering(bus, assign.Nodes{Online: map[string]bool{"n2": online}, - Haves: map[string]map[string]nodeengine.HaveByNodeModuleValue{"n2": {"bus": at(fp("2"))}}}) - if offering(graph.BusState) != online { - t.Errorf("with the bus module's node online %v, bus-state offered %v", online, offering(graph.BusState)) + for _, phase := range []string{nodeengineclient.PhaseRunning, nodeengineclient.PhaseWaitingYes} { + h := at(fp("2")) + h.Phase = phase + offering := p.offering(bus, assign.Nodes{Online: map[string]bool{"n2": online}, + Haves: map[string]map[string]nodeengine.HaveByNodeModuleValue{"n2": {"bus": h}}}) + if offering(graph.BusState) != online { + t.Errorf("with the bus module's node online %v in phase %s, bus-state offered %v", online, phase, offering(graph.BusState)) + } } } } diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/verbs.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/verbs.go index 35a3c35f..369b2c81 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/verbs.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/verbs.go @@ -59,7 +59,9 @@ func (p *passer) served(g graph.Graph, n assign.Nodes) func(string) bool { } // offering is, for this pass, whether a build whose manifest offers a provision runs healthy on a node present (ADR 0603 -// §5, ADR 0614 §5): every running healthy have on an online node, its build's manifest read as servesOf reads it. A +// §5, ADR 0614 §5): every running healthy have on an online node, its build's manifest read as servesOf reads it. A have +// waiting for a person's yes on a newer build counts too: it names the build that still runs and that build's health, and +// that build serves what it offers (A-352); a consumer needing the newer build's forms waits by its kind-4 edge instead. A // healthy build whose manifest cannot be read counts what its module's trunk manifest offers, so a build read late never // holds a consumer for good. func (p *passer) offering(trunk map[string]catalogue.Manifest, n assign.Nodes) func(string) bool { @@ -69,7 +71,7 @@ func (p *passer) offering(trunk map[string]catalogue.Manifest, n assign.Nodes) f continue } for module, h := range haves { - if h.Phase != nodeengineclient.PhaseRunning || h.Health != nodeengineclient.HealthOK { + if h.Phase != nodeengineclient.PhaseRunning && h.Phase != nodeengineclient.PhaseWaitingYes || h.Health != nodeengineclient.HealthOK { continue } m, ok := p.manifestOf(module, h.Fp)