Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
The app steps below are derived from the v0.1.7 source; we have not driven them in T3. We reproduced the Git probe, selected staging branch and restore sequence separately in disposable repositories.
- On Windows with Git for Windows, use a disposable repository with a committed tracked file and a T3 thread associated with its own isolated worktree. No other thread or agent session may use an overlapping directory. The worktree root must contain a
.gitignorewith a blank CRLF line. In Git Bash,printf 'a.txt\r\n\r\nb.txt\r\n' > .gitignorewrites the required bytes directly. - Arrange for a non-ignored untracked file such as
notes.mdto exist in that worktree before the checkpoint used as the rollback target is captured. Leave it untracked. A file created only after the target snapshot would normally be removed on restore, so that would not demonstrate this loss. - Run a turn that edits the tracked file and creates
new.txt, without staging either untracked file in the user’s index. - Inspect the before-turn and after-turn checkpoint commits under
refs/t3/orchestration-v2/checkpoints/withgit ls-tree -r --name-only <checkpoint-ref>. The source predicts that neither containsnotes.md, and the after-turn checkpoint also omitsnew.txt. - Use “Edit from here” on that turn and choose “Revert files too”. The Git simulation predicts that
notes.mdis deleted, even though it existed before the turn.
The isolated-worktree condition matters: v0.1.7’s restore guard rejects file restore for in-place project threads and shared workspaces.
The root cause, reproduced without T3 (Git 2.56.0.windows.4, Git Bash):
git init repro && cd repro
printf 'sentinel\n' > new.txt
printf 'a.txt\n\nb.txt\n' > .gitignore
git check-ignore -v --no-index . # exit 1: not ignored
printf 'a.txt\r\n\r\nb.txt\r\n' > .gitignore
git check-ignore -v --no-index . # .gitignore:2:<TAB>. exit 0: ignored
git ls-files --others --exclude-standard # still lists new.txtExpected behavior
- At a repository’s working-tree root, or in a project folder below it that isn’t genuinely ignored, checkpoint capture includes eligible non-ignored untracked files rather than misclassifying the workspace as an ignored project directory.
- A successful restore preserves files that existed before the target turn and should have been captured. Removing files created after that snapshot remains expected.
Actual behavior
captureCheckpointasksfilterIgnoredPaths(input.cwd, ["."])whether the workspace is ignored (v0.1.7 L1105). If so, it stages withgit add -uinstead of-A(L1177). This check was added in #14892 for project folders that a parent repo ignores.- On the tested Git build, a blank CRLF line in the root
.gitignoremakes the probe report.as ignored, subject to Git’s usual last-matching-pattern rules, while ordinary untracked listing still includesnew.txt. Git’s parser checks for an empty line before stripping CR and trailing spaces, so it passes an empty pattern onward. We also reproduced this with.git/info/exclude, with a globalcore.excludesFile, and with a spaces-only LF line. For a workspace at the repository root, a blank line in a subdirectory’s.gitignoredid not trigger the probe. T3’s.probe can also report a subfolder workspace as ignored when a blank CRLF line appears in its own.gitignoreor an ancestor’s. - In the scratch capture,
-usucceeds but omitsnotes.mdandnew.txtfrom the checkpoint trees. Files already staged in the user’s index have a separate import path; these fixtures leave the sentinel files untracked. - When file restore is permitted,
restoreCheckpointrunsgit restore --source <checkpoint> --worktree --staged -- .andgit clean -fd -- .(L1317, L1346). In the CRLF simulation, clean removed the pre-existingnotes.mdand the agent-creatednew.txt. Their contents cannot be recovered from those incomplete checkpoint trees. Ignored files and untracked nested Git repositories survived the simulation.
The LF control captured the pre-existing file and restored its original contents while removing the agent-created file. In our real repository, earlier read-only sampling of T3 0.1.7 checkpoint trees also found tracked files only; we did not restore any real checkpoint.
Related context: this coverage problem was also described in a comment on the checkpoint-timeout issue #26227. This report tracks the incomplete-capture and restore consequence separately.
Impact
Pre-existing untracked files can be lost when restoring an incomplete checkpoint in an isolated worktree where file restore is permitted. The omission also affects capture coverage in in-place project threads, even though their normal file-restore path is blocked.
core.autocrlf=true, the Git for Windows installer default, can create the triggering CRLF bytes when checking out an LF-committed .gitignore with a blank line. Attributes such as .gitignore text eol=lf or .gitignore -text with LF source contents can prevent that conversion. We verified those checkout cases on Git 2.56.0.windows.4; we have not tested other Git builds or operating systems.
Version or commit
T3 Code (Beta) 0.1.7 desktop. The root probe, staging branch and restore-isolation guard are also present in the upstream main source inspected for this report. Main repeats clean up to four times since #29795; that does not repair missing checkpoint contents.
Environment
Windows 11 Pro, NTFS, Git 2.56.0.windows.4, core.autocrlf=true.
Workaround
- From the workspace folder, run
git check-ignore --no-index .without-v. A printed.means T3’s probe takes the ignored-workspace branch, and with tracked files present that branch omits unstaged untracked files.git check-ignore -v --no-index .names the matching source and pattern; note that verbose output can also describe a negated match. - Remove blank CRLF lines and spaces-only lines from the ignore source the probe reports:
.gitignore,.git/info/excludeor a global excludes file. Pinning.gitignore text eol=lfprevents CRLF checkout for that file, but does not fix spaces-only lines or other ignore sources. - Verify a fresh checkpoint actually contains a non-ignored untracked sentinel. Changing ignore rules does not repair earlier incomplete checkpoints; avoid “Revert files too” against those targets.
Possible fix
When cwd is the repository’s working-tree root, skip the ignored-project-directory classification and use normal -A staging. Keep the parent-ignored handling for nested project directories from #14892. Forcing -A in the CRLF scratch fixture captured the sentinels and preserved the pre-existing file on restore; this is a command-level check, not a tested T3 patch. That alone leaves workspaces below the top level with tracked-only captures, since the probe can report them ignored the same way; a complete fix would also need to discount an empty-pattern match there, while preserving Git’s pattern precedence (git check-ignore -v reports the pattern).
Sent via Claude Opus 5.5 in Claude Code. Other AI models reviewed it before posting.
Activity