Orchestrata Ultimate / Specs / 006-session-management
006-session-management: Session Management
Session Management provides comprehensive lifecycle management for orchestrator work sessions including session opening/closing with full audit trail, fact emission and persistence to dual storage (Redis + Neo4j), portfolio management across multiple projects, context persistence and recovery, carryover task tracking between sessions, and session handover with state preservation.
At a glance
| Item | Value |
|---|---|
| Spec directory | specs/006-session-management/ |
| Status line in the spec | Complete |
| Requirement IDs defined | 144 |
With a @traces citation in src/ |
144 (100.0%) |
With a @traces citation in tests/ |
19 (13.2%) |
| Tracked files | 11 |
| RTM page | 006-session-management |
Reading this spec
Session Management governs the lifecycle of orchestrator work sessions. It tracks all work across sessions with full auditability, so that work continues after a crash or a planned shutdown, development patterns can be analysed historically, and portfolio-level insight spans multiple projects.
The scope is seven user stories: open session, close session and emit facts (priority 1), then session recovery, carryover tasks, portfolio management and context persistence (priority 2). The functional requirements are grouped as core session lifecycle, fact emission and storage, portfolio management, context and carryover, recovery and handover, local context file sync, and archive and integrity.
The central design decision is dual storage. Redis is the hot path, with sub-50ms session operations and active session state. Neo4j is the cold path, holding the full audit trail, historical queries and graph relationships. Prolog provides session governance, constraint checking and policy enforcement.
In the code, the largest tracers are orchestrata_ultimate/session/controller/_core, orchestrata_ultimate/session/redis_store, orchestrata_ultimate/session/fact_emitter, orchestrata_ultimate/session/prolog_interface and orchestrata_ultimate/session/context. The per-requirement view is on the RTM page.
The spec's status line reads Complete. It tracks 11 files and defines 144 requirement IDs, every one of them traced in the source. The full text follows below.
Measured coverage is 144 of 144 requirements cited by at least one @traces in src/ (100.0%), spread over 39 modules; the module citing the most of them is orchestrata_ultimate/session/controller/_core (53 requirements). In tests/, 19 requirements are cited by a test-side @traces.
Coverage gaps: none on the citation measure, every requirement has at least one citing src/ symbol. Test-side citations are thinner than code-side ones (19 against 144).
Requirements
Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.
| ID | Done | Requirement | Traced by |
|---|---|---|---|
REQ-006-US-001-001 |
yes | User can create a new session with a unique session ID | 2 |
REQ-006-US-001-002 |
yes | System generates session ID automatically if not provided | 3 |
REQ-006-US-001-003 |
yes | Session creation includes timestamp and initial state | 4 |
REQ-006-US-001-004 |
yes | Session is registered in the Prolog fact database | 2 |
REQ-006-US-001-005 |
yes | Session creation completes in < 50ms | 2 |
REQ-006-US-001-006 |
yes | Verification: session_exists(SessionID) returns true |
2 |
REQ-006-US-002-001 |
yes | User can explicitly close a session | 9 |
REQ-006-US-002-002 |
yes | System removes session from active sessions list | 4 |
REQ-006-US-002-003 |
yes | Session facts are retracted from Prolog database | 7 |
REQ-006-US-002-004 |
yes | Session cleanup completes successfully | 5 |
REQ-006-US-002-005 |
yes | Session resources are released | 4 |
REQ-006-US-002-006 |
yes | Verification: session_exists(SessionID) returns false after closure |
3 |
REQ-006-US-002-007 |
no | [DRAFT — derived-from-code, UNRATIFIED]: When ending a session, the system auto-detects git-modified files and logs them as session artifacts |
3 |
REQ-006-US-002-008 |
no | [DRAFT — derived-from-code, UNRATIFIED]: When ending a session, the system auto-detects commits made since session start and logs them as work-log entries |
2 |
REQ-006-US-002-009 |
no | [DRAFT — derived-from-code, UNRATIFIED]: When ending a session, the system runs test collection and records the collected test count on session state |
2 |
REQ-006-US-002-010 |
no | [DRAFT — derived-from-code, UNRATIFIED]: When ending a session, the user can interactively commit (and optionally push) pending git changes |
1 |
REQ-006-US-003-001 |
yes | User can query current session state | 8 |
REQ-006-US-003-002 |
yes | System returns all facts associated with session | 7 |
REQ-006-US-003-003 |
yes | Query includes session metadata (ID, timestamp, status) | 4 |
REQ-006-US-003-004 |
yes | Query execution completes in < 10ms | 3 |
REQ-006-US-003-005 |
yes | Results are formatted correctly (JSON/Prolog terms) | 8 |
REQ-006-US-003-006 |
yes | Verification: Query returns expected session data | 3 |
REQ-006-US-004-001 |
yes | User can emit facts to current session | 6 |
REQ-006-US-004-002 |
yes | Facts are immediately available in Prolog database | 5 |
REQ-006-US-004-003 |
yes | Fact emission includes source attribution | 3 |
REQ-006-US-004-004 |
yes | Fact emission completes in < 10ms | 3 |
REQ-006-US-004-005 |
yes | Multiple facts can be emitted in single operation | 7 |
REQ-006-US-004-006 |
yes | Verification: Emitted facts can be queried immediately | 3 |
REQ-006-US-005-001 |
yes | System maintains session-specific context | 8 |
REQ-006-US-005-002 |
yes | Context includes conversation history | 2 |
REQ-006-US-005-003 |
yes | Context includes emitted facts | 2 |
REQ-006-US-005-004 |
yes | Context is isolated per session | 3 |
REQ-006-US-005-005 |
yes | Context persists throughout session lifetime | 3 |
REQ-006-US-005-006 |
yes | Verification: Context queries return session-specific data only | 4 |
REQ-006-US-006-001 |
yes | System triggers on_session_start hook | 15 |
REQ-006-US-006-002 |
yes | System triggers on_session_end hook | 4 |
REQ-006-US-006-003 |
yes | Hooks can execute custom logic | 2 |
REQ-006-US-006-004 |
yes | Hook execution does not block session operations | 1 |
REQ-006-US-006-005 |
yes | Hook failures are logged but do not crash system | 2 |
REQ-006-US-006-006 |
yes | Verification: Hooks are called with correct parameters | 3 |
REQ-006-US-007-001 |
yes | System supports multiple concurrent sessions | 2 |
REQ-006-US-007-002 |
yes | Each session has isolated state | 3 |
REQ-006-US-007-003 |
yes | Sessions do not interfere with each other | 3 |
REQ-006-US-007-004 |
yes | Session switching is supported | 4 |
REQ-006-US-007-005 |
yes | Session list can be queried | 6 |
REQ-006-US-007-006 |
yes | Verification: Multiple sessions can be active simultaneously | 3 |
REQ-006-FR1-001 |
yes | System generates unique session IDs | 2 |
REQ-006-FR1-002 |
yes | Session IDs follow format: session_YYYYMMDD_HHMMSS_UUID (constants.py:generate_session_id()) |
2 |
REQ-006-FR1-003 |
yes | Session IDs are collision-resistant | 2 |
REQ-006-FR1-004 |
yes | Session IDs are human-readable | 2 |
REQ-006-FR1-005 |
yes | Verification: Generated IDs are unique across 1000+ sessions | 2 |
REQ-006-FR2-001 |
yes | Session state is stored in Prolog fact database | 2 |
REQ-006-FR2-002 |
yes | State includes: session ID, timestamp, status, metadata | 2 |
REQ-006-FR2-003 |
yes | State is queryable via Prolog interface | 2 |
REQ-006-FR2-004 |
yes | State updates are atomic | 2 |
REQ-006-FR2-005 |
yes | Verification: State persists across multiple queries | 3 |
REQ-006-FR3-001 |
yes | Facts are tagged with session ID | 9 |
REQ-006-FR3-002 |
yes | Facts include timestamp of emission | 6 |
REQ-006-FR3-003 |
yes | Facts include source attribution | 4 |
REQ-006-FR3-004 |
yes | Facts are queryable by session ID | 5 |
REQ-006-FR3-005 |
yes | Verification: Facts are correctly associated with sessions | 4 |
REQ-006-FR4-001 |
yes | Each session has separate fact namespace | 3 |
REQ-006-FR4-002 |
yes | Queries are scoped to current session by default | 3 |
REQ-006-FR4-003 |
yes | Cross-session queries are explicitly supported | 4 |
REQ-006-FR4-004 |
yes | Session isolation prevents fact leakage | 3 |
REQ-006-FR4-005 |
yes | Verification: Session A cannot access Session B facts without explicit permission | 4 |
REQ-006-FR5-001 |
yes | Closed sessions retract all associated facts | 6 |
REQ-006-FR5-002 |
yes | Session resources are released on closure | 5 |
REQ-006-FR5-003 |
yes | Cleanup is atomic (all-or-nothing) | 3 |
REQ-006-FR5-004 |
yes | Failed cleanup attempts are logged | 3 |
REQ-006-FR5-005 |
yes | Verification: No memory leaks after 1000+ session cycles | 3 |
REQ-006-FR6-001 |
yes | Invalid session IDs return clear error messages | 5 |
REQ-006-FR6-002 |
yes | Operations on closed sessions fail gracefully | 5 |
REQ-006-FR6-003 |
yes | Prolog errors are caught and logged | 3 |
REQ-006-FR6-004 |
yes | System remains stable after errors | 3 |
REQ-006-FR6-005 |
yes | Verification: System continues operating after error conditions | 2 |
REQ-006-FR7-001 |
yes | Session creation: < 50ms | 3 |
REQ-006-FR7-002 |
yes | Fact emission: < 10ms | 2 |
REQ-006-FR7-003 |
yes | Session query: < 10ms (Redis LRANGE + filter, validated in benchmarks) | 3 |
REQ-006-FR7-004 |
yes | Session closure: < 50ms (pipeline cleanup, validated in benchmarks) | 3 |
REQ-006-FR7-005 |
yes | Concurrent operations: 100+ sessions without degradation | 2 |
REQ-006-FR7-006 |
yes | Verification: Performance benchmarks pass | 3 |
REQ-006-FR8-001 |
yes | Python API: emit_fact(session_id, fact_term) |
7 |
REQ-006-FR8-002 |
yes | Supports Prolog term strings | 3 |
REQ-006-FR8-003 |
yes | Supports structured fact dictionaries | 7 |
REQ-006-FR8-004 |
yes | Returns success/failure status | 2 |
REQ-006-FR8-005 |
yes | Verification: API calls succeed with valid inputs | 1 |
REQ-006-FR9-001 |
yes | Python API: query_session(session_id, query_term) |
5 |
REQ-006-FR9-002 |
yes | Returns list of matching facts | 5 |
REQ-006-FR9-003 |
yes | Supports complex Prolog queries | 6 |
REQ-006-FR9-004 |
yes | Returns empty list for no matches | 3 |
REQ-006-FR9-005 |
yes | Verification: Queries return correct results | 4 |
REQ-006-FR10-001 |
yes | Python API: open_session(session_id=None) |
3 |
REQ-006-FR10-002 |
yes | Python API: close_session(session_id) |
4 |
REQ-006-FR10-003 |
yes | Python API: get_session_info(session_id) |
4 |
REQ-006-FR10-004 |
yes | Returns session metadata | 7 |
REQ-006-FR10-005 |
yes | Verification: APIs work as documented | 3 |
REQ-006-FR11-001 |
yes | Hooks are registered via Python API | 5 |
REQ-006-FR11-002 |
yes | Hook signature: hook_function(session_id, **kwargs) (SessionHook protocol in hook_registry.py) |
3 |
REQ-006-FR11-003 |
yes | Hooks execute synchronously during lifecycle events | 2 |
REQ-006-FR11-004 |
yes | Hook failures are logged | 2 |
REQ-006-FR11-005 |
yes | Verification: Hooks execute with correct parameters | 3 |
REQ-006-FR12-001 |
yes | All session operations are logged | 5 |
REQ-006-FR12-002 |
yes | Logs include: session ID, operation, timestamp, result | 2 |
REQ-006-FR12-003 |
yes | Performance metrics are captured | 7 |
REQ-006-FR12-004 |
yes | Errors are logged with stack traces | 2 |
REQ-006-FR12-005 |
yes | Verification: Logs are complete and accurate | 5 |
REQ-006-FR13-001 |
yes | Session management exposed via MCP protocol | 1 |
REQ-006-FR13-002 |
yes | MCP tools can manage sessions (create, get, close) | 3 |
REQ-006-FR13-003 |
yes | MCP clients can query session state and facts | 3 |
REQ-006-FR13-004 |
yes | MCP tool schemas follow standard format | 1 |
REQ-006-FR13-005 |
yes | MCP integration verified with comprehensive tests | 1 |
REQ-006-FR14-001 |
yes | context.json is machine-readable source of truth | 7 |
REQ-006-FR14-002 |
yes | context.md rendered from context.json via Jinja2 | 3 |
REQ-006-FR14-003 |
yes | Atomic writes — both files updated or neither | 2 |
REQ-006-FR14-004 |
yes | context.history.md is canonical archive filename | 2 |
REQ-006-FR14-005 |
yes | Auto-archive when session count exceeds SESSION_LIMIT | 3 |
REQ-006-FR14-006 |
yes | Schema defined by ContextData Pydantic model | 6 |
REQ-006-FR14-007 |
yes | Sync integrity — gapless ascending session numbers | 8 |
REQ-006-FR15-001 |
yes | Auto-archive on session close | 3 |
REQ-006-FR15-002 |
yes | Append-only to context.history.md | 2 |
REQ-006-FR15-003 |
yes | Idempotent archive operation | 3 |
REQ-006-FR16-001 |
yes | Gap detection in session numbering | 2 |
REQ-006-FR16-002 |
yes | Duplicate detection across files | 2 |
REQ-006-FR16-003 |
yes | Sync validation (context.md matches context.json render) | 3 |
REQ-006-FR16-004 |
yes | History continuity (no overlapping ranges) | 4 |
REQ-006-FR17-001 |
yes | Scan git history for lost sessions | 2 |
REQ-006-FR17-002 |
yes | Extract session data from historical commits | 2 |
REQ-006-FR17-003 |
yes | Append with [RECOVERED] annotation | 2 |
REQ-006-FR17-004 |
yes | Non-destructive (never overwrites) | 4 |
REQ-006-FR18-001 |
yes | archive command triggers archive | 2 |
REQ-006-FR18-002 |
yes | archive --verify runs integrity check | 3 |
REQ-006-FR18-003 |
yes | archive --recover runs git recovery | 3 |
REQ-006-FR18-004 |
yes | archive --stats shows statistics | 5 |
REQ-006-FR18-005 |
yes | status command shows current state | 18 |
REQ-006-FR18-006 |
yes | list command shows all sessions | 8 |
REQ-006-FR18-007 |
no | [DRAFT — derived-from-code, UNRATIFIED]: overview command runs a one-shot startup digest reporting infra health, session state, last test verdict, rulings staleness, git status, and project status in seven independently-isolated sections, always exiting 0 with per-section error reporting rather than aborting on subsystem failure |
1 |
REQ-006-FR19-001 |
no | task add adds a deferred/carryover work item (text + optional priority) to the active session |
1 |
REQ-006-FR19-002 |
no | task done <index> marks a carryover task done by index, persisting completion to context.json |
2 |
REQ-006-FR19-003 |
no | task list lists all carryover tasks with index, state, and priority |
1 |
REQ-006-FR19-004 |
no | task status shows aggregate carryover-task statistics by state |
1 |
REQ-006-NFR9-001 |
yes | Archive completes in < 500ms | 2 |
REQ-006-NFR9-002 |
yes | Verification completes in < 1s | 1 |
REQ-006-NFR9-003 |
yes | Git scan max 200 commits | 2 |
Code that traces this spec
Checklists
checklists/constitutional.md
Constitutional Checklist - Session Management
Document: plans/prolog-orchestrator-design.md (Constitutional AI Principles)
Date: 2026-01-13
Status: Implementation Phase
Article IX: Session Management (PRIMARY FOCUS)
Section 1: Session Lifecycle
- [x] Sessions have explicit open and close operations
- [x] Session state is managed through Prolog facts
- [x] Session lifecycle follows constitutional principles
- [x] Session creation is atomic (succeeds completely or fails)
- [x] Session closure is atomic (all facts retracted or rollback)
- [x] Verification: Lifecycle operations are atomic and traceable
Section 2: Fact Emission
- [x] Facts emitted to Prolog are attributed to source
- [x] Facts include session context
- [x] Facts are timestamped
- [x] Facts are immutable after emission
- [x] Facts persist throughout session lifetime
- [x] Verification: Facts maintain integrity and attribution
Section 3: Session Isolation
- [x] Each session maintains separate fact namespace
- [x] Sessions do not share state unless explicitly designed
- [x] Cross-session queries require explicit permission
- [x] Session boundaries are enforced by system
- [x] Isolation prevents unintended fact leakage
- [x] Verification: Sessions are properly isolated
Section 4: Hook System
- [x] Hooks provide extensibility points in session lifecycle
- [x] Hooks execute at: session_start, session_end, fact_emitted
- [x] Hook failures do not crash the system
- [x] Hooks are logged for auditability
- [x] Hooks can be registered dynamically
- [x] Verification: Hooks execute correctly and safely
Article I: Prolog as Constitutional Foundation
Prolog Integration
- [x] Session management uses Prolog as source of truth
- [x] All session state stored as Prolog facts
- [x] Session queries executed through Prolog interface
- [x] Prolog errors are handled gracefully
- [x] Verification: Prolog integration is complete and robust
Fact Representation
- [x] Sessions represented as:
session(SessionID, Status, Timestamp) - [x] Facts represented as:
session_fact(SessionID, FactTerm, Timestamp, Source) - [x] Representation is consistent across system
- [x] Verification: Fact schema is correct and queryable
Article II: Transparency and Auditability
Operation Logging
- [x] All session operations logged with timestamps
- [x] Logs include: session ID, operation type, result, duration
- [x] Logs are human-readable and machine-parseable
- [x] Logs include performance metrics
- [x] Verification: Logs provide complete audit trail
State Visibility
- [x] Session state is always queryable
- [x] Current sessions can be listed
- [x] Session history is preserved (optional)
- [x] State changes are traceable
- [x] Verification: State is fully transparent
Article III: Modularity and Composability
Module Boundaries
- [x] Session management is independent module
- [x] Clear interfaces:
SessionManager,PrologInterface - [x] No circular dependencies
- [x] Module can be tested in isolation
- [x] Verification: Module dependencies are clean
API Design
- [x] APIs follow consistent patterns
- [x] APIs are easy to understand and use
- [x] APIs handle errors gracefully
- [x] APIs are well-documented
- [x] Verification: APIs meet usability standards
Article IV: Graceful Error Handling
Error Recovery
- [x] Invalid session IDs return clear errors
- [x] Operations on closed sessions fail gracefully
- [x] Prolog errors are caught and logged
- [x] System continues operating after errors
- [x] Verification: Error handling is comprehensive
Error Messages
- [x] Errors include: context, session ID, operation, reason
- [x] Error messages are actionable
- [x] Errors distinguish user errors from system errors
- [x] Verification: Error messages are helpful
Article V: Performance Under Constraint
Performance Targets
- [x] Session open: < 50ms
- [x] Fact emission: < 10ms
- [x] Session query: < 10ms (Redis LRANGE + filter, validated in benchmarks)
- [x] Session close: < 50ms (pipeline cleanup, validated in benchmarks)
- [x] Verification: Performance benchmarks pass
Resource Management
- [x] Memory usage is bounded
- [x] No memory leaks in session lifecycle
- [x] Resources are released on session closure
- [x] System scales to 100+ concurrent sessions
- [x] Verification: Resource usage is acceptable
Article VI: Incremental Development
Implementation Strategy
- [x] Core session lifecycle implemented first
- [x] Fact emission added incrementally
- [x] Hook system added after core is stable
- [x] Each increment is tested independently
- [x] Verification: Development follows incremental approach
Testing at Each Stage
- [x] Unit tests for each component
- [x] Integration tests for component interactions
- [x] Performance tests at each milestone
- [x] Tests pass before moving to next increment
- [x] Verification: Testing is comprehensive
Article VII: Human-Readable Outputs
Query Results
- [x] Results formatted as readable Prolog terms
- [x] Results include context and metadata
- [x] Results can be converted to JSON
- [x] Results are unambiguous
- [x] Verification: Output format is clear
Logging Format
- [x] Logs use consistent format
- [x] Timestamps are human-readable
- [x] Session IDs are descriptive
- [x] Verification: Logs are readable
Article VIII: Integration with Orchestrator
Tool Integration
- [x] Session management integrated with tool system
- [x] Tools can access current session context
- [x] Tools can emit facts to session
- [x] Integration is seamless
- [x] Verification: Tools work with session system
MCP Integration
- [x] Session management exposed via MCP protocol (
SessionMCPToolsinmcp_tools.py) - [x] MCP tools can manage sessions (session_create, session_get, session_close)
- [x] MCP clients can query session state (session_query_facts, session_list_active)
- [x] Verification: MCP integration is complete
Article X: Testing as Constitutional Requirement
Test Coverage
- [x] Unit tests for all components
- [x] Integration tests for system interactions
- [x] Performance tests for benchmarks
- [x] Edge case tests for error conditions
- [x] Test coverage > 90% (enforced by
--cov-fail-under=90in CI) - [x] Verification: All tests pass
Test Quality
- [x] Tests use real implementations (no mocking)
- [x] Tests are deterministic
- [x] Tests are fast (< 1s each)
- [x] Tests are maintainable
- [x] Verification: Tests meet quality standards
Article XI: Documentation as Code
Code Documentation
- [x] All public APIs have docstrings
- [x] Docstrings include: purpose, parameters, returns, examples
- [x] Complex logic has inline comments
- [x] Verification: Documentation is complete
System Documentation
- [x] Architecture documented in design-additions.md
- [x] Requirements documented in requirements.md
- [x] Testing documented in testing.md
- [x] Integration documented in CLAUDE.md
- [x] Verification: All documentation is up-to-date
Completion Criteria
Constitutional compliance is complete when:
- [x] All sections of Article IX (Session Management) are implemented
- [x] All other articles are satisfied by session management implementation (see
design-additions.mdSection 5) - [x] Constitutional principles are verified through tests
- [x] Documentation reflects constitutional design (
design-additions.mdcovers all articles) - [x] Code review confirms constitutional compliance
Notes
- Article IX (Session Management) is the primary focus of this implementation
- All other constitutional articles apply to session management design
- Constitutional principles guide implementation decisions
- Violations of constitutional principles must be documented and justified
checklists/requirements.md
The requirement list above comes from this file; 135 of 144 checkbox items are ticked.
checklists/testing.md
Testing Checklist - Session Management
Document: specs/006-session-management/testing.md
Date: 2026-01-13
Status: Implementation Phase
Performance Benchmarks
Session Open Performance (< 50ms)
- [x] Benchmark: Open single session in < 50ms
- [x] Benchmark: Open 100 sessions sequentially in < 5s (50ms avg)
- [x] Benchmark: Open 10 sessions concurrently in < 100ms
- [x] Measurement: Use
time.perf_counter()for precision - [x] Verification: All benchmarks pass consistently
Test Implementation:
def test_session_open_performance():
start = time.perf_counter()
session_id = session_manager.open_session()
duration = (time.perf_counter() - start) * 1000
assert duration < 50, f"Session open took {duration}ms (target: 50ms)"
Fact Emission Performance (< 10ms)
- [x] Benchmark: Emit single fact in < 10ms
- [x] Benchmark: Emit 100 facts sequentially in < 1s (10ms avg)
- [x] Benchmark: Emit 10 facts concurrently in < 20ms
- [x] Measurement: Include Prolog assert time
- [x] Verification: All benchmarks pass consistently
Test Implementation:
def test_fact_emission_performance():
session_id = session_manager.open_session()
start = time.perf_counter()
session_manager.emit_fact(session_id, "test_fact(value)")
duration = (time.perf_counter() - start) * 1000
assert duration < 10, f"Fact emission took {duration}ms (target: 10ms)"
Session Query Performance (< 10ms)
- [x] Benchmark: Query session state in < 10ms
- [x] Benchmark: Query 100 facts in < 10ms
- [x] Benchmark: Complex query (with joins) in < 50ms
- [x] Measurement: Include Prolog query time
- [x] Verification: Query performance meets targets
Session Close Performance (< 50ms)
- [x] Benchmark: Close single session in < 50ms
- [x] Benchmark: Close session with 100 facts in < 50ms
- [x] Benchmark: Close 10 sessions concurrently in < 100ms
- [x] Measurement: Include fact retraction time
- [x] Verification: Closure performance meets targets
Unit Tests
Session Lifecycle Tests
- [x] Test: Create session with auto-generated ID
- [x] Test: Create session with custom ID
- [x] Test: Session exists after creation
- [x] Test: Session does not exist after closure
- [x] Test: Cannot create duplicate session IDs
- [x] Test: Cannot close non-existent session
- [x] Test: Session metadata is correct
- [x] Verification: All lifecycle operations work correctly
Fact Emission Tests
- [x] Test: Emit simple fact to session
- [x] Test: Emit complex fact with multiple arguments
- [x] Test: Emit multiple facts to same session
- [x] Test: Emit fact with timestamp
- [x] Test: Emit fact with source attribution
- [x] Test: Cannot emit to closed session
- [x] Test: Cannot emit to non-existent session
- [x] Verification: Fact emission works correctly
Session Query Tests
- [x] Test: Query all facts in session
- [x] Test: Query specific fact by pattern
- [x] Test: Query returns empty list for no matches
- [x] Test: Query across multiple sessions (if supported)
- [x] Test: Query complex patterns with variables
- [x] Test: Query performance on large fact sets
- [x] Verification: Queries return correct results
Session Isolation Tests
- [x] Test: Session A facts not visible to Session B
- [x] Test: Closing Session A does not affect Session B
- [x] Test: Multiple sessions can have same fact types
- [x] Test: Session-specific queries work correctly
- [x] Verification: Sessions are properly isolated
Error Handling Tests
- [x] Test: Invalid session ID returns error
- [x] Test: Operations on closed session fail gracefully
- [x] Test: Malformed Prolog terms return error
- [x] Test: Prolog interface errors are caught
- [x] Test: System remains stable after errors
- [x] Verification: Error handling is robust
Integration Tests
Prolog Interface Integration
- [x] Test: Session facts stored in Prolog
- [x] Test: Session queries executed via Prolog
- [x] Test: Prolog assertions succeed
- [x] Test: Prolog retractions succeed
- [x] Test: Prolog errors are handled
- [x] Verification: Prolog integration works correctly
Hook System Integration
- [x] Test: on_session_start hook fires
- [x] Test: on_session_end hook fires
- [x] Test: on_fact_emitted hook fires
- [x] Test: Hook receives correct parameters
- [x] Test: Hook failure does not crash system
- [x] Test: Multiple hooks can be registered
- [x] Verification: Hook system works correctly
Multi-Session Integration
- [x] Test: Create 100 concurrent sessions
- [x] Test: Emit facts to multiple sessions
- [x] Test: Query multiple sessions independently
- [x] Test: Close sessions in random order
- [x] Test: System remains stable with many sessions
- [x] Verification: Multi-session support works correctly
Tool Integration
- [x] Test: Tools can access session context
- [x] Test: Tools can emit facts to session
- [x] Test: Tools can query session state
- [x] Test: Tool integration is seamless
- [x] Verification: Tools work with session system
Stress Tests
Load Testing
- [x] Test: Create and close 1000 sessions sequentially
- [x] Test: Emit 10000 facts to single session
- [x] Test: Query large fact sets (1000+ facts)
- [x] Test: 100 concurrent sessions with 100 facts each
- [x] Test: Rapid session creation/closure cycles
- [x] Verification: System handles load gracefully
Memory Testing
- [x] Test: No memory leaks after 1000 session cycles
- [x] Test: Memory usage bounded with large fact sets
- [x] Test: Memory released after session closure
- [x] Test: Memory usage stable with many sessions
- [x] Verification: Memory usage is acceptable
Concurrency Testing
- [x] Test: Concurrent session creation
- [x] Test: Concurrent fact emission
- [x] Test: Concurrent queries
- [x] Test: Concurrent session closure
- [x] Test: No race conditions
- [x] Verification: Concurrent operations are safe
Edge Case Tests
Boundary Conditions
- [x] Test: Session with zero facts
- [x] Test: Session with maximum facts (stress limit)
- [x] Test: Very long session IDs
- [x] Test: Very long fact terms
- [x] Test: Empty fact terms
- [x] Test: Special characters in facts
- [x] Verification: Edge cases handled correctly
Error Conditions
- [x] Test: Prolog interface unavailable
- [x] Test: Disk full (cannot write logs)
- [x] Test: Memory exhausted
- [x] Test: Invalid Python types in API calls
- [x] Test: Corrupted session state
- [x] Verification: Errors handled gracefully
Recovery Testing
- [x] Test: Recover from failed session creation
- [x] Test: Recover from failed fact emission
- [x] Test: Recover from Prolog errors
- [x] Test: System continues after error
- [x] Verification: Recovery is robust
Test Infrastructure
Test Fixtures
- [x] Fixture: Clean Prolog database before each test
- [x] Fixture: Create test session
- [x] Fixture: Emit test facts
- [x] Fixture: Cleanup after test
- [x] Verification: Fixtures work correctly
Test Utilities
- [x] Utility: Generate random session IDs
- [x] Utility: Create test facts
- [x] Utility: Measure performance
- [x] Utility: Validate Prolog state
- [x] Verification: Utilities are available
Test Data
- [x] Sample: Simple facts
- [x] Sample: Complex facts
- [x] Sample: Edge case facts
- [x] Sample: Invalid facts
- [x] Verification: Test data is comprehensive
Continuous Testing
Pre-Commit Tests
- [x] Run unit tests before commit
- [x] Run fast integration tests before commit
- [x] Check code coverage before commit (
scripts/check_coverage.sh) - [x] Verification: Pre-commit tests pass
CI/CD Tests
- [x] Run all tests in CI pipeline (
.gitlab-ci.ymlteststage) - [x] Run performance benchmarks in CI (
.gitlab-ci.ymlbenchmarksjob) - [x] Run stress tests in CI (
.gitlab-ci.ymlstressjob) - [x] Generate coverage report in CI (
.gitlab-ci.ymlcoveragestage, Cobertura + HTML) - [x] Verification: CI tests pass
Regression Tests
- [x] Test suite prevents regressions
- [x] New features include tests
- [x] Bug fixes include tests
- [x] Verification: Regression testing is effective
Test Metrics
Coverage Metrics
- [x] Line coverage > 90% (enforced by
--cov-fail-under=90in CI) - [x] Branch coverage > 85%
- [x] Function coverage > 95%
- [x] Integration coverage > 80%
- [x] Verification: Coverage targets met
Performance Metrics
- [x] All benchmarks pass
- [x] No performance regressions
- [x] Performance trends monitored
- [x] Verification: Performance is acceptable
Quality Metrics
- [x] All tests pass
- [x] No flaky tests (deterministic with real Redis, no mocking)
- [x] Tests run in < 30s total
- [x] Tests are maintainable
- [x] Verification: Test quality is high
Completion Criteria
Testing is complete when:
- [x] All performance benchmarks pass (< 50ms session open, < 10ms fact emission)
- [x] All unit tests pass (100% success rate)
- [x] All integration tests pass (100% success rate)
- [x] All stress tests pass without failures
- [x] All edge case tests pass
- [x] Test coverage > 90% (enforced by
--cov-fail-under=90in CI andscripts/check_coverage.sh) - [x] Performance metrics meet targets
- [x] No memory leaks detected
- [x] No race conditions detected
- [x] CI/CD pipeline passes (
.gitlab-ci.ymlwith lint, test, coverage, benchmark, stress stages)
Notes
- Performance benchmarks are critical: < 50ms session open, < 10ms fact emission
- Tests must use real implementations (no mocking)
- Tests must be deterministic and repeatable
- Tests must run fast (< 30s total for unit tests)
- Integration tests may take longer but should still be efficient
- Stress tests validate system behavior under load
- Edge case tests prevent unexpected failures
- All tests must pass before merging to main branch
Other tracked files
specs/006-session-management/compliance-audit.mdspecs/006-session-management/contracts/api.yamlspecs/006-session-management/contracts/events.yamlspecs/006-session-management/contracts/prolog.plspecs/006-session-management/design-additions.mdspecs/006-session-management/prompt.mdspecs/006-session-management/review-2026-03-25.md
Full spec text
Verbatim from specs/006-session-management/spec.md; headings are pushed down two levels.
SPEC-006: Session Management
Metadata
- Spec ID: 006-session-management
- Title: Session Management
- Author: Mohamed
- Status: Complete
- Created: 2026-01-13
- Last Updated: 2026-03-07
- Priority: P1
- Components: session_management module, Redis, Neo4j, Prolog
- Dependencies: Redis (hot path), Neo4j (cold path, audit), Prolog (governance)
Overview
What
Session Management provides comprehensive lifecycle management for orchestrator work sessions including session opening/closing with full audit trail, fact emission and persistence to dual storage (Redis + Neo4j), portfolio management across multiple projects, context persistence and recovery, carryover task tracking between sessions, and session handover with state preservation.
Why
Track all work across sessions with full auditability, enabling:
- Work continuity after crashes or planned shutdowns
- Historical analysis of development patterns
- Portfolio-level insights across multiple projects
- Governance through Prolog rules
- Fast access via Redis with durable audit trail via Neo4j
How
Dual-storage architecture:
- Redis (hot path): Sub-50ms session operations, active session state
- Neo4j (cold path): Full audit trail, historical queries, graph relationships
- Prolog: Session governance, constraint checking, policy enforcement
User Scenarios & Stories
US-001: Open Session (P1)
As a developer I want to open a new work session with clear goals and context So that my work is tracked and I can resume if interrupted
Acceptance Criteria:
- [ ] Session opens in < 50ms (Redis hot path)
- [ ] Session ID generated with format: sess_YYYYMMDD_HHMMSS_uuid
- [ ] Portfolio association captured
- [ ] Initial context stored (working directory, git branch, environment)
- [ ] Goals recorded
- [ ] Open timestamp persisted to both Redis and Neo4j
- [ ] Prolog facts emitted: session_opened(SessionID, Portfolio, Timestamp)
Example:
session = await session_manager.open_session(
portfolio="orchestrator-ai",
goals=["Implement session management", "Add fact emission"],
context={"branch": "master", "cwd": "/workspace/orchestrator-ai"}
)
# Returns: Session(id="sess_20260113_143022_a1b2c3", status="open", ...)
US-002: Close Session (P1)
As a developer I want to close a session with summary of work completed So that session state is preserved and work is documented
Acceptance Criteria:
- [ ] Session closure in < 100ms
- [ ] Completion status captured (completed/partial/failed)
- [ ] Work summary stored
- [ ] Carryover tasks identified and persisted
- [ ] Close timestamp recorded
- [ ] Session duration calculated
- [ ] All facts flushed to Neo4j
- [ ] Prolog facts emitted: session_closed(SessionID, Status, Duration)
- [ ] Redis session marked as archived after Neo4j sync
Example:
await session_manager.close_session(
session_id="sess_20260113_143022_a1b2c3",
status=SessionStatus.COMPLETED,
summary="Implemented session management with fact emission",
carryover_tasks=["Add Prolog integration tests"]
)
US-003: Emit Facts (P1)
As a session manager I want to emit structured facts about session events So that Prolog can reason about session state and enforce governance
Acceptance Criteria:
- [ ] Facts emitted to Redis immediately (< 10ms)
- [ ] Facts queued for Neo4j persistence
- [ ] Fact schema validated before emission
- [ ] Support fact types:
- session_opened(SessionID, Portfolio, Timestamp)
- session_closed(SessionID, Status, Duration)
- task_started(SessionID, TaskID, Description)
- task_completed(SessionID, TaskID, Duration)
- context_updated(SessionID, Key, Value)
- error_occurred(SessionID, ErrorType, Message)
- [ ] Prolog can query facts via Redis
- [ ] Neo4j stores facts as nodes with relationships
Example:
await fact_emitter.emit(
fact_type="task_started",
session_id="sess_20260113_143022_a1b2c3",
task_id="task_001",
description="Implement fact emission",
timestamp=datetime.now()
)
US-004: Session Recovery (P2)
As a developer I want to recover from a crashed session So that I can resume work without losing context
Acceptance Criteria:
- [ ] Last active session identified from Redis
- [ ] Session state fully reconstructed from Redis + Neo4j
- [ ] Context variables restored
- [ ] Active tasks identified
- [ ] Carryover tasks surfaced
- [ ] Recovery logged as new fact: session_recovered(NewSessionID, OldSessionID)
- [ ] Git state checked and reported
- [ ] Recovery time < 200ms
Example:
recovered = await session_manager.recover_last_session()
# Returns: Session with context={"crash_detected": True, "previous_session": "sess_..."}
US-005: Carryover Tasks (P2)
As a developer I want to track incomplete tasks across sessions So that nothing is forgotten between work periods
Acceptance Criteria:
- [ ] Carryover tasks associated with session closure
- [ ] Tasks categorized by priority (P1/P2/P3)
- [ ] Tasks linked to portfolio
- [ ] New session shows carryover tasks from previous session
- [ ] Carryover task completion tracked
- [ ] Prolog can query: carryover_task(TaskID, FromSession, ToSession, Priority)
Example:
carryover = await session_manager.get_carryover_tasks(
portfolio="orchestrator-ai",
status="pending"
)
# Returns: [Task(id="task_042", description="Add Prolog tests", priority="P2")]
US-006: Portfolio Management (P2)
As a developer working on multiple projects I want to track sessions across different portfolios So that I can see work distribution and switch contexts effectively
Acceptance Criteria:
- [ ] Portfolio registered with metadata (name, path, description)
- [ ] Sessions associated with portfolios
- [ ] Portfolio-level statistics available:
- Total sessions
- Total duration
- Task completion rate
- Active sessions count
- [ ] Cross-portfolio queries supported
- [ ] Prolog facts: portfolio_exists(PortfolioID, Name, Path)
Example:
stats = await portfolio_manager.get_stats("orchestrator-ai")
# Returns: PortfolioStats(sessions=47, total_duration_hours=12.3, completion_rate=0.87)
US-007: Context Persistence (P2)
As a developer I want to store arbitrary context with sessions So that session-specific state is preserved
Acceptance Criteria:
- [ ] Context stored as key-value pairs
- [ ] Context updates emit facts: context_updated(SessionID, Key, Value)
- [ ] Context retrieved in < 20ms from Redis
- [ ] Context historical changes queryable from Neo4j
- [ ] Context types supported: string, int, float, bool, list, dict
- [ ] Context scopes: session, portfolio, global
Example:
await session_manager.update_context(
session_id="sess_20260113_143022_a1b2c3",
key="git_branch",
value="feature/session-management"
)
Functional Requirements
Core Session Lifecycle
FR-001: Session Opening (P1)
- System SHALL open new sessions in < 50ms
- System SHALL generate unique session IDs with format: sess_YYYYMMDD_HHMMSS_uuid
- System SHALL associate sessions with portfolios
- System SHALL capture initial context (cwd, git branch, environment)
- System SHALL emit session_opened fact to Prolog
FR-002: Session Closing (P1)
- System SHALL close sessions in < 100ms
- System SHALL capture completion status (completed/partial/failed)
- System SHALL calculate session duration
- System SHALL flush all facts to Neo4j before closing
- System SHALL emit session_closed fact to Prolog
FR-003: Active Session Tracking (P1)
- System SHALL maintain single active session per portfolio
- System SHALL detect concurrent session attempts and reject/warn
- System SHALL track session heartbeat (last activity timestamp)
- System SHALL auto-close stale sessions (configurable timeout, default 24h)
Fact Emission & Storage
FR-004: Fact Emission (P1)
- System SHALL emit facts to Redis in < 10ms
- System SHALL validate fact schema before emission
- System SHALL queue facts for Neo4j persistence
- System SHALL support fact types: session_opened, session_closed, task_started, task_completed, context_updated, error_occurred
- System SHALL batch Neo4j writes for performance (configurable batch size, default 100)
FR-005: Fact Storage (P1)
- System SHALL store facts in Redis with TTL (configurable, default 7 days)
- System SHALL persist facts to Neo4j as nodes with relationships
- System SHALL create indexes on SessionID, Timestamp, FactType
- System SHALL support fact queries via both Redis and Neo4j
FR-006: Prolog Integration (P1)
- System SHALL expose facts to Prolog via Redis
- System SHALL support Prolog queries for session governance
- System SHALL enforce Prolog constraints on session operations
- System SHALL log constraint violations as facts
Portfolio Management
FR-007: Portfolio Registration (P2)
- System SHALL register portfolios with metadata (name, path, description)
- System SHALL validate portfolio uniqueness by name
- System SHALL track portfolio creation timestamp
- System SHALL emit portfolio_registered fact
FR-008: Portfolio Statistics (P2)
- System SHALL calculate portfolio-level statistics:
- Total sessions count
- Total work duration
- Task completion rate
- Active sessions count
- System SHALL cache statistics in Redis (TTL 5 minutes)
- System SHALL support historical statistics queries from Neo4j
Context & Carryover
FR-009: Context Management (P2)
- System SHALL store context as key-value pairs
- System SHALL support context scopes: session, portfolio, global
- System SHALL emit context_updated fact on changes
- System SHALL retrieve context in < 20ms from Redis
- System SHALL support context history queries from Neo4j
FR-010: Carryover Task Management (P2)
- System SHALL track incomplete tasks as carryover items
- System SHALL categorize carryover tasks by priority (P1/P2/P3)
- System SHALL link carryover tasks between sessions
- System SHALL surface carryover tasks at session open
- System SHALL track carryover task completion
Recovery & Handover
FR-011: Session Recovery (P2)
- System SHALL identify last active session from Redis
- System SHALL reconstruct session state from Redis + Neo4j
- System SHALL restore context variables
- System SHALL identify active tasks
- System SHALL complete recovery in < 200ms
FR-012: Session Handover (P3)
- System SHALL support explicit session handover
- System SHALL transfer session ownership
- System SHALL preserve all context and facts
- System SHALL emit session_handed_over fact
Local Context File Sync
FR-013: Local Context File Sync (P1)
- System SHALL treat context.json as machine-readable source of truth
- System SHALL render context.md from context.json via Jinja2 template
- System SHALL update both files atomically
- System SHALL use context.history.md as canonical archive filename
- System SHALL auto-archive when session count exceeds SESSION_LIMIT (default: 3)
Archive, Integrity & Recovery
FR-014: Automated Session Archive (P1)
- System SHALL auto-archive oldest sessions on session close when session count exceeds SESSION_LIMIT
- System SHALL append archived sessions to context.history.md (append-only)
- Archive operation SHALL be idempotent
FR-015: Context Integrity Verification (P1)
- System SHALL detect gaps in session numbering across context.json and context.history.md
- System SHALL detect duplicate session numbers across files
- System SHALL validate that context.md matches rendered output of context.json
- System SHALL verify history continuity
FR-016: Git-Based Session Recovery (P2)
- System SHALL scan git history for lost sessions (up to configurable max_commits, default 200)
- System SHALL extract session data from historical context.json commits
- System SHALL append recovered sessions to context.history.md with [RECOVERED] annotation
- Recovery SHALL be non-destructive
FR-017: Session CLI Interface (P2)
- CLI command
orchestrata-session archiveSHALL trigger archive now - CLI command
orchestrata-session archive --verifySHALL run integrity verification - CLI command
orchestrata-session archive --recoverSHALL run git-based recovery - CLI command
orchestrata-session statusSHALL show current session state - CLI command
orchestrata-session listSHALL list all sessions across context and history
Non-Functional Requirements
Performance
NFR-001: Response Time
- Session open: < 50ms (P99)
- Session close: < 100ms (P99)
- Fact emission: < 10ms (P99)
- Context retrieval: < 20ms (P99)
- Session recovery: < 200ms (P99)
NFR-002: Throughput
- Support 100 concurrent sessions
- Handle 1000 facts/second emission rate
- Neo4j batch writes: 500 facts/batch
- Redis pipeline operations for bulk reads
NFR-003: Scalability
- Handle 10,000+ sessions in Neo4j
- Support 100+ portfolios
- Redis memory limit: 1GB for active sessions
- Neo4j storage: unlimited (disk-based)
Reliability
NFR-004: Data Durability
- Redis persistence: AOF + RDB snapshots
- Neo4j transaction guarantees: ACID
- No fact loss during normal operation
- Crash recovery from Neo4j within 5 minutes
NFR-005: Availability
- Redis uptime: 99.9%
- Neo4j uptime: 99.9%
- Graceful degradation: Continue with Redis-only if Neo4j unavailable
- Automatic reconnection with exponential backoff
NFR-006: Fault Tolerance
- Detect crashed sessions via heartbeat timeout
- Auto-recovery of last active session
- Fact queue persistence during Neo4j downtime
- Transaction rollback on partial failures
Security
NFR-007: Authentication
- Redis password authentication required
- Neo4j username/password authentication required
- Credentials stored in environment variables
- No hardcoded credentials in code
NFR-008: Authorization
- Session ownership validation
- Portfolio access control (future)
- Prolog constraint enforcement
- Audit logging of all operations
Technical Design
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Orchestrator AI │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Session │────────▶│ Fact Emitter │ │
│ │ Manager │ │ │ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ ├───────────────────▶│ Redis │ │
│ │ │ (Hot Path) │ │
│ │ └─────────────────┘ │
│ │ │ │
│ │ │ Async Batch Write │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ └───────────────────▶│ Neo4j │ │
│ │ (Cold Path) │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Prolog │ │
│ │ (Governance) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Data Models
Session Model:
class Session:
id: str # sess_YYYYMMDD_HHMMSS_uuid
portfolio_id: str
status: SessionStatus # open, closed, crashed
goals: List[str]
context: Dict[str, Any]
opened_at: datetime
closed_at: Optional[datetime]
duration_seconds: Optional[int]
completion_status: Optional[CompletionStatus]
summary: Optional[str]
carryover_tasks: List[str]
Fact Model:
class Fact:
id: str # fact_uuid
type: str # session_opened, task_started, etc.
session_id: str
timestamp: datetime
data: Dict[str, Any]
emitted_to_redis: bool
persisted_to_neo4j: bool
Portfolio Model:
class Portfolio:
id: str # portfolio_uuid
name: str
path: str
description: str
created_at: datetime
total_sessions: int
total_duration_seconds: int
Redis Schema
Keys:
- session:{session_id} → Session JSON (TTL: 7 days)
- session:active:{portfolio_id} → Active session ID
- session:facts:{session_id} → List of fact IDs
- fact:{fact_id} → Fact JSON (TTL: 7 days)
- portfolio:{portfolio_id} → Portfolio JSON
- portfolio:sessions:{portfolio_id} → Set of session IDs
- carryover:{session_id} → List of carryover task IDs
Indexes:
- session:by_portfolio:{portfolio_id} → Sorted set (score=opened_at)
- session:by_status:{status} → Set of session IDs
Neo4j Schema
Nodes:
- (:Session {id, portfolio_id, status, opened_at, closed_at, ...})
- (:Fact {id, type, session_id, timestamp, data})
- (:Portfolio {id, name, path, description, created_at})
- (:Task {id, description, priority, status})
Relationships:
- (:Session)-[:BELONGS_TO]->(:Portfolio)
- (:Fact)-[:ABOUT]->(:Session)
- (:Session)-[:NEXT_SESSION]->(:Session)
- (:Task)-[:CARRIED_OVER_FROM]->(:Session)
- (:Task)-[:CARRIED_OVER_TO]->(:Session)
Indexes:
CREATE INDEX session_id_idx FOR (s:Session) ON (s.id)
CREATE INDEX fact_session_idx FOR (f:Fact) ON (f.session_id)
CREATE INDEX portfolio_name_idx FOR (p:Portfolio) ON (p.name)
Prolog Integration
Fact Format:
session_opened('sess_20260113_143022_a1b2c3', 'orchestrator-ai', '2026-01-13T14:30:22Z').
task_started('sess_20260113_143022_a1b2c3', 'task_001', 'Implement fact emission').
context_updated('sess_20260113_143022_a1b2c3', 'git_branch', 'master').
session_closed('sess_20260113_143022_a1b2c3', 'completed', 3600).
Governance Rules:
% Only one active session per portfolio
:- session_opened(S1, Portfolio, _), session_opened(S2, Portfolio, _),
S1 \= S2, status(S1, open), status(S2, open).
% Session must have goals
:- session_opened(SessionID, _, _), \+ goals(SessionID, _).
% Carryover tasks must be from closed sessions
:- carryover_task(TaskID, FromSession, _, _), status(FromSession, open).
API Specification
SessionManager
class SessionManager:
async def open_session(
self,
portfolio: str,
goals: List[str],
context: Optional[Dict[str, Any]] = None
) -> Session:
"""Open a new session with specified goals and context."""
async def close_session(
self,
session_id: str,
status: CompletionStatus,
summary: str,
carryover_tasks: Optional[List[str]] = None
) -> Session:
"""Close an existing session with completion status."""
async def get_session(self, session_id: str) -> Optional[Session]:
"""Retrieve session by ID from Redis or Neo4j."""
async def get_active_session(self, portfolio: str) -> Optional[Session]:
"""Get currently active session for portfolio."""
async def recover_last_session(self) -> Optional[Session]:
"""Recover last active session after crash."""
async def update_context(
self,
session_id: str,
key: str,
value: Any
) -> None:
"""Update session context and emit fact."""
FactEmitter
class FactEmitter:
async def emit(
self,
fact_type: str,
session_id: str,
**kwargs
) -> str:
"""Emit a fact to Redis and queue for Neo4j."""
async def get_facts(
self,
session_id: str,
fact_type: Optional[str] = None
) -> List[Fact]:
"""Retrieve facts for session from Redis."""
async def flush_to_neo4j(self) -> int:
"""Flush queued facts to Neo4j, return count."""
PortfolioManager
class PortfolioManager:
async def register_portfolio(
self,
name: str,
path: str,
description: str = ""
) -> Portfolio:
"""Register a new portfolio."""
async def get_portfolio(self, portfolio_id: str) -> Optional[Portfolio]:
"""Retrieve portfolio by ID."""
async def get_stats(self, portfolio_id: str) -> PortfolioStats:
"""Get portfolio-level statistics."""
async def list_sessions(
self,
portfolio_id: str,
limit: int = 50
) -> List[Session]:
"""List sessions for portfolio."""
Success Criteria
Primary Success Metrics
Performance:
- Session open < 50ms (P99)
- Fact emission < 10ms (P99)
- Session recovery < 200ms (P99)
Reliability:
- Zero fact loss during normal operation
- Crash recovery within 5 minutes
- 99.9% uptime for Redis and Neo4j
Functionality:
- All facts persisted to Redis immediately
- All facts eventually persisted to Neo4j (within 1 minute)
- Session state fully recoverable after crash
- Carryover tasks tracked across sessions
- Portfolio statistics accurate and performant
Acceptance Tests
Test 1: Session Open/Close Cycle
session = await session_manager.open_session(
portfolio="test-portfolio",
goals=["Test session lifecycle"]
)
assert session.status == SessionStatus.OPEN
assert session.portfolio_id == "test-portfolio"
await session_manager.close_session(
session_id=session.id,
status=CompletionStatus.COMPLETED,
summary="Test completed successfully"
)
closed = await session_manager.get_session(session.id)
assert closed.status == SessionStatus.CLOSED
assert closed.duration_seconds > 0
Test 2: Fact Emission & Retrieval
fact_id = await fact_emitter.emit(
fact_type="task_started",
session_id=session.id,
task_id="task_001",
description="Test task"
)
assert fact_id.startswith("fact_")
facts = await fact_emitter.get_facts(session.id, fact_type="task_started")
assert len(facts) == 1
assert facts[0].data["task_id"] == "task_001"
Test 3: Session Recovery
# Simulate crash by not closing session properly
session = await session_manager.open_session(
portfolio="test-portfolio",
goals=["Test recovery"]
)
original_id = session.id
# Simulate crash and recovery
recovered = await session_manager.recover_last_session()
assert recovered is not None
assert recovered.context["previous_session"] == original_id
Integration Points
| Component | Integration |
|---|---|
| orchestrata-kernel | Session state queries |
| orchestrata-governance | Prolog fact validation |
| orchestrata-cxp | Session-scoped message routing |
| orchestrata-knowledge | Neo4j persistence |
Dependencies
External Systems
Redis (Required)
- Version: >= 7.0
- Configuration: AOF + RDB persistence
- Memory: 1GB minimum
- Port: 6379 (default)
- Authentication: Password required
Neo4j (Required)
- Version: >= 5.0
- Configuration: ACID transactions enabled
- Storage: 10GB minimum
- Port: 7687 (Bolt)
- Authentication: Username/password required
Prolog (Optional)
- SWI-Prolog >= 9.0
- Redis interface library
- Custom predicates for session governance
Open Questions & Decisions
Q1: Session Timeout Configuration
Decision: Use 24 hours as default, allow per-portfolio configuration
Q2: Neo4j Batch Size
Decision: Start with 100, benchmark and adjust based on production load
Q3: Prolog Governance Strictness
Decision: Configurable per rule, default to warnings for non-critical rules
Q4: Redis vs Neo4j for Queries
Decision:
- Redis: Current session, active sessions, recent facts (< 7 days)
- Neo4j: Historical queries, complex graph traversals, analytics
Q5: Session Recovery Strategy
Decision: Create new session with link to crashed session, preserving audit trail
References
Related Specifications
- 005-multi-agent: Agent session context
- 007-prolog-governance: Prolog integration and governance
- 008-knowledge-graph: Neo4j schema and queries
Implementation Files
session_management/session.py- Session lifecyclesession_management/facts.py- Fact emission and persistencesession_management/portfolio.py- Portfolio managementsession_management/context.py- Context managementsession_management/carryover.py- Carryover task trackingsession_management/archive.py- Session archivalsession_management/prolog_interface.py- Prolog integration
Revision History
| Date | Version | Author | Changes |
|---|---|---|---|
| 2026-01-13 | 1.0 | Mohamed | Initial specification |
| 2026-03-07 | 1.1 | Mohamed | Standardized format, added numbered requirements |