Skip to content

Session identity is minted fresh on every open, so a restarted or peer instance cannot resume a session #675

Open

Description

@Yatsuiii

Raised by @rajnisht7 in #661.

SessionManager._open_session() mints a new id on every open
(session/manager.py:150, session_id = str(uuid4())), and
SessionManager.create_session() (:100) takes no parameters, so a caller
has no way to supply an existing one. Two other sites also rotate the id:
the operator session reset (session/state.py:356) and the
attestation-staleness refresh (:380).

The store added in #629 is keyed by session id, session_id TEXT PRIMARY KEY on both session_state and closed_sessions
(session/store.py:52-62). docs/configuration.md describes
session_state_path as making the ratchet "hold per session across
instances and survive a restart". Wiring the store (#653, #661) is
necessary for that but not sufficient while the identity is regenerated on
every open, since a restarted or peer instance looks up a row key it can
never produce again.

Worth noting for whoever picks this up: SessionState is a dataclass that
already accepts session_id=, so the gap is at the manager entry point
rather than in the data model.

This predates #661 and is not introduced by it.

Activity

  1. rajnisht7 commented on Sep 20, 2026

    @rajnisht7
    Member

    Confirmed all the specifics here manager.py:150, the reset/upgrade_attestation rotation sites, and the schema. Diagnosis is right.

    One thing worth flagging before implementing resume: session_id isn't just the session_state_store key, it's also the audit_store key, and AuditChain has no resume awareness, init unconditionally calls _append_session_start() and sequence_number is just len(self._entries), starting at 0 every process. There's also no DB-level guard against this (entry_id, not session_id, is the actual primary key), so it would insert silently rather than failing loudly.

    Reusing a session_id across a restart would write a second session_start and colliding (session_id, sequence_number) rows under one id. A live process's own chain verification stays internally sound (it only checks its own in-memory entries), but the persisted, session_id-keyed audit trail becomes ambiguous concretely, find_orphaned_sessions() (called at every startup) would stop flagging the old incarnation as orphaned once the new one closes cleanly, silently hiding a real unclean shutdown. That's a worse problem than the one being fixed.

    Also worth keeping reset()/upgrade_attestation() out of scope as those rotate the id on purpose, to invalidate trust in the old one. A resume mechanism should only apply to the very first open of a new process, not those.

    Given that, would lean toward not resuming the actual session_id at all keep it process-local and audit-chain-fresh like today, and give session_state_store its own resume key, decoupled from session_id. ctx.agent_manifest is already a stable, process-level (config-bound, not per-call) identity used for kill-switch tracking might be a natural fit, though someone who knows the trust model here should weigh in on whether it's appropriate, and on what happens for anonymous/no-manifest deployments where there'd be no such key. Flagging as a design question rather than proposing a patch, since this touches the audit chain's integrity guarantees and deserves a real decision.

  2. imran-siddique commented on Sep 24, 2026

    @imran-siddique
    Member

    @rajnisht7, keep audit session IDs fresh. Policy-state continuity needs a separate key; it must not resume or overwrite an earlier audit chain.

    A configured manifest identity alone does not authorize resumption. The design must define the authenticated principal, logical session scope and authority to resume, so unrelated sessions cannot share state accidentally. Anonymous deployments need an explicit trusted mechanism or must refuse resumption.

    Please propose that contract before implementation. Cover restart and concurrent-instance continuity, unauthorized resume attempts, missing stored state, reset invalidation and attestation refresh. Preserve the sensitivity ratchet and orphaned-session evidence, with positive controls for legitimate continuity.

  3. dinakarjs commented on Oct 15, 2026

    @dinakarjs
    Contributor

    @rajnisht7 @imran-siddique I can provide independent verification support for the continuity contract before implementation. Keeping Rajnish's design ownership and the ruling above intact, the bounded review matrix I propose is:

    Boundary Legitimate control Refusal / evidence control
    Resume authority Authenticated principal resumes its authorized logical scope Same identifier under a different principal or scope cannot load that state
    Audit incarnation Restart uses a fresh audit session and separate continuity key Earlier chain is not overwritten; unclean incarnation remains observable as orphaned
    Concurrent instances Authorized shared continuity preserves the maximum sensitivity Racing lower-state writes cannot roll back the ratchet or create ambiguous authority
    Missing state Contract explicitly distinguishes new authorized scope from resumed scope Missing/deleted store cannot silently reset a purportedly resumed session to public
    Reset Explicit reset produces its declared invalidation and a fresh audit incarnation Prior resume authority cannot silently restore invalidated trust
    Attestation refresh Legitimate refresh preserves/changes continuity only as the contract declares Old credentials and weaker assurance cannot regain authority through a reused key
    Anonymous operation Explicit trusted resumption mechanism, if supported No configured authenticated mechanism means resumption is refused
    Storage failure Protected store available and namespace correctly selected Unavailable/substituted/stale state is visible; rollback resistance is not inferred from SQLite

    For each selected refusal, retain a valid twin and a weakening that catches the intended authority/ratchet/evidence guard. Separate process-restart persistence from a claim of rollback resistance or hardware protection. These are proposed acceptance obligations, not executed results or permission to implement a new resumption API. I can review a pinned contract/patch against them once you post it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions