Skip to content

T 169


uid: T-169 title: Telegram bot β€” substantiation-note prompt must identify WHICH receipt it's asking about status: done area: telegram-receipts created: 2026-07-16 updated: 2026-07-16 owner: girafeev1 assignee: Records (Infrastructure) related: T-067, T-115


Goal (owner, 2026-07-16)

When a receipt is uploaded without a caption, the bot's follow-up ask read only "πŸ“ Send a business-purpose note for this receipt … note:7412172786-…-9714ffa8" β€” with several receipts in flight the user cannot tell WHICH receipt the bot means; the note:<id> token is machine-correlation, not human information. Owner: adjust the process so the follow-up carries enough for the user to differentiate.

Why it's built this way (constraint)

The prompt fires immediately on photo receipt β€” before the AI parse runs (the note is captured pre-Inngest per DIPN 21), so merchant/amount don't exist yet at prompt time. That's why the message was bare. The differentiators that DO exist at that moment: the photo message itself and the upload time. So: quote the photo (Telegram reply_parameters β†’ the thumbnail renders right above the ask) + stamp the upload time into the text. No pipeline reordering, no schema migration; the note:<pendingId> token and the force-reply matcher are untouched.

What shipped (pages/api/telegram/receipt-webhook.ts)

  • Pending doc gains photoMessageId (the original photo's Telegram message id) so every later prompt about that receipt can quote it β€” including the note-edit re-prompt and the defensive re-ask, which previously had no handle on the photo.
  • Shared notePromptText(pendingId, sentAt, quoted): "…for the receipt quoted above (photo sent Jul 16, 14:02) …" β€” HK-time via formatHkTime; toDateMaybe coerces the Firestore Timestamp. Legacy pendings without photoMessageId degrade to the time-only wording; nothing breaks mid-flight.
  • tgSendForceReply + tgSendMessageWithKeyboard gain optional replyToMessageId β†’ reply_parameters: { message_id, allow_sending_without_reply: true } (deliverable even if the user deleted the photo). All 3 note-prompt sites + the caption-confirm prompt now quote the photo.

Log

  • 2026-07-16 β€” created + done (Records Infrastructure; owner request in-session; owner chose to keep this with Records rather than spawn a dedicated Telegram-bot agent β€” the bot is in-repo Records plumbing and the change is contained). βœ… Read AGENTS.md Β· checked the board by scope (T-007 dropped / T-067 / T-115 adjacent, none cover the note-prompt UX; no dup). Source: Records (Infrastructure) Β· https://claude.ai/code/session_018RDB37kCqfouHdygVXTAtD
  • Verdict: shipped as scoped β€” quote-the-photo + upload-time differentiation on every substantiation-note prompt; correlation token unchanged. Full unfiltered tsc --noEmit clean (after clearing stale .next/types from the bank-accounts retirement β€” not from this diff).
  • Merged to main, no deploy (owner: commit + merge every change; deploys manual β€” a deploy was cancelled mid-build by the owner earlier today to batch more work; this rides the next one).
  • Blast-radius: pages/api/telegram/receipt-webhook.ts only (pending-doc shape gains one nullable field written at create; readers tolerate its absence). The Inngest processor, receipt store, and web Records page are untouched. Owner runtime-verify: upload 2+ receipts without captions in quick succession β†’ each prompt quotes its own photo thumbnail + shows its upload time; reply to one prompt β†’ the note lands on the right receipt (token matching unchanged).