23f597a8f5
The scheduler booked every finished run as end_reason=cron_complete based on the run lifecycle alone. A job whose agent turn died after a tool call, mid-API-wait, or without any assistant text still surfaced as a healthy run — one audited day held 10 such silently-failed sessions whose run history showed green (#93820). Before end_session, the session's LAST message row is now classified through the existing cost-bounded session_lifecycle_statuses helper: only a real assistant reply (a plain answer or the [SILENT] sentinel — both assistant-text rows) keeps cron_complete; the positively recognized pathological statuses (interrupted / error / empty) book the run as cron_incomplete_no_output with a warning. Unknown values and probe failures keep the historical reason — classification is best-effort metadata and must not mislabel a healthy run. The new end_reason is a free-form forensics string like cron_complete (in no recovery/reset whitelist), so session recovery semantics are unchanged. Fixes #93820