Bug
Turn diffs ("Loading checkpoint diff…" / "Filesystem checkpoint is unavailable for turn N") never resolve after a Codex turn completes, even when the project is a valid git repository.
Root cause
There is a race between two independent event handlers that both react to turn completion:
-
ProviderRuntimeIngestion handles turn.diff.updated events and immediately dispatches thread.turn.diff.complete with a placeholder checkpoint entry:
checkpointRef: "provider-diff:<eventId>" (not a real git ref)
status: "missing"
files: []
(apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts, lines 1064-1083)
-
CheckpointReactor handles turn.completed events and is supposed to capture a real git-ref-based checkpoint via CheckpointStore.captureCheckpoint, then dispatch thread.turn.diff.complete with the actual diff data.
(apps/server/src/orchestration/Layers/CheckpointReactor.ts, lines 150-298)
The problem: ProviderRuntimeIngestion wins the race and inserts the placeholder into thread.checkpoints first. When CheckpointReactor later processes turn.completed, it checks:
if (thread.checkpoints.some((checkpoint) => checkpoint.turnId === turnId)) {
return; // ← early exit, real capture never happens
}
(line 169)
Since the placeholder already has the same turnId, the real git checkpoint is never captured. The DiffPanel then tries to resolve provider-diff:UUID via git rev-parse, which fails because it's not an actual git ref.
Observed behavior
- Server logs show
thread.turn-diff-completed events with checkpointRef: "provider-diff:..." and status: "missing"
- DiffPanel shows "Loading checkpoint diff..." indefinitely, then "Filesystem checkpoint is unavailable for turn N"
- No
refs/t3/checkpoints/ git refs are created for the affected turns
Reproduction
- Add any git-initialized project
- Send a message that triggers file changes (e.g., "add a comment to README")
- Wait for turn to complete
- Open the diff panel → stuck on "Loading checkpoint diff..."
Suggested fix
The dedup check in CheckpointReactor (line 169) should either:
- Only skip if an existing checkpoint has a non-placeholder status (i.e., skip
"missing" entries), or
- Replace/upgrade placeholder checkpoints with the real git-based checkpoint when one becomes available
Additionally, there is a secondary CWD inconsistency worth noting: CheckpointReactor turn-completion capture prefers sessionRuntime.cwd while CheckpointDiffQuery only uses resolveThreadWorkspaceCwd. If these ever diverge, refs would be written to one repo but looked up in another.
Environment
- T3 Code dev (main branch)
- Codex provider with GPT-5.4
- Linux (Arch)
Bug
Turn diffs ("Loading checkpoint diff…" / "Filesystem checkpoint is unavailable for turn N") never resolve after a Codex turn completes, even when the project is a valid git repository.
Root cause
There is a race between two independent event handlers that both react to turn completion:
ProviderRuntimeIngestionhandlesturn.diff.updatedevents and immediately dispatchesthread.turn.diff.completewith a placeholder checkpoint entry:checkpointRef: "provider-diff:<eventId>"(not a real git ref)status: "missing"files: [](
apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts, lines 1064-1083)CheckpointReactorhandlesturn.completedevents and is supposed to capture a real git-ref-based checkpoint viaCheckpointStore.captureCheckpoint, then dispatchthread.turn.diff.completewith the actual diff data.(
apps/server/src/orchestration/Layers/CheckpointReactor.ts, lines 150-298)The problem:
ProviderRuntimeIngestionwins the race and inserts the placeholder intothread.checkpointsfirst. WhenCheckpointReactorlater processesturn.completed, it checks:(line 169)
Since the placeholder already has the same
turnId, the real git checkpoint is never captured. The DiffPanel then tries to resolveprovider-diff:UUIDviagit rev-parse, which fails because it's not an actual git ref.Observed behavior
thread.turn-diff-completedevents withcheckpointRef: "provider-diff:..."andstatus: "missing"refs/t3/checkpoints/git refs are created for the affected turnsReproduction
Suggested fix
The dedup check in
CheckpointReactor(line 169) should either:"missing"entries), orAdditionally, there is a secondary CWD inconsistency worth noting:
CheckpointReactorturn-completion capture preferssessionRuntime.cwdwhileCheckpointDiffQueryonly usesresolveThreadWorkspaceCwd. If these ever diverge, refs would be written to one repo but looked up in another.Environment