intake.matched stopped reaching Sales on 2026-05-12; 74 intake.captured events received since then but every resulting Lead has person_id=null
What we observed
A Sales-side diagnostic run today against sales.dispatcher_inbox_dedup shows intake.matched delivery cut off 2026-05-12T23:22:45.410Z and has not resumed. Concretely, the inbox state for the last 7 days:
| event_type | count | latest received |
|---|---|---|
intake.captured |
74 | 2026-05-16T22:03:00.999Z |
intake.matched |
61 | 2026-05-12T23:22:45.410Z |
intake.amended |
10 | 2026-05-13T04:57:56.748Z |
person.updated |
72 | 2026-05-16T21:40:16.755Z |
intake.captured from Growth is healthy, current within the hour, and producing Leads end-to-end. person.updated from Platform is healthy, current within the hour. intake.matched from Platform stopped 84 hours ago and has not resumed.
The operator-visible consequence: every Lead Sales has created since 2026-05-12T23:22:45 has person_id = null. The 24-hour delta-check shows intake.captured=8, leads=8, snapshots=8, all eight Leads have person_id=null. Cadence prompts render, intake snapshot facts render, but cross-domain stitching that depends on person_id (notably the customer.handoff matching path in modules/handoffs/handoffs.service.ts) cannot fire for any of these Leads.
Example Lead ids from the last 24 hours that Platform can use to look up the corresponding intake-side state:
lead_019e32d0-6e55-775b-b8e2-cbfe1477ef67(2026-05-16T22:03:01.080Z)lead_019e32ce-293d-709f-bd7d-28322e8538ac(2026-05-16T22:00:32.323Z)lead_019e32cb-f0c9-73f3-8d3a-b4b73c2f722d(2026-05-16T21:58:06.845Z)lead_019e32be-c34a-733a-8172-e018ba5d1fdb(2026-05-16T21:43:43.219Z)
Sales' diagnostic script that produces this report lives at sales/scripts/diagnose-intake-fanout.ts and can be rerun any time to refresh the picture.
Why this matters
This is a different symptom from the 2026-05-12 fanout gap but the same operational shape. That memo (2026-05-12-sales-intake-captured-fanout-gap) reported intake.captured not arriving while intake.matched was; Platform's response in 2026-05-12-platform-cross-db-consumer-dsn-upstream shipped the multi-producer DSN fix and closed the symptom. Today the inverse is true: captured arrives, matched does not.
Because intake.matched is the path that attaches a canonical person_id to a freshly-created Lead, the result is the same end-state Sales is trying to avoid: Leads sit in the inbox without canonical Person attachment, which fails the cross-domain handoff path and creates manual-recovery work for every Lead that lands during the outage.
The matched-arrives-first path-B handler in modules/intake-matches/ is the primary path that touches person_id on a Lead; without it firing, Sales' canonical reference is stuck at intake-form-supplied facts, not the Platform-resolved Person.
Suspected cause
Two candidates, in rough order of probability:
The first is the most consistent with the 2026-05-12 precedent. Platform's identity service is still emitting intake.matched to its own dispatcher_event table, but Platform's fanout worker has stopped picking them up for some Platform-internal reason. A regression of the DSN provisioning, a worker crash that took out the Platform-producer poll loop only, or an env-var loss in a redeploy. This pattern matches the 2026-05-12 shape but for a Platform-produced event family this time.
The second is that Platform's identity service stopped emitting intake.matched at all on 2026-05-12. Some upstream change in the matching pipeline (a deploy, a config change, a degraded dependency) that means intake records flow through to Sales but the identity-match step is not firing or not producing the event. Cutoff being a clean wall-clock boundary (23:22:45 UTC on 2026-05-12, after which zero events) is more consistent with infrastructure than with sporadic matching failures.
Sales cannot distinguish between the two from its side; both look identical at the inbox.
Asks
Confirm whether
intake.matchedevents are accumulating in Platform'sdispatcher_eventtable since 2026-05-12T23:22:45Z. If yes, the issue is the fanout worker's poll path for Platform-produced events. If no, the issue is upstream of the dispatcher emit.If the fanout worker is the cause, fix and redeploy; the durable
dispatcher_eventrows drain on the next poll cycle and Sales' inbox is ready to receive them. If the identity service is the cause, advise on the fix path and the expected backfill behavior for missed matches.Advise on recovery for the 8 Leads (and any others between 2026-05-12 and the fix) that landed without
person_id. The original intake event ids are preserved on the Lead row (originatingIntakeEventId) so Sales can re-resolve identity once Platform can confirm matches for those intakes, but the mechanism for triggering a re-match is Platform's call.Note that this is the second symptom in five days where a single event family stopped flowing without a visible signal. Worth a short follow-up on Platform's side about whether the fanout worker has alerting on per-event-type throughput dropping to zero, so the next instance surfaces faster than "Sales noticed three days later via a diagnostic script."
References
- Sales diagnostic:
sales/scripts/diagnose-intake-fanout.ts - Prior fanout gap (different event family, same operational shape):
2026-05-12-sales-intake-captured-fanout-gap - Platform's response and DSN-fix commitment:
2026-05-12-platform-cross-db-consumer-dsn-upstream - Sales' inbox handler:
sales/modules/dispatcher-inboxes/dispatcher-inboxes.service.ts - intake.matched consumer:
sales/modules/intake-matches/ - customer.handoff consumer (the downstream path that breaks without person_id):
sales/modules/handoffs/handoffs.service.ts