A-3 judge and claim: the same call again runs once on the router's record of its Approve
The gate sits on both handlers the runner serves, a module's tools (its ledger repairs among them) and the seat verbs its modules hold, before the bundle. The same call again is judged on the router's own record of its act's newest ask: held to the warrant (operatorchannelclient.For), the option and the act it bound (Performs), within 30 minutes of the choice, and claimed by compare-and-set (Client.Take) before it runs, so one approval runs one call. A later call is told it still waits, was declined (not asked again for 10 minutes), or asks anew after expired, approved too long ago or already run. A runner's own tool marked is refused unasked; with no state approvals bound a marked call is refused and an unmarked one runs. The gate's reach (state, publish, the router's record) is the runner's own connection, in one place; it waits for the catalog half's first view on the events the runner hears. Builds: design 46 7-approval-mark §13, §14, §15, §17, §20 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
|
||||
"github.com/novox/mesh-tools/node-tools/internal/approval"
|
||||
"github.com/novox/mesh-tools/node-tools/internal/bus"
|
||||
)
|
||||
|
||||
// The gate's reach through the runner's own connection, in this one place (design 46 7-approval-mark §7, §13, §14): its
|
||||
// state approvals, its publish of an ask under the marked module's name, and its read of the router's record.
|
||||
|
||||
// approvalsState is the runner's state approvals over its connection: a lost compare-and-set is stdio.ErrChanged, as
|
||||
// operator-channel's client reads it.
|
||||
type approvalsState struct {
|
||||
conn *bus.Conn
|
||||
module string
|
||||
}
|
||||
|
||||
func (s approvalsState) Get(key string) (*stdio.StateEntry, error) {
|
||||
e, err := s.conn.StateGet(s.module, approval.StateName, key)
|
||||
if err != nil || e == nil {
|
||||
return nil, err
|
||||
}
|
||||
return &stdio.StateEntry{Key: e.Key, Value: e.Value, Revision: e.Revision, At: e.At}, nil
|
||||
}
|
||||
|
||||
func (s approvalsState) Create(key string, value any) (uint64, error) {
|
||||
raw, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return changedAs(s.conn.StateCreate(s.module, approval.StateName, key, raw))
|
||||
}
|
||||
|
||||
func (s approvalsState) Update(key string, value any, revision uint64) (uint64, error) {
|
||||
raw, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return changedAs(s.conn.StateUpdate(s.module, approval.StateName, key, raw, revision))
|
||||
}
|
||||
|
||||
func (s approvalsState) Put(key string, value any) (uint64, error) {
|
||||
raw, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return s.conn.StatePut(s.module, approval.StateName, key, raw)
|
||||
}
|
||||
|
||||
func (s approvalsState) Keys() ([]string, error) {
|
||||
return s.conn.StateKeys(s.module, approval.StateName)
|
||||
}
|
||||
|
||||
func changedAs(rev uint64, err error) (uint64, error) {
|
||||
if errors.Is(err, bus.ErrStateChanged) {
|
||||
return 0, stdio.ErrChanged
|
||||
}
|
||||
return rev, err
|
||||
}
|
||||
|
||||
// Bound says the runner's membership binds its state approvals now (§13): a membership issued later binds it with no restart.
|
||||
func (s approvalsState) Bound() bool {
|
||||
m := s.conn.Membership(s.module)
|
||||
if m == nil {
|
||||
return false
|
||||
}
|
||||
for _, st := range m.State {
|
||||
if st.Name == approval.StateName && st.Writes {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// publishAsk says an accept on a seat under the module's name, on the runner's own account (§7).
|
||||
func publishAsk(conn *bus.Conn) func(module, subject string, body any, id string) error {
|
||||
return func(module, subject string, body any, id string) error {
|
||||
raw, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = conn.SeatPublish(module, subject, raw, id)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// routerRecord reads the router's record `<module>.<id>` of the seat's state asks, on the runner's own account (§14).
|
||||
func routerRecord(conn *bus.Conn) func(module, id string) (*stdio.StateEntry, error) {
|
||||
return func(module, id string) (*stdio.StateEntry, error) {
|
||||
e, err := conn.SeatRecord(module, "", id)
|
||||
if err != nil || e == nil {
|
||||
return nil, err
|
||||
}
|
||||
return &stdio.StateEntry{Key: e.Key, Value: e.Value, Revision: e.Revision, At: e.At}, nil
|
||||
}
|
||||
}
|
||||
@@ -75,8 +75,9 @@ func main() {
|
||||
// ADR 0615 §1; design 46 7-approval-mark §5).
|
||||
source, stopViews := firstview.Start(context.Background(), conn, log.Printf)
|
||||
defer stopViews()
|
||||
gate := approval.New(approval.Deps{Node: conn.Node(), Runner: cred.Module, Catalog: source.ApprovalCatalog(definitionsOf(seatList)),
|
||||
Findings: source.Findings(), Logf: log.Printf})
|
||||
gate := approval.New(approval.Deps{Node: conn.Node(), Runner: cred.Module, Catalog: source.ApprovalCatalog(definitionsOf(seatList)), Wait: source.WaitCatalog,
|
||||
Findings: source.Findings(), Logf: log.Printf, State: approvalsState{conn: conn, module: cred.Module},
|
||||
Publish: publishAsk(conn), Record: routerRecord(conn)})
|
||||
opts = append(opts, runtime.WithGate(gate))
|
||||
stop, err := runtime.Run(conn, served, envs, log.Printf, opts...)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user