Mindbridge · track status

PERSON-NAME-TRUTH

Ask AMA about a Regina employee by name and the system does not know who they are, though their mail is ingested. Attribution is now fixed in production — and the same messages are still invisible, held out of embeddings, extraction and search by a flag with four writers and no recorded reason.

Promoted to a top-level track 2026-09-05 (owner ruling) — it ran until then as untracked work inside REGINA-DEDUP, separated from that label's fold-cost programme only by a title prefix no tool reads. Founding investigation: docs/plans/20260901-person-name-resolution/README.md. Counts resolve at build.

Next → code — #3826, the low-value gate. Owner ruled 2026-09-05: run the 398 re-attributed messages through the spam/actionable classifier they were skipped by, and clear the flag only where every ingest-side term is false and the classifier returns actionable. 🛑 One blocker is unsolved — the repair wrote no provenance marker, so the exact 398 rows are not yet identifiable; updated_at will not do it, folds churn hundreds of Regina rows an hour. decision — whether the nine :low-value rows belong on this track at all. #3854 is live WhatsApp across five tenants and has nothing to do with names; it is this track's work only in the sense that this track uncovered it.
16 open, of which 7 are the :low-value sub-track. Two distinct failures share this page. The first is attribution — a display name that was really an email address, an ASCII strip that erased non-Latin names, and a sentinel that swallowed 398 messages into one phantom identity. That half is done and verified in production. The second is visibility: the same sentinel branch also set is_low_value, and clearing it turns out to be a much larger problem than the 398 rows that surfaced it.
16open on the track
7of those, the low-value cluster
397/398messages re-attributed, prod
26,464Regina messages hidden — 40% of her corpus
56,604live-WhatsApp messages with no verdict at all
Open workGenerated evidenceWhy this orderStanding rulingsHistory

Open work

The low-value gate — track:person-name-truth:low-value (7 open)

One column, messages.is_low_value, decides whether a message reaches embeddings, extraction envelopes and search. An audit on 2026-09-05 found nine defects in it, eight of them previously unknown.

  • #3852 no provenance — six distinct reasons collapse into one bit at write time and the reason is discarded. This is why #3826 cannot be answered from the data. 🛑 Records reasons going forward only; it gives already-written rows nothing, so it does not block #3826.
  • #3853 the predicate is forked across four connectors and they already disagree — email marks a system message low-value, the WhatsApp export parser explicitly returns false for one. Censused by execution: three sites can produce true — the email adapter (:282), the WhatsApp export parser (:679) and the LLM classifier (:187) — while Slack answers the same question with a hardcoded false. Two sites reset an existing row to false: crud.py:907 and a SQL backfill (20260614125519_backfill_voice_note_transcript_content.sql:25-28), and the SQL one is where no app-side census reaches.
  • #3854 live WhatsApp writes no verdict at all — live_parser.py never mentions the field, so it takes the model default. 56,604 messages across five real tenants, 0 flagged. Largest reach on this track by a wide margin.
  • #3855 one-way ratchet — the flag only ever flips false→true, and the classifier skips anything already flagged, so a parse-time mistake is permanent and survives re-ingest.
  • #3856 backfill — 26,464 of Regina's 66,435 messages hidden; how many wrongly is unknowable until #3852. Blocked on #3852.
  • #3857 banned lexical heuristics — hardcoded English auto-reply strings, a len < 10 cutoff, and a hand-tuned English+Arabic filler list, in a tenant whose mail is Arabic, Japanese and English.
  • #3858 the spam classifier judges a fabricated sender — the phase synthesises [email protected] and hands the LLM that, while the real address sits unused in raw_metadata.
  • #3859 readers disagree on NULL — SQL and PostgREST exclude it, Python includes it, one converter coerces. Latent: 0 NULL rows in production today.
  • #3860 cache key truncates the body at 1,000 characters — two long emails sharing a prefix share a verdict.
  • #3826 the gate itself — the 398 re-attributed messages are correctly named and still not findable. The first and smallest slice of #3856.

🩸 The gap class, worth more than any single row. The materializer-writes hook enforces who writes the row. Nothing enforces who decides the value. Single-writer on the table, N-writer on the predicate — that shape is not in the register in .ai/choke-points.md and will recur for every other derived boolean on messages.

Name and identity — the rest of the track
  • #3784 — the identity gate is structurally blind to email-named person nodes.
  • #3791 — garbage-name detection is disarmed for every non-cased script; capitalization is used as a signal on Arabic, Japanese and Chinese, which have no case.
  • #3827 — _is_automated_sender cannot be replayed: this connector never persisted the headers it reads. A stated gap, not a closable one; kept open so the limit is visible rather than assumed away.

Filed nowhere, and owed. The it role-node reclassification is still deferred behind a 60+ call-site census. And 143 Regina messages carry a reply_to_person_id that is not their parent's person_id, though the intent that defines the column says it is exactly that — the owner was asked on 2026-09-04 whether to file it and has not yet ruled.

🔗 #3007 (name sanitization carries banned lexical heuristics) sits on REGINA-DEDUP and is the pre-existing sibling of #3857 — same class, different subject.

What the audit found — generated

⚠︎ The prose above cites 6 issues that are no longer open

#3854, #3852, #3853, #3857, #3859, #3791. 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.

