Debug
Goals
- Find why a run is stuck, retrying, or failing.
- Correlate Linear issue identity to a Codex session quickly.
- Read the right logs in the right order to isolate root cause.
Log Sources
- Primary runtime log:
log/symphony.log
- Default comes from
SymphonyElixir.LogFile (log/symphony.log).
- Includes orchestrator, agent runner, and Codex app-server lifecycle logs.
- Rotated runtime logs:
log/symphony.log*
- Check these when the relevant run is older.
Correlation Keys
issue_identifier: human ticket key (example: MT-625)
issue_id: Linear UUID (stable internal ID)
session_id: Codex thread-turn pair (<thread_id>-<turn_id>)
symphony/elixir/docs/logging.md documents these fields for issue/session lifecycle logs. Use
them as your join keys during debugging.
Quick Triage (Stuck Run)
- Confirm scheduler/worker symptoms for the ticket.
- Find recent lines for the ticket (
issue_identifier first).
- Extract
session_id from matching lines.
- Trace that
session_id across start, stream, completion/failure, and stall
handling logs.
- Decide class of failure: timeout/stall, app-server startup failure, turn
failure, or orchestrator retry loop.
Commands
# 1) Narrow by ticket key (fastest entry point)
rg -n "issue_identifier=MT-625" log/symphony.log*
# 2) If needed, narrow by Linear UUID
rg -n "issue_id=<linear-uuid>" log/symphony.log*
# 3) Pull session IDs seen for that ticket
rg -o "session_id=[^ ;]+" log/symphony.log* | sort -u
# 4) Trace one session end-to-end
rg -n "session_id=<thread>-<turn>" log/symphony.log*
# 5) Focus on stuck/retry signals
rg -n "Issue stalled|scheduling retry|turn_timeout|turn_failed|Codex session failed|Codex session ended with error" log/symphony.log*
Investigation Flow
- Locate the ticket slice:
- Search by
issue_identifier=<KEY>.
- If noise is high, add
issue_id=<UUID>.
- Establish timeline:
- Identify first
Codex session started ... session_id=....
- Follow with
Codex session completed, ended with error, or worker exit
lines.
- Classify the problem:
- Stall loop:
Issue stalled ... restarting with backoff.
- App-server startup:
Codex session failed ....
- Turn execution failure:
turn_failed, turn_cancelled, turn_timeout, or
ended with error.
- Worker crash:
Agent task exited ... reason=....
- Validate scope:
- Check whether failures are isolated to one issue/session or repeating across
multiple tickets.
- Capture evidence:
- Save key log lines with timestamps,
issue_identifier, issue_id, and
session_id.
- Record probable root cause and the exact failing stage.
Reading Codex Session Logs
In Symphony, Codex session diagnostics are emitted into log/symphony.log and
keyed by session_id. Read them as a lifecycle:
Codex session started ... session_id=...
- Session stream/lifecycle events for the same
session_id
- Terminal event:
Codex session completed ..., or
Codex session ended with error ..., or
Issue stalled ... restarting with backoff
For one specific session investigation, keep the trace narrow:
- Capture one
session_id for the ticket.
- Build a timestamped slice for only that session:
rg -n "session_id=<thread>-<turn>" log/symphony.log*
- Mark the exact failing stage:
- Startup failure before stream events (
Codex session failed ...).
- Turn/runtime failure after stream events (
turn_* / ended with error).
- Stall recovery (
Issue stalled ... restarting with backoff).
- Pair findings with
issue_identifier and issue_id from nearby lines to
confirm you are not mixing concurrent retries.
Always pair session findings with issue_identifier/issue_id to avoid mixing
concurrent runs.
Notes
- Prefer
rg over grep for speed on large logs.
- Check rotated logs (
log/symphony.log*) before concluding data is missing.
- If required context fields are missing in new log statements, align with
elixir/docs/logging.md conventions.
1---2name: debug3description: Investigate stuck runs and execution failures by tracing Symphony and Codex logs with issue/session identifiers; use when runs stall, retry repeatedly, or fail unexpectedly.4---56# Debug78## Goals910- Find why a run is stuck, retrying, or failing.11- Correlate Linear issue identity to a Codex session quickly.12- Read the right logs in the right order to isolate root cause.1314## Log Sources1516- Primary runtime log: `log/symphony.log`17 - Default comes from `SymphonyElixir.LogFile` (`log/symphony.log`).18 - Includes orchestrator, agent runner, and Codex app-server lifecycle logs.19- Rotated runtime logs: `log/symphony.log*`20 - Check these when the relevant run is older.2122## Correlation Keys2324- `issue_identifier`: human ticket key (example: `MT-625`)25- `issue_id`: Linear UUID (stable internal ID)26- `session_id`: Codex thread-turn pair (`<thread_id>-<turn_id>`)2728`symphony/elixir/docs/logging.md` documents these fields for issue/session lifecycle logs. Use29them as your join keys during debugging.3031## Quick Triage (Stuck Run)32331. Confirm scheduler/worker symptoms for the ticket.342. Find recent lines for the ticket (`issue_identifier` first).353. Extract `session_id` from matching lines.364. Trace that `session_id` across start, stream, completion/failure, and stall37 handling logs.385. Decide class of failure: timeout/stall, app-server startup failure, turn39 failure, or orchestrator retry loop.4041## Commands4243```bash44# 1) Narrow by ticket key (fastest entry point)45rg -n "issue_identifier=MT-625" log/symphony.log*4647# 2) If needed, narrow by Linear UUID48rg -n "issue_id=<linear-uuid>" log/symphony.log*4950# 3) Pull session IDs seen for that ticket51rg -o "session_id=[^ ;]+" log/symphony.log* | sort -u5253# 4) Trace one session end-to-end54rg -n "session_id=<thread>-<turn>" log/symphony.log*5556# 5) Focus on stuck/retry signals57rg -n "Issue stalled|scheduling retry|turn_timeout|turn_failed|Codex session failed|Codex session ended with error" log/symphony.log*58```5960## Investigation Flow61621. Locate the ticket slice:63 - Search by `issue_identifier=<KEY>`.64 - If noise is high, add `issue_id=<UUID>`.652. Establish timeline:66 - Identify first `Codex session started ... session_id=...`.67 - Follow with `Codex session completed`, `ended with error`, or worker exit68 lines.693. Classify the problem:70 - Stall loop: `Issue stalled ... restarting with backoff`.71 - App-server startup: `Codex session failed ...`.72 - Turn execution failure: `turn_failed`, `turn_cancelled`, `turn_timeout`, or73 `ended with error`.74 - Worker crash: `Agent task exited ... reason=...`.754. Validate scope:76 - Check whether failures are isolated to one issue/session or repeating across77 multiple tickets.785. Capture evidence:79 - Save key log lines with timestamps, `issue_identifier`, `issue_id`, and80 `session_id`.81 - Record probable root cause and the exact failing stage.8283## Reading Codex Session Logs8485In Symphony, Codex session diagnostics are emitted into `log/symphony.log` and86keyed by `session_id`. Read them as a lifecycle:87881. `Codex session started ... session_id=...`892. Session stream/lifecycle events for the same `session_id`903. Terminal event:91 - `Codex session completed ...`, or92 - `Codex session ended with error ...`, or93 - `Issue stalled ... restarting with backoff`9495For one specific session investigation, keep the trace narrow:96971. Capture one `session_id` for the ticket.982. Build a timestamped slice for only that session:99 - `rg -n "session_id=<thread>-<turn>" log/symphony.log*`1003. Mark the exact failing stage:101 - Startup failure before stream events (`Codex session failed ...`).102 - Turn/runtime failure after stream events (`turn_*` / `ended with error`).103 - Stall recovery (`Issue stalled ... restarting with backoff`).1044. Pair findings with `issue_identifier` and `issue_id` from nearby lines to105 confirm you are not mixing concurrent retries.106107Always pair session findings with `issue_identifier`/`issue_id` to avoid mixing108concurrent runs.109110## Notes111112- Prefer `rg` over `grep` for speed on large logs.113- Check rotated logs (`log/symphony.log*`) before concluding data is missing.114- If required context fields are missing in new log statements, align with115 `elixir/docs/logging.md` conventions.