Monitoring CFO-7362 dead-session redirects
This runbook answers one question. Of the chats we redirected away from, which were genuinely dead, and did we bounce anyone off a chat that was actually alive? Run the DB audit daily. It is the authority, because it compares each redirect against what the database actually holds. The PostHog query is the fast first look and tells you why a redirect fired.1. DB audit (authoritative)
Paste the redirected session ids, timestamps, and the viewing user’s clerk id from the PostHog query below into thevalues list, then run in Supabase.
Worst verdicts sort first.
The clerk_id column is not optional. The session GET scopes rows to the
signed-in user, so a session belonging to someone else correctly reads as
empty and is correctly redirected. An audit that ignores ownership reports
those as REVIEW and sends you chasing a bug that is not there. This happened
on 2026-08-14 with session_0e670456, which had 9 rows owned by a different
user.
REVIEW.
Reading it
When a verdict looks impossible, check ownership before anything else:
first_row_delta_s carries the whole signal. Positive and small, roughly 0 to
2 seconds, means the row landed after we called the session dead. That is a
race, not a dead session.
2. PostHog, daily counts and the reason each redirect fired
chat_session_not_found_fresh_fallback, a small trickle. These should all come backCORRECT: truly deadin the audit.chat_session_load_skipped_in_flightfires on sends whose load would have raced. Harmless. High counts just mean the guard is earning its keep.chat_session_not_found_recheck_recoveredcounts races the re-check caught. These are saves, so a steady trickle is the system working. Watchp50_recheck_attemptsinstead of the raw count: if recoveries routinely need the last attempt before the deadline,DEAD_SESSION_CONFIRM_WINDOW_MSis too tight and should be raised. Redirects sitting at the attempt ceiling say the same thing louder.chat_session_recheck_failed_fallbackshould sit near zero. These are redirects we could not confirm. Sustained non-zero means the session GET is failing, so check Supabase and PostgREST health rather than this code.while_streamingabove zero, orp50_ms_since_sendunder roughly 5000, is a red flag that we are redirecting live chats. Cross-check in the audit above.
Baseline for comparison
Redirects cluster after deploys, when Next.js forces hard navigations on
clients still running the old bundle. A page remount is what makes a load fire
for a session the context does not hold. Check the day of and the day after
every release, not just quiet days.
If the audit returns a WRONG verdict
- Pull that user’s event stream around the redirect:
chat_message_sent, thenworkflow_dispatch, then the fallback event, then the$pageviewto/chat. - Check whether they returned to the session afterwards. If not, they lost that answer. The row exists but was never rendered.
- The guards live in
lib/chat-dead-session.ts, with the reasoning incontexts/shared-chat-context.tsxunderloadSession.