mesh-grants: the machine's runtime hears a node's compositions bucket made later for the bundles it carries

ADR 0593 §6: a bundle such as the provisioner reads mesh-host.composed on the runtime's connection, so the
runtime account gets the stream listing and the creation advisory beside the read of each bucket.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 18:56:19 +01:00
parent 74304052b4
commit d283efdc9f
2 changed files with 16 additions and 0 deletions
@@ -924,6 +924,17 @@ func everyNodesCompositions(t *testing.T) {
if MayPublish(view, "$JS.API.DIRECT.GET.KV_mesh-host_composed.x") {
t.Error("the read is granted as one bucket mesh-host_composed")
}
// A bundle reading them (the provisioner, carried by the machine's runtime) reads them on the runtime's connection.
carried := Principal{Kind: KindNodeTools, Node: "one", Module: RuntimeModule, Nodes: []string{"one", "two"},
Carries: []Declared{{Module: "mesh-provisioner", Reads: []string{delivery.ComposedRead}}}}
runner, err := PermissionsFor(carried)
if err != nil {
t.Fatal(err)
}
if !MayPublish(runner, "$JS.API.STREAM.NAMES") || !MaySubscribe(runner, "$JS.EVENT.ADVISORY.STREAM.CREATED.KV_composed-three") ||
!MayPublish(runner, "$JS.API.DIRECT.GET.KV_composed-two.$KV.composed-two.two.node") {
t.Errorf("the runtime carrying the provisioner cannot read every node's compositions")
}
m := MembershipFor("one", Declared{Module: "mesh-delivery-view", Reads: []string{delivery.ComposedRead}}, Placements{})
if !slices.ContainsFunc(m.State, func(s StateIssued) bool {
return s.Name == delivery.ComposedRead && s.PerNode && s.Bucket == delivery.ComposedBucketPrefix && !s.Writes
@@ -1026,6 +1026,11 @@ func PermissionsFor(p Principal) (Permissions, error) {
for _, d := range p.Carries {
pub = append(pub, stateGrants(stateAccess{Module: d.Module, Node: p.Node, Keeps: stateNames(d.State),
PerMachine: perMachineNames(d.State), Reads: d.Reads, KeyedReads: d.KeyedReads, Nodes: p.Nodes})...)
// A bundle reads every node's compositions on the runtime's own connection (ADR 0593 §6), which hears a node's
// bucket made later by any stream's creation.
if slices.Contains(d.Reads, delivery.ComposedRead) && !slices.Contains(sub, familyCreatedAdvisory) {
sub = append(sub, familyCreatedAdvisory)
}
}
// **And it keeps the logs of the modules it carries** (novox/hq ADR 0297): each module's own, the
// union over them. That one module's code does not append to another's log through it is the