cd /news/ai-agents/my-blog-had-20-unanswered-comments-a… · home topics ai-agents article
[ARTICLE · art-65035] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

My Blog Had 20 Unanswered Comments Across 35 Posts. Nothing Ever Told Me.

A developer discovered that their automated blogging agent had left 20 comments unanswered across 35 posts over several weeks, because the publishing pipeline was never designed to handle post-publish engagement. The developer built a script to detect unreplied comments by recursively checking comment threads and deduplicating against a local drafts file, highlighting a blind spot in AI-generated code where missing features go unnoticed.

read5 min views2 publishedJul 19, 2026

I run a scheduled agent that writes and publishes articles to this account. It's been going since late June, twice a day, and until this week I genuinely believed the loop was complete: write, publish, done. Then I went looking for something unrelated in the DEV.to API and stumbled on GET /api/comments?a_id=...

. Out of curiosity I ran it against all 35 published posts.

Twenty comments. Zero replies. Some of them six weeks old.

Nothing had failed. There was no error in any log, no crash, no red X anywhere. The publishing pipeline had been doing exactly what it was built to do, every single run, for weeks. It just was never built to do anything with what happened after publish. That gap doesn't show up as a bug because there's no failure mode attached to it — a comment that never gets a reply doesn't throw, it just sits there, and nothing in the system was ever going to tell me it was sitting there.

This is the part of "AI writes code fast" that doesn't get talked about much. The loan isn't in the code that gets written badly. It's in the code that never gets written at all, because the thing generating output has no mechanism for noticing what it left behind. Every publish was a small, invisible commitment — I'll come back to this if someone engages — and every one of those commitments quietly went unpaid, because "come back to this" was never a step in the loop. It compounds the same way debt does: not through any single dramatic failure, but through the absence of anyone checking the balance.

The first version of "check for unanswered comments" I wrote was a script that just listed every comment, which is useless — of course there are comments, that's the point of publishing. The question that matters is which ones am I on the hook for, and answering that turned out to be less obvious than "count == 0."

A comment thread can have replies from other people that aren't from me. It can have nested children several levels deep where my reply is buried three levels down, not at the top. Checking comment.replied

isn't a field DEV.to gives you — you have to walk the tree yourself:

ME = "enjoy_kumawat"

def replied_by_me(comment):
    return any(c["user"]["username"] == ME or replied_by_me(c)
               for c in comment["children"])

That's the whole check: recurse through children

, true if I show up anywhere in the subtree. It's four lines, but it's the four lines that turn "list of comments" into "list of things I actually owe a response to." Without it, the script would either nag me about threads I'd already closed out, or — worse — silently skip ones where someone else replied but I never did, because "someone replied" isn't the same claim as "I replied."

The second thing the script had to get right was not re-surfacing the same debt twice once I'd started paying it down. I draft replies into a markdown file and paste them in manually — more on why in a second — so "already handled" means "already sitting in the drafts file," not "already answered on the site":

def pending():
    drafted = open(DRAFTS, encoding="utf-8").read()
    out = []
    for a in api(f"/articles?username={ME}&per_page=100"):
        if not a["comments_count"]:
            continue
        for c in api(f"/comments?a_id={a['id']}"):
            if c["user"]["username"] == ME or replied_by_me(c):
                continue
            if c["id_code"] in drafted:
                continue
            out.append({
                "id_code": c["id_code"],
                "author": c["user"]["username"],
                "article": a["title"],
                "comment_url": f"https://dev.to/{ME}/comment/{c['id_code']}",
                "body": strip_html(c["body_html"]),
            })
    return out

Two dedup checks stacked on top of each other: skip what's already answered on-site, then skip what's already queued locally. Miss either one and the script either nags forever or double-drafts the same reply. Neither failure is loud. Both just make the tool something I'd stop trusting within a week.

The honest answer is that nothing in the publishing loop was ever going to surface it on its own. The scheduled run's whole contract is "check quota, find a trend, write, publish, log it." Replying to comments was never in that contract, so from the loop's point of view, 20 unanswered threads and 0 unanswered threads look identical — both are just not its problem. I only found this because I happened to be poking at a different API endpoint and got curious enough to point it at my own account.

That's the actual lesson, and it's not "write more careful code." The code was fine — create_article

did exactly what it said. It's that a system with no step for "and then check what state this left behind" will happily run for weeks without anyone noticing the debt, because the debt doesn't live anywhere the system looks. If I hadn't gone looking by accident, there'd be no reason to expect I'd have gone looking on purpose — there was no dashboard, no count, no signal that would have prompted it.

I didn't fix this by adding validation or a reminder to "check comments sometimes." I fixed it by writing the one script above and giving it a place to run — the same scheduled loop I already had, with one more step at the end. The API can't post comments for a normal-tier account (POST /api/comments

404s outright, and reactions 401 even with a valid key) so full automation isn't on the table — replies get drafted, then pasted by hand from comment_url

. That's a real constraint, not a workaround I'm proud of, but it beats the alternative, which was a debt that would have kept growing forever because nothing was ever going to ask about it.

If you're running anything on a loop — a scheduler, a cron job, an agent that fires off actions and moves on — the question worth asking isn't "does this work." It's "what does this leave behind that nothing downstream ever checks." That's where the loan quietly accrues.

── more in #ai-agents 4 stories · sorted by recency
── more on @dev.to 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/my-blog-had-20-unans…] indexed:0 read:5min 2026-07-19 ·