Body
### Environment
- codewhale 0.9.13 (Rust TUI), linux x86_64
- provider: zai, model: GLM-5.3-Flash
- trigger: force-quit during a mid-run freeze (see related issue)
### Summary
After force-quitting a frozen run, `codewhale resume` restores nothing
visible although the on-disk session JSON is structurally intact. On every
load, `codewhale_tui::session_manager` logs the **identical** repair warning
for the same tool-call ids, so the repaired history is evidently never
persisted back to disk.
Reproduced on two independent sessions.
### Steps to reproduce
1. Hit the silent mid-run freeze described in the related issue.
2. Force-quit the TUI.
3. Run `codewhale resume` on the same session id.
4. Observe an empty transcript and repeated repair warnings on each load.
### Observed evidence (timestamps UTC)
Session A `a69916b2…`:
- Resume renders an **empty conversation**, even though the on-disk JSON has
95 journal entries, a valid `leaf_id`, and an undamaged message parent
chain (verified by reading the session store directly).
- Within ~35 seconds after startup, the same warning is logged **four times**,
always repairing the same two call ids:
WARN codewhale_tui::session_manager: repaired persisted tool call/result history
session_id=a69916b2…
repaired_call_ids=["call_90fe91cb…", "call_2e5fc194…"]
duplicate_result_ids=[] orphan_result_ids=[]
(2026-09-15T02:29:34Z, 02:29:36Z, 02:29:49Z, 02:30:08Z)
- Session `metadata.updated_at` is touched at resume time, yet the visible
transcript stays empty.
Session B `53b16822…` (independent reproduction):
- After resume, the same warning appears twice for one call id:
WARN codewhale_tui::session_manager: repaired persisted tool call/result history
session_id=53b16822…
repaired_call_ids=["call_26c088d8…"]
(2026-09-15T03:28:01Z, 03:28:29Z)
This session *did* render its history afterwards, but the repair warning
repeating on each load shows the repair result is still not persisted.
### Expected
- Repairing interrupted tool-call pairs (missing tool_result for an
assistant tool_use) should happen **once** and be flushed back to disk.
- Resume should render the full transcript, including repaired entries.
- If the repaired history cannot be persisted, say so explicitly instead of
re-running the same fix on every load.
### Impact
Any force-quit during a long tool-heavy task can make a session unusable via
resume: the user loses interactive access to all prior work context and can
only recover it by hand from the session store.
### Related
- Force-quit is caused by the silent freeze issue (filed separately); this bug
is in the session load/repair/persist path and is independent of what caused
the freeze.
---
Sanitized log excerpts: see `attachment-issue-2-logs.en.md`.
attachment-issue-2-logs.en.md
Body
WARN codewhale_tui::session_manager: repaired persisted tool call/result history
session_id=a69916b2…
repaired_call_ids=["call_90fe91cb…", "call_2e5fc194…"]
duplicate_result_ids=[] orphan_result_ids=[]
(2026-09-15T02:29:34Z, 02:29:36Z, 02:29:49Z, 02:30:08Z)
WARN codewhale_tui::session_manager: repaired persisted tool call/result history
session_id=53b16822…
repaired_call_ids=["call_26c088d8…"]
(2026-09-15T03:28:01Z, 03:28:29Z)
attachment-issue-2-logs.en.md