# Codex Session Status Time Contract

CTM status must be derived from observed work, not from impossible clocks. Codex sessions combine several signals: server PTY activity, SessionStream state, status-hook events, terminal buffer scans, and durable transcript summaries. These signals are allowed to arrive late, but they are not allowed to move activity into the future.

## Rules

- Observed timestamps include `lastActivity`, `lastPtyActivity`, file modified time, stream event time, status-hook capture time, and summary update time.
- Observed timestamps more than 60 seconds ahead of the receiver clock are ignored for freshness, ordering, and Running detection.
- Observed timestamps up to 60 seconds ahead are clamped to the receiver clock to tolerate small clock skew.
- Deadlines are different from observations. Fields such as activation-preservation expiry times may intentionally be in the future and must not use observed-time normalization.
- Live status receipt time and live status event time are separate. Receipt time says when CTM heard a status; event time says when the underlying work actually changed.
- Non-blocking prompt-ready evidence (`input`) is not a permanent waiting state. If it is older than 30 minutes with no newer activity, CTM treats the session as idle. Blocking prompts (`approval` and `choice`) remain waiting until resolved.

## Why

A future `lastPtyActivity` makes checks like `now - lastPtyActivity < runningHoldMs` always true. That pins a stopped Codex session in `Running`, keeps Overview evidence at `last activity just now`, and makes activity sorting unstable. Smoothing windows cannot fix that because the bad timestamp continuously looks fresh.

## Implementation Points

- Server normalization lives in `lib/activity-time.js` and is applied before `_standupLiveStatusForSession`, `/api/sessions`, and session-activity heartbeats project timestamps.
- Overview freshness uses the same helper through `lib/session-standup.js`.
- Browser sorting uses `SessionActivityUtils.normalizeObservedTimeMs`.
- Browser status precedence uses observed-time normalization for activity/event timestamps, while preserving future deadline fields.
- Browser and server status precedence both age out stale non-blocking waiting evidence before it can outrank fresh idle evidence.
- Codex transient `Working (... esc to interrupt)` row cleanup may run when the resolved session status is already non-running, even after the short fresh-status TTL has expired.

## Diagnostics

When the server rejects a future activity timestamp, it records `future-activity-timestamp-ignored` as a session diagnostic and rate-limits repeated warnings per session field.
