CAT-MS1, CAT-MS2: offered and closed carry the operator-channel definition's fields (id, asker, headline, channels; id, asker, how); the page reads them
The test of the five ends holds every key of a body to the seat definition's holder events, so the router and the contract cannot drift. Issue 1968. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -398,9 +398,10 @@ func (o *Overview) Heard(source, event string, body json.RawMessage) {
|
||||
case SourceAsks:
|
||||
switch name {
|
||||
case "offered":
|
||||
o.asks[f.Key] = askRow{Key: f.Key, Asker: f.Asker, Headline: f.Headline, Offered: firstStrings(f.Offered, f.Channels)}
|
||||
k := firstNonEmpty(f.Key, f.Asker+"."+f.ID)
|
||||
o.asks[k] = askRow{Key: k, Asker: f.Asker, Headline: f.Headline, Offered: firstStrings(f.Offered, f.Channels)}
|
||||
case "closed":
|
||||
delete(o.asks, f.Key)
|
||||
delete(o.asks, firstNonEmpty(f.Key, f.Asker+"."+f.ID))
|
||||
}
|
||||
}
|
||||
o.rebuilt = o.now()
|
||||
|
||||
@@ -24,7 +24,7 @@ func newOverviewWorld(t *testing.T) *overviewWorld {
|
||||
TrackerMilestonesVerb: `{"milestones":[{"design":47,"id":"1","outcome":"A merge is never dropped","status":"open","issues":[973,525]},{"design":47,"id":"2","outcome":"Done thing","status":"done","issues":[1]}]}`,
|
||||
TrackerListVerb: `[{"number":973,"title":"The window","status":"fixing"},{"number":525,"title":"The queue","status":"open"}]`,
|
||||
DeliveryGroupsVerb: `[{"id":"fix/a","state":"held","why":"a member is held","members":["x@1"]}]`,
|
||||
AsksVerb: `{"asks":[{"key":"ask-1","asker":"mesh-knowledge","headline":"Approve ADR 0301","state":"open","offered_on":["telegram"]},{"key":"ask-0","asker":"x","headline":"old","state":"answered"}]}`,
|
||||
AsksVerb: `{"asks":[{"key":"mesh-knowledge.1","asker":"mesh-knowledge","headline":"Approve ADR 0301","state":"open","offered_on":["telegram"]},{"key":"ask-0","asker":"x","headline":"old","state":"answered"}]}`,
|
||||
}}
|
||||
w.o = NewOverview(func(key string, body any) (json.RawMessage, error) {
|
||||
if w.fail[key] {
|
||||
@@ -66,7 +66,7 @@ func TestThePageModelHasThreeBlocksKeptByEventsAndAsksNoVerbAgain(t *testing.T)
|
||||
t.Fatalf("the design block: %+v", m.Designs)
|
||||
}
|
||||
if len(m.Accepted) != 2 || len(m.Waiting) != 2 || len(m.Operator.Records) != 1 || m.Operator.Records[0].Record != "ADR 0303" ||
|
||||
len(m.Operator.Asks) != 1 || m.Operator.Asks[0].Key != "ask-1" || len(m.Operator.Groups) != 1 {
|
||||
len(m.Operator.Asks) != 1 || m.Operator.Asks[0].Key != "mesh-knowledge.1" || len(m.Operator.Groups) != 1 {
|
||||
t.Fatalf("%+v", m)
|
||||
}
|
||||
asked := map[string]int{}
|
||||
@@ -76,7 +76,7 @@ func TestThePageModelHasThreeBlocksKeptByEventsAndAsksNoVerbAgain(t *testing.T)
|
||||
// Events change the blocks.
|
||||
w.o.Heard(SourceDelivery, "mesh-delivery-gate.group", json.RawMessage(`{"group":"fix/b","state":"checking","members":["y@2"]}`))
|
||||
w.o.Heard(SourceDelivery, "mesh-delivery-gate.transition", json.RawMessage(`{"group":"fix/a","to":"approved"}`))
|
||||
w.o.Heard(SourceAsks, "messenger.offered", json.RawMessage(`{"key":"ask-2","asker":"mesh-delivery","headline":"Approve the group","channels":["telegram"]}`))
|
||||
w.o.Heard(SourceAsks, "messenger.offered", json.RawMessage(`{"id":"2","asker":"mesh-delivery","headline":"Approve the group","channels":["telegram"]}`))
|
||||
w.o.Heard(SourceTracker, "mesh-issues.opened", json.RawMessage(`{"number":1999,"title":"New","status":"open"}`))
|
||||
w.o.Heard(SourceTracker, "mesh-issues.milestone-moved", json.RawMessage(`{"design":47,"id":"1","to":"done","issues":[973,525,1999]}`))
|
||||
m, _ = w.o.Model()
|
||||
@@ -84,9 +84,9 @@ func TestThePageModelHasThreeBlocksKeptByEventsAndAsksNoVerbAgain(t *testing.T)
|
||||
t.Fatalf("after the events: %+v", m)
|
||||
}
|
||||
w.o.Heard(SourceDelivery, "mesh-delivery-gate.merged", json.RawMessage(`{"group":"fix/a"}`))
|
||||
w.o.Heard(SourceAsks, "messenger.closed", json.RawMessage(`{"key":"ask-1","how":"answered"}`))
|
||||
w.o.Heard(SourceAsks, "messenger.closed", json.RawMessage(`{"id":"1","asker":"mesh-knowledge","how":"answered"}`))
|
||||
m, _ = w.o.Model()
|
||||
if len(m.Operator.Groups) != 1 || m.Operator.Groups[0].ID != "fix/b" || len(m.Operator.Asks) != 1 || m.Operator.Asks[0].Key != "ask-2" {
|
||||
if len(m.Operator.Groups) != 1 || m.Operator.Groups[0].ID != "fix/b" || len(m.Operator.Asks) != 1 || m.Operator.Asks[0].Key != "mesh-delivery.2" {
|
||||
t.Fatalf("after merged and closed: %+v", m.Operator)
|
||||
}
|
||||
for v, n := range asked {
|
||||
@@ -160,7 +160,7 @@ func TestASourceThatDoesNotAnswerIsSaidAndAskedAgainOnABackoff(t *testing.T) {
|
||||
t.Fatalf("%+v", u)
|
||||
}
|
||||
// Its next event (or heartbeat) makes the module ask the verb once, and that answer clears the mark.
|
||||
w.o.Heard(SourceAsks, "messenger.offered", json.RawMessage(`{"key":"ask-9","headline":"x"}`))
|
||||
w.o.Heard(SourceAsks, "messenger.offered", json.RawMessage(`{"id":"9","asker":"x","headline":"x"}`))
|
||||
if w.o.Calls(AsksVerb) != asked+1 || w.o.state[SourceAsks].Mark != nil {
|
||||
t.Fatalf("asked %d, mark %+v", w.o.Calls(AsksVerb), w.o.state[SourceAsks].Mark)
|
||||
}
|
||||
|
||||
@@ -1445,7 +1445,7 @@ func (h *Holder) sayOffered(key string, rec AskRecord) {
|
||||
on = append(on, k)
|
||||
}
|
||||
sort.Strings(on)
|
||||
if err := h.Emit("offered", map[string]any{"key": key, "asker": rec.Asker, "headline": rec.Ask.Headline, "offered_on": on, "at": h.Now()}); err != nil {
|
||||
if err := h.Emit("offered", map[string]any{"id": rec.Ask.ID, "asker": rec.Asker, "headline": rec.Ask.Headline, "channels": on}); err != nil {
|
||||
h.Logf("[messenger] that the ask %s was offered could not be said: %v", key, err)
|
||||
}
|
||||
}
|
||||
@@ -1466,7 +1466,7 @@ func (h *Holder) sayClosed(key string, rec AskRecord, outcome asks.Outcome, word
|
||||
h.mu.Lock()
|
||||
delete(h.offeredSaid, key)
|
||||
h.mu.Unlock()
|
||||
if err := h.Emit("closed", map[string]any{"key": key, "asker": rec.Asker, "headline": rec.Ask.Headline, "how": how, "at": h.Now()}); err != nil {
|
||||
if err := h.Emit("closed", map[string]any{"id": rec.Ask.ID, "asker": rec.Asker, "how": how}); err != nil {
|
||||
h.Logf("[messenger] that the ask %s ended could not be said: %v", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestTheRouterSaysWhenAnAskIsOfferedAndWhenItEnds(t *testing.T) {
|
||||
ends := func() (out []string) {
|
||||
for _, s := range got {
|
||||
if s.event == "closed" {
|
||||
out = append(out, s.body["key"].(string)+"="+s.body["how"].(string))
|
||||
out = append(out, s.body["asker"].(string)+"."+s.body["id"].(string)+"="+s.body["how"].(string))
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -38,7 +38,7 @@ func TestTheRouterSaysWhenAnAskIsOfferedAndWhenItEnds(t *testing.T) {
|
||||
// Answered.
|
||||
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
|
||||
settle(h, c)
|
||||
if len(got) != 1 || got[0].event != "offered" || got[0].body["key"] != "mesh-delivery.d-1" || got[0].body["asker"] != "mesh-delivery" {
|
||||
if len(got) != 1 || got[0].event != "offered" || got[0].body["id"] != "d-1" || got[0].body["asker"] != "mesh-delivery" {
|
||||
t.Fatalf("%+v", got)
|
||||
}
|
||||
release := ticketFor(tg.sends[0], "Release")
|
||||
@@ -82,6 +82,9 @@ func TestTheRouterSaysWhenAnAskIsOfferedAndWhenItEnds(t *testing.T) {
|
||||
offered++
|
||||
}
|
||||
for k := range s.body {
|
||||
if k != "id" && k != "asker" && k != "headline" && k != "channels" && k != "how" {
|
||||
t.Errorf("%s carries %s, which the seat's contract does not have", s.event, k)
|
||||
}
|
||||
if k == "options" || k == "tickets" || k == "token" || k == "proofs" || k == "warrant" {
|
||||
t.Errorf("%s carries %s", s.event, k)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user