Work out a node's declared packages and their difference with the mirror in the SDK, so each engine writes its own key (ADR 0565 clause 6, issue 1953)

The engine composes its node's wants itself, so the derivation the controller keeps
privately moves beside the layout: DeclaredPackagesOf gives the mirror's bytes from the
compositions, DiffDeclaredPackages what the node seat's verb packages compares until the
lease write, and EnginePackagesRead names the state as readers declare it (mesh-host.packages,
as mesh-host.data). Each engine may read the controller mirror's key of its own node alone.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-01 16:02:06 +01:00
parent 67354f8e01
commit 0ef7c0caa4
5 changed files with 184 additions and 3 deletions
+8 -1
View File
@@ -96,6 +96,9 @@ func engineBeyond(user, g string) bool {
strings.Contains(g, "KV_"+EngineActsBucket) || strings.HasPrefix(g, "$KV."+EngineActsBucket+"."+node+".") ||
// And its node's declared packages (novox/hq ADR 0565 clause 6).
strings.Contains(g, "KV_"+EnginePackagesBucket) || g == "$KV."+EnginePackagesBucket+"."+node ||
// And, read, the controller's mirror's key of its node, until the lease write (novox/hq ADR 0565 clause 6).
strings.Contains(g, "KV_"+DeclaredPackagesBucket) && !strings.HasPrefix(g, "$KV.") &&
(!strings.Contains(g, "$KV.") || strings.HasSuffix(g, "$KV."+DeclaredPackagesBucket+"."+node)) ||
// And its own health report (issue 774).
strings.Contains(g, "KV_"+delivery.NodeHealthBucket) || g == "$KV."+delivery.NodeHealthBucket+"."+node ||
// And the provisions of its node's modules, read (novox/hq ADR 0570 clause 6).
@@ -815,7 +818,11 @@ func healthChecks(t *testing.T) {
MayPublish(perms, "$KV.mesh-host_health.b")) {
t.Errorf("the watchman reads the health reports %v, %v", MayPublish(perms, "$JS.API.DIRECT.GET.KV_mesh-host_health.$KV.mesh-host_health.b"), perms.Publish)
}
if u.Kind == KindNode && (!MayPublish(perms, "$KV.mesh-host_packages.a") || MayPublish(perms, "$KV.mesh-host_packages.b")) {
// ADR 0565 clause 6: and it reads the controller's mirror's key of its own node alone, and writes none of it.
if u.Kind == KindNode && (!MayPublish(perms, "$KV.mesh-host_packages.a") || MayPublish(perms, "$KV.mesh-host_packages.b") ||
!MayPublish(perms, "$JS.API.DIRECT.GET.KV_mesh-controller_declared-packages.$KV.mesh-controller_declared-packages.a") ||
MayPublish(perms, "$JS.API.DIRECT.GET.KV_mesh-controller_declared-packages.$KV.mesh-controller_declared-packages.b") ||
MayPublish(perms, "$KV.mesh-controller_declared-packages.a")) {
t.Errorf("node %s writes the packages keys %v", u.Node, perms.Publish)
}
if u.Kind == KindModule && MayPublish(perms, "$KV.mesh-delivery-assigner_policies.x") {
+3 -1
View File
@@ -74,9 +74,11 @@ func engineGrants(p Principal) (pub, sub []string) {
if own, err := NodeKeysGrants(EngineDataBucket, p.Node); err == nil {
pub = append(pub, own...)
}
// And its node's declared packages, its own key alone (ADR 0565 clause 6).
// And its node's declared packages, its own key alone (ADR 0565 clause 6); and, read, the controller's mirror's key
// of its node, which the node seat's verb packages compares it with until the lease write ends the mirror.
if safeSubject.MatchString(p.Node) {
pub = append(pub, EnginePackagesGrants(p.Node)...)
pub = append(pub, readGrants(DeclaredPackagesBucket, p.Node)...)
}
return append(pub, tp...), append(sub, ts...)
}
+2 -1
View File
@@ -288,7 +288,8 @@ var WritersTable = []WriterRow{
KeptIn: "key-value " + PredefinedBucket, Others: "read through `reads` as mesh-controller." + MirrorPredefined,
Subjects: kvOf(PredefinedBucket), Writes: isController},
{State: "the declared-packages mirror", Writer: "controller (lease holder), from the composition of each node, only on a change",
KeptIn: "key-value " + DeclaredPackagesBucket, Others: "read through `reads` as mesh-controller." + MirrorDeclaredPackages,
KeptIn: "key-value " + DeclaredPackagesBucket, Others: "read through `reads` as mesh-controller." + MirrorDeclaredPackages +
", and each node's engine its node's key, until the lease write (ADR 0565 clause 6)",
Subjects: kvOf(DeclaredPackagesBucket), Writes: isController},
// What a machine's provisioner client placed of a module's files (novox/hq ADR 0349 §4, design 57 P6): its own
// machine's word alone, which a walk's end and a gate wait for (ADR 0362, ADR 0349 §15). Kept newest per module