package main import ( "strings" "testing" "time" "git.novox.be/novox/mesh-sdk/go/asks" ) // novox/hq issue 639: an ask's message reads at a glance on the phone. Its body is the asker's summary and points // alone; who asked and when, what each answer does, the expiry and the asker's Details are its note. Once answered // it keeps the question whole, so the operator can read back what they answered (issue 714). // decisionAsk is the ask for ADR 0343 as the knowledge base composes it now (its glance form). func decisionAsk(c *clock) asks.Ask { return asks.Ask{ID: "kb-decision-343-0d1e2f3a", Headline: "Your agents' memory follows you to every machine", Explanation: "What an agent learns in a project's memory is copied to every machine that runs the agent, so a session " + "anywhere starts with it. A file changed on two machines keeps both versions and warns you; secrets in memory files " + "are screened, though not perfectly.\n" + "• Only memory folders travel: links and files over 128 KiB stay where they are\n" + "• A conflict reaches you as a warning that needs you\n" + "• A deleted file is marked, and a newer change elsewhere outlives the deletion", Who: asks.Operator, Expires: c.now().Add(23*time.Hour + 50*time.Minute), OnExpiry: "the record stays proposed; nothing of it is in force", About: "knowledge.decision.343", Details: "ADR 0343, proposed by fix-367@g14; the knowledge base's own review approved it. Fingerprint a59f 361b f60e cb5e d237 a837.\n" + "Read its 13 clauses with the knowledge base's get, number 343.", Options: []asks.Option{ {ID: "approve", Label: "Approve", Does: "the record is accepted and its clauses are in force", Level: asks.Approve, Binds: bound("approve")}, {ID: "decline", Label: "Decline", Does: "the record stays proposed; nothing of it is in force", Level: asks.Approve, Binds: bound("decline")}, }} } func TestAnAsksMessageIsItsSummaryWithTheRestInItsNote(t *testing.T) { h, tg, _, c, store, _ := newRouter(t) link(h, store, c, "42", c.now().Add(-2*time.Hour)) a := decisionAsk(c) submit(t, h, "mesh-knowledge", a) settle(h, c) if len(tg.sends) != 1 { t.Fatalf("telegram got %d messages", len(tg.sends)) } m := tg.sends[0] if m.Title != a.Headline || m.Body != a.Explanation { t.Errorf("the body is not the asker's summary and points alone:\n%s\n%s", m.Title, m.Body) } note := strings.Split(m.Note, "\n") asked := c.now().In(time.UTC).Format("15:04") want := []string{ "Asked by mesh-knowledge at " + asked + ". Unanswered by tomorrow " + a.Expires.In(time.UTC).Format("15:04") + ": the record stays proposed; nothing of it is in force.", "Approve: the record is accepted and its clauses are in force. Decline: the record stays proposed; nothing of it is in force.", "ADR 0343, proposed by fix-367@g14; the knowledge base's own review approved it. Fingerprint a59f 361b f60e cb5e d237 a837.", "Read its 13 clauses with the knowledge base's get, number 343.", } if strings.Join(note, "\n") != strings.Join(want, "\n") { t.Errorf("the note:\n%s\nwant:\n%s", m.Note, strings.Join(want, "\n")) } if n := len(strings.Split(m.Text(), "\n")); n > 9 || len(m.Actions) != 2 { t.Errorf("the message is %d lines offering %s:\n%s", n, labelsOf(m), m.Text()) } // Answered, it keeps its headline, summary, points and Details; below them, how it ended and who acts on it; // its buttons are gone (issue 714: the one line issue 639 made left nothing to read back). if out, err := h.Chosen("telegram", choiceOf(ticketFor(m, "Approve"), "42", c.now())); err != nil || out != "chosen" { t.Fatalf("Approve: %q %v", out, err) } var edited Message for _, e := range tg.edits { edited = e } if edited.Title != a.Headline || edited.Body != a.Explanation+"\n"+want[2]+"\n"+want[3] || edited.Note != "You chose Approve at "+asked+" on Telegram.\nTold to mesh-knowledge, which acts on it itself." || len(edited.Actions) != 0 { t.Errorf("the answered copy: %q\n%q\n%q", edited.Title, edited.Body, edited.Note) } } // An ask that does not read at a glance is shown all the same, and said: refusing it would leave the operator // unasked, and the bound is its asker's to keep. func TestAnAskThatIsAWallOfTextIsShownAndSaid(t *testing.T) { h, tg, _, c, store, _ := newRouter(t) link(h, store, c, "42", c.now().Add(-2*time.Hour)) var said []string h.Logf = func(f string, a ...any) { said = append(said, f) } a := decisionAsk(c) a.Explanation += "\nA fourth point\nA fifth point" submit(t, h, "mesh-knowledge", a) settle(h, c) if len(tg.sends) != 1 || !strings.Contains(strings.Join(said, "\n"), "is a wall of text on the phone") { t.Errorf("sent %d, said %v", len(tg.sends), said) } }