messenger: send an ask's message alone even when only one answer can be given there

The lab's proof showed an ask whose approval was held back (an agent could become root where the
channel runs) folded into a burst's digest with a condition, and its one remaining answer, Decline,
lost with it. A message carrying an ask's answer now always goes alone.
This commit is contained in:
2026-10-09 17:08:17 +02:00
parent 1fc88b9915
commit c1d299336b
2 changed files with 39 additions and 2 deletions
@@ -839,3 +839,38 @@ func codeOf(t *testing.T, m Message) string {
t.Fatalf("no code in %q", m.Body)
return ""
}
// An ask's message goes alone even when only one of its answers can be given on a channel: folded into a burst's
// digest, its one button was lost (found by the lab's proof, mesh-lab asks/, with approval held by an open
// agent-root condition and that condition's message in the same burst).
func TestAnAsksMessageWithOneAnswerIsNotFoldedIntoADigest(t *testing.T) {
h, tg, _, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
settle(h, c)
// Something was just said on the channel, so what follows waits for the burst.
submit(t, h, "mesh-delivery", heldAsk(c, "d-0"))
settle(h, c)
h.mu.Lock()
h.open["machine.anchor.agent-root"] = &Record{Key: "machine.anchor.agent-root", Kind: KindAgentRoot, Severity: Urgent,
Origin: "condition", Raised: c.now()}
h.mu.Unlock()
k := cond("machine.anchor.disk", Urgent, "the disk on anchor is full")
k.Raised = c.now()
h.Condition(EventRaised, k)
before := len(tg.sends)
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
settle(h, c)
var asked *Message
for i := range tg.sends[before:] {
m := tg.sends[before+i]
if ticketFor(m, "Silence for a week") != "" {
asked = &m
}
}
if asked == nil {
t.Fatalf("the ask's one answer was not offered on Telegram: %+v", tg.sends[before:])
}
if ticketFor(*asked, "Release") != "" {
t.Errorf("an approval was offered while an agent can become root there: %q", labelsOf(*asked))
}
}
+4 -2
View File
@@ -287,10 +287,12 @@ func (h *Holder) flushChannel(ch Channel, now time.Time, force bool) {
return
}
if len(entries) > 1 {
// A message that asks the operator something goes alone, so its answers come with it.
// A message that asks the operator something goes alone, so its answers come with it: one with several
// answers, and one carrying an ask's answer even when only one can be given here (the lab's proof found
// an ask whose approval was not offered folded into a digest, and its one answer lost with it).
var alone, rest []entry
for _, e := range entries {
if len(e.msg.Actions) > 1 {
if len(e.msg.Actions) > 1 || (len(e.msg.Actions) > 0 && e.r != nil && e.r.Ask != "") {
alone = append(alone, e)
} else {
rest = append(rest, e)