> ## Documentation Index
> Fetch the complete documentation index at: https://prism.ntecdev.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR-25: ADR-25 — Session lifecycle verbs do not multiplex with messaging

> `prism_start`, `prism_checkpoint`, and `prism_wrap` MUST NOT carry pending signals in their response payloads. These three "session lifecycle" verbs are exempt

<Info>**Status:** `accepted` · **ADR-25** · Filed 2026-04-25</Info>

## Decision

`prism_start`, `prism_checkpoint`, and `prism_wrap` MUST NOT carry pending
signals in their response payloads. These three "session lifecycle" verbs
are exempt from the SPEC-037 per-verb piggyback drain. Pending signals are
delivered via either (a) the explicit `prism_signals_pending` poll, or (b)
implicit piggyback on any non-lifecycle bootstrapped verb call.

This rule is captured as a one-line principle in PRISM.md and elaborated
in SPEC-041. Implementation modifies `mcp/server.py:1649-1661` to remove
the explicit drain from `prism_start`, and updates the `require_bootstrap`
decorator at `mcp/server.py:237-265` to skip `_piggyback_drain` for all
three lifecycle verbs.

## Rationale

Three concerns motivate the separation:

**1. Single responsibility.** A session-lifecycle verb has one job —
manage session state (begin / persist / end). Mixing in messaging
delivery couples two unrelated concerns; every future change to either
has to reason about both. The verb contract grows opaque to vibe-coding
callers, who then write code expecting messaging guarantees from verbs
that should have made only session guarantees.

**2. Race correctness on prism\_start specifically.** Identity-targeted
signals queued before a new session existed are stale by definition.
They may have been intended for the prior (now-wrapped) session of the
same identity, not the fresh one. Delivering them on `prism_start`
silently re-routes them. Forcing the agent to call any other verb first
(or `prism_signals_pending` explicitly) creates an opportunity for
stale-signal hygiene to apply. (This concern does not apply to wrap or
checkpoint — those run after registration. Symmetry of the principle
alone justifies exempting them.)

**3. Composition with hd\_exec.** SPEC-040 introduces `hd_exec` as a
non-start session verb that DOES drain via piggyback. The asymmetry is
intentional and load-bearing: a pickup is a continuation (inherits
unread messages); a fresh start is a beginning (does not). The
distinction collapses if both verbs multiplex messaging.

## Alternatives Considered

**Drain on all bootstrapped verbs uniformly (status quo before this ADR).**
Rejected — couples session lifecycle to messaging, creates the
prism\_start race condition, drives opaque contract growth. Practical
hazard: caller code grew to expect signals on bootstrap, which would
make future protocol changes (push-based delivery, lease-based
ownership) breaking changes.

**Drain only on prism\_start (narrow fix).** Rejected — leaves the
asymmetry where two of three lifecycle verbs (`checkpoint`, `wrap`)
still multiplex while one (`start`) doesn't. Hard to defend the line.
Frank flagged "session lifecycle is session lifecycle" — any
cherry-picking erodes the principle.

**Drain on transitions (start, wrap) but not steady-state (checkpoint).**
Rejected — arbitrary split. Checkpoint is a lifecycle verb regardless
of whether it's a transition or a save-point.

**TTL on queued signals to prevent indefinite accumulation.** Deferred,
not rejected. Current scope is correctness (no signal loss). Hygiene is
a separate concern; if queue growth becomes problematic, a future spec
adds per-type TTL.
