Status:
accepted · ADR-35 · Filed 2026-04-30Title
Two-session model: Work Session (User-level) + Agent Session (process-level)Decision
Introduce two distinct session concepts in the schema and verb surface:-
Work Session — a User-level day-of-work boundary. One row per user per logical work-day. Auto-created on first agent_session of the day for a given user; ends explicitly via
prism_work_session_endor rolls over at midnight. May span multiple machines (Frank on mini1 morning + mini3 afternoon = same Work Session). Used for daily roll-up analytics, retros, signal history grouping. Not a routing filter. -
Agent Session — a process-level binding for one agent on one machine. One row per
prism_start→prism_wrapcycle. Bound to a specific machine + process. Heartbeat-tracked. Backend uses for master election, current-delivery target lookup, audit trail. Not a routing filter.
agent_sessions.work_session_id FK ties each process-level session to the user’s day-of-work.
The legacy controller_registrations table is renamed agent_sessions and gains the work_session_id FK plus the agent_id FK (per ADR on agent_id normalization).
Rationale
The legacy model conflated three concepts under onesession_id:
- The agent’s identity (which agent is this signal for? — now agent_id)
- The current process binding (which mcp-node should I push to? — now agent_session_id)
- The user’s day-of-work grouping (whose day’s-work is this? — now work_session_id)
- Routing continuity across restarts. Solved by agent_id keying (separate ADR). Process-level session can churn freely without losing the routing target.
- Daily roll-up boundary. No clean way to ask “show me all signals from Frank’s day” today — agent_sessions span midnight in messy ways and don’t compose across machines. Work Session is the natural unit.
- Cross-machine continuity. Frank moving from mini1 to mini3 mid-day should preserve the work-day’s audit context even though every agent gets a new agent_session_id on restart. Work Session FK gives this for free.
prism_work_session_start (explicit override; auto-created if not called), prism_work_session_end (explicit close; auto-rolls at midnight if not called). No reach into project lifecycle, no required UX. The column exists, the FK exists, the auto-creation runs — analytics consumers can build on it later.
Alternatives Considered
- One session concept (today’s
session_id), keep conflating. Status quo; surfaced as broken via the SPEC-054 port miss + bell+count regression. Rejected. - Three explicit sessions: Day Session + Process Session + Connection Session. Adds a Connection layer between WS lifecycle and process lifetime. Considered; rejected — the WS reconnect cycle is short-lived and process-bounded, no need for its own row.
- Work Session as a label/tag on agent_sessions, not a separate table. Smaller schema delta but loses the ability to attach explicit
started_at/ended_at/notes. Rejected; the entity is real enough to deserve its own row.
Status
acceptedReferences
- SPEC-056 §Two-session model
- Memory:
feedback_heartbeat_out_of_band(related — separate channels for separate concerns)

