Skip to content

fix(tui): persist one-shot session trails for post-mortem debugging - #138

Merged
alpibrupa merged 1 commit into
mainfrom
persist-one-shot-trail
Sep 5, 2026
Merged

fix(tui): persist one-shot session trails for post-mortem debugging#138
alpibrupa merged 1 commit into
mainfrom
persist-one-shot-trail

Conversation

@alpibrupa

Copy link
Copy Markdown
Contributor

Summary

  • `run_once` used `new_session_with_provider`, which opens an in-memory-only trail log (`persist.open_ephemeral`) discarded the moment the process exits. A one-shot run that stops without producing anything — hits its step budget, say — left no record of what it actually did.
  • Reproduced live today: a real build task burned its whole 50-step budget on bash exploration with nothing to inspect afterward, not even which commands it ran.
  • Switches to `new_session_persistent_with_provider` (already used by graph pipelines), which writes to `.lex/sessions/.db` instead.
  • Not a straight swap: `new_session_from_log` always starts a session's in-memory cache at `messages: []`, regardless of what a log under that id already holds — correct for a pipeline node's id (reused deliberately across runs of the same pipeline), but wrong for the fixed `"cli"` id reused across separate one-shot invocations. A second `bin/lex-code "task"` in the same project would find `"cli"`'s log already holding the first run's events, immediately fail the fresh session's `event_count` check (fix(session): per-turn history check is O(1), not O(n) per turn #136), and refuse before ever reaching the model.
  • `cli_session_id()` generates a fresh id per invocation instead (timestamp + random suffix), so each run gets its own file with no collision. The one-shot output now names the trail file so a stuck or incomplete run can actually be inspected afterward.
  • `repl` is untouched — a live REPL user already watches every step as it happens, which is the case the ephemeral log was originally fine for.

Test plan

  • `lex check`/`lex check --strict` on the modified file, plus a full repo sweep
  • `lex fmt --check src/`, `lex test` (4/4), `lex doc-sync --check`
  • Ran two consecutive one-shot invocations in the same project — both succeeded independently, each with its own trail file, no collision/refusal
  • Confirmed post-mortem inspection actually works: `sqlite3` against a completed run's `.db` file shows the full conversation, including the model's own reasoning text

🤖 Generated with Claude Code

run_once used new_session_with_provider, which opens an in-memory-only
trail log (persist.open_ephemeral) discarded the moment the process
exits. A one-shot run that stops without producing anything -- hits
its step budget, say -- left no record of what it actually did.
Reproduced live today: a real build task burned its whole 50-step
budget on bash exploration with nothing to inspect afterward, not even
which commands it ran.

Switches to new_session_persistent_with_provider (already used by
graph pipelines), which writes to .lex/sessions/<id>.db instead. Not a
straight swap, though: new_session_from_log always starts a session's
in-memory cache at messages: [], regardless of what a log under that
id already holds -- correct for a pipeline node's id, which is reused
deliberately across runs of the SAME pipeline, but wrong for a fixed
"cli" id reused across SEPARATE one-shot invocations. A second
`bin/lex-code "task"` in the same project would find "cli"'s log
already holding the first run's events, immediately fail the fresh
session's event_count check (#136), and refuse before ever reaching
the model.

cli_session_id() generates a fresh id per invocation instead
(timestamp + random suffix), so each run gets its own file with no
collision. The one-shot output now names the trail file so a stuck or
incomplete run can actually be inspected afterward (confirmed live:
sqlite3 against the file shows the full conversation, including tool
calls and the model's own reasoning text).

repl is untouched -- a live REPL user already watches every step as it
happens, which is the case the ephemeral log was originally fine for.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@alpibrupa
alpibrupa merged commit f681254 into main Sep 5, 2026
1 check passed
@alpibrupa
alpibrupa deleted the persist-one-shot-trail branch September 5, 2026 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant