Skip to content

Session diff fallback loses per-file patches for quoted Unicode filenames #183

Closed

Description

@mat973252

I found a Unicode filename issue in the live-workspace fallback used by readLocalSessionDiff(). With Git's normal path quoting enabled, the parser keeps the quoted filename and drops its per-file patch.

I reproduced the parser behavior in a temporary Git repository on Windows:

  1. Set git config core.quotePath true.
  2. Commit a file named 中文.txt containing one line.
  3. Append another line.
  4. Collect git diff HEAD --name-status --, git diff HEAD --numstat --, and git diff HEAD --.
  5. Pass those outputs to parseGitDiffSummary() from the current source.

The returned entry has one addition, but file contains the literal quoted Git escape sequence rather than 中文.txt, and the diff property is absent.

The cause seems to be two related assumptions: the summary parser treats Git's quoted paths as plain filenames, and splitPatchByFile() expects a header starting with diff --git a/, whereas the Unicode filename produces quoted header paths.

Source checked: 33b259bbbeb1c16433390869938191d09bdb0680.

To be clear about the scope: I used real Git output and executed the source parser after stripping TypeScript types. I have not reproduced this through the TUI. This report concerns the fallback when no stored session diff is found, not the separate V2 workspace review parser.

I'd expect the returned filename to be 中文.txt and its patch to be present. NUL-delimited summary output plus proper handling of patch-header quoting may be a good way to avoid depending on the user's Git configuration. A regression test with a tracked Chinese filename would make this easy to check.

Patch prepared

I've pushed a combined fix for this and #184 to my fork (ccc8f8a). It uses NUL-delimited summary output and consistent Unicode patch output, including untracked files. Five real-Git tests through readLocalSessionDiff failed before the fix and pass afterward; typecheck passes too.

Full verification is not green: two release-tool cleanup assertions also fail on the unchanged baseline here, the Windows build encounters a resource-copy EIO error, and a broader capability run had 26 failures alongside 3,493 passes and 11 skips. Those broader failures have not all been individually compared with baseline. No TUI end-to-end acceptance is claimed.

I tried opening a draft PR, but GitHub rejected CreatePullRequest for this account. The branch is available for review under the collaborator-only contribution policy; no upstream PR has been created.

Activity

  1. hetaoBackend commented on Sep 19, 2026

    @hetaoBackend
    Collaborator

    Thanks for including the reproduction scope. I confirmed the fallback uses text-delimited summary paths and a patch-header expression that assumes unquoted a/ and b/ paths. That explains the escaped filename and missing patch you describe.

    I have started one scoped repair for this and #184, since both affect the same fallback parser. It will use real temporary Git repositories to check decoded filenames, per-file patches and rename statistics, including Git quoting settings and unusual path characters. No TUI or native Windows acceptance is claimed yet.

  2. hetaoBackend commented on Sep 19, 2026

    @hetaoBackend
    Collaborator

    The repair is ready for review in #187 (together with #184).

    I reproduced this through readLocalSessionDiff() using temporary real Git repositories and SQLite stores. The fix reads NUL-delimited raw paths and metrics and associates patches in Git's record order, so quoted Unicode headers no longer determine the returned filename or patch lookup. Untracked paths use the same structured handling.

    All 17 regression cases and the full 14-gate pnpm verify passed on macOS arm64 at 0e91cd785fd34d5825433cfa2e594d18f613bae0. Coverage includes both core.quotePath settings and unusual filenames. Native Windows/Linux and TUI presentation have not been locally validated; CI is still running. The PR is open, not merged or released.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions