Return a grant not written and retry the take-in under a condition; drop the plans' events; grant bucket-deleted, restic's backup word and the operator's hand path (issue 1945; the review's D1, F1, H1 and its notes)

With no send left nothing else writes a missed grant, so the take-in of a done key returns it and tries again every
half minute under an urgent condition until it is written. plan-moved and sent go with the plans. The controller's
first-start deletions are said on a granted subject, a node hears only its backup holder, and the operator's account
writes the hand path, an object replaced included (ADR 0539 clauses 2, 7, 10 and 13).
This commit is contained in:
2026-10-24 18:30:24 +02:00
parent 76c48fa074
commit f20d221a60
15 changed files with 350 additions and 48 deletions
+42 -1
View File
@@ -65,7 +65,7 @@ func TestANodeAgentAsksItsOwnBackupHolder(t *testing.T) {
t.Errorf("a node-engine of ace may not publish %s", want)
}
}
if !strings.Contains(strings.Join(p.Subscribe, " "), "mesh.mod.*.event.backed-up") {
if !strings.Contains(strings.Join(p.Subscribe, " "), "mesh.mod.restic.event.backed-up") {
t.Errorf("a node-engine of ace does not hear a backup taken: %v", p.Subscribe)
}
if strings.Contains(all, "node-backup.tool.now.*") || strings.Contains(all, "KV_composed-g14") {
@@ -106,3 +106,44 @@ func TestARaiseAfterTheDeclarationsAssertsNoneOfThem(t *testing.T) {
t.Errorf("after the retirement %d streams are asserted, before %d", len(after.streams), len(before.streams))
}
}
// 1945 (the review of A1, (b) and H1): the operator's account, a person who may invoke every tool, writes release 6's
// hand path: a want of any node, each node's compositions, the digests, and a node's object bucket with what replacing
// an object needs; a person with fewer tools writes none of it.
func TestTheOperatorWritesTheHandPath(t *testing.T) {
users, err := Users(Records{Nodes: []string{"ace", "novox"}, People: map[string][]string{"jochen": {"*"}, "guest": {"mesh-controller.status"}}})
if err != nil {
t.Fatal(err)
}
for _, u := range users {
if u.Kind != KindPerson {
continue
}
perms, err := PermissionsFor(u)
if err != nil {
t.Fatal(err)
}
for _, s := range []string{"$KV.mesh-delivery-assigner_wants.want.>", "$KV.composed-ace.>", "$KV.composed-novox.>",
"$KV.mesh-controller_composed.>", "$O.declaration-files-ace.>", "$JS.API.DIRECT.GET.OBJ_declaration-files-ace.>",
"$JS.API.STREAM.MSG.GET.OBJ_declaration-files-ace", "$JS.API.STREAM.PURGE.OBJ_declaration-files-ace"} {
found := false
for _, p := range perms.Publish {
found = found || p == s
}
if found != (u.Module == "jochen") {
t.Errorf("%s may publish %s: %v", u.Module, s, found)
}
}
}
c, err := PermissionsFor(Principal{Kind: KindController, PasswordHash: "x"})
if err != nil {
t.Fatal(err)
}
found := false
for _, p := range c.Publish {
found = found || p == "mesh.seat.mesh-controller.event.bucket-deleted"
}
if !found {
t.Errorf("the controller may not say bucket-deleted")
}
}