[Bug]: Truncated checkpoint turn diffs lack an incomplete-preview notice #36073
Send to my agentSummary#
When a checkpoint diff exceeds the server's output limit, the Diff panel renders the returned prefix as a normal turn diff and does not tell the reviewer that changes are missing. The panel should disclose that the turn diff is incomplete, as it does for git and tool-call previews. A focused server test confirmed the checkpoint response carries a truncation marker, and a browser render reproduced the missing notice with that response shape.
Before submitting#
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area#
apps/web
Steps to reproduce#
- On commit
c00a373491d20ebcef901b81170abfb9f5f757fe, save the script below asrepro.shin the checkout's parent directory, enter the checkout, and runsh ../repro.sh "$PWD". - The script makes a disposable copy of the existing Diff panel browser fixture, selects a completed turn, and supplies a patch ending in the server's truncation marker.
- The control assertion confirms
first.txtrenders from that turn response; the expected-behavior assertion then looks for the incomplete-preview notice.
The final run reproduced the failure once. An earlier run was inconclusive because the isolated HOME hid the installed Playwright browser; a later assertion failure was classified inconclusive by an overly narrow output matcher. Both setup issues were corrected before the final run.
Prerequisites are the checkout's installed dependencies, vp, Node, Python, ripgrep, and the Playwright Chromium headless shell in the normal browser cache or PLAYWRIGHT_BROWSERS_PATH. The script prints runtime versions, confines its state to a temporary directory, removes its uniquely named test on exit, and leaves the checkout unchanged. Exit 0 means the notice appeared, exit 1 means the file rendered but the notice did not, and exit 2 means the run was inconclusive.
Reproduction script: repro.sh
#!/bin/sh
set -eu
checkout=${1:?Pass the checkout path}
browser_cache=${PLAYWRIGHT_BROWSERS_PATH:-$HOME/Library/Caches/ms-playwright}
scratch=$(mktemp -d)
test_file="$checkout/apps/web/src/components/turn-diff.y05-01.browser.test.tsx"
cleanup() {
rm -f "$test_file"
rm -rf "$scratch"
}
trap cleanup EXIT HUP INT TERM
export HOME="$scratch/home"
export TMPDIR="$scratch/tmp"
export T3CODE_HOME="$scratch/t3"
export PLAYWRIGHT_BROWSERS_PATH="$browser_cache"
mkdir -p "$HOME" "$TMPDIR" "$T3CODE_HOME"
printf 'node: '; node --version
printf 'python: '; python3 --version
printf 'rg: '; rg --version | head -n 1
printf 'vp: '; vp --version
cp "$checkout/apps/web/src/components/DiffPanel.browser.test.tsx" "$test_file"
python3 - "$test_file" <<'PY'
from pathlib import Path
import sys
p = Path(sys.argv[1])
s = p.read_text()
s = s.replace(
'useThreadCheckpointSummaries: () => [],',
'useThreadCheckpointSummaries: () => [{ runId: "run" as never, checkpointTurnCount: 1, checkpointRef: "ref" as never, status: "ready", files: [], assistantMessageId: null, completedAt: "2026-01-01T00:00:00Z" }],',
)
s = s.replace(
'useCheckpointDiff: () => ({ data: null, error: null, isPending: false }),',
'useCheckpointDiff: () => ({ data: { diff: "diff --git a/first.txt b/first.txt\\n--- a/first.txt\\n+++ b/first.txt\\n@@ -0,0 +1 @@\\n+visible\\n\\n[truncated]" }, error: null, isPending: false }),',
)
s += '''
it("shows that a server-truncated turn patch is incomplete", async () => {
using context = setup("origin/orphan");
useDiffPanelStore.getState().selectTurn(context.threadRef, "run" as never);
await using screen = await render(
<RegistryContext.Provider value={context.registry}>
<div style={{ height: 600, display: "flex", flexDirection: "column" }}>
<DiffPanel composerDraftTarget={context.threadRef} workspaceMutationId={null} visible />
</div>
</RegistryContext.Provider>,
);
await expect.element(screen.getByText("first.txt", { exact: true }).first()).toBeVisible();
console.log("CONTROL: rendered first.txt from the truncated checkpoint response");
await expect.element(screen.getByText("This preview exceeds the size limit. Changes shown are incomplete.", { exact: true })).toBeVisible();
});
'''
p.write_text(s)
PY
set +e
(cd "$checkout" && vp test run apps/web/src/components/turn-diff.y05-01.browser.test.tsx -t 'shows that a server-truncated turn patch is incomplete') >"$scratch/test.log" 2>&1
status=$?
set -e
rg 'CONTROL:|^ FAIL|^Error:|^Caused by:|^ *Tests|^ *Test Files|Unhandled Errors' "$scratch/test.log" || true
if [ "$status" -eq 0 ] && rg -q 'CONTROL: rendered first.txt' "$scratch/test.log" && rg -q 'Tests 1 passed' "$scratch/test.log"; then
echo 'RESULT: expected behavior'
exit 0
fi
if rg -q 'CONTROL: rendered first.txt' "$scratch/test.log" && rg -q 'Matcher did not succeed in time' "$scratch/test.log" && rg -q 'Tests 1 failed' "$scratch/test.log" && ! rg -q 'Unhandled Errors' "$scratch/test.log"; then
echo 'RESULT: defect reproduced'
exit 1
fi
echo 'RESULT: inconclusive'
exit 2
Expected behavior#
The Diff panel should disclose that a server-capped turn patch is incomplete, as it already does for incomplete tool-call and git previews (apps/web/src/components/DiffPanel.tsx#L483-L485, apps/web/src/components/DiffPanel.tsx#L1332-L1339). The file list and line totals derived from the returned prefix should not imply that they cover the whole turn.
Actual behavior#
The browser test supplied a valid one-file checkpoint patch followed by the server's \n\n[truncated] marker through a mocked turn-diff response. The file appeared in the Diff panel, but the expected incomplete-preview notice did not. The production query applies a 10,000,000-byte cap and appends that marker on overflow; its return schema contains only the diff string and turn identifiers (apps/server/src/checkpointing/CheckpointDiffQuery.ts#L226-L263, packages/contracts/src/checkpointDiff.ts#L21-L39).
Impact and scope#
Impact: P2 - For checkpoint patches above the server cap, a reviewer can miss later files or hunks while the panel presents the visible prefix and its line totals without an incomplete notice.
The cap is 10,000,000 bytes (apps/server/src/vcs/VcsDriver.ts#L25). A closed Android report documents a real 8,200,127-byte single-turn patch, but the frequency of patches above the cap is NOT_ENOUGH_INFO; production usage data would establish it. Inspecting the Git changes outside this panel may recover omitted content, but that workaround was not tested here.
Earliest failure stage#
Output or presentation.
Analysis or suspected cause#
The existing focused server test shares the turn and full-thread diff budget across real Git batches passed (one test, five skipped). It asserts that the returned turn and full-thread diffs match, stay at or below the byte cap, end in [truncated], and omit a later file (apps/server/src/checkpointing/CheckpointDiffQuery.test.ts#L203-L304).
For a selected turn, the panel reads activeCheckpointDiff.data.diff, but its truncation predicate checks only tool-call and git-preview metadata (apps/web/src/components/DiffPanel.tsx#L478-L486). The notice depends on that predicate (apps/web/src/components/DiffPanel.tsx#L1332-L1339); the header totals come from the rendered files (apps/web/src/components/DiffPanel.tsx#L693-L695, apps/web/src/components/DiffPanel.tsx#L1141-L1148).
Additional context#
The current main version of apps/web/src/components/DiffPanel.tsx#L482-L486 retains the same predicate and apps/web/src/components/DiffPanel.tsx#L1326-L1335 notice gate; the current apps/server/src/checkpointing/CheckpointDiffQuery.ts#L227-L246 still appends the marker on overflow. This was checked through GitHub's file contents API without modifying the checkout.
Evidence provenance: observed server test and browser render, with source inspection. Local verification: reproduced. Reproduction completeness: complete. Missing fact: the frequency of production turn patches above the cap is unknown; production usage data would establish it.
Impact#
Minor bug or occasional failure
Version or commit#
main @ c00a373
Environment#
macOS arm64; Node v26.12.1, Python 3.15.2, ripgrep 15.2.0, vp v1.6.0 with local vite-plus v1.4.0 and Vitest v5.0.5; Chromium browser test.
Logs or stack traces#
node: v26.12.1
python: Python 3.15.2
rg: ripgrep 15.2.0
vp: vp v1.6.0
Local vite-plus:
vite-plus v1.4.0
Tools:
vite v8.3.5
rolldown v1.2.15
vitest v5.0.5
oxfmt v0.74.0
oxlint v1.89.0
oxlint-tsgolint v7.0.2004
tsdown v0.23.1
Environment:
Package manager pnpm v12.14.0
Node.js v26.12.1 (engines.node)
CONTROL: rendered first.txt from the truncated checkpoint response
FAIL |@t3tools/web (browser) (chromium)| src/components/turn-diff.y05-01.browser.test.tsx > shows that a server-truncated turn patch is incomplete
282| console.log("CONTROL: rendered first.txt from the truncated checkpoi…
Caused by: Error: Matcher did not succeed in time.
Test Files 1 failed (1)
Tests 1 failed | 4 skipped (5)
RESULT: defect reproduced
Screenshots, recordings, or supporting files#
No response
Workaround#
No verified workaround. Inspecting Git changes outside this panel may recover omitted content, but this was not tested.
References#
- https://github.com/pingdotgg/t3code/issues/7431 — its completed repair covers branch and working-tree previews; the selected-turn checkpoint path still lacks an incomplete notice.
- https://github.com/pingdotgg/t3code/issues/14649 — documents a large turn patch below the checkpoint cap that reached a client.
- https://github.com/pingdotgg/t3code/pull/10822 — merged repair for progressively loading branch and working-tree review diffs; it does not change the checkpoint turn-diff path.
- https://github.com/pingdotgg/t3code/pull/18395 — merged server change that caps checkpoint diffs across batches; the client still ignores the resulting marker.
github-actions[bot](GitHub profile, opens in a new tab) added labelsvouch:denounced
tanstack-source added labelsbug
juliusmarminge closed this
Sign in to join this conversation.