Skip to content

fix: session status stuck at in_progress — SessionEnd hook never fires in query() mode #48

Description

@Number531

Problem

All sessions remain permanently at in_progress status in the database. The handleSessionEnd() function in hookDBBridge.js (which updates status = 'completed') is dead code — the Agent SDK does not emit SessionEnd or Stop hooks in programmatic query() mode.

Evidence

  • 54K-line production SSE stream log (WTF-IS-THIS-THINKING.md): 259 hook events, zero SessionEnd or Stop events
  • SDK docs explicitly mark SessionEnd as "TypeScript only as SDK callback" (CLI mode only)
  • All 16 production session manifests contain agent_stop events but never session_end

Root Cause

handleSessionEnd() in hookDBBridge.js (lines 615-651) is properly wired:

  • Registered in sdkHooksConfig (sdkHooks.js line 2363)
  • Listed in HOOKS_TO_BRIDGE (hookDBBridge.js line 1155)
  • Routed in persistHookEvent switch (hookDBBridge.js line 710)

But the SDK never triggers it in query() mode. The only two code paths that update sessions.status to completed are:

  1. handleSessionEnd() — never called (dead code in query mode)
  2. archiveOldSessions() — only transitions completedarchived

Fix

Commit: 34adc52 on deploy-week-4-infrastructure

Added status = 'completed' to the existing persistFinalEventMetadata() UPDATE query, which already fires server-side (fire-and-forget) after stream completion:

-- Before:
UPDATE sessions SET metadata = ..., updated_at = NOW()
WHERE session_key = $1

-- After:
UPDATE sessions SET metadata = ..., status = 'completed', updated_at = NOW()
WHERE session_key = $1 AND status = 'in_progress'

Safety

  • Fires only AFTER agentQuery stream is fully consumed and shouldContinue = false
  • Fire-and-forget with .catch() — cannot propagate errors or affect the stream
  • send(finalPayload) already sent to client before this runs
  • Nothing in the codebase polls sessions.status to terminate processes
  • Idempotent: AND status = 'in_progress' guard prevents double-updates

Manual corrections applied

  • 2026-03-13-1773426614completed
  • 2026-03-07-1772900028completed

Future consideration

  • Add status = 'failed' update in the server error/catch path (~line 1706) so errored sessions don't stay at in_progress either
  • handleSessionEnd() and related code (persistSessionMetrics, persistWaveData, persistPhaseSummary, refreshSessionSummaryView) remain dead code in query mode — could be called from persistFinalEventMetadata to rescue that bookkeeping

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions