Skip to content

fix(web): scope recent files to the browse revision - #1686

Open
dipeshbabu wants to merge 4 commits into
sourcebot-dev:mainfrom
dipeshbabu:dipeshbabu/fix-browse-recents-1387
Open

dipeshbabu wants to merge 4 commits into
sourcebot-dev:mainfrom
dipeshbabu:dipeshbabu/fix-browse-recents-1387

Conversation

@dipeshbabu

@dipeshbabu dipeshbabu commented Sep 24, 2026 •

Copy link
Copy Markdown

Fixes #1387

Keep recent files scoped to repository and revision, filter out deleted paths, and cap stored history at 100 entries per repository. Tests cover revision changes, HEAD aliases, stale paths, and eviction.

Validation: application tests, lint, Docker builds, Prisma migration gate, and regression checks passed.


Note

Low Risk
Client-side localStorage and browse file-search UI only; no auth, API, or server behavior changes.

Overview
Fixes browse file search (Cmd/Ctrl+P) showing Recently opened entries from another branch or commit, which could navigate to paths that do not exist on the current revision.

Recent history is now stored per repository in a recentlyOpenedFiles-v2- localStorage key as { revision, file } entries. The UI only shows recents for the active revision (missing revisionName is treated as HEAD, shared with an explicit HEAD). Entries are dropped when the path is no longer in the loaded file list. Legacy repo-only keys are left alone and are not imported. A CHANGELOG note and Vitest regressions cover revision switching, remounts, legacy storage, separator edge cases, and the 100-entry cap.

Reviewed by Cursor Bugbot for commit b029892. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fixes #1387 by scoping recently opened files to the current repository and revision, so switching branches no longer surfaces or navigates to files from another revision.

  • Recent file history is now stored under a key that encodes both repoName and revisionName, with omitted revisions mapped to HEAD so they share history.
  • Legacy repository-only history is left untouched because its revision is unknown.
  • Regression tests cover revision switching, remounts, default HEAD, legacy storage, and separator collisions.

Written for commit ab293d7. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Recently opened files are now kept separate for each repository revision, so files opened in one revision no longer appear in another.

@coderabbitai

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 911ee056-d795-4bd2-beb7-12c0a1e6dadb

📥 Commits

Reviewing files that changed from the base of the PR and between ab293d7 and b029892.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.test.tsx
  • packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • CHANGELOG.md

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 5 remain after this review.


Walkthrough

File search recents now include revision context. The dialog filters recent files by the active revision and current file list, and retains up to 100 entries. Tests cover revision isolation, persistence, stale paths, and history limits.

Changes

File search recents

Layer / File(s) Summary
Scope and resolve recent-file history
packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx, packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.test.tsx, CHANGELOG.md
History entries pair a file with its revision and use a repository-specific versioned storage key. The dialog defaults to HEAD, filters entries by revision, omits paths absent from the current file list, and caps history at 100 entries. Tests cover revision separation, persistence, legacy entries, separator-containing values, stale paths, and the history limit. The changelog records the fix.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to b0298

The change keeps recent files in browse search scoped to the active revision, so selecting one no longer navigates to a path that does not exist there. No merge-blocking risk was found.

Security Architecture Review

Security architecture risk: 🔵 Low · up to b0298

The change is limited to browser recent-file history and strengthens revision isolation by checking entries against the current file list. No expanded access or navigation authority was identified. Storage behavior during repository switches and simultaneous tab updates remains incompletely verified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The direct changed state is recent-file metadata in browser storage for each repository. The inspected change does not add a server caller, credentials, or privileged storage access; navigation still uses the current browse context and returned file list.

Trust Boundaries and Controls

  • observed — Persisted history is advisory rather than navigation authority. A stale or modified stored path is not used directly: it must match the active revision and resolve to a current file-list object before becoming a selectable recent item. This strengthens the base behavior without replacing server access controls.

Resilience and Maintainability Implications

  • inferred — History updates precede navigation, so failed navigation can leave an advisory recent entry. Later display still requires the active revision and a current matching path. Repetition is deduplicated locally; atomic cross-tab updates and repository-key switching remain unverified dependency behavior, not established security findings.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR meets the coding requirement in issue #1387. fileSearchCommandDialog.tsx stores recent files with repository and revision scope. It normalizes an omitted revision to HEAD, keeps repository-…
Out of Scope Changes check ✅ Passed The changes remain within issue #1387. The implementation fixes revision-scoped recent files. The tests verify the required behavior. The changelog documents the same fix. No unrelated product behavio…
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: scoping recent files to the browse revision.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx">

<violation number="1" location="packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx:39">
P3: Each distinct (repo, revision) pair — including every commit SHA the user browses at — permanently creates a new localStorage entry that is never evicted, and legacy `recentlyOpenedFiles-<repo>` keys are intentionally left in place too. Storage clutter grows without bound over time for active browsing. Consider capping the recents array length and pruning keys for revisions no longer reachable, e.g. store one entry per repo holding a `Map`/object of revision → files instead of one key per revision.</violation>

<violation number="2" location="packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx:39">
P2: Scoping the key by revision closes the cross-revision case, but the "Recently opened" list is still rendered as a stored snapshot without validating any entry against the files that currently exist at that revision (`recentlyOpened.map(...)` runs with no cross-check against `files`). If the revision's content moved since the file was opened — a branch advanced and deleted/renamed the path — selecting the entry calls `navigateToPath` to a blob that no longer exists, which is the same end-user failure mode #1387 describes, just narrowed to the matching key. Filter `recentlyOpened` against the current `files` (or remove missing paths on read), e.g. `recentlyOpened.filter(r => files.some(f => f.path === r.path))`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx Outdated
Comment thread packages/web/src/app/(app)/browse/components/fileSearchCommandDialog.tsx Outdated

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File search recents are shared across browse revisions

1 participant