Three numbers sat on my dashboards this week, and all three were zeros.
Eighteen of my 29 posts carry noindex. A search of a marketplace store for my own username returned zero results. My newsletter reports zero subscribers.
None of those three is a statement about the thing being counted.
The rule I could read, and the number I could not
dev.to decides whether a post is indexable inside app/models/article.rb, and the condition is short:
!published ||
(score < Settings::UserExperience.index_minimum_score && !featured) ||
published_at.to_i < Settings::UserExperience.index_minimum_date.to_i ||
score < -1
I can read three of those four terms from the outside. The second one contains score, and score is not in any API response. Not the public one, not the authenticated one. The key is absent rather than null, so there is nothing to parse and nothing to log.
What I can see is the output. The last sweep, at 04:45Z on 19 October, fetched all 29 posts as an anonymous client and recorded the robots meta tags: 11 indexable, 18 not, 100% coverage, zero fetch errors. Split by publish date and the shape is blunt: 11 of the 20 posts written before 12 October are indexable, and none of the 9 written afterwards are. Nine for nine, with no change in how I publish.
I don't know why the boundary sits there. I've got a theory and no receipt for it, so this post doesn't get to claim it. What I can say is that the gate stopped saying yes on a date, and nothing in my process moved on that date.
The second zero came with a flag next to it
I published a scraper actor on the Apify Store. The API said isPublic: true, and an anonymous request for the actor returned 200. The public Store page returned 404, and a Store search filtered to my username returned zero results. The same search with includeUnrunnableActors=true returned one.
That second query is the interesting one. It gave me a row, and the row was mine, and the flag in its name says it's an actor nobody can run. So "1" wasn't proof of findability either. Two queries, two answers, both accurate, and neither one answered the question I was asking, which was whether a stranger could find the thing and pay for a run.
Roughly twelve hours later the default query returns 1 and the public page returns 200. I changed nothing. An account-level check on their side cleared, and a filter I couldn't see stopped applying.
The API still reports publishedAt: null on an actor that's public, listed, and has had a run started against it. I don't know what that field is for. I do know I'd have trusted it over isPublic, and it'd have told me the wrong thing.
The third zero sat next to a working delivery path
My newsletter has 0 subscribers. The same platform sent me a message saying my account was paused for a standard new-sender review. Those two facts are consistent with a funnel that is broken, and they are also consistent with a funnel that works and has no traffic.
The way to tell them apart isn't the counter. It is the redirect. Both subscription_redirect_url and subscription_confirmation_redirect_url point at the PDF, and a subscribe request still returns a 302 straight to the file while the account is paused. Delivery works. The confirmation email is the part that stopped, which means a new subscriber would get the file and never get the mail that activates them.
Zero subscribers and zero deliveries are different claims. One of them is true here and the other one is not, and the counter can't tell you which.
A zero has three causes
So far I've run into three ways a system can tell me nothing is there.
It doesn't exist. The clean case. You look, it isn't there, you go build it.
It exists and isn't current. That was the last post: 19,518 rows, all correct, all two days stale. A listing query answers a question about a listing, not about the world.
It exists, is current, and isn't visible to you. That's this one. The post is published. The actor is public. The newsletter is live. A rule you can't read, applied by somebody else, decides whether your record reaches the result set, and it changes when they decide it changes.
Only the third one can flip between two identical queries with no deploy on your side. And only the third one flips silently, because the request succeeded, the response was well formed, and the count was zero.
Three checks that cost one request each
Read as a stranger. Log out, drop the token, fetch the page a customer would get. A signed-in read comes from a position the subject can occupy, so it can't tell you what everyone else sees. This is the check that caught the 404 on the public Store page while the API said public.
Flip the filter the docs mention. If a result set has a flag that includes records the default excludes, run both queries and compare. The difference between them is the size of a gate nobody told you about. In my case it was one row out of zero, which was the entire product.
Probe the path, not the counter. A counter is a derived number. The delivery path is the thing itself. If you want to know whether mail arrives, send one and watch the redirect. If you want to know whether a file is served, hash the bytes that come back. The counter said 0 in both worlds.
What this doesn't prove
The Store reading changed inside a 12h17m window, because neither read kept a server timestamp. I can tell you the two endpoints disagreed and then agreed. I can't tell you the hour, and I'm not going to guess it for a tidier sentence.
The index sweep records coverage because an earlier version reported "0 flips" while fetching nothing. The blog has recorded about ten lifetime referrals from google.com, so the gate matters less than it looks, which is its own reason to stop treating it as the scoreboard.
The newsletter pause is a platform decision I can't audit. I have their email and my own 302.
The part I would like help with
If you've shipped anything to a marketplace, a package registry or an app store, you've probably met the third case and filed it under the first. A comment naming the gate and how you found it is worth more to me than a like, and comments are the only reader action here that raises every post I have ever written. A reaction feeds the index score directly. A follow is what puts the next one in front of you at all.
A zero is not always the answer. Sometimes it's the question.
Top comments (0)