From 9d2816d001a8c135dc789f96ee672f3d8ffa6294 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 3 Nov 2026 23:42:18 +0100 Subject: [PATCH] =?UTF-8?q?The=20module=20offering=20bus-state=20never=20w?= =?UTF-8?q?aits=20on=20bus=20state=20itself,=20and=20an=20offline=20node's?= =?UTF-8?q?=20build=20offers=20nothing=20(ADR=200614=20=C2=A75;=20issue=20?= =?UTF-8?q?774)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bus module that both offers and asks bus state waited on itself for good at its first such build; it now waits on nobody for it, as the graph and catalogue.Awaited leave a module's own provision out. Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn --- .../cmd/mesh-delivery-assigner/pass_test.go | 10 ++++++++++ .../mesh-delivery-assigner/internal/assign/verbs.go | 6 ++++-- .../internal/assign/wants_test.go | 4 ++++ 3 files changed, 18 insertions(+), 2 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 c3486869..ec5f1bc0 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 @@ -1072,4 +1072,14 @@ func aWantWaitsOnTheVerbEdgesTheGraphKeeps(t *testing.T) { t.Errorf("served(%s) = %v, want %v: the running server's manifest serves w alone, late's is not read", v, served(v), want) } } + // 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. + 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(context.Background(), get, bus, assign.Nodes{Online: map[string]bool{"n2": online}, + Haves: map[string]map[string]delivery.Have{"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)) + } + } } diff --git a/modules/mesh-delivery-assigner/internal/assign/verbs.go b/modules/mesh-delivery-assigner/internal/assign/verbs.go index f41d4360..86466d74 100644 --- a/modules/mesh-delivery-assigner/internal/assign/verbs.go +++ b/modules/mesh-delivery-assigner/internal/assign/verbs.go @@ -27,9 +27,11 @@ func (m Module) verbWaiting(node string) (string, bool) { // bus-state entry, as the module graph reads it) and no build whose manifest offers bus-state runs healthy on a node // present. The provision bus-state is answered with no credential of a consumer's own, so ADR 0603 §5 counts the // provider's own have and no provisioner key is waited for, handed or not. Nil Offering (nothing read of what runs) waits -// for none. It holds under the provisions' rule, its words naming bus state (graph.BusStateWaitWords). +// for none, and neither does a module that offers bus-state itself. It holds under the provisions' rule, its words naming bus state (graph.BusStateWaitWords). func (m Module) busStateWaiting(node string) (string, bool) { - if len(m.Manifest.BusState) == 0 || m.Offering == nil || m.Offering(graph.BusState) { + if len(m.Manifest.BusState) == 0 || m.Offering == nil || m.Offering(graph.BusState) || + slices.Contains(m.Manifest.Offers(), graph.BusState) { // the bus module offering it waits on nobody for it + return "", false } return graph.BusStateWaitWords(m.Name, node), true diff --git a/modules/mesh-delivery-assigner/internal/assign/wants_test.go b/modules/mesh-delivery-assigner/internal/assign/wants_test.go index 96f86432..5e61414d 100644 --- a/modules/mesh-delivery-assigner/internal/assign/wants_test.go +++ b/modules/mesh-delivery-assigner/internal/assign/wants_test.go @@ -161,6 +161,7 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) { // ADR 0614 §5: a module asking bus state is held while no build offering bus-state runs, and moves once one does. {"bus state no running build offers", nil, nil, false, graph.BusState}, {"bus state a running build offers", nil, []string{graph.BusState}, false, ""}, + {"bus state its own module offers", nil, nil, false, ""}, } { m, n := ready() m.Invokes = c.invokes @@ -170,6 +171,9 @@ func TestEachRuleHoldsTheWantBack(t *testing.T) { if strings.HasPrefix(c.name, "bus state") { m.Manifest.BusState = []catalogue.BusStateEntry{{Name: "cache", Storage: "key-value"}} m.Offering = func(p string) bool { return slices.Contains(c.served, p) } + if c.name == "bus state its own module offers" { + m.Manifest.Provides = []catalogue.Offer{{Name: graph.BusState, Scope: catalogue.ScopeMesh}} + } } words := graph.VerbWaitWords(c.holds, "mail", "g14") if c.holds == graph.BusState {