# Dev Diary #20

*Killed duplicate-dispatch bugs in two services by replacing crude cooldowns with idempotent acks and proper redeliver...*

By [henrypye](https://paragraph.com/@henrypye) · 2026-05-18

idempotent handlers, webhook deduplication, rate limiting, reply threading, schema migrations

---

The flashcastr webhook started double-firing replies whenever the inbound payload arrived twice, which it does, often. The 6h per-author cooldown I'd written as a crude rate limiter was the wrong shape — it punished legitimate back-and-forth and did nothing to stop duplicate dispatches from the same payload. Ripped it out, replaced with an inbound rate limit keyed on the mention itself, plus a seen-ack LIKE on the cast so the webhook layer has an idempotent signal before \`conversational-reply\` ever runs. The threading was wrong too: replies were posting as top-level casts instead of actual Farcaster replies, which made the bot look like it was shouting into the void rather than talking to anyone. Two migrations landed alongside — \`0009\_add\_mentions\`, \`0010\_add\_corrections\` — because the self-correction path needs durable state, not in-memory hope. Over in agent-blog the publish handlers were not idempotent under RabbitMQ redelivery. Same class of bug, different surface: a retry would re-publish, and I'd find out via duplicate output. Fixed with a dedupe check before the side effect, tests in \`publish-handlers.spec\` covering the redelivery case explicitly. The dotfiles churn was mostly housekeeping that piled up: \`g checkout\` now \`cd\`s into the right worktree when the branch lives elsewhere, \`wt\` mandates a monitor pane for every lane so I stop losing track of background work, and the \`grid-4x2\` tmux script was only re-tiling the first split in the loop — classic off-by-one, embarrassing once spotted. Also scrubbed PII and org references across the tree before I forgot which files still had them. Universal Limbs got a from-scratch site wired into Sanity so the founder can edit copy without me. Vercel deploy config, OG images, real socials. The Sanity embed inside a React app is a bit awkward — the studio route sits next to the public pages and the auth boundary is fuzzier than I'd like. Still open: the seen-ack LIKE relies on Neynar webhook ordering I haven't fully stress-tested, and the correction-intent flow can probably be tricked by a malicious reply chain. Need to write adversarial fixtures next.

---

*Originally published on [henrypye](https://paragraph.com/@henrypye/dev-diary-20)*
