Summary
The daemon assigns an incoming event to a parent span by intersecting the event's process ancestry
with the list of processes already registered under an existing parent span. That ancestry chain is
walked up to the OS shell/desktop process, which is an ancestor of everything launched
interactively on the machine — so the intersection test can be satisfied between completely
unrelated agents, sessions, and even different days.
This doesn't just hide data, it corrupts it: cost from different models/agents gets summed into one
span. If that span feeds a per-team cost dashboard, the number looks valid and isn't.
Reproduction (controlled)
| Phase |
Session |
Ancestry intersects registered parent? |
Result |
| 1 |
registers a parent span |
— |
parent recorded |
| 2 |
different session, same shell tree |
yes (8 shared PIDs) |
contaminated |
| 3 |
different session, launched independently (no shared shell ancestry) |
no |
not contaminated |
Measured symptom
688 hook invocations from one session sat with zero log line, zero delivery-ledger entry, and zero
dashboard visibility for 2h14min, then were delivered in bulk, attached to a sibling session's trace
instead of their own.
Separately, one aggregate view showed 5 independent sessions (3 Claude Code + 2 Codex) merged into a
single span.
What's confirmed vs. hypothesis
Confirmed: the intersection mechanism, the 3-phase reproduction above, the retention/merge symptom.
Not yet controlled-tested (single uncontrolled observation only): that order-of-session-start decides
which session "wins," and that the registered-process list keeps growing over the daemon's uptime,
making contamination more likely over time.
Suggested fix
Scope span correlation by agent identity and strict process descendance instead of ancestry
intersection, and expire parent_span correlations after a bound.
Related
Summary
The daemon assigns an incoming event to a parent span by intersecting the event's process ancestry
with the list of processes already registered under an existing parent span. That ancestry chain is
walked up to the OS shell/desktop process, which is an ancestor of everything launched
interactively on the machine — so the intersection test can be satisfied between completely
unrelated agents, sessions, and even different days.
This doesn't just hide data, it corrupts it: cost from different models/agents gets summed into one
span. If that span feeds a per-team cost dashboard, the number looks valid and isn't.
Reproduction (controlled)
Measured symptom
688 hook invocations from one session sat with zero log line, zero delivery-ledger entry, and zero
dashboard visibility for 2h14min, then were delivered in bulk, attached to a sibling session's trace
instead of their own.
Separately, one aggregate view showed 5 independent sessions (3 Claude Code + 2 Codex) merged into a
single span.
What's confirmed vs. hypothesis
Confirmed: the intersection mechanism, the 3-phase reproduction above, the retention/merge symptom.
Not yet controlled-tested (single uncontrolled observation only): that order-of-session-start decides
which session "wins," and that the registered-process list keeps growing over the daemon's uptime,
making contamination more likely over time.
Suggested fix
Scope span correlation by agent identity and strict process descendance instead of ancestry
intersection, and expire
parent_spancorrelations after a bound.Related
instead of creating their own root span)