Files
mesh-catalog/modules/messenger/cmd/messenger/review_test.go
T
jschoubben d136806745 messenger: an early desk unlink bars nothing, root lifts any bar, no root-free ask inside the work, no button without its effect (the confirmation review of 2026-10-09)
N1-router: another account's /start offered the desk an unlink of the operator's account in its first
hour, and a desk click, which a program on the desk machine can forge, unlinked it and barred it for a
day, again and again. An unlink at the desk in the first hour now bars nothing: any account, the
operator's too, links again at once with a code from the desk; the day's bar stays for an account
removed by its own approval or by root, and root's allow-link lifts any bar. The words say which.

Lows: the controller's root-free word is asked before the work is taken (it waited up to 10 s inside
it) and the answer is judged with that fresh word; inside the work only a recent word is read, and a
failed ask drops the old one. An answer whose effect the content rule withholds is not offered.
mesh-sdk moves to 16984aa. Each test failed before its fix.
2026-10-09 17:08:17 +02:00

536 lines
22 KiB
Go

package main
// The findings of the review of 2026-10-09, each held here by a test that failed before its fix.
import (
"encoding/json"
"errors"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/asks"
)
// H3: approval rests on the controller's positive, recent word that no agent can become root where the router
// and the channel run (its verb root-free), asked live. Every other answer fails closed.
func TestApprovalNeedsTheControllersWordThatRootIsFree(t *testing.T) {
for name, tc := range map[string]struct {
setup func(h *Holder)
want string
}{
"a router that does not know its machine": {func(h *Holder) { h.Node = "" }, "does not know which machine"},
"a channel whose machine is not said": {func(h *Holder) {
k, _ := h.Bench.Kind("telegram")
k.Node = ""
h.Bench.SetKinds([]KindInfo{k})
}, "has not said which machine"},
"a controller that does not answer": {func(h *Holder) {
h.RootFree = func([]string) (map[string]RootVerdict, error) { return nil, errors.New("no responders") }
}, "could not be asked: no responders"},
"a machine the answer leaves out": {func(h *Holder) {
h.RootFree = func([]string) (map[string]RootVerdict, error) { return map[string]RootVerdict{}, nil }
}, "said nothing of whether an agent can become root on anchor"},
"a machine not free": {func(h *Holder) { rootFreeOf[h]["anchor"] = "the agent account is not judged" },
"may become root on anchor"},
"the router's own machine not free": {func(h *Holder) {
h.Node = "router-machine"
rootFreeOf[h]["router-machine"] = "execute is served there"
}, "may become root on router-machine"},
} {
t.Run(name, func(t *testing.T) {
h, tg, _, c, store, w := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
settle(h, c)
release := ticketFor(tg.sends[0], "Release")
if release == "" {
t.Fatal("not offered while root was free")
}
tc.setup(h)
out, err := h.Chosen("telegram", choiceOf(release, "42", c.now()))
if out != "refused" || err == nil || !strings.Contains(err.Error(), tc.want) {
t.Fatalf("%s %v, want refused for %q", out, err, tc.want)
}
if len(w.of("mesh-delivery")) != 0 {
t.Error("a warrant was issued")
}
if got := h.carriers(asks.Approve); len(got) != 0 {
t.Errorf("approval still carried on %v", got)
}
})
}
}
// H3: the word is asked of the controller's verb, as this module, and read from its answer.
func TestTheRootWordIsAskedOfTheControllersVerb(t *testing.T) {
h, _, _, _, _, _ := newRouter(t)
h.RootFree = nil
var asked []string
h.Ask = func(key string, body any) (json.RawMessage, error) {
asked = append(asked, key)
raw, _ := json.Marshal(body)
if !strings.Contains(string(raw), `"machines":["anchor"]`) {
t.Errorf("asked about %s", raw)
}
return json.RawMessage(`{"machines":[{"machine":"anchor","free":true,"why":"judged","judged":"2026-10-09T10:00:00Z"}]}`), nil
}
info, _ := h.Bench.Kind("telegram")
if why := h.rootFree(info, false); why != "" {
t.Fatalf("free not read: %s", why)
}
if len(asked) != 1 || asked[0] != "seat:mesh-controller.root-free" {
t.Errorf("asked %v", asked)
}
h.Ask = func(string, any) (json.RawMessage, error) { return json.RawMessage(`not json`), nil }
if why := h.rootFree(info, false); !strings.Contains(why, "could not be read") {
t.Errorf("an unreadable answer was a pass: %q", why)
}
h.Ask = nil
if why := h.rootFree(info, false); why == "" {
t.Error("no way to ask was a pass")
}
}
// H3: a message rendered while root is not free offers no approval; a word kept for rendering is never the
// word an answer is judged on.
func TestAMessageRenderedWhileRootIsNotFreeOffersNoApproval(t *testing.T) {
h, tg, _, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
settle(h, c)
rec := h.openAsk(h.open["ask.mesh-delivery.d-1"])
if got := h.offers(rec, "telegram"); len(got) != 3 {
t.Fatalf("offers %v", got)
}
rootFreeOf[h]["anchor"] = "not judged"
c.pass(RootFreeKept)
if got := h.offers(rec, "telegram"); len(got) != 0 {
t.Errorf("rendered with an approval while root is not free: %v", got)
}
// Free again, but the kept word is not: the answer asks anew and is taken.
delete(rootFreeOf[h], "anchor")
out, err := h.Chosen("telegram", choiceOf(ticketFor(tg.sends[0], "Release"), "42", c.now()))
if err != nil || out != "chosen" {
t.Errorf("judged on a kept word: %s %v", out, err)
}
}
// H3: a capability the controller's word no longer says stays no longer than the word is fresh: a router that
// cannot read the kinds again promises no verified sender.
func TestAStaleWordOnTheKindsPromisesNoVerifiedSender(t *testing.T) {
h, _, _, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
if !h.Bench.Promises("telegram", "verified-sender") {
t.Fatal("not promised while fresh")
}
c.pass(KindsFresh + time.Second)
h.Bench.Stand("telegram", Standing{Ready: true, At: c.now()})
if h.Bench.Promises("telegram", "verified-sender") || len(h.carriers(asks.Approve)) != 0 {
t.Error("a stale word still promises a verified sender")
}
if !h.Bench.Promises("telegram", "choice") {
t.Error("a stale word stopped the channel sending")
}
}
// C6: a link's code is marked secret on every path to a channel, the desk's own role included, so the channel
// keeps no copy (the review found it dropped where the desk's role sends).
func TestALinksCodeIsSecretOnEveryPath(t *testing.T) {
c := start()
bench := NewBench(c.now)
bench.SetKinds([]KindInfo{
{Kind: "telegram", Module: "telegram", Node: "anchor", Capabilities: []string{"reaches-away", "choice", "verified-sender", "exact-render"}},
{Kind: "desktop", Module: "desk-channel", Node: "anchor", Capabilities: []string{"choice", "exact-render", "private"}},
})
bench.Stand("telegram", Standing{Ready: true, At: c.now()})
bench.Stand("desktop", Standing{Ready: true, At: c.now()})
var mu sync.Mutex
put := map[string][]asks.Message{}
publish := func(subject string, body any, id string) error {
mu.Lock()
defer mu.Unlock()
if m, ok := body.(asks.Message); ok {
put[subject] = append(put[subject], m)
}
return nil
}
h := &Holder{Away: &SeatChannel{Bench: bench, Role: RoleAway, Publish: publish},
Desk: &SeatChannel{Bench: bench, Role: RoleDesk, Publish: publish}, Bench: bench, Publish: publish,
Asks: newMemAsks(), Node: "anchor", Now: c.now, Logf: t.Logf, Zone: func() *time.Location { return time.UTC }}
h.init()
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
shown := put[asks.ChannelSubject(asks.Send, "desktop")]
if len(shown) != 1 || !strings.Contains(shown[0].Body, "send this code") {
t.Fatalf("the code was not shown on the desk: %+v", put)
}
if !shown[0].Secret {
t.Error("the code went to the desk not marked secret: the channel would keep a copy")
}
}
// L1: a warrant's message id is new each time: one anyone could foresee lets another publisher on the stream
// take it first, and the bus would drop the warrant as a duplicate.
func TestAWarrantsMessageIdCannotBeForeseen(t *testing.T) {
h, tg, _, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
var ids []string
h.Publish = func(subject string, body any, id string) error {
if _, ok := body.(asks.Warrant); ok {
ids = append(ids, id)
}
return nil
}
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
settle(h, c)
if out, err := h.Chosen("telegram", choiceOf(ticketFor(tg.sends[0], "Release"), "42", c.now())); out != "chosen" {
t.Fatalf("%s %v", out, err)
}
_ = h.tell(*store.asks["mesh-delivery.d-1"].Warrant)
if len(ids) != 2 || ids[0] == ids[1] {
t.Fatalf("ids %v", ids)
}
for _, id := range ids {
if strings.Contains(id, "d-1") || strings.Contains(id, "mesh-delivery") {
t.Errorf("the id %q is made of what anyone knows of the ask", id)
}
}
}
// M2: an ask's message says who asks, as the bus proves it, what each answer does, and what happens if nobody
// answers.
func TestAnAsksMessageSaysWhoAsksWhatEachAnswerDoesAndWhatExpiryDoes(t *testing.T) {
h, tg, _, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
settle(h, c)
body := tg.sends[0].Body
for _, want := range []string{"Asked by mesh-delivery.", "Release: the delivery goes on.", "Stop: the delivery ends.",
"Silence for a week: nothing more is said of it for a week.",
"If nobody answers by " + c.now().Add(2*time.Hour-BurstWindow).In(time.UTC).Format("15:04") + ": the delivery stays held."} {
if !strings.Contains(body, want) {
t.Errorf("the message does not say %q:\n%s", want, body)
}
}
}
// M3: the router's own unlink binds the account it asks about: an approval from that account, after another was
// linked in its place, unlinks nothing.
func TestAnUnlinkUnlinksOnlyTheAccountItNamed(t *testing.T) {
h, tg, _, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
if _, err := h.Unlink("telegram"); err != nil {
t.Fatal(err)
}
unlink := ticketFor(tg.sends[len(tg.sends)-1], "Unlink")
delete(store.ids, identityKey("telegram", "42"))
store.ids[identityKey("telegram", "77")] = Identity{Kind: "telegram", Identity: "77", Display: "Al",
Linked: c.now().Add(-2 * time.Hour), ApproveFrom: c.now().Add(-time.Hour)}
_, _ = h.Chosen("telegram", choiceOf(unlink, "42", c.now()))
if _, still := store.ids[identityKey("telegram", "77")]; !still {
t.Error("an approval to unlink 42 unlinked 77")
}
if got := store.asks; len(got) == 0 {
t.Fatal("no ask")
}
for _, rec := range store.asks {
if rec.Act != nil && rec.Act.Identity != "42" {
t.Errorf("the ask binds %q", rec.Act.Identity)
}
}
}
// M3: a link is checked again as it is made: an approved relink does not link a second account of a kind.
func TestALinkIsNotMadeWhileAnotherAccountIsLinked(t *testing.T) {
h, tg, dt, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
_, _ = h.Unlink("telegram")
_, _ = h.Chosen("telegram", choiceOf(ticketFor(tg.sends[len(tg.sends)-1], "Unlink"), "42", c.now()))
h.Link("telegram", asks.LinkAsked{ID: "l9", At: c.now(), Sender: asks.Sender{Identity: "666", Display: "Eve", Authenticated: true}})
code := codeOf(t, dt.sends[len(dt.sends)-1])
_ = h.Prove("telegram", asks.Code{Sender: asks.Sender{Identity: "666", Authenticated: true}, Code: code})
asked := tg.sends[len(tg.sends)-1]
// Meanwhile root linked another account (allowed at the machine).
store.ids[identityKey("telegram", "77")] = Identity{Kind: "telegram", Identity: "77", Linked: c.now(), ApproveFrom: c.now().Add(time.Hour)}
_, _ = h.Chosen("telegram", choiceOf(ticketFor(asked, "Allow"), "42", c.now()))
if _, linked := store.ids[identityKey("telegram", "666")]; linked {
t.Errorf("a second account of a kind was linked: %v", store.ids)
}
}
// M3: an account unlinked less than a day ago is not linked again by a code: no code is shown for it.
func TestAnUnlinkedAccountDoesNotComeBackByACodeWithinADay(t *testing.T) {
h, tg, dt, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
_, _ = h.Unlink("telegram")
_, _ = h.Chosen("telegram", choiceOf(ticketFor(tg.sends[len(tg.sends)-1], "Unlink"), "42", c.now()))
shown := len(dt.sends)
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
if _, pending := store.links["telegram"]; pending {
t.Error("a link was begun for the account unlinked an hour ago")
}
for _, m := range dt.sends[shown:] {
if strings.Contains(m.Body, "send this code") {
t.Error("a code was shown for it")
}
}
if len(store.ids) != 0 {
t.Error("linked again")
}
}
// H4: an account still in its first hour cannot approve yet, so whoever is at the desk may unlink it — asked
// there when another account asks to be linked — and past its hour the desk no longer can.
func TestAnAccountInItsFirstHourIsUnlinkedFromTheDesk(t *testing.T) {
h, tg, dt, c, store, w := newRouter(t)
link(h, store, c, "666", c.now().Add(-10*time.Minute)) // an account the operator did not link
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
if reply := tg.sends[len(tg.sends)-1]; !strings.Contains(reply.Body, "unlink it at your desk") {
t.Fatalf("the sender was not told how: %q", reply.Body)
}
asked := dt.sends[len(dt.sends)-1]
if labelsOf(asked) != "Unlink it" || !strings.Contains(asked.Body, "number 666") {
t.Fatalf("the desk was not asked: %+v", asked)
}
ch := choiceOf(ticketFor(asked, "Unlink it"), "g14", c.now())
ch.Sender.Authenticated = false
if out, err := h.Chosen("desktop", ch); err != nil || out != "chosen" {
t.Fatalf("%s %v", out, err)
}
if len(store.ids) != 0 {
t.Errorf("not unlinked: %v", store.ids)
}
if len(w.of(SelfAsker)) != 0 {
t.Error("the router's own act was told to an asker")
}
// Past its hour, no question goes to the desk.
h2, tg2, dt2, c2, store2, _ := newRouter(t)
link(h2, store2, c2, "666", c2.now().Add(-2*time.Hour))
h2.Link("telegram", asks.LinkAsked{ID: "l1", At: c2.now(), Sender: asks.Sender{Identity: "42", Authenticated: true}})
for _, m := range dt2.sends {
if labelsOf(m) == "Unlink it" {
t.Error("the desk was asked to unlink an account past its first hour")
}
}
if !strings.Contains(tg2.sends[len(tg2.sends)-1].Body, "own approval, or as root") {
t.Errorf("%q", tg2.sends[len(tg2.sends)-1].Body)
}
}
// H4 (C4): while the desk cannot show a code now — its notifications paused — no link is begun and no code is
// made or queued; the sender is told why.
func TestNoLinkIsBegunWhileTheDeskCannotShowTheCode(t *testing.T) {
h, tg, dt, c, store, _ := newRouter(t)
h.Bench.Stand("desktop", Standing{Ready: false, Why: "notifications are paused on the desk", At: c.now()})
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
if _, pending := store.links["telegram"]; pending {
t.Error("a link was begun")
}
if len(dt.sends) != 0 {
t.Errorf("something was put to the desk: %+v", dt.sends)
}
if reply := tg.sends[len(tg.sends)-1].Body; !strings.Contains(reply, "notifications are paused on the desk") {
t.Errorf("the sender was not told why: %q", reply)
}
}
// L5: links are bounded per account, and kept in the router's state: a stranger's tries do not stop the
// operator's link, and a restart forgets no count.
func TestLinksAreBoundedPerAccountAndTheCountIsKept(t *testing.T) {
h, tg, dt, c, store, _ := newRouter(t)
eve := asks.Sender{Identity: "666", Display: "Eve", Authenticated: true}
for i := 0; i < LinksAnHour; i++ {
h.Link("telegram", asks.LinkAsked{ID: "e" + string(rune('0'+i)), At: c.now(), Sender: eve})
}
shown := len(dt.sends)
h.Link("telegram", asks.LinkAsked{ID: "jo", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
if len(dt.sends) != shown+1 || !strings.Contains(dt.sends[len(dt.sends)-1].Body, "(number 42)") {
t.Fatalf("a stranger's tries stopped the operator's link: %q", tg.sends[len(tg.sends)-1].Body)
}
// A router started again on the same state still counts the stranger's tries.
h2, tg2, dt2, c2, _, _ := newRouter(t)
h2.Asks = store
c2.pass(c.now().Sub(c2.now()))
stand(h2, c2)
before := len(dt2.sends)
h2.Link("telegram", asks.LinkAsked{ID: "e9", At: c2.now(), Sender: eve})
if len(dt2.sends) != before || !strings.Contains(tg2.sends[len(tg2.sends)-1].Body, "Try again in an hour") {
t.Error("a restart forgot the count")
}
}
// L7: two answers to one ask arriving at once — on two routers sharing the state — make exactly one warrant.
func TestTwoAnswersAtOnceMakeOneWarrant(t *testing.T) {
h1, tg, _, c, store, w1 := newRouter(t)
link(h1, store, c, "42", c.now().Add(-2*time.Hour))
submit(t, h1, "mesh-delivery", heldAsk(c, "d-1"))
settle(h1, c)
release, stop := ticketFor(tg.sends[0], "Release"), ticketFor(tg.sends[0], "Stop")
h2, _, _, _, _, w2 := newRouter(t)
h2.Asks = store
h2.Now = h1.Now
if err := h2.loadAsks(); err != nil {
t.Fatal(err)
}
var wg sync.WaitGroup
outs := make([]string, 2)
for i, pick := range []struct {
h *Holder
ticket string
}{{h1, release}, {h2, stop}} {
wg.Add(1)
go func(i int, h *Holder, ticket string) {
defer wg.Done()
outs[i], _ = h.Chosen("telegram", choiceOf(ticket, "42", c.now()))
}(i, pick.h, pick.ticket)
}
wg.Wait()
n := len(w1.of("mesh-delivery")) + len(w2.of("mesh-delivery"))
if n != 1 {
t.Fatalf("%d warrants for one ask (%v)", n, outs)
}
if (outs[0] == "chosen") == (outs[1] == "chosen") {
t.Errorf("not exactly one chosen: %v", outs)
}
}
// The confirmation review of 2026-10-09, N1-router: another account's /start offers the desk an unlink of the
// operator's account while it is in its first hour; a desk click — which a program on the desk machine can forge
// — unlinked it and barred it for a day, again and again, so the operator never approved anything. A desk
// unlink in the first hour bars nothing: the operator links again at once with a code from the desk, and the
// next link waits for nobody. The bar is for an account removed deliberately later.
func TestAnUnlinkFromTheDeskInTheFirstHourBarsNothing(t *testing.T) {
h, tg, dt, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-10*time.Minute)) // the operator's own, linked just now
h.Link("telegram", asks.LinkAsked{ID: "l1", At: c.now(), Sender: asks.Sender{Identity: "666", Display: "X", Authenticated: true}})
asked := dt.sends[len(dt.sends)-1]
ch := choiceOf(ticketFor(asked, "Unlink it"), "g14", c.now()) // a click nobody can prove was the operator's
ch.Sender.Authenticated = false
if out, err := h.Chosen("desktop", ch); err != nil || out != "chosen" {
t.Fatalf("%s %v", out, err)
}
if len(store.ids) != 0 {
t.Fatalf("not unlinked: %v", store.ids)
}
if u := h.recentUnlink("telegram"); u != nil {
t.Errorf("a desk unlink in the first hour bars relinking: %+v", u)
}
// The operator sends /start again: a code is shown at once, and the code links without waiting for anybody.
c.pass(time.Minute)
stand(h, c)
h.Link("telegram", asks.LinkAsked{ID: "l2", At: c.now(), Sender: asks.Sender{Identity: "42", Display: "Jo", Authenticated: true}})
code := ""
for _, m := range dt.sends {
if strings.Contains(m.Body, "number 42") && strings.Contains(m.Body, "send this code") {
code = codeIn(t, m.Body)
}
}
if code == "" {
t.Fatalf("no code was shown to relink the operator's account; said %q", tg.sends[len(tg.sends)-1].Body)
}
if a := h.Prove("telegram", asks.Code{Sender: asks.Sender{Identity: "42", Authenticated: true}, Code: code, Purpose: "link"}); !a.Accepted ||
!strings.Contains(a.Words, "Linked") {
t.Fatalf("the operator's code was not taken at once: %+v", a)
}
}
// And break-glass lifts any bar: root's allow-link at the router's machine, with no link waiting, ends a day's bar.
func TestBreakGlassLiftsABarOnRelinking(t *testing.T) {
h, tg, _, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
_, _ = h.Unlink("telegram")
_, _ = h.Chosen("telegram", choiceOf(ticketFor(tg.sends[len(tg.sends)-1], "Unlink"), "42", c.now()))
if h.recentUnlink("telegram") == nil {
t.Fatal("the control: a deliberate unlink bars relinking for a day")
}
h.StateDir = t.TempDir()
was := fileOwner
t.Cleanup(func() { fileOwner = was })
fileOwner = func(os.FileInfo) uint32 { return 0 }
_ = os.WriteFile(filepath.Join(h.StateDir, "allow-link.telegram"), nil, 0o600)
h.Tick()
if u := h.recentUnlink("telegram"); u != nil {
t.Errorf("root's allow-link left the bar: %+v", u)
}
}
// codeIn is the six digits a link's notice shows, "123 456".
func codeIn(t *testing.T, body string) string {
t.Helper()
m := regexp.MustCompile(`(\d{3}) (\d{3})\.`).FindStringSubmatch(body)
if m == nil {
t.Fatalf("no code in %q", body)
}
return m[1] + m[2]
}
// The confirmation review of 2026-10-09 (low): the router asked the controller's root-free word — up to ten
// seconds — while holding its work, so every ask, answer and link waited behind one slow controller. It now
// asks before it takes the work, and judges with the word it was given then.
func TestTheRootFreeWordIsNotAskedWhileTheWorkIsHeld(t *testing.T) {
h, tg, _, c, store, w := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
settle(h, c)
release := ticketFor(tg.sends[0], "Release")
asking, slow := make(chan struct{}), make(chan struct{})
var once sync.Once
free := h.RootFree
h.RootFree = func(machines []string) (map[string]RootVerdict, error) {
once.Do(func() { close(asking); <-slow })
return free(machines)
}
done := make(chan string, 1)
go func() {
out, _ := h.Chosen("telegram", choiceOf(release, "42", c.now()))
done <- out
}()
<-asking
linked := make(chan struct{})
go func() {
h.Link("telegram", asks.LinkAsked{ID: "l9", At: c.now(), Sender: asks.Sender{Identity: "77", Authenticated: true}})
close(linked)
}()
select {
case <-linked:
case <-time.After(2 * time.Second):
close(slow)
t.Fatal("a link waited for the controller's root-free word: the work was held while it was asked")
}
close(slow)
if out := <-done; out != "chosen" || len(w.of("mesh-delivery")) != 1 {
t.Fatalf("the answer after the word: %s, %v", out, w.of("mesh-delivery"))
}
}
// The confirmation review of 2026-10-09 (low, on M2): an answer whose line — what it does — the content rule
// withholds is not offered either; its button went out alone, and a tap would choose what was not shown.
func TestAnAnswerWhoseEffectIsWithheldIsNotOffered(t *testing.T) {
h, _, _, c, store, _ := newRouter(t)
link(h, store, c, "42", c.now().Add(-2*time.Hour))
submit(t, h, "mesh-delivery", heldAsk(c, "d-1"))
key := askKey("mesh-delivery", "d-1")
h.mu.Lock()
e := h.asks[key]
e.rec.Ask.Options[0].Does = "the delivery reads /etc/shadow"
h.asks[key] = e
r := h.open["ask."+key]
h.mu.Unlock()
m := h.sayOn(r, "asked", "telegram")
for _, a := range m.Actions {
if a.Label == "Release" {
t.Errorf("Release was offered with its effect withheld: %+v", m.Actions)
}
}
if strings.Contains(m.Body, "/etc/shadow") {
t.Errorf("the withheld words were said: %q", m.Body)
}
if len(m.Actions) == 0 {
t.Error("the answers whose effect was said were not offered either")
}
}