<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jack</title>
    <description>The latest articles on DEV Community by Jack (@jackzhouqd).</description>
    <link>https://dev.to/jackzhouqd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4108963%2F0906cfef-402e-4712-bf9e-457d6077dd46.png</url>
      <title>DEV Community: Jack</title>
      <link>https://dev.to/jackzhouqd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jackzhouqd"/>
    <language>en</language>
    <item>
      <title>Two of my "independent sources" were the same company. Here's the test I use now.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Thu, 24 Sep 2026 02:49:57 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/two-of-my-independent-sources-were-the-same-company-heres-the-test-i-use-now-442h</link>
      <guid>https://dev.to/jackzhouqd/two-of-my-independent-sources-were-the-same-company-heres-the-test-i-use-now-442h</guid>
      <description>&lt;p&gt;I run a small site that aggregates something boring: Roblox game codes. The only&lt;br&gt;
thing that makes it different from the dozen larger sites doing the same job is a&lt;br&gt;
rule I wrote for myself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A code only goes on my page if at least two independent sources list it as&lt;br&gt;
working, and no majority calls it dead.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Simple enough to implement in an afternoon. The word that turned out to be hard&lt;br&gt;
was &lt;em&gt;independent&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The day the rule fired for the wrong reason
&lt;/h2&gt;

&lt;p&gt;Two codes showed up for one game. Two sites listed them. Two is my threshold, so&lt;br&gt;
in they go — except I looked at the two sites first.&lt;/p&gt;

&lt;p&gt;One was Pocket Tactics. The other was PCGamesN. Both are Network N properties.&lt;br&gt;
Same company, same code desk, in practice the same list published twice.&lt;/p&gt;

&lt;p&gt;That's not two sources. That's one source with two domains, and my rule would&lt;br&gt;
have been satisfied by a single editorial decision at a single publisher. The&lt;br&gt;
whole point of requiring two was to make a single mistake insufficient.&lt;/p&gt;

&lt;p&gt;So I didn't add the codes, and I wrote down why.&lt;/p&gt;

&lt;h2&gt;
  
  
  The harder case: two sites with no visible relationship
&lt;/h2&gt;

&lt;p&gt;Shared ownership is the easy version — you can look it up. The version that&lt;br&gt;
actually worries me is syndication: site A licenses or scrapes site B's table,&lt;br&gt;
and nothing on either page says so.&lt;/p&gt;

&lt;p&gt;Here's the test I settled on, and it needs no external data:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compare the two tables as &lt;em&gt;sequences&lt;/em&gt;, not as sets. If the entries appear in&lt;br&gt;
the same order &lt;strong&gt;and&lt;/strong&gt; the reward wording matches word for word — including in&lt;br&gt;
the expired section — treat them as one source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Order is the load-bearing part. Two teams independently tracking the same game&lt;br&gt;
will arrive at overlapping sets; that's expected and it's exactly the agreement&lt;br&gt;
I'm trying to measure. What they will not do is independently arrive at the same&lt;br&gt;
&lt;em&gt;arrangement&lt;/em&gt;, and they will not independently phrase a reward as&lt;br&gt;
"5 Exotic Ingots, 10 Reforge Stones" down to the comma.&lt;/p&gt;

&lt;p&gt;The expired section is the best signal of all. Nobody curates their dead-code&lt;br&gt;
list. It's append-only junk, ordered by whenever someone got around to moving a&lt;br&gt;
row. When two sites' junk drawers match, they're the same drawer.&lt;/p&gt;

&lt;p&gt;On one game I found two sites whose active sections agreed on 28 of 33 entries in&lt;br&gt;
identical order, with identical reward wording — and whose expired sections had&lt;br&gt;
all nine rows in the same sequence. I stopped counting them as two.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I got wrong, and had to write into the rule
&lt;/h2&gt;

&lt;p&gt;I assumed "these two sites are the same source" was a property of the &lt;em&gt;sites&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It isn't. It's a property of the &lt;strong&gt;site pair on a specific topic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I had flagged one pair as syndicated based on their table for game A. Later I&lt;br&gt;
checked the same pair on game B, expecting to confirm it. They had 12 entries&lt;br&gt;
versus 17, different sets, different reward wording line by line. On game B they&lt;br&gt;
were plainly independent.&lt;/p&gt;

