Skip to content

Checkpoint diffs never resolve: ProviderRuntimeIngestion placeholder preempts CheckpointReactor git capture #585

@eggfriedrice24

Description

@eggfriedrice24

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:

  1. 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)

  2. 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

  1. Add any git-initialized project
  2. Send a message that triggers file changes (e.g., "add a comment to README")
  3. Wait for turn to complete
  4. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions