fix(telemetry): emit the shutdown marker at the session's own disposal edge

Review finding (Codex P1), pinned red-first: the marker was tied to
telemetry-plugin lifetime, but receivers key crash detection on its
absence per session. A normally closed session in a long-running host
retired silently (classified as a crash once stale), while a telemetry
reload marked every still-live session as cleanly ended.

The session/disposed handler now emits the marker at the session's own
termination edge before retiring it; the dispose-time sweep only marks
sessions still alive at application teardown (their own edge would fire
unobserved). READMEs restate the marker semantics: telemetry stopped
observing cleanly — a marker followed by more session events is a
telemetry reload, not a session restart.
This commit is contained in:
kingwl
2026-07-25 21:21:45 +08:00
parent 416bcd8562
commit ec38cac8ef
4 changed files with 61 additions and 22 deletions

View File

@@ -8,7 +8,7 @@ The telemetry seam: the CAPTURE side of session-event reporting, behind a backen
## Capture points
The coordinator registers, all through the composing fiber's effects: `session/created` (adopt: record the header, read the log back through the projection — seed events from fork/resume never re-emit on the firehose), `session/event` (project, deep-copy, redact, hand off; zero I/O), `session/flush` (forward the optional `flush()` hint and return void — the loop's awaited parallel must never wait on telemetry), `session/disposed` (retire: release the adopted entry so a long-lived backend neither retains closed sessions nor stamps dispose-time markers for them), `agent/error` (the one live-bus relay; turn-enclosure structurally bars those errors from the log), a dispose effect (per still-adopted session emit its `shutdown` operational record, then await the backend's `shutdown()`; failures warn instead of throwing), and an adoption sweep of `ctx.sessions.list()` (a hot reload does not replay `session/created`).
The coordinator registers, all through the composing fiber's effects: `session/created` (adopt: record the header, read the log back through the projection — seed events from fork/resume never re-emit on the firehose), `session/event` (project, deep-copy, redact, hand off; zero I/O), `session/flush` (forward the optional `flush()` hint and return void — the loop's awaited parallel must never wait on telemetry), `session/disposed` (emit the session's `shutdown` operational record at its own termination edge — where receivers key crash detection — then retire it, so a long-lived backend neither retains closed sessions nor re-marks them at unload), `agent/error` (the one live-bus relay; turn-enclosure structurally bars those errors from the log), a dispose effect (mark each session still alive at teardown, then await the backend's `shutdown()`; failures warn instead of throwing), and an adoption sweep of `ctx.sessions.list()` (a hot reload does not replay `session/created`).
## The redact waterfall