&lt;p&gt;Which makes sense once you say it out loud: a site can republish someone else's&lt;br&gt;
table for the games it doesn't cover itself, and write its own for the ones it&lt;br&gt;
does. So the rule now reads "this pair, on this topic, as of this date," and I&lt;br&gt;
re-check rather than carry the verdict forward.&lt;/p&gt;

&lt;p&gt;If you're building anything that scores agreement across sources, I'd suggest&lt;br&gt;
assuming this is true of your sources too until you've checked per topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the rule looks like when it refuses to fire
&lt;/h2&gt;

&lt;p&gt;Three days, same rule, three different outcomes. I think the third is the one&lt;br&gt;
worth talking about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day one&lt;/strong&gt; — it &lt;em&gt;rejected&lt;/em&gt;. Two listings, one publisher, codes held back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day two&lt;/strong&gt; — it &lt;em&gt;accepted&lt;/em&gt;. Two more sites, genuinely unrelated, published the&lt;br&gt;
same codes. Threshold met, codes added. Same rule, opposite direction, one day&lt;br&gt;
apart. That mattered to me, because a rule that only ever says no is&lt;br&gt;
indistinguishable from being slow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day three&lt;/strong&gt; — it &lt;em&gt;declined to act&lt;/em&gt;. A code I'd been carrying got moved to the&lt;br&gt;
expired table by two independent sites. Under the symmetric version of my rule&lt;br&gt;
that's enough to flip it. But this particular row wasn't something I had taken on&lt;br&gt;
anyone's word — I'd typed it into the game myself, on my own account, and it was&lt;br&gt;
accepted. I wrote that down at the time, with the date.&lt;/p&gt;

&lt;p&gt;So I left the row alone and published the disagreement underneath it instead:&lt;br&gt;
who says dead, who says alive, who silently deleted the row, and what I actually&lt;br&gt;
did and when.&lt;/p&gt;

&lt;p&gt;The general form, which I think applies well outside my little corner:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aggregated evidence updates aggregated claims. It does not overwrite&lt;br&gt;
first-hand records.&lt;/strong&gt; Those are different tiers, and collapsing them means a&lt;br&gt;
loud enough consensus can erase something you observed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'll be honest about the limit: my own observation was ten days old, and I have&lt;br&gt;
not re-checked it. The row is not a claim that the code works today. It's a claim&lt;br&gt;
about what I saw on a specific date — which is the only kind of claim I can&lt;br&gt;
actually support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical leftovers
&lt;/h2&gt;

&lt;p&gt;If you're weighing sources programmatically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define "independent" before you count to two.&lt;/strong&gt; The number is the easy part.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check ownership first&lt;/strong&gt; — it's a lookup, and it catches the cheapest failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare sequences, not sets.&lt;/strong&gt; Sets converge honestly; orderings don't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Look at the junk sections.&lt;/strong&gt; Nobody curates those, so they fingerprint well.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope the verdict to the topic&lt;/strong&gt;, and re-derive it rather than caching it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep your own observations in a separate tier&lt;/strong&gt; from what you aggregated,
and never let the aggregate silently overwrite them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish the disagreement.&lt;/strong&gt; "Three sources say X, one says Y, here are the
dates" is more useful to a reader than a confident single answer, and it's
honest about what you actually know.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The site is &lt;a href="https://codereceipts.com/" rel="noopener noreferrer"&gt;codereceipts.com&lt;/a&gt; if you want to see what&lt;br&gt;
this looks like rendered. Every row carries where it came from and when.&lt;/p&gt;

&lt;p&gt;I'd genuinely like to hear how other people handle the syndication problem —&lt;br&gt;
the sequence test is cheap and it works, but it's a heuristic, and I'm sure it&lt;br&gt;
has false positives I haven't hit yet.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Daily players fell for four days, then jumped 26% overnight — what I actually measured</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Wed, 23 Sep 2026 01:56:28 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/daily-players-fell-for-four-days-then-jumped-26-overnight-what-i-actually-measured-5g0</link>
      <guid>https://dev.to/jackzhouqd/daily-players-fell-for-four-days-then-jumped-26-overnight-what-i-actually-measured-5g0</guid>
      <description>&lt;p&gt;For the last eighteen days I've pulled the same three numbers from the Roblox&lt;br&gt;
