DEV Community

Cover image for dev.to's Dashboard Can't Count Its Own Posts

dev.to's Dashboard Can't Count Its Own Posts

Daniel Nwaneri on August 03, 2026

This is a submission for DEV's Summer Bug Smash: Clear the Lineup powered by Sentry. Project Overview forem is the open source platform...
Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Great post! I'd love to contribute something to Forem one day as well!

Also... those submissions are way too good. I was counting on winning that skateboard! 😂

Collapse
 
dannwaneri profile image
Daniel Nwaneri

Sylwia, do it . mine sat starred and uncloned for months before I actually opened it. The hardest part isn't the code, it's the opening. (And honestly, I'd trade the skateboard for the merge . still waiting on that part.)

Collapse
 
anmolbaranwal profile image
Anmol Baranwal

nice. I have also noticed the reading experience on devto has gotten way better. keep smashing bugs :)

Collapse
 
merbayerp profile image
Mustafa ERBAY

I enjoyed the emphasis on verification over confidence. Not knowing Ruby didn’t stop you from reasoning about the bug because the underlying problem—cached state diverging from filtered data—is language-agnostic. Regression tests and CI are much stronger evidence than “it looks right.” Great contribution, and good luck with the merge!

Collapse
 
dannwaneri profile image
Daniel Nwaneri

Mustafa, language-agnostic is the plausible way to say what I was circling. The shape of the bug (cache vs. filtered view drifting apart) I could reason about cold.

Writing the actual fix in idiomatic Ruby and knowing counter_culture's real behavior instead of guessing at it, wasn't language-agnostic at all. That's the part I still needed Claude for.

Collapse
 
merbayerp profile image
Mustafa ERBAY

That’s a distinction I completely agree with. Understanding the failure mode and implementing an idiomatic fix are two different skills.

AI is becoming remarkably good at bridging language-specific knowledge, but it’s still up to the developer to define the problem, challenge assumptions, and verify that the solution preserves the system’s intended behavior. That’s where engineering judgment still makes the difference. Thanks for the clarification

Thread Thread
 
dannwaneri profile image
Daniel Nwaneri

That's the whole job description now, honestly. defining the problem and setting the verification bar are the parts that don't delegate.

Collapse
 
gnlassi profile image
Ghulam Nabi

Well said.
Reasoning about the bug = language agnostic.
Shipping the fix in idiomatic Ruby + knowing counter_culture internals = not agnostic at all 😅

Glad Claude helped bridge that gap.

Collapse
 
hemapriya_kanagala profile image
Hemapriya Kanagala

I don't know Ruby either, so this was nice to read 😄 I'd love to contribute to Forem one day too, but the Ruby codebase has always made me a little hesitant to try.

Hoping your PR gets merged, Daniel! Great work on this one.

Collapse
 
dannwaneri profile image
Daniel Nwaneri

Hema ,same boat not knowing Ruby is basically the whole premise of this one. The blocker was never reading Rails, it was reading Rails alone. Claude did the actual code work; I picked the target and gated everything that left my machine before it shipped. That's a real workaround for genuinely not knowing a languag, not a training-wheels version. What's the first thing you'd want to fix if you gave it a shot??

Collapse
 
hemapriya_kanagala profile image
Hemapriya Kanagala

I haven't explored the Forem repo much yet, so I don't have a specific fix in mind 😄 I'd probably start with one of the good first issues and see where that takes me. Definitely want to give it a shot though!

Thread Thread
 
dannwaneri profile image
Daniel Nwaneri

Hema, heads up before you go looking: I checked and "good first issue" had zero open matches on forem/forem when I went hunting for mine . 213 closed, none open. The "always open for contribution" bug label is what's actually active right now. Worth starting there instead.

Collapse
 
svyatov profile image
Leonid Svyatov

@hemapriya_kanagala look at the controller snippet in the post, most of a Rails app looks like that. Ruby is much easier to read than to write, the hesitation drops fast once you start.

Collapse
 
hemapriya_kanagala profile image
Hemapriya Kanagala

That's reassuring to hear 😄 The controller snippet did look more readable than I expected. I think I just need to stop overthinking the Ruby part and actually spend some time exploring the codebase. Thanks for the encouragement, Leonid!

Collapse
 
motedb profile image
mote

This is a perfect example of why cached counts are always a liability when the query shape can evolve independently.

The specific failure mode — a counter_culture cache that counts everything, sitting next to a filtered view that counts a strict subset — is one of the most common consistency bugs in production systems. The fix you landed on (scoped helper that mirrors the actual query shape) is right, but it raises a subtler question: who owns the contract between the cache and the view?

In a system with one team, the answer is implicit. In forem — open source, with contributors who may not know about the articles_count cache when they add a new article type or filter — it's a structural hazard. Every time someone adds a new article type or a new filter condition, someone has to remember to update the posts_count_for helper. That's a tribal knowledge trap.

