Assigner and grants part: record hand acts and warrants through the seat mesh-hand-acts, the controller's log only while that seat has no holder and the controller holds its lease (issue 1953 D8)

Pins mesh-sdk 2d2aa7b in the L5 modules.
This commit is contained in:
2026-10-29 22:24:00 +01:00
parent 3b6f3af38e
commit 5235bb2e79
15 changed files with 90 additions and 33 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-grants
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029212112-2d2aa7ba9bbd
github.com/nats-io/nats.go v1.54.0
)
+2 -2
View File
@@ -1,5 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635 h1:ImOyj4WqH9lwxOr95aH9Wq2iJkUwdtnEyPrASm9TrYA=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029212112-2d2aa7ba9bbd h1:WhqMEXFZ9Zc+fEfLsnf1jhhGkc4IqMwUpXXwZq+V3+E=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029212112-2d2aa7ba9bbd/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
+7 -2
View File
@@ -1388,9 +1388,14 @@ func TestGrants(t *testing.T) {
row.between()
}
said = nil
calls := len(b.calls)
if err := p.Warranted(row.option, warrant(id)); err != nil {
t.Fatal(err)
}
// 1953/D8 (ADR 0565 §11): a switch made is recorded in the hand-act log's seat; one refused or declined is not.
if recorded := slices.Contains(b.calls[calls:], grants.CallRecordWarrant); recorded != (row.outcome == "recorded") {
t.Errorf("recorded in the hand-act log %v, the act %s", recorded, row.outcome)
}
l := last()
if l.Said != row.outcome || l.Ask != id || p.SwitchState() != row.state {
t.Errorf("the act = %+v, the switch %s; want %s and %s", l, p.SwitchState(), row.outcome, row.state)
@@ -1642,8 +1647,8 @@ func TestGrants(t *testing.T) {
}
}
for _, c := range b.calls {
if c != grants.CallUsers && c != grants.CallStreams {
t.Errorf("called %s: the part calls only the bus module's read tools", c)
if c != grants.CallUsers && c != grants.CallStreams && c != grants.CallRecordWarrant {
t.Errorf("called %s: the part calls only the bus module's read tools, and the hand-act log for a switch", c)
}
}
for _, e := range b.events {
@@ -52,7 +52,7 @@ const (
)
// Invokes is every tool the part calls.
var Invokes = []string{CallUsers, CallUserCan, CallStreams, CallRootFree}
var Invokes = []string{CallUsers, CallUserCan, CallStreams, CallRootFree, CallRecordWarrant, CallRecordWarrantController}
// Reader reads another part's state, named `<module>.<state>`. A refusal (a read not granted yet, a bucket not there) is
// an error the part names as a gap and composes past: it never stops for one.
@@ -1,6 +1,8 @@
package grants
import (
"git.novox.be/novox/mesh-sdk/go/handacts"
"crypto/rand"
"encoding/hex"
"encoding/json"
@@ -378,6 +380,7 @@ func (p *Part) Warranted(o asks.Option, w asks.Warrant) error {
if err := p.finish(s, a); err != nil {
return err
}
p.recordWarrant(w.Ask)
// The bus node turns on the key: written now, so the switch reaches it on the operator's yes (ADR 0547 clause 8).
if err := p.syncFollow(s.State); err != nil {
return fmt.Errorf("the switch is recorded and the key the bus node follows could not be written (the next pass writes it): %w", err)
@@ -512,3 +515,37 @@ func (p *Part) TakeOverState() (any, error) {
}
return out, nil
}
// Module is the grants part's module, the asker of its take-over and hand-back.
const Module = "mesh-grants"
// The hand-act log's verbs the part records its switches by (novox/hq ADR 0565 §11, ADR 0547 §6): the seat's, and the
// controller's while the seat has no holder and the controller holds its lease (handacts.Recorder).
const (
CallRecordWarrant = "seat:" + handacts.Seat + ".warranted"
CallRecordWarrantController = "seat:mesh-controller.warranted"
)
// recordWarrant records, in the hand-act log, that a take-over or a hand-back was made on the operator's warrant for ask.
// Said, never fatal: the switch stands either way.
func (p *Part) recordWarrant(ask string) {
if p.Call == nil {
return
}
rec := handacts.Recorder{Ask: p.Call.Call, LeaseAway: func() bool {
if p.Read == nil {
return false
}
away, _ := leaseHandedAway(p.Read)
return away
}}
taken, err := rec.RecordWarrant(Module, ask)
if p.Logf == nil {
return
}
if err != nil {
p.Logf("the switch on the warrant %s is not recorded in the hand-act log: %v", ask, err)
return
}
p.Logf("the switch on the warrant %s is recorded in the log of %s", ask, taken.Log)
}
+3 -1
View File
@@ -30,7 +30,9 @@
"nats.nats_streams",
"nats.nats_user_can",
"nats.nats_users",
"seat:mesh-controller.root-free"
"seat:mesh-controller.root-free",
"seat:mesh-hand-acts.warranted",
"seat:mesh-controller.warranted"
],
"emits": [
"asserted",