Let one hand act warrant a retirement of several consumers

mesh-hand-acts records one what per act, so an approve of two consumers
could never be warranted. The judge reads each word of the act's what as a
name, and nox records one act listing the consumers (issue 1126 review 1).

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 12:29:56 +01:00
parent 0f0ec66e9a
commit 9e9877e6ec
2 changed files with 11 additions and 2 deletions
@@ -8,7 +8,7 @@ package main
// - the operator's account: a caller the runtime proves as `person.<name>`; or
// - a recorded hand act: any other proven caller names (`act`) the hand act it recorded through mesh-hand-acts for
// this verb, read back here by its id: recorded by that same caller, within HandActWithin, for this verb, and
// naming what it acts on when the verb acts on something named.
// naming what it acts on when the verb acts on something named (several names in one act's what, space-separated).
//
// Nothing else passes: an unproven caller, a module with no act, an act of another caller, verb or subject. A `by`
// argument is a word, never the proof (actOf keeps it beside the proven caller).
@@ -65,8 +65,13 @@ func JudgeSensitive(read ActReader, now func() time.Time, caller, verb, act stri
case a.Verb != verb && !strings.HasSuffix(a.Verb, "."+verb):
return fmt.Errorf("%s: the hand act %s is %q: it warrants no %s", verb, act, a.Verb, verb)
}
// mesh-hand-acts records one what; an act for several names lists them space-separated, so each word is a name.
var named []string
for _, arg := range a.Args {
named = append(named, strings.Fields(arg)...)
}
for _, name := range about {
if !slices.Contains(a.Args, name) {
if !slices.Contains(named, name) {
return fmt.Errorf("%s: the hand act %s names %s, not %s", verb, act, strings.Join(a.Args, " "), name)
}
}
@@ -16,6 +16,8 @@ func TestEachSensitiveVerbJudgesItsOwnCaller(t *testing.T) {
"old": {ID: "old", By: "novox.mesh-healers", At: now.Add(-25 * time.Hour), Verb: "rotate", Args: []string{"own/g14/app/key"}},
"other": {ID: "other", By: "novox.mesh-config", At: now.Add(-time.Hour), Verb: "rotate", Args: []string{"own/g14/app/key"}},
"del": {ID: "del", By: "novox.mesh-healers", At: now.Add(-time.Hour), Verb: "provisioner_delete", Args: []string{"d-app"}},
// As mesh-hand-acts records nox's act: one what, the consumers space-separated (review 1 of issue 1126).
"two": {ID: "two", By: "shanks.node-tools", At: now.Add(-time.Minute), Verb: "mesh-vault.provisioner_retire_approve", Args: []string{"c1 c2"}},
}
read := func(id string) (*HandActSeen, error) {
if a, ok := acts[id]; ok {
@@ -41,6 +43,8 @@ func TestEachSensitiveVerbJudgesItsOwnCaller(t *testing.T) {
{"an act too old", "novox.mesh-healers", SensitiveRotate, "old", []string{"own/g14/app/key"}, "older than"},
{"an act not recorded", "novox.mesh-healers", SensitiveDelete, "none", []string{"d-app"}, "holds no hand act"},
{"a delete's own act", "novox.mesh-healers", SensitiveDelete, "del", []string{"d-app"}, ""},
{"one act for two consumers", "shanks.node-tools", SensitiveRetireApprove, "two", []string{"c1", "c2"}, ""},
{"one act naming two, asked for a third", "shanks.node-tools", SensitiveRetireApprove, "two", []string{"c1", "c3"}, "not c3"},
} {
err := JudgeSensitive(read, clock, row.caller, row.verb, row.act, row.about...)
if (row.want == "") != (err == nil) || (err != nil && !strings.Contains(err.Error(), row.want)) {