Not yet assessed — filed after the audit
  • #3784 [L2-g5-w2] [person-name-truth] identity gate is structurally blind to email-named person…
  • #3826 [L1-g2-w4] [person-name-truth] is_low_value still gates the 398 re-attributed messages…
  • #3827 [person-name-truth] _is_automated_sender cannot be replayed — this connector never…
  • #3855 [L1-g2-w9] [person-name-truth] is_low_value is a one-way ratchet — a parse-time mistake…
  • #3856 [L1-g1-w8,L1-g2-w13,L1-g2-w15] [person-name-truth] backfill: 26,464 of Regina's 66,435…
  • #3858 [L1-g2-w14] [person-name-truth] the spam classifier judges a fabricated sender address
  • #3860 [person-name-truth] classification cache key truncates the body at 1,000 characters
  • #3889 [person-name-truth] reply_to_person_id disagrees with the parent's person_id on 143…
  • #3947 [L1-g2-w8,L1-g2-w9,L1-g2-w15] [person-name-truth] the taxonomy stops carrying the…
  • #3948 [person-name-truth] deception is its own question, not a taxonomy label
  • #3965 [person-name-truth] extract a shared panel-lane workflow — two copies of the RULE ONE…
  • #3980 [person-name-truth] content_cache_key's three callers hand-maintain their version — the…
  • #4030 [person-name-truth] 513 persons are suppressed on Regina by unreviewed impersonation…
  • #4223 [L1-g2-w13] [person-name-truth] Automated email (receipts, invoices, billing notices) is…
  • #4224 [L1-g2-w16] [person-name-truth] Graph nodes extracted from a message stay live after the…
  • #4239 [L1-g5-w2] [person-name-truth] Workspace Gmail historical pull is one-shot — a…

Why this order

#3826 first, because it is finishable and unblocked. It is the last piece of the attribution half: the mail is correctly named and still not findable, so the track's original complaint is not actually resolved until it ships. Nothing in the low-value cluster blocks it — #3852 is forward-only.

Then #3854, on reach. 56,604 messages across five tenants against 398 in one. It is independent of every other row here and needs no design decision from the cluster.

#3852 before #3856, and that is the only hard dependency on this page. Sizing the backfill means knowing which reason flagged each row, and nothing records it today.

🛑 docs/status/next_queue.py orders every open issue by priority label and has no dependency awareness — it will not know #3856 waits on #3852. That constraint lives here and in the issue bodies, nowhere else.

Standing rulings

History & forensics

The founding defect (measured 2026-09-01). Regina staff were unfindable by name because their From: display name was their email address. _is_garbage_display_name had a username branch meant to catch exactly that — but every address contains a dot, and the dot disarmed the branch. The person node's canonical_name became the raw address, and nothing a human would type ever matched it. Compounding it, three alias stores existed and the resolver read the emptiest: node_aliases held 2 rows against 4,042 identities.

Waves 1–3, all merged 2026-09-01/02. #3712 made derive_person_name() the one implementation and person_canonical_name() the writer-path choke-point. #3715 gave each alias its own provenance. #3722 was the prerequisite that made wave 2 non-vacuous — the provenance column had shipped empty and unfillable, with 9 of 20,764 rows carrying a method and 0 also satisfying the binding clauses. #3733 rebound the resolver through node_aliases and was proved live: AMA answered “who is Ahmed Mohy?” with his real HR-role profile. #3748 added a script-scoped name fold (Arabic harakat, tatweel, hamza-seat alef); #3746 added a gated trigram fallback.

Wave 5 — the sentinel repair, run in production 2026-09-04/05. An ASCII strip erased non-Latin display names, the sentinel Unknown Sender absorbed them, and 398 messages collapsed onto one phantom identity. #3810 re-attributed 397 of 398 (one held back deliberately: [email protected], a system sender). #3831 re-pointed 72 of 72 reply pointers and deleted 23 interaction edges on the phantom node. The edge rebuild on 2026-09-05 took 163s and moved tenant REPLIED_TO from 4,962 to 4,993, now targeting the real names — عادل فاروق, يس ى عبد الرشيد, 早瀬 大一 — the exact non-Latin names the strip had erased.

🪤 A scheduled fold never rebuilds interaction edges after an in-place repair. Measured over 8.5h: 0 REPLIED_TO edges created or updated while 3,609 edges of other types were created. An in-place UPDATE messages bumps no delta signal, so the delta pass skips the interaction phase; only --start-from forces a full mode.

🩸 Two claims this page's own predecessor carried, both false, both acted on for two sessions. That is_low_value was “set by the same sentinel branch” — it has four writers, and the dominant one is an LLM. And that it “cannot be honestly re-derived” because the stripped body is not stored — it can: the content builder returns the bare subject when the body is empty, so content == subject is exactly the empty-body case. Check the constructor before declaring a fidelity gap.

Refuted while auditing, so nobody re-opens them. The email classification cache is tenant-scoped by design (PK (tenant_id, email_hash), FK cascade, RLS service-role only); has_actionable_content is derived identically on the cache-hit and LLM paths, so a cache hit and a fresh classification cannot disagree; NULL rows in production = 0 across all 130,893 messages.

🩸 This page got the writer census wrong twice, and both were caught by its own review panel rather than by its author. Round one: “the SQL lane writes is_low_value in 0 migrations” — false, 20260614125519_backfill_voice_note_transcript_content.sql:25-28 is an UPDATE messages … SET … is_low_value = false; the census behind it was a line-scoped grep and the column sits three lines below its own verb, so the pattern could not see it. Round two: the correction said “four writers set it true, three reset it to false” — also false. materializer.py:331 and :607 are DOCSTRINGS describing crud.py:907, counted as write sites; and Slack's hardcoded false can never set true. 🔑 A number that replaces a refuted number is exactly as unverified as the one it replaced — re-derive it, do not reason from the old one.

What this page does not claim. The 26,464 is the hidden population, not a count of wrongly-hidden messages — that number does not exist yet and cannot until #3852. The live-WhatsApp figures are a divergence between two paths answering the same question, not a defect count; whether live media should be hidden is a product call the export path has already made one way. Regina's 33,740 cached classification hashes are not a coverage figure: multi-recipient mail collapses roughly 3:1 by hash.