Make new_suggestions and Send to Google Chat recoverable
CI / ci (push) Successful in 6m48s
CI / ci (pull_request) Successful in 6m26s

MQ-167-01: a scheduled or manual batch now emits new_suggestions:{batchId}
in the transaction that first stores its Side quests, so the cards and
their notification commit together. A later round that fails, or a
failure recording the batch's end, no longer loses the event; a later
round's emit is a no-op by key; a notification that cannot be stored
fails that store, leaving no unannounced cards. Replenish batches still
never notify. finishBatch goes back to recording status only.

MQ-167-02: migration 0017 adds shopping_lists.chat_send_unconfirmed_at.
SendToChat records the send as begun before posting, clears it with
sent_to_chat_at once Google Chat accepts, and clears it alone when Chat
refuses. A post Chat does not answer, or one it accepts that cannot be
recorded, is ErrSendUnconfirmed (502 chat_unconfirmed, not retryable)
and leaves the marker, as does a crash mid-send; a repeat without resend
never reposts, and resend posts again. The Supply run screen re-reads
the list after a failed send, shows an unconfirmed send, offers no Retry
for it, and sends again only with resend.

Task: f0cd9d50-9c11-41be-a945-7bae9f5f28a4

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 16:26:19 -04:00
co-authored by Claude Opus 5.5
parent 45c4f8a803
commit 80a8dd0edf
23 changed files with 586 additions and 175 deletions
@@ -0,0 +1,10 @@
-- 0017_shopping_list_chat_send_unconfirmed: a send of a Supply run to
-- Google Chat is recorded as begun, in chat_send_unconfirmed_at, before it
-- is posted, and cleared when Google Chat's answer is known: with
-- sent_to_chat_at when it accepted the post, alone when it refused it. A
-- value left behind (Google Chat did not answer, the process stopped, or
-- recording the answer failed) means the post may or may not have been
-- made, so it is never posted again without resend. Existing rows have no
-- send under way.
ALTER TABLE shopping_lists ADD COLUMN chat_send_unconfirmed_at TEXT;
+18 -4
View File
@@ -89,13 +89,27 @@ UPDATE shopping_lists
SET title = ?, updated_at = ?
WHERE id = ? AND title IS NULL AND status = 'current' AND frozen_at IS NULL;
-- name: MarkShoppingListSentToChat :execrows
-- Records list id sent to Google Chat at sent_to_chat_at, unless it is
-- frozen into the Supply archive.
-- name: BeginShoppingListChatSend :execrows
-- Records a send of list id to Google Chat begun at
-- chat_send_unconfirmed_at, before it is posted, unless the list is frozen
-- into the Supply archive.
UPDATE shopping_lists
SET sent_to_chat_at = ?, updated_at = ?
SET chat_send_unconfirmed_at = ?, updated_at = ?
WHERE id = ? AND status = 'current' AND frozen_at IS NULL;
-- name: MarkShoppingListSentToChat :execrows
-- Records list id sent to Google Chat at sent_to_chat_at, its send
-- confirmed, unless it is frozen into the Supply archive.
UPDATE shopping_lists
SET sent_to_chat_at = ?, chat_send_unconfirmed_at = NULL, updated_at = ?
WHERE id = ? AND status = 'current' AND frozen_at IS NULL;
-- name: ClearShoppingListChatSend :execrows
-- Clears the send of list id begun, once Google Chat refused it.
UPDATE shopping_lists
SET chat_send_unconfirmed_at = NULL, updated_at = ?
WHERE id = ?;
-- name: FreezeShoppingList :execrows
-- Freezes list id into the Supply archive at frozen_at, unless it is
-- frozen already.