Skip to content

T 172


uid: T-172 title: Receipt pipeline fits Hobby windows β€” split the Inngest mega-step (fixes I-036) status: done area: telegram-receipts created: 2026-07-21 updated: 2026-07-21 owner: girafeev1 assignee: Records (Infrastructure) related: T-170, T-171, I-036


Goal (owner, 2026-07-21: "make them actually work")

Receipt uploads died with Inngest's "Your server returned HTTP 504 before the SDK responded" (I-036): the pipeline's single process-receipt step ran extract + Gemini clean(Γ—3) + verify + crop in ONE /api/inngest invocation β€” "~10s of pipeline" on Pro that exceeds the 60s window on Hobby compute (Vercel SIGKILL β†’ 504 β†’ Inngest retry loop).

What shipped (lib/inngest/receipt-processor.ts, lib/telegram/receiptProcessor.ts)

  • The mega-step is split so each serverless invocation holds ~one Gemini round-trip: parse-fields β†’ clean-image-1..3 (ONE clean+verify attempt per step; drift retries get fresh invocations) β†’ crop-fallback (deterministic crop + sharp polish, only when no verified clean). Phase order, retry semantics, drift handling, fallbacks, and the assembled processed object are byte-identical to GeminiReceiptProcessor.process(); state rides between steps as JSON/base64 exactly like the existing download step.
  • DocumentAI escape hatch preserved: extractFields failure runs the processor's full process() (which carries the DocumentAI fallback) in one step β€” the old behavior for that path.
  • Interface: ReceiptProcessor gains OPTIONAL extractFields/cleanImage/verifyCleanedImage; the split engages only when all three exist β€” a processor without them (e.g. DocumentAI-primary) keeps the original single process-receipt step.
  • Works hand-in-hand with T-171 phase 2: RECEIPT_CROPPER_URL now points at the NAS cropper, so the crop-fallback step's crop is a fast remote call instead of skipped-entirely (the prod URL slot previously held a 1,124-char pasted JSON blob β€” same accident family as the deleted dev CRON_SECRET β€” so NO cropping ran anywhere; documented in T-171).

Log

  • 2026-07-21 β€” created + done (Records Infrastructure; owner "Let's move everything to the NAS and make them actually work"). βœ… Read AGENTS.md Β· checked the board by scope (I-036 is the symptom ticket; T-171 owns the infra side; this task owns the code split β€” no dup). Source: Records (Infrastructure) Β· https://claude.ai/code/session_018RDB37kCqfouHdygVXTAtD
  • Full unfiltered tsc --noEmit clean. Merged to main; activation deploy per T-171 phase 2 (one deploy carries the split + the NAS service env). Owner runtime-verify: upload a captionless receipt β†’ note prompt quotes the photo (T-169) β†’ processing completes without the 504; status line walks Reading β†’ Cleaning β†’ (Verifying/Cropping) β†’ summary.
  • Blast-radius: the Inngest receipt function's step layout changed (in-flight runs at deploy time may replay oddly β€” one-off); ReceiptProcessor interface widened (optional members only). Webhook, store, Records page untouched.