From daa937270cb1e81cf95b6e0832dae4b5ba87d8b6 Mon Sep 17 00:00:00 2001 From: JOUNGWOOK KWON Date: Sun, 19 Apr 2026 16:00:31 +0900 Subject: [PATCH] fix: apply session reset fix to SessionStore.createSDKSession (correct location) Previous fix was applied to sessions/create.ts which is unused. The actual method called by the worker is SessionStore.createSDKSession in src/services/sqlite/SessionStore.ts. Now resets started_at_epoch when session is completed or older than the 4-hour wall-clock limit, preventing age limit blocks after mac sleep/resume without proper SessionEnd. Co-Authored-By: Claude Sonnet 4.6 --- src/services/sqlite/SessionStore.ts | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/services/sqlite/SessionStore.ts b/src/services/sqlite/SessionStore.ts index 0f15f464..a043213a 100644 --- a/src/services/sqlite/SessionStore.ts +++ b/src/services/sqlite/SessionStore.ts @@ -1626,10 +1626,31 @@ export class SessionStore { // Session reuse: Return existing session ID if already created for this contentSessionId. const existing = this.db.prepare(` - SELECT id, platform_source FROM sdk_sessions WHERE content_session_id = ? - `).get(contentSessionId) as { id: number; platform_source: string | null } | undefined; + SELECT id, platform_source, completed_at_epoch, started_at_epoch FROM sdk_sessions WHERE content_session_id = ? + `).get(contentSessionId) as { id: number; platform_source: string | null; completed_at_epoch: number | null; started_at_epoch: number } | undefined; + + // 4-hour wall-clock limit (must match SDKAgent.MAX_SESSION_WALL_CLOCK_MS) + const MAX_SESSION_MS = 4 * 60 * 60 * 1000; if (existing) { + // Reset session if completed OR older than the wall-clock age limit. + // Handles mac sleep/resume where worker restarts but SessionEnd never fired, + // leaving a stale started_at_epoch that blocks all observations and summaries. + const ageMs = nowEpoch - existing.started_at_epoch; + const needsReset = !!existing.completed_at_epoch || ageMs > MAX_SESSION_MS; + if (needsReset) { + logger.info('SESSION', 'Resetting stale session on resume (mac sleep/worker-restart detected)', { + contentSessionId, + ageHours: Math.round(ageMs / 36e5 * 10) / 10, + wasCompleted: !!existing.completed_at_epoch + }); + this.db.prepare(` + UPDATE sdk_sessions + SET started_at_epoch = ?, started_at = ?, completed_at_epoch = NULL, completed_at = NULL, status = 'active' + WHERE content_session_id = ? + `).run(nowEpoch, now.toISOString(), contentSessionId); + } + // Backfill project if session was created by another hook with empty project if (project) { this.db.prepare(`