Review: a blip swallows no escalation or waiting reminder; replace safely (issue 373)
mesh/merge-gate pass: builds desk-channel, messenger, telegram → novox; no bus step; every machine composes with the change as it did without (4 of 4 compo…
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery-group group fix/373-one-message-per-condition ready: every member ready, and composed together they pass
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate pass: builds desk-channel, messenger, telegram → novox; no bus step; every machine composes with the change as it did without (4 of 4 compo…
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery-group group fix/373-one-message-per-condition ready: every member ready, and composed together they pass
mesh/delivery superseded: a newer head of the same pull request
- A comeback before the clearing was said rings when it is urgent now, and says the reminder or escalation that was waiting when it cleared. - Comebacks never said are counted apart, so "again, Nth time" counts only what the operator was told; an urgent comeback after a said clearing rings again in place of its message. - telegram sends the new message before deleting the earlier one, so a failed send leaves the operator a message. - desk-channel keeps a machine's notification on record when its replace fails, and says a message shown nowhere as failed. - A store that cannot be read sends a new message instead of holding it. - Tests for each, and for a reminder in a burst and a clearing the channel could not take.
This commit is contained in:
@@ -9,8 +9,9 @@ as the operator.
|
||||
buttons — each button carries only the router's one-time ticket — or an edit of a message shown before.
|
||||
It sends to the account the router names as linked, or, before one is, to the chat a `/start` came from.
|
||||
A message sent under a handle already shown (a reminder, an escalation) **replaces** it (issue 373): the
|
||||
earlier message is deleted and the new one sent, ringing as its kind rings, since an edit here notifies
|
||||
nobody; one the service will not delete loses its buttons and says a newer message follows.
|
||||
new message is sent, ringing as its kind rings (an edit here notifies nobody), and then the earlier one is
|
||||
deleted; one the service will not delete loses its buttons and says a newer message follows. A send that
|
||||
fails leaves the earlier message.
|
||||
- **Says what the operator chose** on `intake` under its own kind: a tapped button (`choice`), with the
|
||||
sender as Telegram authenticated it; `/start` (`link`); a message it could not deliver (`failed`); and
|
||||
whether it can send (`standing`). Only a private chat with the account itself counts.
|
||||
|
||||
@@ -11,7 +11,8 @@ package main
|
||||
// clearing arrives without sound, an urgent message or a question rings (D4). A rate limit is waited out
|
||||
// as told (D5); a refusal is a permanent failure, said to the router, never retried; an edit to the same
|
||||
// text is a success (D6). A message that cannot be delivered after three tries is said as failed. A
|
||||
// `send` or `show` under a handle already shown replaces that message: deleted, and the new one sent.
|
||||
// `send` or `show` under a handle already shown replaces that message: the new one sent, then the earlier
|
||||
// one deleted.
|
||||
// - **What arrives** is long-polled: outbound only. A tapped button is said as a `choice` with the sender
|
||||
// the service authenticated, and acknowledged on the phone with the router's word on it — what was
|
||||
// recorded, or why it was not — which comes as a reply to the tap; without one in TapWait, with words that
|
||||
@@ -232,19 +233,21 @@ func (c *Channel) Take(subject string, body json.RawMessage) error {
|
||||
}
|
||||
words, buttons := text(m), c.buttons(m)
|
||||
silent := m.Silent || (!m.Urgent && len(buttons) == 0)
|
||||
var place *Placed
|
||||
if verb == asks.Edit || !m.Secret {
|
||||
// **A message said again under a handle already shown replaces it** (issue 373): a reminder or an
|
||||
// escalation is one message per problem, not one more beside it. An edit here notifies nobody, so this one
|
||||
// is sent, ringing as its kind rings, and only then is the earlier one deleted — one the service will not
|
||||
// delete loses its buttons and says a newer message follows. A send that fails leaves the earlier one.
|
||||
var place, earlier *Placed
|
||||
switch {
|
||||
case verb == asks.Edit:
|
||||
if place, err = c.Store.Placed(m.Handle); err != nil {
|
||||
return err // the state is away: offered again
|
||||
}
|
||||
}
|
||||
if verb != asks.Edit && place != nil {
|
||||
// **A message said again under a handle already shown replaces it** (issue 373): a reminder or an
|
||||
// escalation is one message per problem, not one more beside it. An edit here notifies nobody, so the
|
||||
// earlier message is deleted and this one sent, ringing as its kind rings; one the service will not
|
||||
// delete loses its buttons and says where the newer one is.
|
||||
c.replaced(*place)
|
||||
place = nil
|
||||
case !m.Secret:
|
||||
if earlier, err = c.Store.Placed(m.Handle); err != nil {
|
||||
c.Logf("[telegram] where an earlier message under this handle is could not be read (%v): sent as a new one", err)
|
||||
earlier = nil
|
||||
}
|
||||
}
|
||||
for try := 1; ; try++ {
|
||||
var id int64
|
||||
@@ -261,6 +264,9 @@ func (c *Channel) Take(subject string, body json.RawMessage) error {
|
||||
err = c.newMessage(m.Handle, chat, words, buttons, silent, &id)
|
||||
}
|
||||
if err == nil {
|
||||
if earlier != nil {
|
||||
c.replaced(*earlier)
|
||||
}
|
||||
c.mu.Lock()
|
||||
c.lastSent, c.lastErr = c.Now(), ""
|
||||
c.delivered++
|
||||
|
||||
@@ -625,3 +625,18 @@ func TestAMessageSaidAgainUnderItsHandleReplacesTheEarlierOne(t *testing.T) {
|
||||
t.Errorf("its buttons stayed: %s", kb)
|
||||
}
|
||||
}
|
||||
|
||||
// The review of PR 176: the new message is sent before the earlier one is deleted, so a send that fails leaves
|
||||
// the operator the earlier message rather than none.
|
||||
func TestAReplacementThatCannotBeSentLeavesTheEarlierMessage(t *testing.T) {
|
||||
c, f, _, st := newChannel(t, goodToken)
|
||||
st.Place("m1", Placed{Chat: 42, ID: 7})
|
||||
f.answer["sendMessage"] = func(map[string]any) (int, string) {
|
||||
return 400, `{"ok":false,"error_code":400,"description":"Bad Request: chat not found"}`
|
||||
}
|
||||
subject, body := work(asks.Send, asks.Message{Handle: "m1", Title: "Still open: ace silent", Urgent: true, To: "42"})
|
||||
_ = c.Take(subject, body)
|
||||
if len(f.of("deleteMessage")) != 0 || st.placed["m1"].ID != 7 {
|
||||
t.Fatalf("the earlier message was taken away though its replacement was not sent: %+v", f.of("deleteMessage"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user