“Which person node is this user?” had five independent implementations and three delete paths that destroyed the answer. Those three delete paths are now hardened (ADR-142); one adjacent path is not β two humans sharing a name still fuse into one node. The opposite failure β one human arriving through two connectors becomes two people β has now been MEASURED, end to end: detector run fleet-wide, Regina sized, 8 pairs judged, the one same verdict owner-confirmed a false positive. Zero confirmed cross-connector splits on all of production β and the measurement showed why the number is so hard to move: 81% of identities are single-connector and cannot even express a split.
π The calendar identity gap (#3418) left this track on 2026-08-30 β it now lives on CONNECTOR-TRUTH. It was filed here as a viewer-resolution question, but the messages do carry person ids; what is missing is the person_sources write that links them to the connector, which is a connector defect. Calendar remains one of the five email-authoritative source types, so if it is fixed the live-pair count on this page changes with it.
β #3148 (client viewer resolution disagreed with the server) and #3162 (17 expressions, no detector) both closed β one accessor now stands per lane, backed by a cross-lane parity test and a firing check.py rule. Detail in History.
β #3265 (create-with-no-person tier loss) closed 2026-08-19 β create_tenant_user now finds-or-creates the person_identities row through the ADR-084 single writer and writes the tier there. Its concurrent-create residue stays open below.
β #3176 (viewer-resolution detector had 4 bypasses) closed 2026-08-31 β all four now fire, each pinned by an armed test. Detail in History.
β #3424 (alias index missing tenant_id) closed 2026-08-31 β tenant-scoped index live in prod plus a boundary guard on every write; #3446 (its recovery census) closed 2026-08-27 as measured-no-damage; #3489 (dedup ignored deterministic identity signal) closed 2026-08-31 β shipped as a partition gate, verified reachable against a live tenant. Detail in History.
Finish the collapse, then the blockers, then the create path, then triage. Re-read 2026-09-02: the identity-fusion cohort is no longer unsized β it is measured (zero confirmed splits, judge = veto-not-proposer), so the head of the queue is the two owner rulings that measurement bought (#3416 re-scope-or-close; wave-3 build-or-not) and the free-but-expiring pairing window before Regina's WhatsApp onboarding. The client lane (#3148) and the missing detector (#3162) β which finished ADR-142 and stopped an 18th expression β both closed (08-29/08-31), as did the detector-bypass follow-up (#3176, 08-31) and the identity-substrate tail (#3424, #3446, #3489, all by 08-31). Remaining: the four uncensused questions that block calling done (#3173, #3174, #3172, #3179), ordered so #3174 unblocks #3172; the tier-claim residue (#3270 only β #3265 and #3267 both closed); then live-bug triage, ordered by whether exposure is live (#3276 blanks a Mizo surface, #3243 halves Regina's audience) before silent or latent defects.
Deliberately ignored: priority labels alone (all but three are p1, so the label cannot order them); filing order and age (#1314 is the oldest, filed 2026-05, and sorts last); how cheap or well-understood a fix looks; and the severity a body asserts before exposure was measured.
#3546, #3418, #3174, #3172, #3276, #3080, #1314. A closed issue named as current work is the drift this section exists to surface β re-derive the prose, or move the reference into History.
Evidence below is generated from the read-only audit of 2026-08-29 and reconciled against the open issues at build time. Every claim cites the issue it came from. Nothing here is a decision β rulings stay in the prose above, which is written by hand.
No shared expression exists and the site count is LARGER than filed. Absence of a helper: `git grep -nE "def (node_display_text|display_text_for_node|one_line_text|node_one_line)" origin/main -- backend/app` β zero hits. Live Python sites of the exact three-field fallback (`git grep -n "searchable_text or " origin/main -- backend/app`, population = all of backend/app): services/analysis/conversation.py:808, services/analysis/conversation_matching.py:150, services/ask/connection_resolver.py:452 and :499, services/ask/content_resolver.py:370 and :684, services/ask/decision_resolver.py:325, services/ask/question_resolver.py:299, services/ask/tools/_unmet_needs.py:333/:404/:459, services/connections/pattern_matchers/duplicate_work.py:162/:163, services/connections/pattern_matchers/problem_solution.py:266/:268 β 16 occurrences, versus the three Python sites the issue names. Python-embedded SQL lane still forked: backend/app/repositories/feed_intelligence_repository.py:261, :320, :436 carry `COALESCE(NULLIF(tgt.searchable_text, ''), tgt.display_name, tgt.canonical_name, '')` verbatim. SQL lane: the same expression appears three times per redefinition of the needs-you view, latest at supabase/migrations/20260819104315_fix_viewer_needs_you_labeled_passthrough_3389.sql:99, :159, :211 β the issue's cited migration (20260807105944) has been superseded five times since, which is exactly the drift the issue predicts.
23 assessed issues closed since the audit and are not shown β a closed issue's evidence is history, and printing it as current is how a page starts lying.
2026-08-29β31 β ADR-142's last two lanes, the detector hardening, and the identity-substrate tail all closed. Finish-the-collapse: #3148 (client viewer resolution disagreed with the server) closed 2026-08-29 β client/services/viewer.ts now calls the current_viewer_person_id RPC instead of bridging through provenance_person_ids itself. #3162 (17 expressions, no detector) closed 2026-08-31 after independent re-verification of all five acceptance bullets: one accessor per lane, a cross-lane parity test, the duplicate find_person_node_ids_by_user_ids gone, and the viewer-resolution-single-reader check.py rule live in CI. Detector hardening: #3176 (4 bypasses) closed the same day β split/concatenated literals, the receiver-name gate, getattr indirection and the PostgREST alternates all now fire, each with an armed test. The identity-substrate tail: #3424 (alias index missing tenant_id) closed 2026-08-31 β tenant-scoped index live in prod plus a choke-point boundary guard on every add_alias call; its residue census #3446 closed 2026-08-27 as measured-no-damage (zero confirmed lost alias rows across all 9 tenants). #3489 (dedup ignored deterministic identity signal) closed 2026-08-31 β shipped as a partition gate consulting email/JID/domain/address identifiers plus graph-relationship corroboration, verified reachable against Regina's live, unpaused tenant. The tier-claim ruling shipped: #3265 (create-with-no-person tier loss) closed 2026-08-19 β the console now finds-or-creates the identity row through the ADR-084 single writer rather than refusing the tier or losing it to the reconciler; its concurrent-create race split to #3270, still open. Every one of these went through the same verification discipline: triage proposed 26 closures fleet-wide and an adversarial critic re-derived each p0/p1 verdict independently rather than accepting it, holding 13.
The 2026-08-20β25 wave β from “unrun detector” to a measured answer. PR #3530 (another session, 08-22) unioned provenance_person_ids onto merge survivors in both consolidation write paths β a permanent, non-self-healing identity drop on every merge that had ever run; the detector's under-count fell with it (invisible 459 β 217, multi-identity nodes 0 β 18). PR #3538 (08-23) made the detector runnable at Regina scale (chunked exact KNN over the query_ids seam) and re-labelled its fusion counters after #3530 falsified their docstring. The owner-gated judge run followed: 8 pairs, 8 LLM calls, one same verdict β confirmed false positive (“yasmine el-daly” vs “[email protected]”, cosine 0.833 β a surname embedding-matched an email local-part), which also filed #3546. The strategic finding stands on its own: the judge is a reliable VETO and a poor PROPOSER. The jid-minting sub-fleet then took the WhatsApp half (see the note block above; #3555/#3561/#3566 merged, #3572 open, Regina still 0 JIDs, the pairing window unexpired).
The spine is merged and live. W0 stop-loss (PR #3103) stopped disconnect+merge from deleting a user's identity. W1 the spine (PR #3122) built viewer_bindings β one row per (tenant, account), composite FK, ON DELETE RESTRICT, one reconciler β and backfilled 10 rows. W2 the resolver (PR #3152) minted current_viewer_person_id(), repointed 7 SQL functions and 2 Python sites, shipped the platform resolvability console, and carried the disclosure fix. Verified from the database, not run metadata.
W2 carried a cross-user disclosure fix β W1's reconciler counted its refusal over a de-duplicated set and its warning over the raw one, so an account bridging two nodes would bind while the log said it had not.
The census, run after W2 merged (#3162): 17 expressions on main, 3 of 12 corrected, no cross-lane detector β get_viewer_person_id is mocked in every test touching it, which is how every lane looked closed from inside itself. The real-DB parity test shipped in the sweep below.
The choke-point sweep (PR #3169, merged 2026-08-08) found three defects in its own code, all one shape β a repoint carried the new source over and left behind a guarantee the old code had: a dropped runaway-page bound, a dropped sort order (one concurrent insert silently drops an account from the recipient list), and a roster field needing a different id space that broke every tier edit (0 of 4,978 nodes carry a shared id). The gate itself could be silenced by a string literal β the suppression token matched the raw line.
The four uncensused questions, now measured: display NAME (now 5-6 implementations, #3173); suppression scope (ruled per-viewer, #3177); access TIER β the reconciler is live (PR #3249 β 7dfedb9e7, pg_cron PR #3258 β ff097766a, hourly at :26), the write gap that fed the drift closed (PR #3272 for #3234), re-measured 0 of 14 diverging; identity subsumption (the reverse join, #3174).
“The nine ways a user arrives” was the wrong unit, and it undercounted (re-derived 2026-08-18). Journeys are stories, and stories do not enumerate β which is why nobody could say whether nine was all of them. What decides whether one human becomes two people is not which story they lived but which key their connector can hand the resolver, and there is exactly ONE resolver: find_or_create_person_by_alias, a six-rung ladder β group alias β cross-group alias β email β canonical name β first-name prefix β base name. An earlier trace read WhatsApp and email ingest as separate mechanisms; they are not. slices/node/materializer.py routes every PERSON intent through that same ladder. The split is not caused by different code. It is caused by which rungs are reachable.
Two key-spaces, declared per source type in slices/message/model.py: email-authoritative β gmail, maildir, exchange, google_calendar, exchange_calendar β and name-resolved with no email β whatsapp, whatsapp_live. (slack is neither β its key is the Slack user id, not an email β so it is NOT counted below.) For a human present in one of each, the email rung is measured never to fire: WhatsApp identities are 99.7% email-less on production (1,145 of 1,149) while gmail and maildir identities are ~100% email-bearing. π Measured, not structural. _get_sender_emails reads from_address/from_email off raw_metadata for ANY message and never consults the source type β the partition is a fact about what each PARSER populates (grep confirms the WhatsApp connector writes neither field, 0 occurrences), not an invariant anything enforces. A parser change moves this silently, and no detector would fire. The only bridge left is exact canonical_name β an LLM-merged pushName against an email display name β and for the 115 WhatsApp identities whose name IS a phone number, no rung can match at all. So the countable unit is connector PAIRS that guarantee a split: 2 Γ 5 = 10. The nine journeys covered exactly ONE of them (WhatsApp Γ Gmail, the old journey 3).
Why the duplicate census looks clean and is not: 2 name-duplicates and 2 email-duplicates out of 5,137 identities, and zero identities spanning two source types. That reads as health; it is an artifact of the detector. A split pair shares no key, so no census the system can currently run can see it. Live today: only gmail/maildir and whatsapp/whatsapp_live currently MINT person identities in production, so 4 of the 10 pairs are live and the rest are latent. exchange and slack have no production sources at all; google_calendar does have sources and ingests messages, but resolves zero persons, so it cannot split anyone and is not counted among the four. The concentration risk is Regina: 3,865 maildir identities and no WhatsApp β maildir is the single largest identity producer on the fleet and appeared in none of the nine journeys. The day a second connector lands there, thousands split at once.
What the arrival paths actually are: 7 live production routes to an auth.users row, and 3 produce a zero-binding user unconditionally β Mizo form signup, Mizo Google-OAuth signup, and admin-create-without-a-person. Every ordinary product signup starts unbound. POST /api/identity/link is live, registered and rate-limited with no caller in any frontend β and that is a regression, not a gap: commit 456d5d7c7 (“delete the legacy enterprise web app and every live reference to it”, PR #2889, 2026-07-31) removed the one call site, which lived only in the deleted app; no equivalent was added to client/.
What this re-derivation CLOSED: the old “merge two people” family (journeys 5, 9) is largely fixed and this page said otherwise. ADR-142's viewer_bindings hardened all three delete paths, the dedup merge now re-points bindings onto the survivor, and the node prune excludes bound nodes β converting what was silent corruption into DENIAL rather than EXPOSURE, deliberately. What it did NOT close: nodes_v2 still upserts on (tenant_id, node_type, lower(canonical_name)), so two different humans sharing one name in a tenant still become ONE node. That is the exposure direction, and its only defence is application-layer “decline to bind either” β not a constraint the database enforces. Unresolved: google_calendar has 2,766 ingested messages across 3 tenants and attributes zero persons, though its resolver is wired unconditionally.
Cron delivery is now observed (#3259, PR #3394, merged 2026-08-17). Both halves of the check had shipped and neither had ever taken effect: the middleware ran on every internal request but only UPDATEs cron_route_heartbeats, the rows are CREATED by a sweep, and nothing scheduled the sweep β so every arrival matched no row, production showed 0 heartbeat rows, and that read as a healthy fleet. The issue was CLOSED with no state:not-in-effect label, which is why it looked finished. The PR carried the migration and its route-census test, and scheduled the sweep hourly at :19; it fired at 20:19:01Z and created a heartbeat row for each of the 15 POSTing jobs β the 14 already scheduled, plus the sweep itself. Registration is not arrival: a row exists for a route from the moment it is censused, and carries an arrival only once that job next fires β so at the first pass the two longest-period jobs, the 03:00 nightly and the 12-hourly Exchange renewal, had no arrival simply because neither was due yet. An empty arrival on a long-period route is not evidence of silence until its own period has elapsed, which is the distinction the sweep's grace window encodes. The tier reconciler above POSTs its own route, so it is now watched by this. Residual, filed: the sweep's unreadable finding class is dropped before Sentry (#3393) β dormant while every scheduled job stays parseable.
What this report does not claim: W2 made no production account newly resolvable β re-measured 14 linked, 10 bound, 4 unresolvable, unchanged, and all ten that resolve already resolved before it. An earlier version said Regina went from zero to one resolvable; that was true only of the bridge, not the serving path. And the zeros are two different zeros β the latent measure (no node fuses two linked identities, no account bridges to two nodes) is the load-bearing one, and it is exactly the precondition for both the disclosure defect and the client divergence.