Why the count is an estimate

The sentence

This is Pithy’s estimate from your own invite records. Google’s count is authoritative and no API exposes it.

It appears in the package README, in the API response as a required field, in the CLI output of every status command, and at the foot of every email this capability sends.

It is not a disclaimer bolted on afterwards. It is the shape of the thing.

The last two lines print on every invocation, including --json. They are not behind a flag, because a developer reading day 13 of 14 is about to make a decision on it.

So the capability owns its own model

Who you invited, who agreed, who followed the confirmation link through to the store, and a clock replayed from those events.

That is a well-informed estimate of Google’s figure. It is not that figure, and the two diverge — most obviously when a tester opts out without telling anyone, which Google sees and this cannot.

Every field derived from it is named estimated.

successProbability is nullable, so we do not know is representable rather than faked as a plausible number.

reconciliation.supported is false with the reason attached, because we checked and cannot and we never considered it are different facts.

The half that is fact

Activity is not an estimate. Because auth owns sessions and the device registry, a tester’s invited address resolves to their user, and from there to when they last opened the app.

This is the only early-warning signal that exists. A tester dark for eight days is the one most likely to have quietly opted out or uninstalled — and that is actionable on day eight rather than on day fourteen when the count finally moves.

And the caveat that has to be stated rather than discovered

Activity exists only for testers who authenticate — which is a limit of what the Play APIs expose rather than a choice. Using Testers has the roster; the reference marks every estimated field; pithy testers reports them.

Somebody who installs and never signs in is invisible, and an app whose test flow requires no sign-in produces no activity data at all.

Those testers report never_linked rather than inactive, their health is null rather than a low score, and the forecast widens its confidence band in exact proportion to how much of the cohort is unobservable.

A UI must render them gray, never red. Absence of evidence is not evidence of risk.

The clock is replayed, never counted

The streak comes from an append-only event log.

A counter can only be overwritten, which destroys both the old value and the evidence that it changed. Replaying makes a correction an insert: add the event that was missing, recompute, and every snapshot written beforehand survives as an accurate record of what was believed on that day — which is exactly what a trend chart claims to show.

Only four things move a tester’s state: an invitation, their answer to it, following the link through to the store, and an explicit opt-out or removal.

Signing in is not one of them — that is activity, and it belongs entirely to the observed half.

Inactivity is not one of them, and that is load-bearing. The moment a cron is allowed to lapse somebody for going quiet, the count stops being a record of who confirmed and becomes a guess dressed as a record.

accepted and opted_in are separate.

Saying yes is consent; it is not enrollment, and counting it as one would inflate the estimate with people who agreed and never joined.

Days are UTC, and the response says so

Google’s day boundary is undocumented and may not be the same one — one more reason not to start trusting the estimate on day thirteen.

The reset policy is exposed as the assumption it is

Nobody outside Google knows whether Play pauses or restarts the counter when you dip to eleven.

The default is reset, deliberately pessimistic: being told day fourteen while actually on day three is the expensive mistake, and the reverse costs a shrug.

Two numbers, reported separately

Success needs two independent things: reaching the target, and holding it.

Multiplying them into one percentage destroys the only actionable information in the pair. 62% tells you nothing. You will reach twelve (95%) but only hold it 65% of the time tells you to invite four more people this afternoon.

The hold half is an exact Poisson-binomial over every opted-in tester’s own survival probability — one convolution per tester, deterministic, and explainable in a sentence: roll each tester’s chance of lasting the remaining days into the exact odds that at least twelve of them do.

invitesNeeded is usually worth more than the probability beside it, and recommendedRosterSize answers the question a developer is actually asking. “Carry twelve” is the advice that fails, because twelve is the number that must still be standing at the end, not the number to start with.

Every constant is yours

The survival priors and the health weights are config fields. They are numbers somebody chose, not values fitted to anybody’s data, and the API says so in a calibration field.

If you disagree, change them — and bump modelVersion, so your trend chart annotates where your change took effect. A chart that silently spans two models is a lie.

ESC