# Codex Resume State Guard

## Problem

CTM has three separate identities that must not be collapsed:

- `ctm_sessions.id`: the CTM tab/session id.
- `agent_sessions.agent_session_id`: the canonical provider transcript id.
- JSONL path: the durable transcript file location.

For Codex there is a fourth practical locator: `~/.codex/state_5.sqlite`.
`codex resume <id>` resolves the id through this SQLite database before it
opens a rollout JSONL. If `state_5.sqlite` maps the resume id to a different
rollout than `agent_sessions.jsonl_path`, CTM can restore the right tab id and
still have Codex append new turns to the wrong JSONL.

The observed failure mode:

1. CTM tab `c495...` maps to Codex agent session `019dd971...`.
2. `agent_sessions.jsonl_path` points to `rollout-...019dd971....jsonl`.
3. Codex `state_5.sqlite` maps `019dd971...` to
   `rollout-...019dd241....jsonl`.
4. CTM launches `codex resume 019dd971...`.
5. Codex writes new output to `019dd241...`.
6. CTM continues reading/rendering `019dd971...`, so recent chats appear lost.

## Contract

Before spawning Codex for a resume or restart restore, CTM should inspect this:

```text
resume id == expected rollout filename id
Codex state row for resume id points to expected rollout path
expected rollout file exists and its session metadata matches the resume id
```

If the contract cannot be proven, CTM records diagnostics and may warn the UI,
but it must still spawn Codex. `state_5.sqlite` is Codex-owned provider state;
Codex owns repair prompts, migrations, and final resume behavior.

## Behavior

### Healthy State DB

If `state_5.sqlite` is readable, passes an integrity check, and has a
thread row whose rollout path differs from CTM's mapped JSONL, the normal CTM
resume path treats this as an inspect-only diagnostic. CTM must not mutate
`state_5.sqlite` before spawning Codex.

Manual repair tooling, if used, must be intentionally narrow:

- backup `state_5.sqlite` first;
- update only `threads.rollout_path` for the exact resume id;
- do not rewrite JSONL files;
- do not change CTM `agent_sessions` ownership;
- verify the row after update.

### Corrupt Or Unusable State DB

If the DB is corrupt, unreadable, lacks the expected row, or cannot be repaired,
CTM records diagnostics and still launches `codex resume`. Blocking is not
allowed because it prevents Codex from showing its own repair prompt and turns
CTM into the owner of provider state.

The UI/API may receive a non-blocking warning telling the user that provider
state could not be verified and terminal output may temporarily diverge from
the Conversation tab.

### Diagnostics

Every mismatch, repair, or unverifiable state result must be recorded in:

- the in-memory session diagnostics ring for immediate UI/debug access;
- the durable CTM DB diagnostics table for post-restart investigation;
- telemetry event names that identify the reason without including full paths.

## Data Repair

This guard stops new corruption. Existing split transcripts still require a
separate repair pass because a wrong rollout may already contain legitimate
turns for another CTM tab. Data repair must be timestamp/process aware and
should not blindly move messages between JSONLs.

## Non-Goals

- Do not make `session_index` authoritative again. It is legacy residue.
- Do not assume Codex has a path-based resume flag; current Codex CLI help only
  exposes `codex resume [SESSION_ID]`.
- Do not auto-repair a corrupt SQLite file in-place.
- Do not block `codex resume`; let Codex own its provider database and repair UI.
