warranted takes no word of the caller's: the record is the router's alone (hq ADR 0274 review)
A caller's own line, recorded first under the one id the ask decides, would stand for every node's.
This commit is contained in:
@@ -537,10 +537,10 @@ func (a *verbArguments) commandLine() ([]string, error) {
|
||||
}
|
||||
return argv, nil
|
||||
case "warranted":
|
||||
if err := need("asker", "ask", "what"); err != nil {
|
||||
if err := need("asker", "ask"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []string{"hand-act", "warrant", "--asker", str("asker"), "--ask", str("ask"), str("what")}, nil
|
||||
return []string{"hand-act", "warrant", "--asker", str("asker"), "--ask", str("ask")}, nil
|
||||
case "hand-acts":
|
||||
argv := []string{"hand-acts", "--json"}
|
||||
if d := str("days"); d != "" {
|
||||
|
||||
@@ -2,13 +2,14 @@ package main
|
||||
|
||||
// A module's act on the operator's warrant, recorded in the hand-act log (novox/hq ADR 0274, ADR 0259 §6).
|
||||
//
|
||||
// mesh-controller hand-act warrant --asker <module> --ask <id> <what was done>
|
||||
// mesh-controller hand-act warrant --asker <module> --ask <id>
|
||||
//
|
||||
// The verb `warranted` runs it. A module that asks the operator (an asker) acts on the warrant with its own grants;
|
||||
// the controller's log is where a person's decisions are read back, so the module asks the controller to record
|
||||
// it. **What is recorded is the router's word, never the caller's**: the controller reads the router's own record
|
||||
// of that asker's ask — the bus lets only the router write it — and records who chose, through which channel, with
|
||||
// which proofs, and which answer. The caller gives only what it did, said as its own words. Recorded once per
|
||||
// which proofs, and which answer. The caller gives nothing but which ask: a word of its own, recorded first under
|
||||
// the one id, would stand for every node's (the review of 2026-10-10). Recorded once per
|
||||
// ask, under an id the ask decides, however many of the module's instances ask; an ask still open, ended without
|
||||
// a choice, or another asker's is refused and nothing is written.
|
||||
|
||||
@@ -19,7 +20,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
|
||||
@@ -36,7 +36,7 @@ func warrantedID(asker, ask string) string { return "warrant-" + asker + "-" + a
|
||||
|
||||
// warrantedAct is the entry for an asker's act on the warrant the router recorded for its ask (state, w), or why
|
||||
// none is written.
|
||||
func warrantedAct(asker, ask, what, caller, state string, w *asks.Warrant) (link.HandAct, error) {
|
||||
func warrantedAct(asker, ask, caller, state string, w *asks.Warrant) (link.HandAct, error) {
|
||||
switch {
|
||||
case !askerModule.MatchString(asker):
|
||||
return link.HandAct{}, fmt.Errorf("%q is not a module's name", asker)
|
||||
@@ -44,8 +44,6 @@ func warrantedAct(asker, ask, what, caller, state string, w *asks.Warrant) (link
|
||||
return link.HandAct{}, errors.New("the controller records its own acts on a warrant as it performs them")
|
||||
case !asks.UsableID(ask):
|
||||
return link.HandAct{}, fmt.Errorf("%q is not an ask's id", ask)
|
||||
case strings.TrimSpace(what) == "":
|
||||
return link.HandAct{}, errors.New("say what was done on the warrant")
|
||||
case state == "" || w == nil:
|
||||
return link.HandAct{}, fmt.Errorf("the router holds no closed record of %s's ask %s", asker, ask)
|
||||
case state == "open":
|
||||
@@ -57,7 +55,7 @@ func warrantedAct(asker, ask, what, caller, state string, w *asks.Warrant) (link
|
||||
case w.AskDigest == "":
|
||||
return link.HandAct{}, fmt.Errorf("the router's warrant for %s's ask %s names no ask digest", asker, ask)
|
||||
}
|
||||
return link.HandAct{ID: warrantedID(asker, ask), Verb: handActWarrant, Args: []string{strings.TrimSpace(what)},
|
||||
return link.HandAct{ID: warrantedID(asker, ask), Verb: handActWarrant, Args: []string{fmt.Sprintf("%s acted on %s, chosen on its ask %s", asker, w.Label, ask)},
|
||||
Why: fmt.Sprintf("%s (ask %s of %s)", w.Says(), ask, asker), By: byWords(*w), Cause: conditions.CauseOperatorAnswer,
|
||||
Via: viaWords(*w), Ask: ask, Proofs: w.Proofs, RequestedBy: asker + ", recorded at the word of " + caller,
|
||||
Outcome: "done by " + asker, At: w.At.UTC()}, nil
|
||||
@@ -94,9 +92,8 @@ func handActWarrantCommand(ctx context.Context, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
what := strings.TrimSpace(strings.Join(positionals, " "))
|
||||
if *asker == "" || *ask == "" || what == "" {
|
||||
return errors.New("hand-act warrant --asker <module> --ask <id> <what was done on the warrant>")
|
||||
if *asker == "" || *ask == "" || len(positionals) > 0 {
|
||||
return errors.New("hand-act warrant --asker <module> --ask <id>: what is recorded is the router's record, and nothing else")
|
||||
}
|
||||
open, err := openStores(ctx)
|
||||
if err != nil {
|
||||
@@ -115,7 +112,7 @@ func handActWarrantCommand(ctx context.Context, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
act, err := warrantedAct(*asker, *ask, what, link.Caller(), state, w)
|
||||
act, err := warrantedAct(*asker, *ask, link.Caller(), state, w)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w. Nothing was recorded", err)
|
||||
}
|
||||
@@ -127,7 +124,7 @@ func handActWarrantCommand(ctx context.Context, args []string) error {
|
||||
fmt.Printf("already recorded as %s: %s\n", act.ID, act.Why)
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("recorded as %s: %s, through %s; %s\n", act.ID, act.Why, act.Via, what)
|
||||
fmt.Printf("recorded as %s: %s, through %s\n", act.ID, act.Why, act.Via)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,15 +21,15 @@ func chosenWarrant() *asks.Warrant {
|
||||
// What is recorded of a module's act on a warrant is the router's word (novox/hq ADR 0274): who chose, how and
|
||||
// with which proofs; the caller gives only what it did. Nothing is recorded without a person's choice.
|
||||
func TestAWarrantIsRecordedFromTheRoutersRecordAlone(t *testing.T) {
|
||||
act, err := warrantedAct("claude-code", "instr-1", "claude-code proposal instr-1 approved on shanks",
|
||||
"node-tools.shanks", "chosen", chosenWarrant())
|
||||
act, err := warrantedAct("claude-code", "instr-1", "node-tools.shanks", "chosen", chosenWarrant())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if act.ID != "warrant-claude-code-instr-1" || act.Verb != handActWarrant || act.Cause != conditions.CauseOperatorAnswer ||
|
||||
act.By != "the operator, as telegram identity 42" || act.Ask != "instr-1" || !slices.Equal(act.Proofs, []string{"P1"}) ||
|
||||
!strings.Contains(act.Why, "the operator, via telegram (user id verified), chose Approve") ||
|
||||
!strings.Contains(act.RequestedBy, "node-tools.shanks") {
|
||||
!strings.Contains(act.RequestedBy, "node-tools.shanks") ||
|
||||
!slices.Equal(act.Args, []string{"claude-code acted on Approve, chosen on its ask instr-1"}) {
|
||||
t.Fatalf("recorded as %+v", act)
|
||||
}
|
||||
for name, c := range map[string]struct {
|
||||
@@ -53,18 +53,21 @@ func TestAWarrantIsRecordedFromTheRoutersRecordAlone(t *testing.T) {
|
||||
return w
|
||||
}},
|
||||
} {
|
||||
if _, err := warrantedAct(c.asker, c.ask, "did it", "x", c.state, c.w()); err == nil {
|
||||
if _, err := warrantedAct(c.asker, c.ask, "x", c.state, c.w()); err == nil {
|
||||
t.Errorf("%s: recorded", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTheWarrantedVerbRunsTheWarrantLineWithoutAWhy(t *testing.T) {
|
||||
argv, err := argvFor("warranted", map[string]any{"asker": "claude-code", "ask": "instr-1", "what": "approved on shanks"})
|
||||
if _, err := argvFor("warranted", map[string]any{"asker": "claude-code", "ask": "instr-1", "what": "a word of the caller's"}); err == nil {
|
||||
t.Error("the caller's own words were taken into the record")
|
||||
}
|
||||
argv, err := argvFor("warranted", map[string]any{"asker": "claude-code", "ask": "instr-1"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !slices.Equal(argv, []string{"hand-act", "warrant", "--asker", "claude-code", "--ask", "instr-1", "approved on shanks"}) {
|
||||
if !slices.Equal(argv, []string{"hand-act", "warrant", "--asker", "claude-code", "--ask", "instr-1"}) {
|
||||
t.Fatalf("%v", argv)
|
||||
}
|
||||
if repairingCommand(argv) != "" {
|
||||
|
||||
Reference in New Issue
Block a user