The teller checks a settle ask's warrant against mesh-delivery.settle, the act its options bind (issue 1280, ADR 0556 clause 5)

This commit is contained in:
2026-10-26 20:58:20 +01:00
parent f907be2c14
commit 351ca7c290
2 changed files with 27 additions and 8 deletions
@@ -286,16 +286,17 @@ func (t *Teller) catchUp(id string) {
t.said(h, *w, err)
}
// mergeAct is what the approve option of the gate's ask binds: this ask, the answer, and the heads it covers. It is
// spelled as the gate composes it (mesh-catalog modules/mesh-delivery-gate approval.go mergeAct, from
// mergeAct is what the approve option of the gate's ask binds: the ask's verb (delivery.AskVerb: mesh-delivery.merge, or
// mesh-delivery.settle for a person's settle ask, novox/hq ADR 0556 clause 5), this ask, the answer, and the heads it covers.
// It is spelled as the gate composes it (mesh-catalog modules/mesh-delivery-gate approval.go mergeAct, from
// modules/mesh-delivery approval.go:63-65) and as mesh-controller verifies it (cmd/mesh-controller/moved.go:98-106).
func mergeAct(ask, option string, heads map[string]string) asks.Act {
func mergeAct(verb, ask, option string, heads map[string]string) asks.Act {
var out []string
for id, sha := range heads {
out = append(out, id+"="+sha)
}
sort.Strings(out)
return asks.Act{"verb": "mesh-delivery.merge", "ask": ask, "option": option, "heads": strings.Join(out, ",")}
return asks.Act{"verb": verb, "ask": ask, "option": option, "heads": strings.Join(out, ",")}
}
// headsOf is the heads an ask covers as an act names them: a delivery's id, `owner/repository@<twelve characters of its
@@ -363,7 +364,7 @@ func (t *Teller) Answer(o asks.Option, w asks.Warrant) error {
return fmt.Errorf("the gate's ask %s is no longer the ask the operator answered (its digest is %s, the warrant's %s)",
s.Key, ga.Ask.Digest(), w.AskDigest)
}
if err := o.Performs(mergeAct(w.Ask, o.ID, headsOf(ga.Heads))); err != nil {
if err := o.Performs(mergeAct(delivery.AskVerb(ga.Group), w.Ask, o.ID, headsOf(ga.Heads))); err != nil {
return err
}
body, err := delivery.EncodeAnswer(delivery.Answer{Option: o.ID, Warrant: warrantID(w), Words: w.Says()})
@@ -189,7 +189,13 @@ func gateAsk(t *testing.T, heads, boundTo []delivery.Head) (key string, value []
// go/delivery Ask.Asking), the first asking's the key's own.
func gateAskN(t *testing.T, heads, boundTo []delivery.Head, asking int) (key string, value []byte, ask delivery.Ask) {
t.Helper()
key, err := delivery.MergeAskKey("g", heads)
return gateAskOf(t, "g", "mesh-delivery.merge", heads, boundTo, asking)
}
// gateAskOf is gateAskN for a group whose options bind the verb given.
func gateAskOf(t *testing.T, group, verb string, heads, boundTo []delivery.Head, asking int) (key string, value []byte, ask delivery.Ask) {
t.Helper()
key, err := delivery.MergeAskKey(group, heads)
if err != nil {
t.Fatal(err)
}
@@ -197,13 +203,13 @@ func gateAskN(t *testing.T, heads, boundTo []delivery.Head, asking int) (key str
a := asks.Ask{ID: id, Headline: "Merge into main: novox/mesh-delivery#12", Explanation: "Merges two pull requests.\nReview: approved.",
Who: asks.Operator, Expires: now.Add(asks.ApproveLasts - 10*time.Minute), OnExpiry: "the merge stays held", About: "delivery.mesh-delivery.12"}
for _, o := range []struct{ id, label, does string }{{"approve", "Approve", "merges"}, {"decline", "Decline", "merges nothing"}} {
binds, err := asks.ActDigest(mergeAct(id, o.id, headsOf(boundTo)))
binds, err := asks.ActDigest(mergeAct(verb, id, o.id, headsOf(boundTo)))
if err != nil {
t.Fatal(err)
}
a.Options = append(a.Options, asks.Option{ID: o.id, Label: o.label, Does: o.does, Level: asks.Approve, Binds: binds})
}
ask = delivery.Ask{Group: "g", Heads: heads, Asking: asking, Ask: a}
ask = delivery.Ask{Group: group, Heads: heads, Asking: asking, Ask: a}
value, err = delivery.EncodeAsk(ask)
if err != nil {
t.Fatal(err)
@@ -308,6 +314,18 @@ func TestAWarrantThatHoldsWritesOneAnswerAndASecondWritesNone(t *testing.T) { //
if len(b.conds) != 0 {
t.Errorf("conditions said: %+v", b.conds)
}
// 1280 (ADR 0556 clause 5): a settle ask holds when its options bind mesh-delivery.settle, and not when they bind a merge.
for verb, holds := range map[string]bool{"mesh-delivery.settle": true, "mesh-delivery.merge": false} {
b := newBed(t)
group := delivery.SettleGroup([]string{"novox/mesh-delivery@" + headA[:12]})
key, value, ga := gateAskOf(t, group, verb, twoHeads(), twoHeads(), 1)
b.gate[key] = value
b.t.OnAsk(key, 1, value)
b.deliver(t, warrantFor(ga.Ask, "approve"))
if _, written := b.answers.written[delivery.AnswerKey(key)]; written != holds {
t.Errorf("a settle ask binding %s: answer written %v, want %v", verb, written, holds)
}
}
}
func TestAWarrantThatDoesNotHoldWritesNoAnswerAndRaisesTheCondition(t *testing.T) { // 1343/AC3