NATS8: the bus module's ask lasts its level's bound and a refused ask ends its request with the router's words
Builds: design 47 G §570 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -145,3 +145,21 @@ func TestAPersonsRequestIsHandedToTheKeeperAsTheProvedCaller(t *testing.T) {
|
||||
t.Errorf("an end not written: %+v on %d watch(es)", r, watches)
|
||||
}
|
||||
}
|
||||
|
||||
// The ask for a recreate or a drop lasts what its highest option level allows (design 47 G §570), so the asker client
|
||||
// takes it: an expiry at the bound passes occ.Check, and the fixed 12 hours it was is refused.
|
||||
func TestTheAskLastsWhatItsLevelAllows(t *testing.T) {
|
||||
now := time.Now()
|
||||
r := keeper.Request{ID: "r1", Verb: keeper.VerbDrop, Module: "m", Local: "drafts", Why: "unused", Caller: "person.jo"}
|
||||
a, err := askFor(r, now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := occ.Check(a, now); err != nil {
|
||||
t.Errorf("the ask is refused by the asker client: %v", err)
|
||||
}
|
||||
a.Expires = occ.FormatTime(now.Add(12 * time.Hour))
|
||||
if err := occ.Check(a, now); err == nil || !strings.Contains(err.Error(), "at most") {
|
||||
t.Errorf("12 hours is held to the level's bound: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,6 +656,22 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) {
|
||||
}},
|
||||
// CAT-N8: a person's requests: a drop removes an orphan alone, only on the operator's warrant binding exactly
|
||||
// that drop, after a snapshot, said dropped and recorded; a recreate rebuilds a drifted entry the same way.
|
||||
{"an ask the router refused ends its request with the router's words (§570)", func(t *testing.T, k *Keeper, bus *fakeBus, out *said) {
|
||||
store := k.Store.(*memStore)
|
||||
k.Heard(Accepted{Module: "m", Revision: 1, BusState: []catalogue.BusStateEntry{drafts}})
|
||||
k.Heard(Accepted{Module: "m", Revision: 2, BusState: nil})
|
||||
w := &oc.Warrant{Ask: "bus-1", Asker: Module, Outcome: oc.WarrantOutcomeRefused, Words: "an ask that destroys lasts at most 10m0s"}
|
||||
k.Warrant = func(string) (*oc.Ask, *oc.Warrant, error) { return nil, w, nil }
|
||||
raw, _ := json.Marshal(Request{ID: "rr", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-1", Caller: "person.jo", At: k.now()})
|
||||
_, _ = store.Put(StateRequests, "rr", raw)
|
||||
k.ActOnRequests()
|
||||
raw, _, _, _ = store.Get(StateRequests, "rr")
|
||||
var got Request
|
||||
_ = json.Unmarshal(raw, &got)
|
||||
if got.Done.IsZero() || got.Waiting != "" || !strings.Contains(got.Error, "refused") || !strings.Contains(got.Error, w.Words) || len(bus.deleted) != 0 {
|
||||
t.Errorf("ended %+v, deleted %v: the router's refusal and its words, nothing removed", got, bus.deleted)
|
||||
}
|
||||
}},
|
||||
{"a drop waits for the warrant, refuses another act's, then acts after a snapshot", func(t *testing.T, k *Keeper, bus *fakeBus, out *said) {
|
||||
store := k.Store.(*memStore)
|
||||
k.Heard(Accepted{Module: "m", Revision: 1, BusState: []catalogue.BusStateEntry{drafts, log}})
|
||||
@@ -994,7 +1010,7 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) {
|
||||
_ = json.Unmarshal(raw, &got)
|
||||
return got
|
||||
}
|
||||
raw, _ := json.Marshal(Request{ID: "r7", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-7", Caller: "person.jo", At: k.now().Add(-time.Hour)})
|
||||
raw, _ := json.Marshal(Request{ID: "r7", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-7", Caller: "person.jo", At: k.now().Add(-AskLasts / 2)})
|
||||
_, _ = store.Put(StateRequests, "r7", raw)
|
||||
raw, _ = json.Marshal(Request{ID: "r8", Verb: VerbDrop, Module: "m", Local: "drafts", Ask: "bus-8", Caller: "person.jo", At: k.now().Add(-AskLasts - time.Minute)})
|
||||
_, _ = store.Put(StateRequests, "r8", raw)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
)
|
||||
|
||||
// A person's request (design 25 § 12.3; CAT-N8): the bus module's tools hold no grant of the seat's acting verbs, so
|
||||
@@ -67,10 +68,11 @@ type Request struct {
|
||||
Unrecorded string `json:"unrecorded,omitempty"`
|
||||
}
|
||||
|
||||
// AskLasts is how long the operator's ask for a recreate or a drop waits for an answer: shorter than the day the state
|
||||
// requests keeps a key, so a request whose ask ended unanswered is ended by the keeper, saying so, before its key ages
|
||||
// out, and the warrant's acted key (ActedKey) outlives the ask it spends.
|
||||
const AskLasts = 12 * time.Hour
|
||||
// AskLasts is how long the operator's ask for a recreate or a drop waits for an answer: the bound of its highest option
|
||||
// level, destroy (design 47 G §570: no asker asks for longer than its level allows; the asker client refuses more). It is
|
||||
// shorter than the day the state requests keeps a key, so a request whose ask ended unanswered is ended by the keeper,
|
||||
// saying so, before its key ages out, and the warrant's acted key (ActedKey) outlives the ask it spends.
|
||||
const AskLasts = occ.DestroyLasts
|
||||
|
||||
// ActedPrefix started the spend record's key while it was kept in StateRequests (`acted.<ask id>`); a key of that form
|
||||
// still met there is no request and is skipped.
|
||||
@@ -288,6 +290,11 @@ func (k *Keeper) warranted(r *Request) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: the router's record of the ask %s cannot be read now: %v", ErrNoWarrant, r.Ask, err)
|
||||
}
|
||||
// An ask the router refused at take-in ends its request with the router's words, never "not answered yet" (design 47 G
|
||||
// §570).
|
||||
if w != nil && w.Outcome == oc.WarrantOutcomeRefused {
|
||||
return fmt.Errorf("the router refused the operator's ask %s, so nothing is removed: %s", r.Ask, w.Words)
|
||||
}
|
||||
// An ask that ended unanswered ends its request, said: never a request that waits until its key ages out. And a
|
||||
// warrant is not acted on once its ask ended, so a request handed after its acted key aged out acts on nothing.
|
||||
var expires time.Time
|
||||
|
||||
Reference in New Issue
Block a user