Archon/migrations/016_session_ended_reason.sql
Rasmus Widing 99bbec9f79
Store session deactivation reasons in database (#303) (#385)
* Investigate issue #303: session deactivation reasons not stored

Root cause: deactivateSession() only sets active=false and ended_at,
but doesn't accept or persist the reason. All 9 call sites already
compute the trigger for logging but don't pass it to the DB.

Fix: add ended_reason column + update function signature + thread
reason through all call sites.

* Store session deactivation reasons in database (#303)

Session deactivation reasons were logged to console but not persisted.
Migration 010 added transition_reason for session creation but missed
ended_reason for deactivation. This completes the audit trail.

Changes:
- Add ended_reason TEXT column (migration 016 + SQLite schema)
- Update deactivateSession() to accept optional reason parameter
- Pass trigger reason at all 9 call sites (7 commands + cleanup + transition)
- Update Session interface and tests

Fixes #303

* Harden session deactivation: required reason, TOCTOU safety, stronger types

- Make `reason` parameter required on `deactivateSession()` to enforce
  audit trail at compile time (was optional, undermining the invariant)
- Add function overloads to `getTriggerForCommand()` so known commands
  return non-null, eliminating dead-code `?? fallback` at all 7 call sites
- Use `TransitionTrigger | null` in Session interface instead of
  `string | null` to connect read/write type paths
- Handle TOCTOU race: wrap deactivation calls in `safeDeactivateSession()`
  helper that treats `SessionNotFoundError` as benign (concurrent cleanup
  or duplicate command could deactivate between check and use)
- Same TOCTOU protection in cleanup service `onConversationClosed()`
- Add missing test assertions for /setcwd, /repo, /repo-remove, and
  /worktree-remove deactivation reasons
- Add cleanup service test for 'conversation-closed' reason
2026-02-16 13:54:41 +02:00

9 lines
437 B
SQL

-- Migration: Add ended_reason to track why sessions were deactivated
-- Completes the audit trail started in migration 010 (transition_reason for creation)
-- Backward compatible: new column is nullable
ALTER TABLE remote_agent_sessions
ADD COLUMN IF NOT EXISTS ended_reason TEXT;
COMMENT ON COLUMN remote_agent_sessions.ended_reason IS
'Why this session was deactivated: reset-requested, cwd-changed, conversation-closed, etc.';