Record a module's act on the operator's warrant from the router's own record (hq ADR 0274)
A module that asks the operator acts with its own grants, and the hand-act log is where a person's decisions are read back. The new verb warranted records who chose, how and with which proofs from the router's record, never the caller's word, once per ask however many instances ask.
This commit is contained in:
@@ -122,6 +122,33 @@ func RecordHandAct(ctx context.Context, conn *nats.Conn, act HandAct) (HandAct,
|
||||
return act, err
|
||||
}
|
||||
|
||||
// RecordHandActOnce writes one entry under the id it carries, only where none is: an act recorded once however
|
||||
// often it is asked, such as a module's act on a warrant, asked by each of its instances (novox/hq ADR 0274). It
|
||||
// answers false, with no error, when the entry was already there.
|
||||
func RecordHandActOnce(ctx context.Context, conn *nats.Conn, act HandAct) (bool, error) {
|
||||
if act.ID == "" || strings.TrimSpace(act.Why) == "" {
|
||||
return false, errors.New("an act recorded once carries its id and why")
|
||||
}
|
||||
if act.At.IsZero() {
|
||||
act.At = time.Now().UTC()
|
||||
}
|
||||
kv, err := handActs(ctx, conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
body, err := json.Marshal(act)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if _, err := kv.Create(ctx, act.ID, body); err != nil {
|
||||
if errors.Is(err, jetstream.ErrKeyExists) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// HandActs is every entry since a moment, oldest first.
|
||||
func HandActs(ctx context.Context, conn *nats.Conn, since time.Time) ([]HandAct, error) {
|
||||
kv, err := handActs(ctx, conn)
|
||||
|
||||
@@ -57,3 +57,30 @@ func TestNatsAnActByHandIsKeptWithWhyAndARepeatIsFound(t *testing.T) {
|
||||
t.Fatalf("%q", acts[2].ID)
|
||||
}
|
||||
}
|
||||
|
||||
// An act on a warrant asked by each of a module's instances is recorded once (novox/hq ADR 0274).
|
||||
func TestNatsAnActRecordedOnceIsWrittenOnce(t *testing.T) {
|
||||
js := aBus(t)
|
||||
api, err := jetstream.New(js.Conn())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = api.DeleteKeyValue(t.Context(), broker.HandActsBucket)
|
||||
if err := js.EnsureControllerBuckets(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
act := HandAct{ID: "warrant-claude-code-instr-1", Verb: "warrant", Why: "the operator chose Approve", By: "the operator"}
|
||||
if _, err := RecordHandActOnce(t.Context(), js.Conn(), HandAct{Verb: "warrant", Why: "x"}); err == nil {
|
||||
t.Fatal("an act without its id was written")
|
||||
}
|
||||
for i, want := range []bool{true, false, false} {
|
||||
written, err := RecordHandActOnce(t.Context(), js.Conn(), act)
|
||||
if err != nil || written != want {
|
||||
t.Fatalf("ask %d: written %v, %v", i, written, err)
|
||||
}
|
||||
}
|
||||
acts, err := HandActs(t.Context(), js.Conn(), time.Now().Add(-time.Hour))
|
||||
if err != nil || len(acts) != 1 || acts[0].ID != act.ID {
|
||||
t.Fatalf("%v %+v", err, acts)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user