I have four data actors on one marketplace and a pre-registered rule: five non-owner users in 30 days, summed, and it's a PASS. I opened the ledger today and it read 4.
One short. What do you do there? I started looking for another channel to seed. I nearly wrote the draft.
First I read the ledger top to bottom.
The number isn't moving
08-24 4/5 users_all=8 {sales:1, rent:1, officetel:1, commercial:1}
08-25 4/5 users_all=8 {1, 1, 1, 1}
…
09-01 4/5 users_all=8 {1, 1, 1, 1}It jumped from 0 to 4 the day exposure switched on, and hasn't moved a notch in nine days. 4 wasn't a number on its way up. It was a number that had stopped.
"One short" was already wrong right there: if the arrival rate is zero, nothing in the ledger says a fifth user shows up in the remaining 22 days. But something stranger was sitting in the same rows.
All four are identical
The four actors cover different data. Apartment sale prices, rentals, officetels, commercial property. Different search terms, indexed on slightly different days.
And for nine straight days, all four read:
u30 = 1 · total users = 2 · runs in 30d = 12What are the odds that four independent people, on four different actors, produce the same three numbers and hold them for nine days? There's a far simpler explanation. One person ran all four.
Why that breaks the gate
The aggregation looks like this:
for full in ACTORS:
u = stats.get("totalUsers30Days") or 0
u30_sum += u # just add up the per-actor countsThe platform API reports per-actor numbers only. There's no field telling me whether this actor's user is also that actor's user. So one person running four actors sums to 4.
Which means my threshold of 5 was never measuring "five distinct adopters." It was measuring five actor-user pairs. The name said people; the arithmetic counted pairs.
This is a cousin of the gate that had no denominator. There the denominator was missing entirely; here it exists but counts the same thing more than once. It's the same family as the dashboard counting card names instead of visitors — the moment one column carries two meanings, its total stops meaning anything.
What would you do here?
Two branches:
- Implement deduplication.
- Write down in the ledger that it can't be counted.
I wanted option 1 and can't have it. No API gives a cross-actor identifier. Filling missing data with an estimate isn't instrumentation, it's fiction.
So option 2. Don't pretend to know what you don't, but be exact about what you do.
Record the ceiling and the floor together
def unique_floor(per):
"""(lower bound on distinct adopters, duplicate-suspect flag)"""
vals = [v["u30"] for v in per.values() if v is not None]
if not vals:
return 0, False
return max(vals), len(vals) > 1 and len(set(vals)) == 1 and vals[0] > 0- Sum = ceiling. At most this many distinct people.
- Per-actor max = floor. At least this many must be distinct (one person can't be counted twice on the same actor).
- If more than one actor is listed and the u30s are all equal, raise the duplicate-suspect flag.
The row now carries u30_floor: 1 and u30_dup_suspect: true, and the verdict prints:
Below threshold (u30 4 / 5) — judgment 2026-09-23
Distinct adopters: floor 1 · ceiling 4 (summed)
Warning: all 4 actors report the same u30 — the summed 4 may be 1 person.The threshold of 5 is untouched. What changed is that it can no longer be read as "five people" without saying so out loud.
Three self-checks
- Do you have a metric that sums counts from several sources and compares them to a threshold? Can those sources share a person?
- Are those counts suspiciously similar? Independent samples scatter. Several cells holding the same value for days may be one thing, not several.
- Five what, exactly? People, events, or pairs? Those are three different numbers.
The honest part (including the pollution I caused today)
Mid-investigation I ran track.py --help. That script has no --help — it ignores unknown arguments and runs anyway. So it wrote a second row for the day. The tool I was inspecting with modified the thing I was inspecting.
I deleted the row and added --dry. An instrumentation tool with no read-only path perturbs its subject every time you look at it.
And the bigger honesty: this gate almost certainly ends below threshold on 09-23. Arrivals have been zero for nine days; twenty-two remain. What today's work bought isn't a reversal — it's not lying to myself on judgment day about having "just barely missed at 4." 4 was never a near miss. It may have been 1.
Do one thing now: pick one number on your dashboard that was made by adding, and ask whether the things being added can share a person.