fix: cross-session file change leak in Files Changed tab - #301
Merged
Conversation
…dits When a session has step-start/step-finish snapshots but zero completed tool parts with filediff metadata (e.g. a plan-only session), return [] immediately instead of falling through to Fallback 1. Fallback 1 reads message.summary.diffs, which are populated by computeDiff — an unfiltered snapshot diff that captures ALL worktree changes between the two tree hashes, including edits from other concurrent sessions. This was the primary cross-session contamination vector for the Files Changed tab: a plan-mode session would show another session's file edits because the snapshot system uses a single shadow git repo per project. The early return is safe: if snapshots exist (from is defined), the session is 'modern' — Fallback 1 was designed for legacy sessions that predate the snapshot infrastructure, not as a supplement to the primary path. Closes harmoniqs/amicode#733 follow-up (computeDiff filtering).
Defense-in-depth: computeDiff now extracts agent-touched files from completed edit/write/patch/apply_patch tool parts and filters the snapshot diff to only those files, preventing cross-session changes from being stored in message.summary.diffs in the first place. Three cases: - Agent files exist (filediff metadata) → filter to those files only - Tools ran but none have filediff (e.g. bash) → return full diff (can't determine which files the agent touched) - No tools at all (plan-only) → return empty (all changes are external) This is the follow-up explicitly called out in the #733 commit message: 'a follow-up in the fork will add agent-file filtering to computeDiff to fix the leak at the source'.
Replace keepPreviousData with a session-scoped placeholder function that only preserves data from the same sessionID. This prevents the cross-session flash: when switching from Session A to Session B, the diff query no longer serves Session A's diffs as placeholder data in Session B's review panel. Intra-session refetches (diff_version bumps during a turn) still get smooth transitions — the placeholder is kept because the sessionID matches. Only inter-session switches (params.id change) drop the stale data, falling to the tool-metadata fallback which is correctly scoped to the new session's messages. Applied to both sessionDiffQuery and touchedFilesQuery.
The key was added to en.ts in 77d7f8d but missing from all non-English locale files, failing the i18n parity test.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
File edits made in one session leak into the "Files Changed" tab of other sessions sharing the same project folder. A plan-mode session (zero edits) shows file changes from concurrent build-mode sessions.
Reported: harmoniqs/amicode#733 follow-up
Root cause
All sessions share a single shadow git repository per project. Snapshots capture the entire worktree — session isolation is enforced by filtering. Three gaps in the filter chain allowed cross-session contamination:
1.
Session.diff()Fallback 1 serves unfilteredsummary.diffs(primary)computeDiff()(summary.ts) runssnapshot.diffFull(T1, T2)— an unfiltered snapshot diff that captures ALL worktree changes, including other sessions' edits. The result is stored inmessage.summary.diffs.When the client fetches
GET /session/{id}/diff, plan-mode sessions have zero tool filediff metadata, soagentFilesAbsolute.size === 0, the filtered primary path is skipped, and Fallback 1 reads the contaminatedsummary.diffsand returns them.2.
computeDiffstores contaminated data (defense-in-depth)Even for sessions WITH edits,
computeDiffstored the full unfiltered diff. The primary path filtered at query time, but the stored data was dirty.3.
keepPreviousDataon session switch (client-side)When switching tabs, TanStack Query served the old session's diffs as placeholder data for the new session, briefly showing wrong files.
Fix (4 commits)
fix(session)Session.diff()when snapshots exist but no tools ran — return[]instead of falling through to Fallback 1fix(summary)computeDiffby agent-touched files: filediff-tracked → filter; bash-only → full diff; no tools → emptyfix(app)placeholderDatato the same session ID — intra-session refetches still smooth, inter-session switches drop stale datachore(i18n)session.exportTracekey to all locale files (pre-existing parity failure)Testing
summary.diffs→ endpoint returns[]session-diff-scopedtests pass (8/8)snapshot-tool-racetest passes (bash-tool sessions still work)