Case 379
The id answers which record, not which person — 10 accounts, 6 people
the_id_answers_which_record_not_which_person.eml counts new signups two ways from the same rows.
ok: true — round-trip fixpoint reached (python1 == python2)updated 2026-08-14
EML
eml# Self-authored for the EML case corpus (no external origin). The index answers
# "is there a record with this id". The question asked was "is this a new
# customer".
#
# Nothing is wrong with the index. Account id is the right key for an account
# table, it is unique, the lookup is correct, and every count computed from it
# is a correct count of accounts.
#
# The two questions come apart exactly when one person holds more than one
# account, which is not an edge case - it is what happens when someone signs up
# again with a work address, or a household shares a card.
#
# Both counts are computed from the same rows. Neither is an estimate.
# [account_id, owner, signup_month]
# Month 1 deliberately contains no returning person. That month is the control:
# where each new account is a new person the two counts coincide, so the
# account count is not simply always inflated.
[["a1", "kai@x", 1], ["a2", "mei@x", 1], ["a4", "ravi@x", 1], ["a3", "kai@work", 2], ["a5", "sol@x", 2], ["a6", "mei@home", 2], ["a7", "tam@x", 2], ["a8", "kai@x2", 2], ["a9", "ravi@alt", 2], ["a10", "wen@x", 2]] => accounts
# The owner strings differ per account. Who is actually the same person is a
# separate fact, and it is stated as data rather than guessed from the string.
[["kai@x", "kai"], ["kai@work", "kai"], ["kai@x2", "kai"], ["mei@x", "mei"], ["mei@home", "mei"], ["ravi@x", "ravi"], ["ravi@alt", "ravi"], ["sol@x", "sol"], ["tam@x", "tam"], ["wen@x", "wen"]] => identity
def person_of(owner):
for p in identity:
if p[0] == owner:
return p[1]
return owner
def accounts_in(month):
0 => c
for a in accounts:
if a[2] == month:
c + 1 => c
return c
def people_first_seen_in(month):
[] => seen
for a in accounts:
if a[2] < month:
person_of(a[1]) => p
0 => have
for s in seen:
if s == p:
1 => have
if have == 0:
seen + [p] => seen
0 => fresh
[] => counted
for a in accounts:
if a[2] == month:
person_of(a[1]) => p
0 => have
for s in seen:
if s == p:
1 => have
for s in counted:
if s == p:
1 => have
if have == 0:
fresh + 1 => fresh
counted + [p] => counted
return fresh
"rows" ^0
" accounts : " + str(len(accounts)) ^0
[] => people
for a in accounts:
person_of(a[1]) => p
0 => have
for s in people:
if s == p:
1 => have
if have == 0:
people + [p] => people
" distinct people : " + str(len(people)) ^0
"" ^0
"new this month, two ways" ^0
for m in [1:2]:
" month " + str(m) + " : " + str(accounts_in(m)) + " accounts, " + str(people_first_seen_in(m)) + " people" ^0
"" ^0
accounts_in(1) + accounts_in(2) => acc_total
people_first_seen_in(1) + people_first_seen_in(2) => ppl_total
" totals : " + str(acc_total) + " accounts, " + str(ppl_total) + " people" ^0
" the account number is larger by : " + str(acc_total - ppl_total) ^0
"" ^0
# ---- who is responsible for the gap ----
"people holding more than one account" ^0
0 => multi
for p in people:
0 => c
for a in accounts:
if person_of(a[1]) == p:
c + 1 => c
if c > 1:
multi + 1 => multi
" " + p + " : " + str(c) + " accounts" ^0
" people with more than one : " + str(multi) ^0
"" ^0
# ---- the control: a month where the two questions coincide ----
#
# Month 1 has no returning person, so both counts agree there. Without this the
# reader cannot tell whether the account count is simply always inflated.
if accounts_in(1) == people_first_seen_in(1):
"In month 1 the two counts agree - every new account was a new person." ^0
"In month 2 they do not: " + str(accounts_in(2)) + " accounts, " + str(people_first_seen_in(2)) + " people." ^0
"" ^0
"The index is correct and the count is correct. Both answer a question about" ^0
"accounts, and growth is usually asked about people." ^0Python (deterministic transpilation)
pythonaccounts = [["a1", "kai@x", 1], ["a2", "mei@x", 1], ["a4", "ravi@x", 1], ["a3", "kai@work", 2], ["a5", "sol@x", 2], ["a6", "mei@home", 2], ["a7", "tam@x", 2], ["a8", "kai@x2", 2], ["a9", "ravi@alt", 2], ["a10", "wen@x", 2]]
identity = [["kai@x", "kai"], ["kai@work", "kai"], ["kai@x2", "kai"], ["mei@x", "mei"], ["mei@home", "mei"], ["ravi@x", "ravi"], ["ravi@alt", "ravi"], ["sol@x", "sol"], ["tam@x", "tam"], ["wen@x", "wen"]]
def person_of(owner):
for p in identity:
if p[0] == owner:
return p[1]
return owner
def accounts_in(month):
c = 0
for a in accounts:
if a[2] == month:
c = c + 1
return c
def people_first_seen_in(month):
seen = []
for a in accounts:
if a[2] < month:
p = person_of(a[1])
have = 0
for s in seen:
if s == p:
have = 1
if have == 0:
seen = seen + [p]
fresh = 0
counted = []
for a in accounts:
if a[2] == month:
p = person_of(a[1])
have = 0
for s in seen:
if s == p:
have = 1
for s in counted:
if s == p:
have = 1
if have == 0:
fresh = fresh + 1
counted = counted + [p]
return fresh
print("rows")
print(" accounts : " + str(len(accounts)))
people = []
for a in accounts:
p = person_of(a[1])
have = 0
for s in people:
if s == p:
have = 1
if have == 0:
people = people + [p]
print(" distinct people : " + str(len(people)))
print("")
print("new this month, two ways")
for m in range(1, 3):
print(" month " + str(m) + " : " + str(accounts_in(m)) + " accounts, " + str(people_first_seen_in(m)) + " people")
print("")
acc_total = accounts_in(1) + accounts_in(2)
ppl_total = people_first_seen_in(1) + people_first_seen_in(2)
print(" totals : " + str(acc_total) + " accounts, " + str(ppl_total) + " people")
print(" the account number is larger by : " + str(acc_total - ppl_total))
print("")
print("people holding more than one account")
multi = 0
for p in people:
c = 0
for a in accounts:
if person_of(a[1]) == p:
c = c + 1
if c > 1:
multi = multi + 1
print(" " + p + " : " + str(c) + " accounts")
print(" people with more than one : " + str(multi))
print("")
if accounts_in(1) == people_first_seen_in(1):
print("In month 1 the two counts agree - every new account was a new person.")
print("In month 2 they do not: " + str(accounts_in(2)) + " accounts, " + str(people_first_seen_in(2)) + " people.")
print("")
print("The index is correct and the count is correct. Both answer a question about")
print("accounts, and growth is usually asked about people.")stdout (executed)
textrows
accounts : 10
distinct people : 6
new this month, two ways
month 1 : 3 accounts, 3 people
month 2 : 7 accounts, 3 people
totals : 10 accounts, 6 people
the account number is larger by : 4
people holding more than one account
kai : 3 accounts
mei : 2 accounts
ravi : 2 accounts
people with more than one : 3
In month 1 the two counts agree - every new account was a new person.
In month 2 they do not: 7 accounts, 3 people.
The index is correct and the count is correct. Both answer a question about
accounts, and growth is usually asked about people.Trace event types
eml:run:starteml:assigneml:defeml:outputeml:calleml:returneml:run:done