The robust version of this is query-derived counts computed on read (accept the p99 hit on the dashboard), or an explicit scope_version field that the cache is keyed to, so any scope change bumps the cache key and forces recompute. Neither is free, but both eliminate the class of bug entirely rather than patching the specific instance.

The point about CI catching a real failure in your test — not the fix — is the most important paragraph in the piece. That's the signal that you were actually outside your confidence region. Someone reading this who hasn't shipped a bad test they were sure was correct will not have the reference to understand why this matters.

Collapse
 
akash_yadav_03c587d791345 profile image
akash yadav

Dev.to’s dashboard may sometimes display an incorrect post count because of caching delays, draft or published status differences, deleted posts, or temporary synchronization issues. If the number does not match the posts visible on your profile, checking the published-post list, refreshing the dashboard, or waiting for the platform to update may help.

At Aqva Marketing, accurate content tracking is important for measuring publishing consistency, audience engagement, and SEO performance. When platform dashboards show inconsistent data, it is better to verify the actual published content and use additional analytics tools rather than relying on one metric alone.

Collapse
 
publiflow profile image
PubliFlow

Good technical content. Quick mention: we just launched tools.shopveigo.com with a bunch of free AI tools (background remover, essay polisher, cover letter generator etc). Built for developers and content creators. Feedback welcome!

Collapse
 
talha_ramzan_3878156fea8c profile image
Talha Ramzan

"I don't write Ruby" and then casually opens a PR against the actual dev.to codebase is the programming equivalent of "I don't really cook" right before someone plates a soufflé. Also deeply relatable that the bug was a counter counting things a filter refuses to show, the "it's not lying, it's just answering a different question" defense is doing a lot of work for both software and my own excuses on why my step count doesn't match how tired I feel.

Collapse
 
leob profile image
leob

I think I've noticed some occasional "glitches" in 'like' counters on articles and comments, but the glitches always seemed ephemeral or temporary ... nice job you did with this one!

Collapse
 
dannwaneri profile image
Daniel Nwaneri

leo , that tracks, actually. Reactions run through the same counter_culture mechanism I found powering the posts count in this bug (app/models/reaction.rb). I didn't dig into why yours self-corrects but same underlying pattern, different symptom. If it's reproducible, might be worth its own issue.

Collapse
 
leob profile image
leob

I ran into one instance where it did not self-correct - the scenario was like this:

I posted a comment, and then normally it always starts with 1 like - that happens automatically, even when nobody clicks "like": it starts with 1, not with 0 ...

But in this case it started with zero :-)

So I just liked my own comment (only case I've ever done that, lol), to "fix" it :-)

Thread Thread
 
dannwaneri profile image
Daniel Nwaneri

hadn't heard that before — comments seeding at 1, not 0, by default. If that's real, that's a different failure shape than mine: I had a stale read, yours sounds more like a missing default write. The self-fix by liking your own comment is the best repro step in this whole thread, 😀😀😀

Thread Thread
 
leob profile image
leob • Edited

Very, very rare "glitch", a comment starting out at 0 instead of 1 (likes, that is) - in all those years I've seen it just once ... yeah, liking my own comment was a very effective fix! 😁

Thread Thread
 
dannwaneri profile image
Daniel Nwaneri

leo, one in years is basically the control group confirming it's real. 😁

Collapse
 
publiflow profile image
PubliFlow

Interesting perspective. One thing I'd add is that context matters a lot here — the right approach depends heavily on team size, project stage, and existing infrastructure. There's rarely a one-size-fits-all solution.

Collapse
 
tech_grundy profile image
The Tech Grundy

"A cached count drifting from what a filtered view actually renders" is such a classic, language-agnostic bug.

The decision not to touch the global articles_count cache on User is spot on. Leaving the raw counter intact for spam heuristics while introducing a dedicated helper (posts_count_for) scoped to active, non-archived full posts fixes the UX without breaking background logic. Great writeup on tracing the flow through DashboardsController without relying on Ruby familiarity!

Loved the section on relying on CI when local setups aren't available. Catching the create(:article, type_of: "status") validation failure because the factory default included markdown body text was a neat demonstration of how factory defaults and model validations can surprise you.

Writing explicit regression specs asserting that a user with 1 post, 1 status, and 1 archived post sees a count of exactly 1 makes this PR super clean. Great contribution to the Bug Smash!

Collapse
 
gnlassi profile image
Ghulam Nabi

Excellent piece of post.

Collapse
 
svyatov profile image
Leonid Svyatov

@dannwaneri I read my own dev.to numbers through the API and not the dashboard, mostly out of habit. Now I have an actual reason :)