Commit graph

1 commit

Author SHA1 Message Date
Rasmus Widing
a1a4496132
feat: Add session state machine with immutable sessions for audit trail (#302)
* feat: Add session state machine with immutable sessions for audit trail

This PR implements an explicit session state machine that tracks why sessions
are created/deactivated, enabling debugging of agent decision history.

Changes:
- Add TransitionTrigger type as single source of truth for session transitions
- Add parent_session_id and transition_reason columns to sessions table
- Add transitionSession(), getSessionHistory(), getSessionChain() functions
- Update orchestrator to use transitionSession() for all session creation
- Add trigger logging to all command-handler deactivation points
- Add comprehensive unit tests for new functionality

The session chain can be walked to understand the full history of a conversation,
with each session recording why it was created (first-message, plan-to-execute,
reset-requested, isolation-changed, etc.)

* docs: Update documentation for session state machine

* fix: Address PR review feedback - improve type safety and error handling

- Add SessionNotFoundError and rowCount validation to updateSession,
  deactivateSession, and updateSessionMetadata
- Strengthen createSession signature to accept TransitionTrigger instead
  of string for transition_reason
- Replace TransitionTrigger arrays with TRIGGER_BEHAVIOR Record for
  compile-time exhaustiveness checking
- Improve isBranchMerged/getLastCommitDate error handling - log unexpected
  errors while still returning false/null for cleanup safety
- Fix ESLint template expression warnings by adding non-null assertions
  to getTriggerForCommand calls (values guaranteed to exist)
- Add tests: SessionNotFoundError cases, getSessionChain with non-existent
  ID, transitionSession error propagation, null input handling

* refactor: Simplify session code per code-simplifier review

- Consolidate duplicate error assertion patterns in tests
- Simplify shouldDeactivateSession logic: !== 'none' instead of
  checking both 'creates' and 'deactivates' explicitly
2026-01-19 22:14:39 +02:00