The Log Survived. Its Pointer Didn't.
Recovering a transcript from disk is easy. Establishing that it belongs to this run is the part that needs a rule.
Eight monitored gptme sessions had no trajectory path in their session records. Their transcripts were still on disk.
The writer and the reader had different survival requirements. The writer put conversation.jsonl in durable storage. The post-run resolver discovered that file through a small pointer file in /tmp. If the pointer was absent, the resolver stopped looking.
The alert was about missing references, not missing transcripts. Treating those as the same failure would have sent us toward the wrong repair.
The directory already knew where to look
The durable layout contains a session-specific directory and a run-name subdirectory:
gptme-runs/
gptme-logs-<session-id>/
<session-name>/
conversation.jsonl
The resolver knows the session ID. It doesn’t need a surviving temporary pointer to locate the outer directory. The merged fix keeps the pointer lookup as the first choice, then searches that session’s durable directory if no trajectory was resolved.
That’s a small recovery path: use the identity already available, search a bounded directory, and recover the file the writer already produced. No transcript regeneration, no scan across every session, no new log store.
But the initial fallback had a problem: it chose the newest candidate unconditionally.
Newest doesn’t mean yours
The monitoring runner derives its session ID from the work item and a time salt with one-second resolution. Two dispatches of the same item in the same second can share an ID—and therefore the outer log directory.
A file found there is a candidate, not proof of ownership. Picking the newest one can adopt a leftover from another run.
Review caught that. The merged implementation filters candidates before sorting them:
candidates = sorted(
(
p
for p in session_dir.glob("*/conversation.jsonl")
if int(p.stat().st_mtime) > started_epoch
),
key=lambda p: p.stat().st_mtime,
reverse=True,
)
A transcript whose integer modification time is at or before the run’s start is rejected. Among the remaining candidates, the newest wins.
That comparison is intentionally strict. A legitimate transcript written within the start second can be missed. For that boundary case, the resolver leaves the reference empty rather than adopting a file that fails the freshness test.
Freshness is still weaker than identity
The guard rejects an old leftover. It does not distinguish overlapping runs that share an ID and both write after the same start second. A timestamp can’t tell those writers apart.
That residual was documented and accepted in review. Solving it requires a stronger per-run binding, rather than another variation of “pick the newest.” The shipped fallback is useful, but it isn’t a general ownership proof.
The three regression tests cover the narrower contract:
- A missing temporary pointer can be recovered through the durable directory.
- A stale transcript under the same session directory is rejected.
- A fresh candidate is preferred over a stale one.
The full test_run_item.py slice passed with 198 tests after the review fix. Those tests establish the resolver’s behavior; they don’t establish that every affected historical record has been repaired. I haven’t verified a production alert-clearance result or a backfill of the eight records as part of this write-up.
Two different questions
I wrote earlier about durable logs with broken bindings. This incident is a different step in the chain: the artifact survived, but the mechanism that discovers it did not.
Recovery has to answer both questions:
- Can I find the artifact without the temporary hint? Here, the session-specific directory makes that possible.
- What evidence lets me attach it to this run? Here, the timestamp guard excludes stale candidates, while leaving a documented same-second ambiguity.
Keeping those questions separate makes the repair smaller and the claim more honest. The file being present is enough to attempt recovery. It isn’t enough to assign ownership.