diff --git a/modules/mesh-delivery-indexer/judge/rules.go b/modules/mesh-delivery-indexer/judge/rules.go index 46931311..6db28dad 100644 --- a/modules/mesh-delivery-indexer/judge/rules.go +++ b/modules/mesh-delivery-indexer/judge/rules.go @@ -3984,8 +3984,8 @@ func processAccountProblems(m catalogue.Manifest, processID, user string) []stri } // busKeeps says the process resource r's bus declares `keeps` (novox/hq ADR 0626 §1): read from the resource as -// written, since catalogue.ProcessBus does not carry the key yet (a request to mesh-sdk). Any value but false or absent -// counts, so a refusal is never dodged by its spelling. +// written rather than through catalogue.ProcessBus, so any value but false or absent counts and a refusal is never dodged +// by its spelling. func busKeeps(r map[string]any) bool { b, _ := r["bus"].(map[string]any) v, present := b["keeps"] @@ -4050,6 +4050,11 @@ func toolsBusProblems(m catalogue.Manifest) []string { continue } b := *a.Bus + if b.Keeps { + problems = append(problems, fmt.Sprintf("%s's tools bundle %s's bus keeps the bus's entries; only the keeper, the "+ + "process of the module holding %s with its own bus account, may (novox/hq ADR 0626 §1, §3)", m.Module, a.Name, + catalogue.BrokerSeat)) + } if len(b.Queues) > 0 || b.Asks { problems = append(problems, fmt.Sprintf("%s's tools bundle %s's bus consumes a queue or reads asks; a tools "+ "bundle runs per call and holds no consumer (novox/hq ADR 0564 Limits 4)", m.Module, a.Name)) diff --git a/modules/mesh-delivery-indexer/judge/rules_test.go b/modules/mesh-delivery-indexer/judge/rules_test.go index c18ab3bf..3368d42f 100644 --- a/modules/mesh-delivery-indexer/judge/rules_test.go +++ b/modules/mesh-delivery-indexer/judge/rules_test.go @@ -2484,6 +2484,8 @@ func TestAProcessDeclaresItsBusAndIsAccepted(t *testing.T) { {name: "a removal outside the set", manifest: tools(broker, `{"removes":["EVENTS.a_m"]}`), refused: "not one of"}, {name: "a removal beside a grant", manifest: tools(broker, `{"removes":["mesh-host_acts"],"invokes":["nats.nats_streams"]}`), refused: "with nothing else"}, {name: "another module's tools removing", manifest: tools(`[]`, `{"removes":["mesh-host_acts"]}`), refused: "only the bus module"}, + // ADR 0626 §1, §3: only the keeper process keeps the bus's entries, never a tools bundle, the bus module's included. + {name: "the bus module's tools keeping", manifest: tools(broker, `{"keeps":true}`), refused: "only the keeper"}, {name: "a tools bundle consuming a queue", manifest: tools(broker, `{"queues":["x"]}`), refused: "holds no consumer"}, {name: "a process removing", manifest: mailSenderProcessManifest(t, `{"removes":["mesh-host_acts"]}`), refused: "only a tools bundle"}, // The runtime's account reads the account's secret: it lies where others may pass (the host agent, 2026-10-29).