AM-C1: the operator-channel client puts a key prefix before every key of its own state
Client.KeyPrefix is put before the keys the client writes and reads in its own State; empty for every asker today, so today's keys stay; Where still reads the router's record under <module>.<id>. Builds: design 46 milestone 7 §10, §22 (design 47 G, approval mark) Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
@@ -27,6 +27,9 @@ type Client struct {
|
||||
Module string
|
||||
// State is the module's own state the asks are kept in.
|
||||
State Store
|
||||
// KeyPrefix is put before every key of State the client writes and reads; empty for every asker today, so
|
||||
// today's keys stay (design 46 milestone 7 §10). The router's record Where reads is never prefixed.
|
||||
KeyPrefix string
|
||||
// Now is the clock; nil is time.Now.
|
||||
Now func() time.Time
|
||||
// Publish, Record and Subscribe reach the bus; nil is the stdio SDK's, through the module's runtime.
|
||||
@@ -63,7 +66,7 @@ type Kept struct {
|
||||
Answer *seat.Warrant `json:"answer,omitempty"`
|
||||
}
|
||||
|
||||
func key(id string) string { return "ask." + id }
|
||||
func (c *Client) key(id string) string { return c.KeyPrefix + "ask." + id }
|
||||
|
||||
// Ask checks an ask, keeps it, and publishes it under the module's own name. An ask with an id already kept
|
||||
// is refused: a new question is a new id.
|
||||
@@ -71,7 +74,7 @@ func (c *Client) Ask(a seat.Ask) error {
|
||||
if err := Check(a, c.now()); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.State.Create(key(a.ID), Kept{Ask: a, Asked: c.now()}); err != nil {
|
||||
if _, err := c.State.Create(c.key(a.ID), Kept{Ask: a, Asked: c.now()}); err != nil {
|
||||
if errors.Is(err, stdio.ErrChanged) {
|
||||
return fmt.Errorf("an ask %s was already made: a new question is a new id", a.ID)
|
||||
}
|
||||
@@ -130,7 +133,7 @@ func (c *Client) Take(w seat.Warrant, act func(seat.Option, seat.Warrant) error)
|
||||
if w.Asker != c.Module {
|
||||
return Refused, fmt.Errorf("a warrant for %s reached %s", w.Asker, c.Module)
|
||||
}
|
||||
e, err := c.State.Get(key(w.Ask))
|
||||
e, err := c.State.Get(c.key(w.Ask))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -147,7 +150,7 @@ func (c *Client) Take(w seat.Warrant, act func(seat.Option, seat.Warrant) error)
|
||||
if w.Outcome != OutcomeChosen {
|
||||
k.Ended = w.Outcome
|
||||
k.Answer = &w
|
||||
if _, err := c.State.Update(key(w.Ask), k, e.Revision); err != nil && !errors.Is(err, stdio.ErrChanged) {
|
||||
if _, err := c.State.Update(c.key(w.Ask), k, e.Revision); err != nil && !errors.Is(err, stdio.ErrChanged) {
|
||||
return "", err
|
||||
}
|
||||
return Recorded, nil
|
||||
@@ -158,7 +161,7 @@ func (c *Client) Take(w seat.Warrant, act func(seat.Option, seat.Warrant) error)
|
||||
}
|
||||
// Marked before acting: of two deliveries, or two instances, only the one whose write stands acts.
|
||||
k.Acted, k.Ended, k.Answer = true, OutcomeChosen, &w
|
||||
if _, err := c.State.Update(key(w.Ask), k, e.Revision); err != nil {
|
||||
if _, err := c.State.Update(c.key(w.Ask), k, e.Revision); err != nil {
|
||||
if errors.Is(err, stdio.ErrChanged) {
|
||||
return Done, nil
|
||||
}
|
||||
|
||||
@@ -139,3 +139,25 @@ func TestAnAskEndedWithoutAChoiceIsRecordedAndNothingDone(t *testing.T) {
|
||||
t.Errorf("%s", h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAKeyPrefixIsPutBeforeEveryKeyOfTheClientsOwnStateAndNotBeforeWhere(t *testing.T) {
|
||||
for _, tc := range []struct{ prefix, key string }{{"n1.", "n1.ask.d-1"}, {"", "ask.d-1"}} {
|
||||
c, _ := client()
|
||||
store := c.State.(*mem)
|
||||
c.KeyPrefix = tc.prefix
|
||||
var asked string
|
||||
c.Record = func(k string) (*stdio.StateEntry, error) { asked = k; return nil, nil }
|
||||
if err := c.Ask(askedHeld()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := store.vals[tc.key]; len(store.vals) != 1 || !ok {
|
||||
t.Fatalf("prefix %q: keys written %v, want %s", tc.prefix, store.vals, tc.key)
|
||||
}
|
||||
if h, err := c.Take(askedWarrant(), func(seat.Option, seat.Warrant) error { return nil }); h != Acted || err != nil {
|
||||
t.Fatalf("prefix %q: the warrant was not read from %s: %s %v", tc.prefix, tc.key, h, err)
|
||||
}
|
||||
if _, _, err := c.Where("an-asker.d-1"); err != nil || asked != "an-asker.d-1" {
|
||||
t.Errorf("prefix %q: Where read %q", tc.prefix, asked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user