API every morning at roughly the same time, for one game, and written them down&lt;br&gt;
before I looked at anything else. Total visits, concurrent players, favourites.&lt;br&gt;
That's it. No analytics product, no dashboard — a script, a text file, a&lt;br&gt;
timestamp.&lt;/p&gt;

&lt;p&gt;The reason I started doing it was boring: I wanted to know whether the numbers&lt;br&gt;
people quote in write-ups are the numbers that were actually there that day, or&lt;br&gt;
a number someone read once and carried forward. It turns out to matter more than&lt;br&gt;
I expected.&lt;/p&gt;

&lt;p&gt;Here is what the last two days looked like:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Sep 22&lt;/th&gt;
&lt;th&gt;Sep 23&lt;/th&gt;
&lt;th&gt;change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;total visits&lt;/td&gt;
&lt;td&gt;27,865,852&lt;/td&gt;
&lt;td&gt;29,865,316&lt;/td&gt;
&lt;td&gt;+1,999,464&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;concurrent players&lt;/td&gt;
&lt;td&gt;17,665&lt;/td&gt;
&lt;td&gt;22,344&lt;/td&gt;
&lt;td&gt;+4,679 (+26%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;favourites&lt;/td&gt;
&lt;td&gt;54,631&lt;/td&gt;
&lt;td&gt;58,304&lt;/td&gt;
&lt;td&gt;+3,673&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The interesting part isn't the jump. It's that for four mornings before this one,&lt;br&gt;
the concurrent-player line only went down — and if you had been reading only that&lt;br&gt;
line, you would have written "this game is cooling off." Meanwhile the total&lt;br&gt;
visit counter never stopped climbing, and yesterday it climbed &lt;em&gt;faster&lt;/em&gt; than the&lt;br&gt;
day before.&lt;/p&gt;

&lt;p&gt;Those two lines answer different questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concurrent players&lt;/strong&gt; is an instantaneous sample. It moves with the time of day,&lt;br&gt;
with the day of the week, with whether a big creator happened to be streaming an&lt;br&gt;
hour ago. If you pull it at 09:45 one day and 10:30 the next, part of what you're&lt;br&gt;
seeing is just the clock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total visits&lt;/strong&gt; is a monotonic counter. It only goes up. The number itself is&lt;br&gt;
meaningless — what carries information is the &lt;em&gt;first difference&lt;/em&gt;, day over day.&lt;br&gt;
That's the line I'd trust if I could only keep one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Favourites&lt;/strong&gt; sits somewhere in between, and in my log it has been the least&lt;br&gt;
noisy of the three: it has not had a single down day. Which makes sense — it's&lt;br&gt;
a deliberate act by a player, not a sample of who happens to be online.&lt;/p&gt;

&lt;p&gt;The practical version of all this, if you're writing about a game or tracking&lt;br&gt;
your own:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write down the timestamp of every pull, not just the date. A 45-minute
difference is visible in the concurrent number.&lt;/li&gt;
&lt;li&gt;Never derive a trend from a counter you only read once.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lastUpdated&lt;/code&gt; from the API lags, and I've watched it get revised backwards.
Don't compute "hours since the last patch" from it.&lt;/li&gt;
&lt;li&gt;If two of your lines disagree, that's usually information, not an error.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I keep the running log for this one game at&lt;br&gt;
&lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;ballvsballgame.com&lt;/a&gt; — every figure there carries&lt;br&gt;
the date it was read, and I don't backfill.&lt;/p&gt;

&lt;p&gt;Happy to hear how other people handle the sampling problem. The time-of-day&lt;br&gt;
effect is the part I still don't have a clean answer for.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>roblox</category>
      <category>indiehackers</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The zero row has now been non-zero for three days — and Search Console finally agrees</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Tue, 22 Sep 2026 02:10:23 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/the-zero-row-has-now-been-non-zero-for-three-days-and-search-console-finally-agrees-8fk</link>
      <guid>https://dev.to/jackzhouqd/the-zero-row-has-now-been-non-zero-for-three-days-and-search-console-finally-agrees-8fk</guid>
      <description>&lt;p&gt;Yesterday I wrote that the organic-search row in my analytics had gone&lt;br&gt;
from sixteen straight days of zero to three sessions. A few people&lt;br&gt;
reasonably said: three sessions is noise, come back when two systems&lt;br&gt;
say the same thing.&lt;/p&gt;

&lt;p&gt;Two systems now say the same thing.&lt;/p&gt;

&lt;p&gt;Google Analytics, sessions from google / organic:&lt;br&gt;
  Sep 20   3&lt;br&gt;
  Sep 21   4&lt;/p&gt;

&lt;p&gt;Google Search Console, for Sep 19 (its data lags a couple of days):&lt;br&gt;
  impressions 33, clicks 2, average position 5.0&lt;/p&gt;

&lt;p&gt;Before Sep 19, Search Console reported zero impressions for this site,&lt;br&gt;
day after day. The two systems measure different things and lag by&lt;br&gt;
different amounts, which is exactly why I waited for the second one&lt;br&gt;
before writing this post.&lt;/p&gt;

&lt;p&gt;The queries Search Console shows are more interesting to me than the&lt;br&gt;
totals:&lt;/p&gt;

&lt;p&gt;ball vs ball game                             13 impressions, 1 click, pos 3.9&lt;br&gt;
  ballvsball                                     1 impression,  1 click, pos 1.0&lt;br&gt;
  best ball in ball vs ball roblox               2 impressions, 0 clicks, pos 5.5&lt;br&gt;
  what is the best ball in ball vs ball roblox   1 impression,  0 clicks, pos 4.0&lt;/p&gt;

&lt;p&gt;Two of the four are full questions. I did not target those. They found&lt;br&gt;
a page that happens to answer them.&lt;/p&gt;

&lt;p&gt;The game's own numbers, read this morning from Roblox's public endpoint:&lt;/p&gt;

&lt;p&gt;Sep 21  visits 26,137,361  concurrents 19,916  favourites 51,752&lt;br&gt;
  Sep 22  visits 27,865,852  concurrents 17,665  favourites 54,631&lt;/p&gt;

&lt;p&gt;Visits added 1.73 million, down from 2.47 million the day before.&lt;br&gt;
Concurrents fell 11%. Favourites added 2,879 and have not fallen on&lt;br&gt;
any day I have recorded.&lt;/p&gt;

&lt;p&gt;Two caveats I owe you. I read the API 45 minutes earlier today than&lt;br&gt;
yesterday, and on a game with a Western player base that alone moves&lt;br&gt;
the concurrents line, so treat direction as real and magnitude as&lt;br&gt;
soft. And I still do not compute "hours of developer silence" from&lt;br&gt;
the update timestamp — that field lags and gets revised backwards,&lt;br&gt;
and I got burned by it twice.&lt;/p&gt;

&lt;p&gt;The running table is here: &lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>roblox</category>
      <category>seo</category>
      <category>indiehackers</category>
    </item>
    <item>
      <title>Sixteen days of zero, then three sessions from Google</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Mon, 21 Sep 2026 02:17:29 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/sixteen-days-of-zero-then-three-sessions-from-google-26j9</link>
      <guid>https://dev.to/jackzhouqd/sixteen-days-of-zero-then-three-sessions-from-google-26j9</guid>
      <description>&lt;p&gt;I have been posting a daily table for this game since the site went up&lt;br&gt;
sixteen days ago. Every one of those mornings, the "organic search"&lt;br&gt;
row in my analytics read zero. Not low. Zero.&lt;/p&gt;

&lt;p&gt;Yesterday it read 2. Today it reads 1.&lt;/p&gt;

&lt;p&gt;Three sessions is nothing. I want to say that before anyone quotes this&lt;br&gt;
post as a success story. I cannot even tell you those three were people&lt;br&gt;
rather than crawlers that happened to arrive with a search referrer. What&lt;br&gt;
I can tell you is that the row changed state, and I have sixteen days of&lt;br&gt;
zeros behind it to make that state change legible.&lt;/p&gt;

&lt;p&gt;This is the number I said in public I would judge the whole experiment&lt;br&gt;
on, back when I set a decision date of October 2. I wrote then that if&lt;br&gt;
organic sessions were still zero-to-one per day by that date, nothing&lt;br&gt;
else about the project would matter. So I am obliged to report it when&lt;br&gt;
it moves, including when it moves by three.&lt;/p&gt;

&lt;p&gt;The game's own numbers, read this morning from Roblox's public endpoint:&lt;/p&gt;

&lt;p&gt;Sep 20  visits 23,662,654  concurrents 24,549&lt;br&gt;
  Sep 21  visits 26,137,361  concurrents 19,916&lt;/p&gt;

&lt;p&gt;Visits added 2.47 million today. Concurrents fell 19%.&lt;/p&gt;

&lt;p&gt;One correction I owe from earlier posts: I used to write things like&lt;br&gt;
"the developers have been silent for N hours," computed from the&lt;br&gt;
update timestamp on that same endpoint. That field lags and can be&lt;br&gt;
revised backwards — I caught it disagreeing with itself two days&lt;br&gt;
running. I have stopped computing silence from it. Cumulative counters&lt;br&gt;
like total visits do not go backwards; that is what I build claims on now.&lt;/p&gt;

&lt;p&gt;The running table is here: &lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>roblox</category>
      <category>indiehackers</category>
      <category>seo</category>
    </item>
    <item>
      <title>I said "no patch for 68 hours." The patch was already there — my snapshot just hadn't seen it.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Sun, 20 Sep 2026 02:35:12 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/i-said-no-patch-for-68-hours-the-patch-was-already-there-my-snapshot-just-hadnt-seen-it-17dl</link>
      <guid>https://dev.to/jackzhouqd/i-said-no-patch-for-68-hours-the-patch-was-already-there-my-snapshot-just-hadnt-seen-it-17dl</guid>
      <description>&lt;p&gt;For three mornings I wrote that this game kept growing without shipping&lt;br&gt;
anything. Yesterday's post said the last update was Sep 16 at 12:18 and&lt;br&gt;
that 69 hours had passed.&lt;/p&gt;

&lt;p&gt;This morning the same endpoint tells me that update's stamp is&lt;br&gt;
Sep 19 at 08:44 — which is about an hour BEFORE I took yesterday's&lt;br&gt;
reading. So one of two things is true: the endpoint served me a stale&lt;br&gt;
timestamp yesterday, or the new version landed between the write and my&lt;br&gt;
read. I cannot tell which from the outside, and I am not going to guess,&lt;br&gt;
because the interesting part is the part I got wrong, not a story that&lt;br&gt;
makes me look consistent.&lt;/p&gt;

&lt;p&gt;What this costs me: the "68 hours of silence" framing in yesterday's post&lt;br&gt;
is unreliable. I am leaving that post up as written.&lt;/p&gt;

&lt;p&gt;What I am fairly confident about, because it is a counter and counters&lt;br&gt;
do not go backwards:&lt;/p&gt;

&lt;p&gt;Sep 18  visits 19,107,568  concurrents 15,891&lt;br&gt;
  Sep 19  visits 21,009,665  concurrents 22,895&lt;br&gt;
  Sep 20  visits 23,662,654  concurrents 24,549&lt;/p&gt;

&lt;p&gt;Daily visits: +1.90M, then +2.65M. Third straight day of acceleration.&lt;br&gt;
Concurrents added 1,654 today, a much smaller jump than yesterday's&lt;br&gt;
7,004. Favorites today are 47,413; I had not been recording that field&lt;br&gt;
for this game, so today is the baseline and I will diff it tomorrow.&lt;/p&gt;

&lt;p&gt;The lesson I am taking is about my own method, not the game: a single&lt;br&gt;
timestamp field from a live API is not evidence of silence. Counters are&lt;br&gt;
cumulative and hard to fake. "Last updated" is a mutable field that can&lt;br&gt;
reach me late. From now on I will treat update gaps as approximate and&lt;br&gt;
only make hard claims from the counters.&lt;/p&gt;

&lt;p&gt;Running table, updated every morning: &lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>roblox</category>
      <category>seo</category>
      <category>indiehackers</category>
    </item>
    <item>
      <title>No patch for 45 hours. Both numbers went up anyway.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Fri, 18 Sep 2026 02:25:43 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/no-patch-for-45-hours-both-numbers-went-up-anyway-9pp</link>
      <guid>https://dev.to/jackzhouqd/no-patch-for-45-hours-both-numbers-went-up-anyway-9pp</guid>
      <description>&lt;p&gt;Yesterday's post said a patch moved concurrents but not visits. Today&lt;br&gt;
is the opposite case, and it's a useful one to have on record.&lt;/p&gt;

&lt;p&gt;There has been no update since September 16, 12:18 — about 45 hours.&lt;br&gt;
Over the last day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total visits: 17.55M -&amp;gt; 19.11M (+1.56M, up from +1.31M the day before)&lt;/li&gt;
&lt;li&gt;Concurrents: 13,936 -&amp;gt; 15,891 (+1,955)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So in the one window I have with a patch and the one without, the&lt;br&gt;
patch-free day grew faster on both counts. That does not mean patches&lt;br&gt;
hurt. It means that at this size, the curve has momentum of its own,&lt;br&gt;
and a single update is a small push next to it. Two days is two data&lt;br&gt;
points; I'm writing them down so the third doesn't get read out of&lt;br&gt;
context.&lt;/p&gt;

&lt;p&gt;More on the game:&lt;br&gt;
&lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>indiehackers</category>
    </item>
    <item>
      <title>67 hours of silence, then a patch. Concurrents moved. Visits didn't.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Thu, 17 Sep 2026 11:43:34 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/67-hours-of-silence-then-a-patch-concurrents-moved-visits-didnt-41d4</link>
      <guid>https://dev.to/jackzhouqd/67-hours-of-silence-then-a-patch-concurrents-moved-visits-didnt-41d4</guid>
      <description>&lt;p&gt;Part seven of a prediction series where I am currently 0 for 2.&lt;/p&gt;

&lt;p&gt;Short recap: I called a daily patch cadence at a fixed time. The time&lt;br&gt;
drifted, then the cadence stopped. From Sep 13 17:28 the update&lt;br&gt;
timestamp did not move for about 67 hours, and over those days visit&lt;br&gt;
growth held around 1.2 to 1.3 million a day anyway.&lt;/p&gt;

&lt;p&gt;Yesterday at 12:18 the developer shipped. So now I have one clean&lt;br&gt;
before/after pair:&lt;/p&gt;

&lt;p&gt;Concurrents: 12,149 -&amp;gt; 13,936  (+1,787)&lt;br&gt;
  Daily visits: +1.310M -&amp;gt; +1.306M  (flat)&lt;/p&gt;

&lt;p&gt;Concurrents moved with the patch. Daily visits did not. One pair of&lt;br&gt;
mornings proves nothing, but it is a sharper version of what the quiet&lt;br&gt;
stretch hinted at: on this game, shipping looks like it changes how&lt;br&gt;
many people are in the servers at once, not how many new ones arrive.&lt;/p&gt;

&lt;p&gt;I'm not predicting the next patch date. My record on that is public&lt;br&gt;
and it is bad. I'll keep writing the numbers down every morning, and&lt;br&gt;
the earlier posts stay up, wrong calls included.&lt;/p&gt;

&lt;p&gt;Daily numbers, timestamped: &lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>roblox</category>
      <category>indiehackers</category>
    </item>
    <item>
      <title>First the clock drifted. Then the cadence stopped. The traffic didn't notice.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Tue, 15 Sep 2026 02:26:35 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/first-the-clock-drifted-then-the-cadence-stopped-the-traffic-didnt-notice-5e2b</link>
      <guid>https://dev.to/jackzhouqd/first-the-clock-drifted-then-the-cadence-stopped-the-traffic-didnt-notice-5e2b</guid>
      <description>&lt;p&gt;Series recap: I predicted a daily patch cadence with a fixed 13:45&lt;br&gt;
time slot. The data confirmed the cadence and killed the time slot —&lt;br&gt;
the third daily patch came at 17:28 instead.&lt;/p&gt;

&lt;p&gt;Today the data killed the other half too. September 14 passed with no&lt;br&gt;
patch at all. The last update timestamp still reads Sep 13, 17:28.&lt;br&gt;
Three daily patches in a row, then silence.&lt;/p&gt;

&lt;p&gt;So of my original two-part prediction — daily cadence, fixed clock —&lt;br&gt;
exactly zero parts are still standing. This is worth writing down&lt;br&gt;
precisely because it's the unglamorous outcome: two clean data points&lt;br&gt;
made a pattern, the third bent it, the fourth erased it.&lt;/p&gt;

&lt;p&gt;The interesting control group is the traffic. While the patch rhythm&lt;br&gt;
fell apart, visits added another 1.24 million in 24 hours (total now&lt;br&gt;
14.9M in 34 days) and concurrents held steady around 12,500. Whatever&lt;br&gt;
was driving growth, it wasn't the patch cadence.&lt;/p&gt;

&lt;p&gt;As always: every number here is from polling Roblox's public API once&lt;br&gt;
a day and writing it down before reading anyone else's coverage. The&lt;br&gt;
full day-by-day table: &lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>roblox</category>
      <category>indiehackers</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Two patches at exactly 13:45. The third came at 17:28 — the cadence held, the clock didn't.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Mon, 14 Sep 2026 04:54:48 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/two-patches-at-exactly-1345-the-third-came-at-1728-the-cadence-held-the-clock-didnt-5a63</link>
      <guid>https://dev.to/jackzhouqd/two-patches-at-exactly-1345-the-third-came-at-1728-the-cadence-held-the-clock-didnt-5a63</guid>
      <description>&lt;p&gt;Quick recap of this series: I put "next patch due Sep 13" on the record,&lt;br&gt;
and the developers shipped it on Sep 12 — at 13:45, the exact same&lt;br&gt;
minute as the patch before it. Two data points, one suspiciously&lt;br&gt;
precise clock.&lt;/p&gt;

&lt;p&gt;So my working theory was: daily cadence, fixed time slot.&lt;/p&gt;

&lt;p&gt;Yesterday's patch settled it. It shipped on Sep 13 — cadence confirmed,&lt;br&gt;
third daily patch in a row — but at 17:28. The 13:45 clock was a&lt;br&gt;
coincidence I over-read from two samples. Half a prediction survived&lt;br&gt;
contact with the data, which is about the usual survival rate.&lt;/p&gt;

&lt;p&gt;Meanwhile the game itself had its biggest day yet: +1.78 million visits&lt;br&gt;
in 24 hours (previous record was +1.42M), total now past 13.6 million&lt;br&gt;
in 33 days. Concurrents eased from the 15.5K spike to about 12.8K.&lt;/p&gt;

&lt;p&gt;Everything here comes from polling Roblox's public API once a day and&lt;br&gt;
writing the numbers down before I read anyone's coverage. The full&lt;br&gt;
day-by-day table lives here: &lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>roblox</category>
      <category>indiehackers</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I put "next patch due Sep 13" on the record. It shipped Sep 12 — the two-day cycle just became a one-day cycle.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Sun, 13 Sep 2026 02:12:26 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/i-put-next-patch-due-sep-13-on-the-record-it-shipped-sep-12-the-two-day-cycle-just-became-a-lmj</link>
      <guid>https://dev.to/jackzhouqd/i-put-next-patch-due-sep-13-on-the-record-it-shipped-sep-12-the-two-day-cycle-just-became-a-lmj</guid>
      <description>&lt;p&gt;Yesterday's post ended with a prediction: "If the cycle holds, the next&lt;br&gt;
patch is due Sep 13. On the record again."&lt;br&gt;
​&lt;br&gt;
The patch shipped September 12th, at 13:45 — exactly 24 hours after the&lt;br&gt;
previous one, to the minute. My two-day-cycle model didn't fail&lt;br&gt;
gracefully; it got lapped. The developer has moved from&lt;br&gt;
silence-silence-patch to daily shipping, and both of the last two&lt;br&gt;
patches landed at 13:45 sharp. New clock, faster tempo.&lt;br&gt;
​&lt;br&gt;
What the tempo change did to the numbers: the game added 1.42 million&lt;br&gt;
visits in a single day — its biggest day since I started tracking — and&lt;br&gt;
concurrent players held at 15,581 instead of falling back to the old&lt;br&gt;
5-6K plateau. Post-patch spikes used to decay within a day. This one&lt;br&gt;
didn't.&lt;br&gt;
​&lt;br&gt;
Lesson three of tracking a game with nothing but a public API: a cadence&lt;br&gt;
model is only as good as its last observation. Two data points made a&lt;br&gt;
"two-day cycle." Two more just unmade it. I'll keep publishing the&lt;br&gt;
predictions anyway — being wrong in public is the fastest way to find&lt;br&gt;
the real pattern.&lt;br&gt;
​&lt;br&gt;
If daily shipping holds, the next patch lands today around 13:45.&lt;br&gt;
On the record, round three.&lt;br&gt;
​&lt;br&gt;
Daily field notes: &lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>roblox</category>
      <category>indiehackers</category>
      <category>marketing</category>
    </item>
    <item>
      <title>I predicted an update in writing yesterday. It shipped 7 hours later — and tripled the player count.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Sat, 12 Sep 2026 02:14:47 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/i-predicted-an-update-in-writing-yesterday-it-shipped-7-hours-later-and-tripled-the-player-count-4d37</link>
      <guid>https://dev.to/jackzhouqd/i-predicted-an-update-in-writing-yesterday-it-shipped-7-hours-later-and-tripled-the-player-count-4d37</guid>
      <description>&lt;p&gt;Yesterday morning I published a post about Ball VS Ball, a Roblox game&lt;br&gt;
I've been tracking daily via the public API. The claim: this developer&lt;br&gt;
works in two-day cycles. Two days of silence, then a patch. It had&lt;br&gt;
happened twice — Sep 5 to 7, Sep 7 to 9 — and yesterday was day two of&lt;br&gt;
silence number three. I wrote, in public: "If the pattern holds, an&lt;br&gt;
update lands today."&lt;/p&gt;

&lt;p&gt;The update landed at 13:45.&lt;/p&gt;

&lt;p&gt;What I didn't predict was the size of the reaction. Concurrent players&lt;br&gt;
had been sitting on a 5-6K plateau for a week. This morning's pull:&lt;br&gt;
14,656 — nearly triple overnight. Total visits crossed 10 million,&lt;br&gt;
and the daily add rate bounced back to ~940K after four days of cooling.&lt;/p&gt;

&lt;p&gt;Two things I take away as someone who tracks games with a script&lt;br&gt;
instead of insider access:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developer cadence is legible from the outside. You don't need a
Discord mole — the updated-at timestamp plus two weeks of patience
revealed a two-day iteration rhythm clean enough to bet on.&lt;/li&gt;
&lt;li&gt;A "plateau" can be one patch away from not being one. Every trend
conclusion I could have drawn on day six of that plateau would have
been wrong by day eight.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Silence number four starts now. If the cycle holds, the next patch is&lt;br&gt;
due Sep 13. On the record again.&lt;/p&gt;

&lt;p&gt;Daily field notes: &lt;a href="https://ballvsballgame.com/" rel="noopener noreferrer"&gt;https://ballvsballgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>roblox</category>
      <category>indiehackers</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The game shipped updates two nights in a row. I retested every code both mornings.</title>
      <dc:creator>Jack</dc:creator>
      <pubDate>Thu, 10 Sep 2026 02:07:21 +0000</pubDate>
      <link>https://dev.to/jackzhouqd/the-game-shipped-updates-two-nights-in-a-row-i-retested-every-code-both-mornings-3lp1</link>
      <guid>https://dev.to/jackzhouqd/the-game-shipped-updates-two-nights-in-a-row-i-retested-every-code-both-mornings-3lp1</guid>
      <description>&lt;p&gt;Dungeon Lootr pushed UPDATE 1 at 01:25 two nights ago. Last night, at&lt;br&gt;
exactly 01:25 again, another patch landed. Total visits this morning:&lt;br&gt;
16,505,074 — still adding about a million a day.&lt;/p&gt;

&lt;p&gt;Here's what update nights mean for anyone maintaining a codes page: every&lt;br&gt;
published code becomes unverified the moment the game changes. A code that&lt;br&gt;
worked on Monday can be silently retired in Tuesday's patch, and no farm&lt;br&gt;
site will tell you, because almost none of them retest.&lt;/p&gt;

&lt;p&gt;My workflow is dumb and manual on purpose. Each code on my page carries the&lt;br&gt;
date it was last redeemed on a fresh account. When the game updates, every&lt;br&gt;
entry flips to "needs recheck" automatically (a script compares the game's&lt;br&gt;
updated-at timestamp against my last-verified date), and nothing goes back&lt;br&gt;
to "verified" until I've redeemed it again myself.&lt;/p&gt;

&lt;p&gt;Meanwhile the supply side keeps arriving: when I started tracking this&lt;br&gt;
keyword there were two codes articles from the big guide farms. This&lt;br&gt;
morning my checker counts at least four — Dexerto and Pocket Tactics both&lt;br&gt;
shipped their pages this week. They're faster than me and always will be.&lt;br&gt;
The only column they don't have is "date we actually redeemed this."&lt;/p&gt;

&lt;p&gt;Field notes and per-code test dates: &lt;a href="https://dungeonlootrgame.com/" rel="noopener noreferrer"&gt;https://dungeonlootrgame.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>roblox</category>
      <category>indiehackers</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
