fix9-9: the grants part composes the node-engine's state bounds (key write with a time to live, delete, watch) for every node's engine

Builds: design 47 G §560, A-77, A-92

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 01:18:52 +01:00
parent 8fc1997b1b
commit bc1857ec73
5 changed files with 59 additions and 6 deletions
@@ -0,0 +1,34 @@
package buscompose
import "testing"
// Design 47 G A-77, A-92: the node-engine's account is granted the state bounds, to write a bound key with its time to live,
// to delete it, and to watch it for the bus's marker; and no other node-engine state or module's bucket by that grant.
func TestTheNodeEngineIsGrantedItsBoundsState(t *testing.T) {
users, err := Users(Records{Nodes: []string{"one"}, Engine: &Declared{Module: EngineModule}})
if err != nil {
t.Fatal(err)
}
var node Principal
for _, u := range users {
if u.Kind == KindNode {
node = u
}
}
perms, err := PermissionsFor(node)
if err != nil {
t.Fatal(err)
}
for _, want := range []string{
"$KV.mesh-host_bounds.recovery.act-1", "$JS.API.STREAM.INFO.KV_mesh-host_bounds",
"$JS.API.CONSUMER.CREATE.KV_mesh-host_bounds.*.$KV.mesh-host_bounds.recovery.act-1",
"$JS.API.CONSUMER.DELETE.KV_mesh-host_bounds.x",
} {
if !MayPublish(perms, want) {
t.Errorf("the node-engine of one may not publish %s", want)
}
}
if MayPublish(perms, "$KV.other_bounds.recovery.act-1") {
t.Error("the node-engine of one may publish another module's bounds")
}
}
@@ -34,6 +34,17 @@ var EnginePackagesBucket = BucketName(EngineModule, EnginePackagesState)
// condition.
var EngineFindingsBucket = BucketName(EngineModule, "findings")
// EngineBoundsBucket is the engine's state `bounds` (design 47 G §560, A-77, A-92): one key `<what>.<id>` for each bound a wait of a
// node's engine runs against, written with its own time to live by that engine, watched for the bus's marker when it ends and
// deleted when the wait ends first. The key names no node, so each node's engine is granted the whole bucket.
var EngineBoundsBucket = BucketName(EngineModule, "bounds")
// EngineBoundsGrants is what a node's engine publishes to keep a bound: the writes of the bucket's keys (the create with its time to
// live, the delete) and what a watch of them needs.
func EngineBoundsGrants() []string {
return append([]string{"$KV." + EngineBoundsBucket + ".>"}, readGrants(EngineBoundsBucket, "")...)
}
// EngineFindingsGrants is what a node's engine publishes to write and clear its node's findings: its own node's keys alone,
// and their read. Without it the finding that the node waits for the seat list is refused on the bus and never raised.
func EngineFindingsGrants(node string) []string {
@@ -126,5 +137,7 @@ func engineGrants(p Principal) (pub, sub []string) {
if safeSubject.MatchString(p.Node) {
pub = append(pub, EngineFindingsGrants(p.Node)...)
}
// And the bounds of its waits (design 47 G A-77, A-92): the state bounds, written with a time to live and watched.
pub = append(pub, EngineBoundsGrants()...)
return append(pub, tp...), append(sub, ts...)
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -213,6 +213,12 @@ var WritersTable = []WriterRow{
{State: "a machine's data items", Writer: "the node-engine of the machine, under its own keys `<node>.>`",
KeptIn: "key-value " + EngineDataBucket, Others: "read by the node's disk-load through `reads`, its own node's keys alone",
Subjects: kvOf(EngineDataBucket), Writes: ownNodeKeys},
// The bounds of a node's engine's waits (design 47 G A-77, A-92): keys `<what>.<id>` with a time to live of their own, which name no
// node, so every node's engine writes the bucket.
{State: "a node-engine's bounds", Writer: "the node-engine of any machine, keys `<what>.<id>` with a time to live",
KeptIn: "key-value " + EngineBoundsBucket + ", the node-engine's declared state bounds",
Others: "read by nobody but the engines: the bus's marker of an expired key ends the wait", Subjects: kvOf(EngineBoundsBucket),
Writes: func(p Principal, pattern string) bool { return p.Kind == KindNode }},
{State: "a machine's hand acts", Writer: "the node-engine of the machine, under its own keys `<node>.>`, compare-and-set",
KeptIn: "key-value " + EngineActsBucket + ", the node-engine's declared state acts",
Others: "read through the node seat's verb acts", Subjects: kvOf(EngineActsBucket),