Back to Blog
build-in-publicindie-hackersengagementtwitterbug-post-mortem

168 mentions, 0 replies. The 4-line bug that was silencing our audience.

Nemo5 min
Share:
TL;DR — BlogBurst logged 168 Twitter mention-received events in 24 hours and replied to 0 of them. The 168 was actually 27 unique tweets from 17 people (our log had a dedup bug). The more serious bug: a 7-day author blacklist designed to prevent reply-spam was silencing every on-ICP follow-up. We narrowed the blacklist to 24 hours and added tweet_id dedup on the inbox log. Within 90 minutes the system fired its first-ever mention reply — to an 800-follower account who had asked for a coffee chat.

168 mentions, 0 replies.

That is the actual row count from our agent_activity_logs table for one product yesterday: 168 notification_reply_received events and 0 corresponding engagement_mention_reply events. Every single person who @-mentioned @BlogBurstAI on Twitter got silence.

When you post "build in public" content and 168 humans write back at you, the fastest way to burn their interest is to not reply to any of them.

What the 168 actually was

The real picture is both better and worse than the raw number.

Better: those 168 rows were only 27 unique tweets from 17 unique people. Our notification-scan cron was re-fetching the same batch every 3 hours and logging each mention fresh every time, so the inbox feed inflated 6× over a day.

Worse: of those 17 people, several were the most on-ICP replies we had ever received — including one ("Can we have a coffee chat?") from an 800-follower account.

Going silent on them is worse than never being mentioned at all.

The bug was a "nice guy" protection rule

When you run any kind of auto-engagement system, you quickly learn to throttle how often you reply to the same person. Reply too often to one account and Twitter's abuse heuristics start flagging you. So we wrote this:

# event_engine.py — mention reply phase
responded_author_ids = set()
for mem in recent_responses_last_7_days:
    responded_author_ids.add(mem.evidence.get("author_id", ""))

for mention in mentions:
    author_id = mention.author.id
    if author_id in responded_author_ids:
        continue  # we talked to them this week, skip

Looks reasonable. Looks like a good neighbor rule. It also happens to be the exact thing that silenced every on-ICP reply we received.

Here is how it played out for one specific user — @slwl_dev, indie hacker, 33 followers, building a screenshot API for developers:

  1. Day 1 — our proactive engagement cycle searches for relevant conversations, finds one of his tweets about developer tools, replies with a thoughtful take. We log the reply with his author_id under notification_response.
  2. Day 2 — he sees our reply, follows us, comes to our profile, reads a few of our build-in-public posts, and @-mentions us with a genuine question.
  3. Our system pulls his mention. Checks our 7-day blacklist. Finds his author_id. Skips.
  4. Day 3 — he mentions us again with follow-up context. Skip.
  5. Day 4 — again. Skip.
  6. Day 5 — he has moved on.

Want this done automatically for your product?

Try BlogBurst — 7 Days Free

The rule was designed to prevent us from reply-spamming the same person. It ended up preventing us from having a conversation with the one kind of person who was actually trying to start one.

The fix

Two changes to the same file:

1. Narrow the author blacklist from 7 days to 24 hours. Inside a single day we absolutely should not reply to the same account twice. Beyond that, silence is worse than repetition.

2. Add dedup on the notification-received log itself. Before writing a notification_reply_received row, check if we already logged the same tweet_id in the last 7 days. Skip if yes. This kills the 6× inflation and makes the inbox a clean record of distinct mentions.

# Narrow author window to 24h
recent_authors_24h = db.query(MarketingMemory).filter(
    MarketingMemory.product_id == product.id,
    MarketingMemory.memory_type.in_(['notification_response', 'engagement_log']),
    MarketingMemory.created_at >= datetime.utcnow() - timedelta(hours=24),
).all()

Deployed at 10:29 Beijing this morning. Within 90 minutes of the next cron cycle, the system fired its first-ever reply on a mention received: a reply back to the 800-follower account who had asked for a coffee chat.

What this bug is really about

Engagement automation has a natural bias toward caution. Every throttle, every dedup, every "don't annoy the user" rule makes your system a little safer — and a little more silent.

In our case we had 168 rows of people trying to talk to us. A 4-line fix released all the backed-up replies in one cycle.

The larger lesson: audit your "nice guy" rules. The ones you added because you were worried about misbehaving often end up muzzling you more than they protect you. Our reply-per-author cap was meant for a 2023-era spam problem on an account with a real audience. We are an indie product with 44 followers. A 7-day cooldown at this scale is absurd — we are nowhere near the spam ceiling.

You do not need to remove the rule. You need to scale its aggressiveness with the account's actual activity. A brand with a million followers does need a long cooldown. An indie hacker account with 44 followers and 17 mention-senders a week does not.

I am watching the next 48 hours of mention traffic to see whether the fix sticks — and whether any of the previously-silenced accounts come back.

Stop posting manually. Let AI do it 24/7.

BlogBurst writes, publishes, and grows your social media across Twitter, Bluesky, Telegram & Discord — while you sleep. 7-day free trial, no credit card.

Start 7-Day Free Trial

7-day free trial · No credit card required