feat(web): pull request files can be marked as viewed - #7721

Open
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream
Open

feat(web): pull request files can be marked as viewed#7721
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream

Conversation

@yordis

@yordisyordis commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
  • A review spread over an afternoon, or picked up on a second machine, starts again from the top every time, so large changes get read in the browser and only small ones stay here.
  • The marks are the host's wherever the host keeps any, because a checkbox that looks like the one GitHub shows and quietly disagrees with it leaves a reviewer unsure which of the two knows what they have actually read.
  • GitLab keeps its own viewed files in one browser's local storage, where nothing outside that browser can read or write them, so there is no shared record to be the host's. The marks are this environment's instead, and the surface says so rather than implying gitlab.com will show them.
  • Declared per provider as where the marks live rather than whether they exist, so a host with nowhere to keep them hides the control instead of offering one that cannot keep its promise.
  • Read apart from the patch, because viewed state moves on every press and a patch moves only when somebody pushes; sharing one read would mean either re-fetching a three-hundred-file diff per checkbox or showing a reader their own last press as stale.

Note

Medium Risk
Large cross-provider pull-request surface area (new persistence, caching, and Azure diff assembly); regressions could affect diff accuracy, viewed-state correctness, or Azure/GitHub API behavior under rate limits.

Overview
Adds per-file “viewed” tracking for pull requests end-to-end on the server: new filesViewed / setFilesViewed on PullRequestService, RPC auth for pullRequestsFilesViewed and pullRequestsSetFilesViewed, and provider support split by viewedFiles: "host" (GitHub GraphQL read/write) vs "environment" (SQLite marks plus host file revision lookups to detect pushes).

For environment-backed providers, migration 044 creates pull_request_files_viewed and PullRequestFilesViewedRepository stores cleared paths with a revision stamp; the service compares revisions (with caching, stale-while-revalidate, per-PR write ordering, and invalidation) so re-pushed files show as dismissed without re-fetching the whole diff on every checkbox.

Azure DevOps gains a real Code tab: capabilities.diff flips on, REST moves from az rest to az devops invoke, iteration changes are paged and turned into unified patches via the new diff dependency and azureDevOpsDiff.ts, plus getFileRevisions for viewed-state staleness. Bitbucket and GitLab add getFileRevisions (patch index lines / head blob GraphQL). Extensive unit tests cover paging limits, truncated diffs, and mark isolation across repos and PR numbers.

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

Note

Add ability to mark pull request files as viewed across providers

  • Adds a "Viewed" checkbox to the PR code tab UI. Toggling a file collapses it and marks it viewed; changing the file's head revision shows a "Changed" indicator.
  • GitHub viewed marks are stored on the host. GitLab, Bitbucket, and Azure DevOps marks are stored in the environment via a new SQLite table created by migration 044_PullRequestFilesViewed.
  • The server fetches per-path head revisions to detect stale marks for environment-scoped providers.
  • Risk: Azure DevOps PRs now use AzureDevOpsRepositoryLocation instead of threadsUrl. normalizeGitRemoteUrl now normalizes Azure DevOps SSH remotes to web spelling.

Macroscope summarized 6e9d61c.

@coderabbitai

coderabbitaiBot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db5e0854-7bcc-4529-902c-248e00159c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 20, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI: the new viewed-file checkbox in the diff header, the counter in the toolbar, and the fold/overlay logic modules. Two findings, both on changed lines in PullRequestCodeTab.tsx.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a substantial cross-provider viewed-file workflow with persistent state, new authenticated RPCs, provider integrations, and a newly enabled Azure DevOps diff path. It also changes authorization behavior and provider capability defaults, so the production blast radius warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI changes (PullRequestCodeTab.tsx, pullRequestDiff.logic.ts, pullRequestFilesViewed.logic.ts, usePullRequestFilesViewed.ts) for shared-primitive use, Tailwind/CSS ownership and virtualizer behavior.

Both findings from the previous run are resolved: the Checkbox no longer carries a partial size-* override, and truncated is now threaded through the hook and surfaced in the meta line with the same Tooltip + TriangleAlertIcon treatment the withheld-diff caveat uses. Two remaining items below — one virtualizer regression risk, one accessible-name issue on the new control.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
yordis added 10 commits August 20, 2026 18:06
A review spread over an afternoon, or picked up on a second machine, started
again from the top every time, so large changes were read in the browser and
only small ones stayed here.
The marks are the host's rather than ours because a checkbox only this app
remembers is worse than none: it looks like the one GitHub shows, disagrees
with it, and leaves a reviewer unsure which of the two knows what they have
actually read.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he window resets
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…since
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…at it is partial
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he wrong way
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…count
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…carries
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A press moved the whole viewed view, and every file header on screen was memoized on it, so one tick cost a rebuild of all of them. The same mark also has to say whether the control is offered at all, or a capability arriving after the first paint leaves the headers without a box.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
It borrowed its name from the label beside it, and that label turns into "Changed" once the file has been pushed to, leaving a reader who cannot see it with no idea what the box does.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordisforce-pushed the yordis/feat-pr-files-viewed-upstream branch from 1296cb6 to 6b44e51CompareAugust 20, 2026 22:07
@yordis

yordis commented Aug 20, 2026

Copy link
Copy Markdown
ContributorAuthor

GitHub

Screen.Recording.2026-08-20.at.6.15.29.PM.mov

The branch had drifted behind main far enough to conflict, which blocked
review of the change itself.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
The button exists for a reader who can see that what they are looking at is
behind, so leaving one part of the page on the last read defeats the point of
pressing it. A push since that read is exactly when the mark beside a ticked
file stops being true.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
An error the reader cannot act on, about a press they have already replaced,
reads as their current tick having been lost when it has not.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new viewed-files hook: the command-failure path surfaces an error toast for interrupt-only failures, which diverges from the repo's established useAtomCommand failure convention. Everything else in the web scope (Checkbox/Tooltip primitive use, the amber caveat icon matching the adjacent meta-line pattern, header portal render-prop stability via refs, explicit environmentId threading) looks consistent.

Posted via Macroscope — UI Consistency

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…equest
GitLab keeps viewed files in one browser's local storage, so there was
nothing to read or write there. The marks are this environment's instead,
and the surface says whose they are rather than implying gitlab.com will
show them.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 30, 2026
The only signal that GitLab's own site would never show these ticks was a
tooltip on a small icon, and the first reader to use it went looking for
the marks on gitlab.com instead. The count says it now.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

GitLab

Screen.Recording.2026-08-30.at.10.59.33.AM.mov

The server derives a ref's repository from the project identity, and Azure DevOps
is the one host where that is not the recorded path. Clients spelled it the other
way, so the server turned their refs away at the door and the link fell through to
the browser. The rule now lives where both sides can read it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bitbucket records nothing about what a reviewer has already read, so the marks are
this environment's own. Without a revision to compare against they could not tell a
file still as it was read from one pushed to since, which is the distinction that
makes the marks worth keeping at all.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The adapter never read what a pull request changed, so the panel reported no files
and the Code tab was hidden outright. Azure serves no patch of its own, and its
record of what a reviewer has read sits behind an endpoint it has never released,
so both are answered from what it does state: the files an iteration changed, and
the blob each side holds.
Reading the conversation moved off `az rest` in the process. It mints its own token
against whichever tenant `az` defaults to, which is not the one an organisation
necessarily lives in, so that read had been failing wherever the two differ.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

Azure DevOps

CleanShot.2026-08-30.at.18.22.41.mp4

@yordis

Copy link
Copy Markdown
ContributorAuthor

Bitbucket

CleanShot.2026-08-30.at.18.30.34.mp4

The marks are this environment's own rows and cost nothing to read, but every read
of them blocked on a host call that only the Changed badge needed, and a press paid
for that call twice over. On Azure, where each one is a process spawn, coming back
to a review left the checkboxes empty for seconds at a time.
Correcting a badge a moment late is cheaper than making a reader wait for it, so a
held answer now stands while the next one is fetched. The press itself still asks
outright, since it stamps what it stores.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestProvider.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
Azure pages its change list and answers for a binary file in an encoding of its own, so a large pull request came back as part of a change presented as the whole of it, and a file whose contents az would not hand over took the rest of the slice down with it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A host that answers for part of a change said nothing about the rest, and that silence was read as deletion, so every file past the cut was cleared over a version nobody ever looked at. Two presses on one file could also finish in the other order, and two Azure repositories of the same name shared one row of ticks.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75c0bb8. Configure here.

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
…f it
A page Azure names but the read stops at was reported as the end of the change, so files it never listed read as removed from the pull request.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the Azure-safe repository selector is applied to the right-panel branch but not to the sibling /pull-requests navigation in the same function, so an Azure DevOps link still opens a ref the server refuses.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/lib/openPullRequestLink.ts Outdated
… per file
One file's diff was bounded but a slice of them was not, and the page opening a review passed the URL's spelling of a repository where the panel passed the server's.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…th no hunks
A failed side read was degraded to a file listed without its hunks whatever the reason, so a signed-out or throttled host produced a whole change of empty files instead of a failure the app pauses on.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the new "viewed" segment in the Code tab toolbar cannot shrink, which makes the already-tight meta strip overflow sooner in narrow panels. Everything else in scope looks consistent — the checkbox uses the shared Checkbox primitive with the same label-wrapping pattern as the other call sites, the render props stay identity-stable through refs with the marks folded into item.version, and usePullRequestFilesViewed resolves its environment from the explicit environmentId prop.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One convention finding: a known-tag recovery is expressed with Effect.catchIf instead of Effect.catchTags. Everything else in the new Effect service code (the PullRequestFilesViewed repository module's Context.Service/make/layer shape, namespace imports, dependency acquisition via yield*, and the new structured error mappings) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…strip
The count was spelled out at a fixed width beside controls that cannot give way, and the Azure per-file recovery named its failures through a predicate where the tags say it plainly.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@yordis
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(web): pull request files can be marked as viewed - #7721

Open
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream
Open

feat(web): pull request files can be marked as viewed#7721
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream

Conversation

@yordis

@yordisyordis commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
  • A review spread over an afternoon, or picked up on a second machine, starts again from the top every time, so large changes get read in the browser and only small ones stay here.
  • The marks are the host's wherever the host keeps any, because a checkbox that looks like the one GitHub shows and quietly disagrees with it leaves a reviewer unsure which of the two knows what they have actually read.
  • GitLab keeps its own viewed files in one browser's local storage, where nothing outside that browser can read or write them, so there is no shared record to be the host's. The marks are this environment's instead, and the surface says so rather than implying gitlab.com will show them.
  • Declared per provider as where the marks live rather than whether they exist, so a host with nowhere to keep them hides the control instead of offering one that cannot keep its promise.
  • Read apart from the patch, because viewed state moves on every press and a patch moves only when somebody pushes; sharing one read would mean either re-fetching a three-hundred-file diff per checkbox or showing a reader their own last press as stale.

Note

Medium Risk
Large cross-provider pull-request surface area (new persistence, caching, and Azure diff assembly); regressions could affect diff accuracy, viewed-state correctness, or Azure/GitHub API behavior under rate limits.

Overview
Adds per-file “viewed” tracking for pull requests end-to-end on the server: new filesViewed / setFilesViewed on PullRequestService, RPC auth for pullRequestsFilesViewed and pullRequestsSetFilesViewed, and provider support split by viewedFiles: "host" (GitHub GraphQL read/write) vs "environment" (SQLite marks plus host file revision lookups to detect pushes).

For environment-backed providers, migration 044 creates pull_request_files_viewed and PullRequestFilesViewedRepository stores cleared paths with a revision stamp; the service compares revisions (with caching, stale-while-revalidate, per-PR write ordering, and invalidation) so re-pushed files show as dismissed without re-fetching the whole diff on every checkbox.

Azure DevOps gains a real Code tab: capabilities.diff flips on, REST moves from az rest to az devops invoke, iteration changes are paged and turned into unified patches via the new diff dependency and azureDevOpsDiff.ts, plus getFileRevisions for viewed-state staleness. Bitbucket and GitLab add getFileRevisions (patch index lines / head blob GraphQL). Extensive unit tests cover paging limits, truncated diffs, and mark isolation across repos and PR numbers.

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

Note

Add ability to mark pull request files as viewed across providers

  • Adds a "Viewed" checkbox to the PR code tab UI. Toggling a file collapses it and marks it viewed; changing the file's head revision shows a "Changed" indicator.
  • GitHub viewed marks are stored on the host. GitLab, Bitbucket, and Azure DevOps marks are stored in the environment via a new SQLite table created by migration 044_PullRequestFilesViewed.
  • The server fetches per-path head revisions to detect stale marks for environment-scoped providers.
  • Risk: Azure DevOps PRs now use AzureDevOpsRepositoryLocation instead of threadsUrl. normalizeGitRemoteUrl now normalizes Azure DevOps SSH remotes to web spelling.

Macroscope summarized 6e9d61c.

@coderabbitai

coderabbitaiBot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db5e0854-7bcc-4529-902c-248e00159c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 20, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI: the new viewed-file checkbox in the diff header, the counter in the toolbar, and the fold/overlay logic modules. Two findings, both on changed lines in PullRequestCodeTab.tsx.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a substantial cross-provider viewed-file workflow with persistent state, new authenticated RPCs, provider integrations, and a newly enabled Azure DevOps diff path. It also changes authorization behavior and provider capability defaults, so the production blast radius warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI changes (PullRequestCodeTab.tsx, pullRequestDiff.logic.ts, pullRequestFilesViewed.logic.ts, usePullRequestFilesViewed.ts) for shared-primitive use, Tailwind/CSS ownership and virtualizer behavior.

Both findings from the previous run are resolved: the Checkbox no longer carries a partial size-* override, and truncated is now threaded through the hook and surfaced in the meta line with the same Tooltip + TriangleAlertIcon treatment the withheld-diff caveat uses. Two remaining items below — one virtualizer regression risk, one accessible-name issue on the new control.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
yordis added 10 commits August 20, 2026 18:06
A review spread over an afternoon, or picked up on a second machine, started
again from the top every time, so large changes were read in the browser and
only small ones stayed here.
The marks are the host's rather than ours because a checkbox only this app
remembers is worse than none: it looks like the one GitHub shows, disagrees
with it, and leaves a reviewer unsure which of the two knows what they have
actually read.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he window resets
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…since
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…at it is partial
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he wrong way
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…count
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…carries
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A press moved the whole viewed view, and every file header on screen was memoized on it, so one tick cost a rebuild of all of them. The same mark also has to say whether the control is offered at all, or a capability arriving after the first paint leaves the headers without a box.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
It borrowed its name from the label beside it, and that label turns into "Changed" once the file has been pushed to, leaving a reader who cannot see it with no idea what the box does.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordisforce-pushed the yordis/feat-pr-files-viewed-upstream branch from 1296cb6 to 6b44e51CompareAugust 20, 2026 22:07
@yordis

yordis commented Aug 20, 2026

Copy link
Copy Markdown
ContributorAuthor

GitHub

Screen.Recording.2026-08-20.at.6.15.29.PM.mov

The branch had drifted behind main far enough to conflict, which blocked
review of the change itself.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
The button exists for a reader who can see that what they are looking at is
behind, so leaving one part of the page on the last read defeats the point of
pressing it. A push since that read is exactly when the mark beside a ticked
file stops being true.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
An error the reader cannot act on, about a press they have already replaced,
reads as their current tick having been lost when it has not.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new viewed-files hook: the command-failure path surfaces an error toast for interrupt-only failures, which diverges from the repo's established useAtomCommand failure convention. Everything else in the web scope (Checkbox/Tooltip primitive use, the amber caveat icon matching the adjacent meta-line pattern, header portal render-prop stability via refs, explicit environmentId threading) looks consistent.

Posted via Macroscope — UI Consistency

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…equest
GitLab keeps viewed files in one browser's local storage, so there was
nothing to read or write there. The marks are this environment's instead,
and the surface says whose they are rather than implying gitlab.com will
show them.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 30, 2026
The only signal that GitLab's own site would never show these ticks was a
tooltip on a small icon, and the first reader to use it went looking for
the marks on gitlab.com instead. The count says it now.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

GitLab

Screen.Recording.2026-08-30.at.10.59.33.AM.mov

The server derives a ref's repository from the project identity, and Azure DevOps
is the one host where that is not the recorded path. Clients spelled it the other
way, so the server turned their refs away at the door and the link fell through to
the browser. The rule now lives where both sides can read it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bitbucket records nothing about what a reviewer has already read, so the marks are
this environment's own. Without a revision to compare against they could not tell a
file still as it was read from one pushed to since, which is the distinction that
makes the marks worth keeping at all.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The adapter never read what a pull request changed, so the panel reported no files
and the Code tab was hidden outright. Azure serves no patch of its own, and its
record of what a reviewer has read sits behind an endpoint it has never released,
so both are answered from what it does state: the files an iteration changed, and
the blob each side holds.
Reading the conversation moved off `az rest` in the process. It mints its own token
against whichever tenant `az` defaults to, which is not the one an organisation
necessarily lives in, so that read had been failing wherever the two differ.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

Azure DevOps

CleanShot.2026-08-30.at.18.22.41.mp4

@yordis

Copy link
Copy Markdown
ContributorAuthor

Bitbucket

CleanShot.2026-08-30.at.18.30.34.mp4

The marks are this environment's own rows and cost nothing to read, but every read
of them blocked on a host call that only the Changed badge needed, and a press paid
for that call twice over. On Azure, where each one is a process spawn, coming back
to a review left the checkboxes empty for seconds at a time.
Correcting a badge a moment late is cheaper than making a reader wait for it, so a
held answer now stands while the next one is fetched. The press itself still asks
outright, since it stamps what it stores.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestProvider.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
Azure pages its change list and answers for a binary file in an encoding of its own, so a large pull request came back as part of a change presented as the whole of it, and a file whose contents az would not hand over took the rest of the slice down with it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A host that answers for part of a change said nothing about the rest, and that silence was read as deletion, so every file past the cut was cleared over a version nobody ever looked at. Two presses on one file could also finish in the other order, and two Azure repositories of the same name shared one row of ticks.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75c0bb8. Configure here.

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
…f it
A page Azure names but the read stops at was reported as the end of the change, so files it never listed read as removed from the pull request.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the Azure-safe repository selector is applied to the right-panel branch but not to the sibling /pull-requests navigation in the same function, so an Azure DevOps link still opens a ref the server refuses.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/lib/openPullRequestLink.ts Outdated
… per file
One file's diff was bounded but a slice of them was not, and the page opening a review passed the URL's spelling of a repository where the panel passed the server's.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…th no hunks
A failed side read was degraded to a file listed without its hunks whatever the reason, so a signed-out or throttled host produced a whole change of empty files instead of a failure the app pauses on.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the new "viewed" segment in the Code tab toolbar cannot shrink, which makes the already-tight meta strip overflow sooner in narrow panels. Everything else in scope looks consistent — the checkbox uses the shared Checkbox primitive with the same label-wrapping pattern as the other call sites, the render props stay identity-stable through refs with the marks folded into item.version, and usePullRequestFilesViewed resolves its environment from the explicit environmentId prop.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One convention finding: a known-tag recovery is expressed with Effect.catchIf instead of Effect.catchTags. Everything else in the new Effect service code (the PullRequestFilesViewed repository module's Context.Service/make/layer shape, namespace imports, dependency acquisition via yield*, and the new structured error mappings) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…strip
The count was spelled out at a fixed width beside controls that cannot give way, and the Azure per-file recovery named its failures through a predicate where the tags say it plainly.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@yordis
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): pull request files can be marked as viewed - #7721

Open
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream
Open

feat(web): pull request files can be marked as viewed#7721
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream

Conversation

@yordis

@yordisyordis commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
  • A review spread over an afternoon, or picked up on a second machine, starts again from the top every time, so large changes get read in the browser and only small ones stay here.
  • The marks are the host's wherever the host keeps any, because a checkbox that looks like the one GitHub shows and quietly disagrees with it leaves a reviewer unsure which of the two knows what they have actually read.
  • GitLab keeps its own viewed files in one browser's local storage, where nothing outside that browser can read or write them, so there is no shared record to be the host's. The marks are this environment's instead, and the surface says so rather than implying gitlab.com will show them.
  • Declared per provider as where the marks live rather than whether they exist, so a host with nowhere to keep them hides the control instead of offering one that cannot keep its promise.
  • Read apart from the patch, because viewed state moves on every press and a patch moves only when somebody pushes; sharing one read would mean either re-fetching a three-hundred-file diff per checkbox or showing a reader their own last press as stale.

Note

Medium Risk
Large cross-provider pull-request surface area (new persistence, caching, and Azure diff assembly); regressions could affect diff accuracy, viewed-state correctness, or Azure/GitHub API behavior under rate limits.

Overview
Adds per-file “viewed” tracking for pull requests end-to-end on the server: new filesViewed / setFilesViewed on PullRequestService, RPC auth for pullRequestsFilesViewed and pullRequestsSetFilesViewed, and provider support split by viewedFiles: "host" (GitHub GraphQL read/write) vs "environment" (SQLite marks plus host file revision lookups to detect pushes).

For environment-backed providers, migration 044 creates pull_request_files_viewed and PullRequestFilesViewedRepository stores cleared paths with a revision stamp; the service compares revisions (with caching, stale-while-revalidate, per-PR write ordering, and invalidation) so re-pushed files show as dismissed without re-fetching the whole diff on every checkbox.

Azure DevOps gains a real Code tab: capabilities.diff flips on, REST moves from az rest to az devops invoke, iteration changes are paged and turned into unified patches via the new diff dependency and azureDevOpsDiff.ts, plus getFileRevisions for viewed-state staleness. Bitbucket and GitLab add getFileRevisions (patch index lines / head blob GraphQL). Extensive unit tests cover paging limits, truncated diffs, and mark isolation across repos and PR numbers.

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

Note

Add ability to mark pull request files as viewed across providers

  • Adds a "Viewed" checkbox to the PR code tab UI. Toggling a file collapses it and marks it viewed; changing the file's head revision shows a "Changed" indicator.
  • GitHub viewed marks are stored on the host. GitLab, Bitbucket, and Azure DevOps marks are stored in the environment via a new SQLite table created by migration 044_PullRequestFilesViewed.
  • The server fetches per-path head revisions to detect stale marks for environment-scoped providers.
  • Risk: Azure DevOps PRs now use AzureDevOpsRepositoryLocation instead of threadsUrl. normalizeGitRemoteUrl now normalizes Azure DevOps SSH remotes to web spelling.

Macroscope summarized 6e9d61c.

@coderabbitai

coderabbitaiBot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db5e0854-7bcc-4529-902c-248e00159c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 20, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI: the new viewed-file checkbox in the diff header, the counter in the toolbar, and the fold/overlay logic modules. Two findings, both on changed lines in PullRequestCodeTab.tsx.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a substantial cross-provider viewed-file workflow with persistent state, new authenticated RPCs, provider integrations, and a newly enabled Azure DevOps diff path. It also changes authorization behavior and provider capability defaults, so the production blast radius warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI changes (PullRequestCodeTab.tsx, pullRequestDiff.logic.ts, pullRequestFilesViewed.logic.ts, usePullRequestFilesViewed.ts) for shared-primitive use, Tailwind/CSS ownership and virtualizer behavior.

Both findings from the previous run are resolved: the Checkbox no longer carries a partial size-* override, and truncated is now threaded through the hook and surfaced in the meta line with the same Tooltip + TriangleAlertIcon treatment the withheld-diff caveat uses. Two remaining items below — one virtualizer regression risk, one accessible-name issue on the new control.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
yordis added 10 commits August 20, 2026 18:06
A review spread over an afternoon, or picked up on a second machine, started
again from the top every time, so large changes were read in the browser and
only small ones stayed here.
The marks are the host's rather than ours because a checkbox only this app
remembers is worse than none: it looks like the one GitHub shows, disagrees
with it, and leaves a reviewer unsure which of the two knows what they have
actually read.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he window resets
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…since
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…at it is partial
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he wrong way
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…count
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…carries
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A press moved the whole viewed view, and every file header on screen was memoized on it, so one tick cost a rebuild of all of them. The same mark also has to say whether the control is offered at all, or a capability arriving after the first paint leaves the headers without a box.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
It borrowed its name from the label beside it, and that label turns into "Changed" once the file has been pushed to, leaving a reader who cannot see it with no idea what the box does.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordisforce-pushed the yordis/feat-pr-files-viewed-upstream branch from 1296cb6 to 6b44e51CompareAugust 20, 2026 22:07
@yordis

yordis commented Aug 20, 2026

Copy link
Copy Markdown
ContributorAuthor

GitHub

Screen.Recording.2026-08-20.at.6.15.29.PM.mov

The branch had drifted behind main far enough to conflict, which blocked
review of the change itself.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
The button exists for a reader who can see that what they are looking at is
behind, so leaving one part of the page on the last read defeats the point of
pressing it. A push since that read is exactly when the mark beside a ticked
file stops being true.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
An error the reader cannot act on, about a press they have already replaced,
reads as their current tick having been lost when it has not.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new viewed-files hook: the command-failure path surfaces an error toast for interrupt-only failures, which diverges from the repo's established useAtomCommand failure convention. Everything else in the web scope (Checkbox/Tooltip primitive use, the amber caveat icon matching the adjacent meta-line pattern, header portal render-prop stability via refs, explicit environmentId threading) looks consistent.

Posted via Macroscope — UI Consistency

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…equest
GitLab keeps viewed files in one browser's local storage, so there was
nothing to read or write there. The marks are this environment's instead,
and the surface says whose they are rather than implying gitlab.com will
show them.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 30, 2026
The only signal that GitLab's own site would never show these ticks was a
tooltip on a small icon, and the first reader to use it went looking for
the marks on gitlab.com instead. The count says it now.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

GitLab

Screen.Recording.2026-08-30.at.10.59.33.AM.mov

The server derives a ref's repository from the project identity, and Azure DevOps
is the one host where that is not the recorded path. Clients spelled it the other
way, so the server turned their refs away at the door and the link fell through to
the browser. The rule now lives where both sides can read it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bitbucket records nothing about what a reviewer has already read, so the marks are
this environment's own. Without a revision to compare against they could not tell a
file still as it was read from one pushed to since, which is the distinction that
makes the marks worth keeping at all.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The adapter never read what a pull request changed, so the panel reported no files
and the Code tab was hidden outright. Azure serves no patch of its own, and its
record of what a reviewer has read sits behind an endpoint it has never released,
so both are answered from what it does state: the files an iteration changed, and
the blob each side holds.
Reading the conversation moved off `az rest` in the process. It mints its own token
against whichever tenant `az` defaults to, which is not the one an organisation
necessarily lives in, so that read had been failing wherever the two differ.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

Azure DevOps

CleanShot.2026-08-30.at.18.22.41.mp4

@yordis

Copy link
Copy Markdown
ContributorAuthor

Bitbucket

CleanShot.2026-08-30.at.18.30.34.mp4

The marks are this environment's own rows and cost nothing to read, but every read
of them blocked on a host call that only the Changed badge needed, and a press paid
for that call twice over. On Azure, where each one is a process spawn, coming back
to a review left the checkboxes empty for seconds at a time.
Correcting a badge a moment late is cheaper than making a reader wait for it, so a
held answer now stands while the next one is fetched. The press itself still asks
outright, since it stamps what it stores.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestProvider.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
Azure pages its change list and answers for a binary file in an encoding of its own, so a large pull request came back as part of a change presented as the whole of it, and a file whose contents az would not hand over took the rest of the slice down with it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A host that answers for part of a change said nothing about the rest, and that silence was read as deletion, so every file past the cut was cleared over a version nobody ever looked at. Two presses on one file could also finish in the other order, and two Azure repositories of the same name shared one row of ticks.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75c0bb8. Configure here.

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
…f it
A page Azure names but the read stops at was reported as the end of the change, so files it never listed read as removed from the pull request.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the Azure-safe repository selector is applied to the right-panel branch but not to the sibling /pull-requests navigation in the same function, so an Azure DevOps link still opens a ref the server refuses.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/lib/openPullRequestLink.ts Outdated
… per file
One file's diff was bounded but a slice of them was not, and the page opening a review passed the URL's spelling of a repository where the panel passed the server's.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…th no hunks
A failed side read was degraded to a file listed without its hunks whatever the reason, so a signed-out or throttled host produced a whole change of empty files instead of a failure the app pauses on.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the new "viewed" segment in the Code tab toolbar cannot shrink, which makes the already-tight meta strip overflow sooner in narrow panels. Everything else in scope looks consistent — the checkbox uses the shared Checkbox primitive with the same label-wrapping pattern as the other call sites, the render props stay identity-stable through refs with the marks folded into item.version, and usePullRequestFilesViewed resolves its environment from the explicit environmentId prop.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One convention finding: a known-tag recovery is expressed with Effect.catchIf instead of Effect.catchTags. Everything else in the new Effect service code (the PullRequestFilesViewed repository module's Context.Service/make/layer shape, namespace imports, dependency acquisition via yield*, and the new structured error mappings) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…strip
The count was spelled out at a fixed width beside controls that cannot give way, and the Azure per-file recovery named its failures through a predicate where the tags say it plainly.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@yordis
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): pull request files can be marked as viewed - #7721

Open
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream
Open

feat(web): pull request files can be marked as viewed#7721
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream

Conversation

@yordis

@yordisyordis commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
  • A review spread over an afternoon, or picked up on a second machine, starts again from the top every time, so large changes get read in the browser and only small ones stay here.
  • The marks are the host's wherever the host keeps any, because a checkbox that looks like the one GitHub shows and quietly disagrees with it leaves a reviewer unsure which of the two knows what they have actually read.
  • GitLab keeps its own viewed files in one browser's local storage, where nothing outside that browser can read or write them, so there is no shared record to be the host's. The marks are this environment's instead, and the surface says so rather than implying gitlab.com will show them.
  • Declared per provider as where the marks live rather than whether they exist, so a host with nowhere to keep them hides the control instead of offering one that cannot keep its promise.
  • Read apart from the patch, because viewed state moves on every press and a patch moves only when somebody pushes; sharing one read would mean either re-fetching a three-hundred-file diff per checkbox or showing a reader their own last press as stale.

Note

Medium Risk
Large cross-provider pull-request surface area (new persistence, caching, and Azure diff assembly); regressions could affect diff accuracy, viewed-state correctness, or Azure/GitHub API behavior under rate limits.

Overview
Adds per-file “viewed” tracking for pull requests end-to-end on the server: new filesViewed / setFilesViewed on PullRequestService, RPC auth for pullRequestsFilesViewed and pullRequestsSetFilesViewed, and provider support split by viewedFiles: "host" (GitHub GraphQL read/write) vs "environment" (SQLite marks plus host file revision lookups to detect pushes).

For environment-backed providers, migration 044 creates pull_request_files_viewed and PullRequestFilesViewedRepository stores cleared paths with a revision stamp; the service compares revisions (with caching, stale-while-revalidate, per-PR write ordering, and invalidation) so re-pushed files show as dismissed without re-fetching the whole diff on every checkbox.

Azure DevOps gains a real Code tab: capabilities.diff flips on, REST moves from az rest to az devops invoke, iteration changes are paged and turned into unified patches via the new diff dependency and azureDevOpsDiff.ts, plus getFileRevisions for viewed-state staleness. Bitbucket and GitLab add getFileRevisions (patch index lines / head blob GraphQL). Extensive unit tests cover paging limits, truncated diffs, and mark isolation across repos and PR numbers.

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

Note

Add ability to mark pull request files as viewed across providers

  • Adds a "Viewed" checkbox to the PR code tab UI. Toggling a file collapses it and marks it viewed; changing the file's head revision shows a "Changed" indicator.
  • GitHub viewed marks are stored on the host. GitLab, Bitbucket, and Azure DevOps marks are stored in the environment via a new SQLite table created by migration 044_PullRequestFilesViewed.
  • The server fetches per-path head revisions to detect stale marks for environment-scoped providers.
  • Risk: Azure DevOps PRs now use AzureDevOpsRepositoryLocation instead of threadsUrl. normalizeGitRemoteUrl now normalizes Azure DevOps SSH remotes to web spelling.

Macroscope summarized 6e9d61c.

@coderabbitai

coderabbitaiBot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db5e0854-7bcc-4529-902c-248e00159c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 20, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI: the new viewed-file checkbox in the diff header, the counter in the toolbar, and the fold/overlay logic modules. Two findings, both on changed lines in PullRequestCodeTab.tsx.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a substantial cross-provider viewed-file workflow with persistent state, new authenticated RPCs, provider integrations, and a newly enabled Azure DevOps diff path. It also changes authorization behavior and provider capability defaults, so the production blast radius warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI changes (PullRequestCodeTab.tsx, pullRequestDiff.logic.ts, pullRequestFilesViewed.logic.ts, usePullRequestFilesViewed.ts) for shared-primitive use, Tailwind/CSS ownership and virtualizer behavior.

Both findings from the previous run are resolved: the Checkbox no longer carries a partial size-* override, and truncated is now threaded through the hook and surfaced in the meta line with the same Tooltip + TriangleAlertIcon treatment the withheld-diff caveat uses. Two remaining items below — one virtualizer regression risk, one accessible-name issue on the new control.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
yordis added 10 commits August 20, 2026 18:06
A review spread over an afternoon, or picked up on a second machine, started
again from the top every time, so large changes were read in the browser and
only small ones stayed here.
The marks are the host's rather than ours because a checkbox only this app
remembers is worse than none: it looks like the one GitHub shows, disagrees
with it, and leaves a reviewer unsure which of the two knows what they have
actually read.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he window resets
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…since
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…at it is partial
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he wrong way
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…count
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…carries
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A press moved the whole viewed view, and every file header on screen was memoized on it, so one tick cost a rebuild of all of them. The same mark also has to say whether the control is offered at all, or a capability arriving after the first paint leaves the headers without a box.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
It borrowed its name from the label beside it, and that label turns into "Changed" once the file has been pushed to, leaving a reader who cannot see it with no idea what the box does.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordisforce-pushed the yordis/feat-pr-files-viewed-upstream branch from 1296cb6 to 6b44e51CompareAugust 20, 2026 22:07
@yordis

yordis commented Aug 20, 2026

Copy link
Copy Markdown
ContributorAuthor

GitHub

Screen.Recording.2026-08-20.at.6.15.29.PM.mov

The branch had drifted behind main far enough to conflict, which blocked
review of the change itself.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
The button exists for a reader who can see that what they are looking at is
behind, so leaving one part of the page on the last read defeats the point of
pressing it. A push since that read is exactly when the mark beside a ticked
file stops being true.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
An error the reader cannot act on, about a press they have already replaced,
reads as their current tick having been lost when it has not.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new viewed-files hook: the command-failure path surfaces an error toast for interrupt-only failures, which diverges from the repo's established useAtomCommand failure convention. Everything else in the web scope (Checkbox/Tooltip primitive use, the amber caveat icon matching the adjacent meta-line pattern, header portal render-prop stability via refs, explicit environmentId threading) looks consistent.

Posted via Macroscope — UI Consistency

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…equest
GitLab keeps viewed files in one browser's local storage, so there was
nothing to read or write there. The marks are this environment's instead,
and the surface says whose they are rather than implying gitlab.com will
show them.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 30, 2026
The only signal that GitLab's own site would never show these ticks was a
tooltip on a small icon, and the first reader to use it went looking for
the marks on gitlab.com instead. The count says it now.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

GitLab

Screen.Recording.2026-08-30.at.10.59.33.AM.mov

The server derives a ref's repository from the project identity, and Azure DevOps
is the one host where that is not the recorded path. Clients spelled it the other
way, so the server turned their refs away at the door and the link fell through to
the browser. The rule now lives where both sides can read it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bitbucket records nothing about what a reviewer has already read, so the marks are
this environment's own. Without a revision to compare against they could not tell a
file still as it was read from one pushed to since, which is the distinction that
makes the marks worth keeping at all.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The adapter never read what a pull request changed, so the panel reported no files
and the Code tab was hidden outright. Azure serves no patch of its own, and its
record of what a reviewer has read sits behind an endpoint it has never released,
so both are answered from what it does state: the files an iteration changed, and
the blob each side holds.
Reading the conversation moved off `az rest` in the process. It mints its own token
against whichever tenant `az` defaults to, which is not the one an organisation
necessarily lives in, so that read had been failing wherever the two differ.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

Azure DevOps

CleanShot.2026-08-30.at.18.22.41.mp4

@yordis

Copy link
Copy Markdown
ContributorAuthor

Bitbucket

CleanShot.2026-08-30.at.18.30.34.mp4

The marks are this environment's own rows and cost nothing to read, but every read
of them blocked on a host call that only the Changed badge needed, and a press paid
for that call twice over. On Azure, where each one is a process spawn, coming back
to a review left the checkboxes empty for seconds at a time.
Correcting a badge a moment late is cheaper than making a reader wait for it, so a
held answer now stands while the next one is fetched. The press itself still asks
outright, since it stamps what it stores.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestProvider.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
Azure pages its change list and answers for a binary file in an encoding of its own, so a large pull request came back as part of a change presented as the whole of it, and a file whose contents az would not hand over took the rest of the slice down with it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A host that answers for part of a change said nothing about the rest, and that silence was read as deletion, so every file past the cut was cleared over a version nobody ever looked at. Two presses on one file could also finish in the other order, and two Azure repositories of the same name shared one row of ticks.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75c0bb8. Configure here.

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
…f it
A page Azure names but the read stops at was reported as the end of the change, so files it never listed read as removed from the pull request.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the Azure-safe repository selector is applied to the right-panel branch but not to the sibling /pull-requests navigation in the same function, so an Azure DevOps link still opens a ref the server refuses.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/lib/openPullRequestLink.ts Outdated
… per file
One file's diff was bounded but a slice of them was not, and the page opening a review passed the URL's spelling of a repository where the panel passed the server's.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…th no hunks
A failed side read was degraded to a file listed without its hunks whatever the reason, so a signed-out or throttled host produced a whole change of empty files instead of a failure the app pauses on.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the new "viewed" segment in the Code tab toolbar cannot shrink, which makes the already-tight meta strip overflow sooner in narrow panels. Everything else in scope looks consistent — the checkbox uses the shared Checkbox primitive with the same label-wrapping pattern as the other call sites, the render props stay identity-stable through refs with the marks folded into item.version, and usePullRequestFilesViewed resolves its environment from the explicit environmentId prop.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One convention finding: a known-tag recovery is expressed with Effect.catchIf instead of Effect.catchTags. Everything else in the new Effect service code (the PullRequestFilesViewed repository module's Context.Service/make/layer shape, namespace imports, dependency acquisition via yield*, and the new structured error mappings) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…strip
The count was spelled out at a fixed width beside controls that cannot give way, and the Azure per-file recovery named its failures through a predicate where the tags say it plainly.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@yordis
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(web): pull request files can be marked as viewed - #7721

Open
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream
Open

feat(web): pull request files can be marked as viewed#7721
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream

Conversation

@yordis

@yordisyordis commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
  • A review spread over an afternoon, or picked up on a second machine, starts again from the top every time, so large changes get read in the browser and only small ones stay here.
  • The marks are the host's wherever the host keeps any, because a checkbox that looks like the one GitHub shows and quietly disagrees with it leaves a reviewer unsure which of the two knows what they have actually read.
  • GitLab keeps its own viewed files in one browser's local storage, where nothing outside that browser can read or write them, so there is no shared record to be the host's. The marks are this environment's instead, and the surface says so rather than implying gitlab.com will show them.
  • Declared per provider as where the marks live rather than whether they exist, so a host with nowhere to keep them hides the control instead of offering one that cannot keep its promise.
  • Read apart from the patch, because viewed state moves on every press and a patch moves only when somebody pushes; sharing one read would mean either re-fetching a three-hundred-file diff per checkbox or showing a reader their own last press as stale.

Note

Medium Risk
Large cross-provider pull-request surface area (new persistence, caching, and Azure diff assembly); regressions could affect diff accuracy, viewed-state correctness, or Azure/GitHub API behavior under rate limits.

Overview
Adds per-file “viewed” tracking for pull requests end-to-end on the server: new filesViewed / setFilesViewed on PullRequestService, RPC auth for pullRequestsFilesViewed and pullRequestsSetFilesViewed, and provider support split by viewedFiles: "host" (GitHub GraphQL read/write) vs "environment" (SQLite marks plus host file revision lookups to detect pushes).

For environment-backed providers, migration 044 creates pull_request_files_viewed and PullRequestFilesViewedRepository stores cleared paths with a revision stamp; the service compares revisions (with caching, stale-while-revalidate, per-PR write ordering, and invalidation) so re-pushed files show as dismissed without re-fetching the whole diff on every checkbox.

Azure DevOps gains a real Code tab: capabilities.diff flips on, REST moves from az rest to az devops invoke, iteration changes are paged and turned into unified patches via the new diff dependency and azureDevOpsDiff.ts, plus getFileRevisions for viewed-state staleness. Bitbucket and GitLab add getFileRevisions (patch index lines / head blob GraphQL). Extensive unit tests cover paging limits, truncated diffs, and mark isolation across repos and PR numbers.

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

Note

Add ability to mark pull request files as viewed across providers

  • Adds a "Viewed" checkbox to the PR code tab UI. Toggling a file collapses it and marks it viewed; changing the file's head revision shows a "Changed" indicator.
  • GitHub viewed marks are stored on the host. GitLab, Bitbucket, and Azure DevOps marks are stored in the environment via a new SQLite table created by migration 044_PullRequestFilesViewed.
  • The server fetches per-path head revisions to detect stale marks for environment-scoped providers.
  • Risk: Azure DevOps PRs now use AzureDevOpsRepositoryLocation instead of threadsUrl. normalizeGitRemoteUrl now normalizes Azure DevOps SSH remotes to web spelling.

Macroscope summarized 6e9d61c.

@coderabbitai

coderabbitaiBot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db5e0854-7bcc-4529-902c-248e00159c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 20, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI: the new viewed-file checkbox in the diff header, the counter in the toolbar, and the fold/overlay logic modules. Two findings, both on changed lines in PullRequestCodeTab.tsx.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a substantial cross-provider viewed-file workflow with persistent state, new authenticated RPCs, provider integrations, and a newly enabled Azure DevOps diff path. It also changes authorization behavior and provider capability defaults, so the production blast radius warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI changes (PullRequestCodeTab.tsx, pullRequestDiff.logic.ts, pullRequestFilesViewed.logic.ts, usePullRequestFilesViewed.ts) for shared-primitive use, Tailwind/CSS ownership and virtualizer behavior.

Both findings from the previous run are resolved: the Checkbox no longer carries a partial size-* override, and truncated is now threaded through the hook and surfaced in the meta line with the same Tooltip + TriangleAlertIcon treatment the withheld-diff caveat uses. Two remaining items below — one virtualizer regression risk, one accessible-name issue on the new control.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
yordis added 10 commits August 20, 2026 18:06
A review spread over an afternoon, or picked up on a second machine, started
again from the top every time, so large changes were read in the browser and
only small ones stayed here.
The marks are the host's rather than ours because a checkbox only this app
remembers is worse than none: it looks like the one GitHub shows, disagrees
with it, and leaves a reviewer unsure which of the two knows what they have
actually read.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he window resets
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…since
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…at it is partial
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he wrong way
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…count
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…carries
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A press moved the whole viewed view, and every file header on screen was memoized on it, so one tick cost a rebuild of all of them. The same mark also has to say whether the control is offered at all, or a capability arriving after the first paint leaves the headers without a box.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
It borrowed its name from the label beside it, and that label turns into "Changed" once the file has been pushed to, leaving a reader who cannot see it with no idea what the box does.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordisforce-pushed the yordis/feat-pr-files-viewed-upstream branch from 1296cb6 to 6b44e51CompareAugust 20, 2026 22:07
@yordis

yordis commented Aug 20, 2026

Copy link
Copy Markdown
ContributorAuthor

GitHub

Screen.Recording.2026-08-20.at.6.15.29.PM.mov

The branch had drifted behind main far enough to conflict, which blocked
review of the change itself.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
The button exists for a reader who can see that what they are looking at is
behind, so leaving one part of the page on the last read defeats the point of
pressing it. A push since that read is exactly when the mark beside a ticked
file stops being true.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
An error the reader cannot act on, about a press they have already replaced,
reads as their current tick having been lost when it has not.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new viewed-files hook: the command-failure path surfaces an error toast for interrupt-only failures, which diverges from the repo's established useAtomCommand failure convention. Everything else in the web scope (Checkbox/Tooltip primitive use, the amber caveat icon matching the adjacent meta-line pattern, header portal render-prop stability via refs, explicit environmentId threading) looks consistent.

Posted via Macroscope — UI Consistency

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…equest
GitLab keeps viewed files in one browser's local storage, so there was
nothing to read or write there. The marks are this environment's instead,
and the surface says whose they are rather than implying gitlab.com will
show them.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 30, 2026
The only signal that GitLab's own site would never show these ticks was a
tooltip on a small icon, and the first reader to use it went looking for
the marks on gitlab.com instead. The count says it now.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

GitLab

Screen.Recording.2026-08-30.at.10.59.33.AM.mov

The server derives a ref's repository from the project identity, and Azure DevOps
is the one host where that is not the recorded path. Clients spelled it the other
way, so the server turned their refs away at the door and the link fell through to
the browser. The rule now lives where both sides can read it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bitbucket records nothing about what a reviewer has already read, so the marks are
this environment's own. Without a revision to compare against they could not tell a
file still as it was read from one pushed to since, which is the distinction that
makes the marks worth keeping at all.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The adapter never read what a pull request changed, so the panel reported no files
and the Code tab was hidden outright. Azure serves no patch of its own, and its
record of what a reviewer has read sits behind an endpoint it has never released,
so both are answered from what it does state: the files an iteration changed, and
the blob each side holds.
Reading the conversation moved off `az rest` in the process. It mints its own token
against whichever tenant `az` defaults to, which is not the one an organisation
necessarily lives in, so that read had been failing wherever the two differ.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

Azure DevOps

CleanShot.2026-08-30.at.18.22.41.mp4

@yordis

Copy link
Copy Markdown
ContributorAuthor

Bitbucket

CleanShot.2026-08-30.at.18.30.34.mp4

The marks are this environment's own rows and cost nothing to read, but every read
of them blocked on a host call that only the Changed badge needed, and a press paid
for that call twice over. On Azure, where each one is a process spawn, coming back
to a review left the checkboxes empty for seconds at a time.
Correcting a badge a moment late is cheaper than making a reader wait for it, so a
held answer now stands while the next one is fetched. The press itself still asks
outright, since it stamps what it stores.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestProvider.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
Azure pages its change list and answers for a binary file in an encoding of its own, so a large pull request came back as part of a change presented as the whole of it, and a file whose contents az would not hand over took the rest of the slice down with it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A host that answers for part of a change said nothing about the rest, and that silence was read as deletion, so every file past the cut was cleared over a version nobody ever looked at. Two presses on one file could also finish in the other order, and two Azure repositories of the same name shared one row of ticks.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75c0bb8. Configure here.

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
…f it
A page Azure names but the read stops at was reported as the end of the change, so files it never listed read as removed from the pull request.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the Azure-safe repository selector is applied to the right-panel branch but not to the sibling /pull-requests navigation in the same function, so an Azure DevOps link still opens a ref the server refuses.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/lib/openPullRequestLink.ts Outdated
… per file
One file's diff was bounded but a slice of them was not, and the page opening a review passed the URL's spelling of a repository where the panel passed the server's.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…th no hunks
A failed side read was degraded to a file listed without its hunks whatever the reason, so a signed-out or throttled host produced a whole change of empty files instead of a failure the app pauses on.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the new "viewed" segment in the Code tab toolbar cannot shrink, which makes the already-tight meta strip overflow sooner in narrow panels. Everything else in scope looks consistent — the checkbox uses the shared Checkbox primitive with the same label-wrapping pattern as the other call sites, the render props stay identity-stable through refs with the marks folded into item.version, and usePullRequestFilesViewed resolves its environment from the explicit environmentId prop.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One convention finding: a known-tag recovery is expressed with Effect.catchIf instead of Effect.catchTags. Everything else in the new Effect service code (the PullRequestFilesViewed repository module's Context.Service/make/layer shape, namespace imports, dependency acquisition via yield*, and the new structured error mappings) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…strip
The count was spelled out at a fixed width beside controls that cannot give way, and the Azure per-file recovery named its failures through a predicate where the tags say it plainly.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@yordis
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): pull request files can be marked as viewed - #7721

Open
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream
Open

feat(web): pull request files can be marked as viewed#7721
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream

Conversation

@yordis

@yordisyordis commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
  • A review spread over an afternoon, or picked up on a second machine, starts again from the top every time, so large changes get read in the browser and only small ones stay here.
  • The marks are the host's wherever the host keeps any, because a checkbox that looks like the one GitHub shows and quietly disagrees with it leaves a reviewer unsure which of the two knows what they have actually read.
  • GitLab keeps its own viewed files in one browser's local storage, where nothing outside that browser can read or write them, so there is no shared record to be the host's. The marks are this environment's instead, and the surface says so rather than implying gitlab.com will show them.
  • Declared per provider as where the marks live rather than whether they exist, so a host with nowhere to keep them hides the control instead of offering one that cannot keep its promise.
  • Read apart from the patch, because viewed state moves on every press and a patch moves only when somebody pushes; sharing one read would mean either re-fetching a three-hundred-file diff per checkbox or showing a reader their own last press as stale.

Note

Medium Risk
Large cross-provider pull-request surface area (new persistence, caching, and Azure diff assembly); regressions could affect diff accuracy, viewed-state correctness, or Azure/GitHub API behavior under rate limits.

Overview
Adds per-file “viewed” tracking for pull requests end-to-end on the server: new filesViewed / setFilesViewed on PullRequestService, RPC auth for pullRequestsFilesViewed and pullRequestsSetFilesViewed, and provider support split by viewedFiles: "host" (GitHub GraphQL read/write) vs "environment" (SQLite marks plus host file revision lookups to detect pushes).

For environment-backed providers, migration 044 creates pull_request_files_viewed and PullRequestFilesViewedRepository stores cleared paths with a revision stamp; the service compares revisions (with caching, stale-while-revalidate, per-PR write ordering, and invalidation) so re-pushed files show as dismissed without re-fetching the whole diff on every checkbox.

Azure DevOps gains a real Code tab: capabilities.diff flips on, REST moves from az rest to az devops invoke, iteration changes are paged and turned into unified patches via the new diff dependency and azureDevOpsDiff.ts, plus getFileRevisions for viewed-state staleness. Bitbucket and GitLab add getFileRevisions (patch index lines / head blob GraphQL). Extensive unit tests cover paging limits, truncated diffs, and mark isolation across repos and PR numbers.

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

Note

Add ability to mark pull request files as viewed across providers

  • Adds a "Viewed" checkbox to the PR code tab UI. Toggling a file collapses it and marks it viewed; changing the file's head revision shows a "Changed" indicator.
  • GitHub viewed marks are stored on the host. GitLab, Bitbucket, and Azure DevOps marks are stored in the environment via a new SQLite table created by migration 044_PullRequestFilesViewed.
  • The server fetches per-path head revisions to detect stale marks for environment-scoped providers.
  • Risk: Azure DevOps PRs now use AzureDevOpsRepositoryLocation instead of threadsUrl. normalizeGitRemoteUrl now normalizes Azure DevOps SSH remotes to web spelling.

Macroscope summarized 6e9d61c.

@coderabbitai

coderabbitaiBot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db5e0854-7bcc-4529-902c-248e00159c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 20, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI: the new viewed-file checkbox in the diff header, the counter in the toolbar, and the fold/overlay logic modules. Two findings, both on changed lines in PullRequestCodeTab.tsx.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a substantial cross-provider viewed-file workflow with persistent state, new authenticated RPCs, provider integrations, and a newly enabled Azure DevOps diff path. It also changes authorization behavior and provider capability defaults, so the production blast radius warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI changes (PullRequestCodeTab.tsx, pullRequestDiff.logic.ts, pullRequestFilesViewed.logic.ts, usePullRequestFilesViewed.ts) for shared-primitive use, Tailwind/CSS ownership and virtualizer behavior.

Both findings from the previous run are resolved: the Checkbox no longer carries a partial size-* override, and truncated is now threaded through the hook and surfaced in the meta line with the same Tooltip + TriangleAlertIcon treatment the withheld-diff caveat uses. Two remaining items below — one virtualizer regression risk, one accessible-name issue on the new control.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
yordis added 10 commits August 20, 2026 18:06
A review spread over an afternoon, or picked up on a second machine, started
again from the top every time, so large changes were read in the browser and
only small ones stayed here.
The marks are the host's rather than ours because a checkbox only this app
remembers is worse than none: it looks like the one GitHub shows, disagrees
with it, and leaves a reviewer unsure which of the two knows what they have
actually read.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he window resets
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…since
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…at it is partial
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he wrong way
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…count
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…carries
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A press moved the whole viewed view, and every file header on screen was memoized on it, so one tick cost a rebuild of all of them. The same mark also has to say whether the control is offered at all, or a capability arriving after the first paint leaves the headers without a box.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
It borrowed its name from the label beside it, and that label turns into "Changed" once the file has been pushed to, leaving a reader who cannot see it with no idea what the box does.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordisforce-pushed the yordis/feat-pr-files-viewed-upstream branch from 1296cb6 to 6b44e51CompareAugust 20, 2026 22:07
@yordis

yordis commented Aug 20, 2026

Copy link
Copy Markdown
ContributorAuthor

GitHub

Screen.Recording.2026-08-20.at.6.15.29.PM.mov

The branch had drifted behind main far enough to conflict, which blocked
review of the change itself.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
The button exists for a reader who can see that what they are looking at is
behind, so leaving one part of the page on the last read defeats the point of
pressing it. A push since that read is exactly when the mark beside a ticked
file stops being true.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
An error the reader cannot act on, about a press they have already replaced,
reads as their current tick having been lost when it has not.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new viewed-files hook: the command-failure path surfaces an error toast for interrupt-only failures, which diverges from the repo's established useAtomCommand failure convention. Everything else in the web scope (Checkbox/Tooltip primitive use, the amber caveat icon matching the adjacent meta-line pattern, header portal render-prop stability via refs, explicit environmentId threading) looks consistent.

Posted via Macroscope — UI Consistency

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…equest
GitLab keeps viewed files in one browser's local storage, so there was
nothing to read or write there. The marks are this environment's instead,
and the surface says whose they are rather than implying gitlab.com will
show them.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 30, 2026
The only signal that GitLab's own site would never show these ticks was a
tooltip on a small icon, and the first reader to use it went looking for
the marks on gitlab.com instead. The count says it now.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

GitLab

Screen.Recording.2026-08-30.at.10.59.33.AM.mov

The server derives a ref's repository from the project identity, and Azure DevOps
is the one host where that is not the recorded path. Clients spelled it the other
way, so the server turned their refs away at the door and the link fell through to
the browser. The rule now lives where both sides can read it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bitbucket records nothing about what a reviewer has already read, so the marks are
this environment's own. Without a revision to compare against they could not tell a
file still as it was read from one pushed to since, which is the distinction that
makes the marks worth keeping at all.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The adapter never read what a pull request changed, so the panel reported no files
and the Code tab was hidden outright. Azure serves no patch of its own, and its
record of what a reviewer has read sits behind an endpoint it has never released,
so both are answered from what it does state: the files an iteration changed, and
the blob each side holds.
Reading the conversation moved off `az rest` in the process. It mints its own token
against whichever tenant `az` defaults to, which is not the one an organisation
necessarily lives in, so that read had been failing wherever the two differ.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

Azure DevOps

CleanShot.2026-08-30.at.18.22.41.mp4

@yordis

Copy link
Copy Markdown
ContributorAuthor

Bitbucket

CleanShot.2026-08-30.at.18.30.34.mp4

The marks are this environment's own rows and cost nothing to read, but every read
of them blocked on a host call that only the Changed badge needed, and a press paid
for that call twice over. On Azure, where each one is a process spawn, coming back
to a review left the checkboxes empty for seconds at a time.
Correcting a badge a moment late is cheaper than making a reader wait for it, so a
held answer now stands while the next one is fetched. The press itself still asks
outright, since it stamps what it stores.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestProvider.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
Azure pages its change list and answers for a binary file in an encoding of its own, so a large pull request came back as part of a change presented as the whole of it, and a file whose contents az would not hand over took the rest of the slice down with it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A host that answers for part of a change said nothing about the rest, and that silence was read as deletion, so every file past the cut was cleared over a version nobody ever looked at. Two presses on one file could also finish in the other order, and two Azure repositories of the same name shared one row of ticks.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75c0bb8. Configure here.

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
…f it
A page Azure names but the read stops at was reported as the end of the change, so files it never listed read as removed from the pull request.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the Azure-safe repository selector is applied to the right-panel branch but not to the sibling /pull-requests navigation in the same function, so an Azure DevOps link still opens a ref the server refuses.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/lib/openPullRequestLink.ts Outdated
… per file
One file's diff was bounded but a slice of them was not, and the page opening a review passed the URL's spelling of a repository where the panel passed the server's.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…th no hunks
A failed side read was degraded to a file listed without its hunks whatever the reason, so a signed-out or throttled host produced a whole change of empty files instead of a failure the app pauses on.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the new "viewed" segment in the Code tab toolbar cannot shrink, which makes the already-tight meta strip overflow sooner in narrow panels. Everything else in scope looks consistent — the checkbox uses the shared Checkbox primitive with the same label-wrapping pattern as the other call sites, the render props stay identity-stable through refs with the marks folded into item.version, and usePullRequestFilesViewed resolves its environment from the explicit environmentId prop.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One convention finding: a known-tag recovery is expressed with Effect.catchIf instead of Effect.catchTags. Everything else in the new Effect service code (the PullRequestFilesViewed repository module's Context.Service/make/layer shape, namespace imports, dependency acquisition via yield*, and the new structured error mappings) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…strip
The count was spelled out at a fixed width beside controls that cannot give way, and the Azure per-file recovery named its failures through a predicate where the tags say it plainly.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@yordis
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): pull request files can be marked as viewed - #7721

Open
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream
Open

feat(web): pull request files can be marked as viewed#7721
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream

Conversation

@yordis

@yordisyordis commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
  • A review spread over an afternoon, or picked up on a second machine, starts again from the top every time, so large changes get read in the browser and only small ones stay here.
  • The marks are the host's wherever the host keeps any, because a checkbox that looks like the one GitHub shows and quietly disagrees with it leaves a reviewer unsure which of the two knows what they have actually read.
  • GitLab keeps its own viewed files in one browser's local storage, where nothing outside that browser can read or write them, so there is no shared record to be the host's. The marks are this environment's instead, and the surface says so rather than implying gitlab.com will show them.
  • Declared per provider as where the marks live rather than whether they exist, so a host with nowhere to keep them hides the control instead of offering one that cannot keep its promise.
  • Read apart from the patch, because viewed state moves on every press and a patch moves only when somebody pushes; sharing one read would mean either re-fetching a three-hundred-file diff per checkbox or showing a reader their own last press as stale.

Note

Medium Risk
Large cross-provider pull-request surface area (new persistence, caching, and Azure diff assembly); regressions could affect diff accuracy, viewed-state correctness, or Azure/GitHub API behavior under rate limits.

Overview
Adds per-file “viewed” tracking for pull requests end-to-end on the server: new filesViewed / setFilesViewed on PullRequestService, RPC auth for pullRequestsFilesViewed and pullRequestsSetFilesViewed, and provider support split by viewedFiles: "host" (GitHub GraphQL read/write) vs "environment" (SQLite marks plus host file revision lookups to detect pushes).

For environment-backed providers, migration 044 creates pull_request_files_viewed and PullRequestFilesViewedRepository stores cleared paths with a revision stamp; the service compares revisions (with caching, stale-while-revalidate, per-PR write ordering, and invalidation) so re-pushed files show as dismissed without re-fetching the whole diff on every checkbox.

Azure DevOps gains a real Code tab: capabilities.diff flips on, REST moves from az rest to az devops invoke, iteration changes are paged and turned into unified patches via the new diff dependency and azureDevOpsDiff.ts, plus getFileRevisions for viewed-state staleness. Bitbucket and GitLab add getFileRevisions (patch index lines / head blob GraphQL). Extensive unit tests cover paging limits, truncated diffs, and mark isolation across repos and PR numbers.

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

Note

Add ability to mark pull request files as viewed across providers

  • Adds a "Viewed" checkbox to the PR code tab UI. Toggling a file collapses it and marks it viewed; changing the file's head revision shows a "Changed" indicator.
  • GitHub viewed marks are stored on the host. GitLab, Bitbucket, and Azure DevOps marks are stored in the environment via a new SQLite table created by migration 044_PullRequestFilesViewed.
  • The server fetches per-path head revisions to detect stale marks for environment-scoped providers.
  • Risk: Azure DevOps PRs now use AzureDevOpsRepositoryLocation instead of threadsUrl. normalizeGitRemoteUrl now normalizes Azure DevOps SSH remotes to web spelling.

Macroscope summarized 6e9d61c.

@coderabbitai

coderabbitaiBot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db5e0854-7bcc-4529-902c-248e00159c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 20, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI: the new viewed-file checkbox in the diff header, the counter in the toolbar, and the fold/overlay logic modules. Two findings, both on changed lines in PullRequestCodeTab.tsx.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a substantial cross-provider viewed-file workflow with persistent state, new authenticated RPCs, provider integrations, and a newly enabled Azure DevOps diff path. It also changes authorization behavior and provider capability defaults, so the production blast radius warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI changes (PullRequestCodeTab.tsx, pullRequestDiff.logic.ts, pullRequestFilesViewed.logic.ts, usePullRequestFilesViewed.ts) for shared-primitive use, Tailwind/CSS ownership and virtualizer behavior.

Both findings from the previous run are resolved: the Checkbox no longer carries a partial size-* override, and truncated is now threaded through the hook and surfaced in the meta line with the same Tooltip + TriangleAlertIcon treatment the withheld-diff caveat uses. Two remaining items below — one virtualizer regression risk, one accessible-name issue on the new control.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
yordis added 10 commits August 20, 2026 18:06
A review spread over an afternoon, or picked up on a second machine, started
again from the top every time, so large changes were read in the browser and
only small ones stayed here.
The marks are the host's rather than ours because a checkbox only this app
remembers is worse than none: it looks like the one GitHub shows, disagrees
with it, and leaves a reviewer unsure which of the two knows what they have
actually read.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he window resets
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…since
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…at it is partial
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he wrong way
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…count
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…carries
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A press moved the whole viewed view, and every file header on screen was memoized on it, so one tick cost a rebuild of all of them. The same mark also has to say whether the control is offered at all, or a capability arriving after the first paint leaves the headers without a box.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
It borrowed its name from the label beside it, and that label turns into "Changed" once the file has been pushed to, leaving a reader who cannot see it with no idea what the box does.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordisforce-pushed the yordis/feat-pr-files-viewed-upstream branch from 1296cb6 to 6b44e51CompareAugust 20, 2026 22:07
@yordis

yordis commented Aug 20, 2026

Copy link
Copy Markdown
ContributorAuthor

GitHub

Screen.Recording.2026-08-20.at.6.15.29.PM.mov

The branch had drifted behind main far enough to conflict, which blocked
review of the change itself.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
The button exists for a reader who can see that what they are looking at is
behind, so leaving one part of the page on the last read defeats the point of
pressing it. A push since that read is exactly when the mark beside a ticked
file stops being true.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
An error the reader cannot act on, about a press they have already replaced,
reads as their current tick having been lost when it has not.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new viewed-files hook: the command-failure path surfaces an error toast for interrupt-only failures, which diverges from the repo's established useAtomCommand failure convention. Everything else in the web scope (Checkbox/Tooltip primitive use, the amber caveat icon matching the adjacent meta-line pattern, header portal render-prop stability via refs, explicit environmentId threading) looks consistent.

Posted via Macroscope — UI Consistency

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…equest
GitLab keeps viewed files in one browser's local storage, so there was
nothing to read or write there. The marks are this environment's instead,
and the surface says whose they are rather than implying gitlab.com will
show them.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 30, 2026
The only signal that GitLab's own site would never show these ticks was a
tooltip on a small icon, and the first reader to use it went looking for
the marks on gitlab.com instead. The count says it now.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

GitLab

Screen.Recording.2026-08-30.at.10.59.33.AM.mov

The server derives a ref's repository from the project identity, and Azure DevOps
is the one host where that is not the recorded path. Clients spelled it the other
way, so the server turned their refs away at the door and the link fell through to
the browser. The rule now lives where both sides can read it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bitbucket records nothing about what a reviewer has already read, so the marks are
this environment's own. Without a revision to compare against they could not tell a
file still as it was read from one pushed to since, which is the distinction that
makes the marks worth keeping at all.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The adapter never read what a pull request changed, so the panel reported no files
and the Code tab was hidden outright. Azure serves no patch of its own, and its
record of what a reviewer has read sits behind an endpoint it has never released,
so both are answered from what it does state: the files an iteration changed, and
the blob each side holds.
Reading the conversation moved off `az rest` in the process. It mints its own token
against whichever tenant `az` defaults to, which is not the one an organisation
necessarily lives in, so that read had been failing wherever the two differ.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

Azure DevOps

CleanShot.2026-08-30.at.18.22.41.mp4

@yordis

Copy link
Copy Markdown
ContributorAuthor

Bitbucket

CleanShot.2026-08-30.at.18.30.34.mp4

The marks are this environment's own rows and cost nothing to read, but every read
of them blocked on a host call that only the Changed badge needed, and a press paid
for that call twice over. On Azure, where each one is a process spawn, coming back
to a review left the checkboxes empty for seconds at a time.
Correcting a badge a moment late is cheaper than making a reader wait for it, so a
held answer now stands while the next one is fetched. The press itself still asks
outright, since it stamps what it stores.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestProvider.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
Azure pages its change list and answers for a binary file in an encoding of its own, so a large pull request came back as part of a change presented as the whole of it, and a file whose contents az would not hand over took the rest of the slice down with it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A host that answers for part of a change said nothing about the rest, and that silence was read as deletion, so every file past the cut was cleared over a version nobody ever looked at. Two presses on one file could also finish in the other order, and two Azure repositories of the same name shared one row of ticks.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75c0bb8. Configure here.

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
…f it
A page Azure names but the read stops at was reported as the end of the change, so files it never listed read as removed from the pull request.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the Azure-safe repository selector is applied to the right-panel branch but not to the sibling /pull-requests navigation in the same function, so an Azure DevOps link still opens a ref the server refuses.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/lib/openPullRequestLink.ts Outdated
… per file
One file's diff was bounded but a slice of them was not, and the page opening a review passed the URL's spelling of a repository where the panel passed the server's.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…th no hunks
A failed side read was degraded to a file listed without its hunks whatever the reason, so a signed-out or throttled host produced a whole change of empty files instead of a failure the app pauses on.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the new "viewed" segment in the Code tab toolbar cannot shrink, which makes the already-tight meta strip overflow sooner in narrow panels. Everything else in scope looks consistent — the checkbox uses the shared Checkbox primitive with the same label-wrapping pattern as the other call sites, the render props stay identity-stable through refs with the marks folded into item.version, and usePullRequestFilesViewed resolves its environment from the explicit environmentId prop.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One convention finding: a known-tag recovery is expressed with Effect.catchIf instead of Effect.catchTags. Everything else in the new Effect service code (the PullRequestFilesViewed repository module's Context.Service/make/layer shape, namespace imports, dependency acquisition via yield*, and the new structured error mappings) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…strip
The count was spelled out at a fixed width beside controls that cannot give way, and the Azure per-file recovery named its failures through a predicate where the tags say it plainly.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@yordis
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(web): pull request files can be marked as viewed - #7721

Open
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream
Open

feat(web): pull request files can be marked as viewed#7721
yordis wants to merge 26 commits into
pingdotgg:mainfrom
TrogonStack:yordis/feat-pr-files-viewed-upstream

Conversation

@yordis

@yordisyordis commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
  • A review spread over an afternoon, or picked up on a second machine, starts again from the top every time, so large changes get read in the browser and only small ones stay here.
  • The marks are the host's wherever the host keeps any, because a checkbox that looks like the one GitHub shows and quietly disagrees with it leaves a reviewer unsure which of the two knows what they have actually read.
  • GitLab keeps its own viewed files in one browser's local storage, where nothing outside that browser can read or write them, so there is no shared record to be the host's. The marks are this environment's instead, and the surface says so rather than implying gitlab.com will show them.
  • Declared per provider as where the marks live rather than whether they exist, so a host with nowhere to keep them hides the control instead of offering one that cannot keep its promise.
  • Read apart from the patch, because viewed state moves on every press and a patch moves only when somebody pushes; sharing one read would mean either re-fetching a three-hundred-file diff per checkbox or showing a reader their own last press as stale.

Note

Medium Risk
Large cross-provider pull-request surface area (new persistence, caching, and Azure diff assembly); regressions could affect diff accuracy, viewed-state correctness, or Azure/GitHub API behavior under rate limits.

Overview
Adds per-file “viewed” tracking for pull requests end-to-end on the server: new filesViewed / setFilesViewed on PullRequestService, RPC auth for pullRequestsFilesViewed and pullRequestsSetFilesViewed, and provider support split by viewedFiles: "host" (GitHub GraphQL read/write) vs "environment" (SQLite marks plus host file revision lookups to detect pushes).

For environment-backed providers, migration 044 creates pull_request_files_viewed and PullRequestFilesViewedRepository stores cleared paths with a revision stamp; the service compares revisions (with caching, stale-while-revalidate, per-PR write ordering, and invalidation) so re-pushed files show as dismissed without re-fetching the whole diff on every checkbox.

Azure DevOps gains a real Code tab: capabilities.diff flips on, REST moves from az rest to az devops invoke, iteration changes are paged and turned into unified patches via the new diff dependency and azureDevOpsDiff.ts, plus getFileRevisions for viewed-state staleness. Bitbucket and GitLab add getFileRevisions (patch index lines / head blob GraphQL). Extensive unit tests cover paging limits, truncated diffs, and mark isolation across repos and PR numbers.

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

Note

Add ability to mark pull request files as viewed across providers

  • Adds a "Viewed" checkbox to the PR code tab UI. Toggling a file collapses it and marks it viewed; changing the file's head revision shows a "Changed" indicator.
  • GitHub viewed marks are stored on the host. GitLab, Bitbucket, and Azure DevOps marks are stored in the environment via a new SQLite table created by migration 044_PullRequestFilesViewed.
  • The server fetches per-path head revisions to detect stale marks for environment-scoped providers.
  • Risk: Azure DevOps PRs now use AzureDevOpsRepositoryLocation instead of threadsUrl. normalizeGitRemoteUrl now normalizes Azure DevOps SSH remotes to web spelling.

Macroscope summarized 6e9d61c.

@coderabbitai

coderabbitaiBot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db5e0854-7bcc-4529-902c-248e00159c3c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 20, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI: the new viewed-file checkbox in the diff header, the counter in the toolbar, and the fold/overlay logic modules. Two findings, both on changed lines in PullRequestCodeTab.tsx.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a substantial cross-provider viewed-file workflow with persistent state, new authenticated RPCs, provider integrations, and a newly enabled Azure DevOps diff path. It also changes authorization behavior and provider capability defaults, so the production blast radius warrants human review.

You can add or adjust custom eligibility rules. Learn more.

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
Comment threadapps/server/src/sourceControl/githubGraphQlBudget.ts Outdated
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI changes (PullRequestCodeTab.tsx, pullRequestDiff.logic.ts, pullRequestFilesViewed.logic.ts, usePullRequestFilesViewed.ts) for shared-primitive use, Tailwind/CSS ownership and virtualizer behavior.

Both findings from the previous run are resolved: the Checkbox no longer carries a partial size-* override, and truncated is now threaded through the hook and surfaced in the meta line with the same Tooltip + TriangleAlertIcon treatment the withheld-diff caveat uses. Two remaining items below — one virtualizer regression risk, one accessible-name issue on the new control.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
yordis added 10 commits August 20, 2026 18:06
A review spread over an afternoon, or picked up on a second machine, started
again from the top every time, so large changes were read in the browser and
only small ones stayed here.
The marks are the host's rather than ours because a checkbox only this app
remembers is worse than none: it looks like the one GitHub shows, disagrees
with it, and leaves a reviewer unsure which of the two knows what they have
actually read.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he window resets
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…since
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…at it is partial
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…he wrong way
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…count
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…carries
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A press moved the whole viewed view, and every file header on screen was memoized on it, so one tick cost a rebuild of all of them. The same mark also has to say whether the control is offered at all, or a capability arriving after the first paint leaves the headers without a box.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
It borrowed its name from the label beside it, and that label turns into "Changed" once the file has been pushed to, leaving a reader who cannot see it with no idea what the box does.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis
yordisforce-pushed the yordis/feat-pr-files-viewed-upstream branch from 1296cb6 to 6b44e51CompareAugust 20, 2026 22:07
@yordis

yordis commented Aug 20, 2026

Copy link
Copy Markdown
ContributorAuthor

GitHub

Screen.Recording.2026-08-20.at.6.15.29.PM.mov

The branch had drifted behind main far enough to conflict, which blocked
review of the change itself.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx
The button exists for a reader who can see that what they are looking at is
behind, so leaving one part of the page on the last read defeats the point of
pressing it. A push since that read is exactly when the mark beside a ticked
file stops being true.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/web/src/components/pullRequest/usePullRequestFilesViewed.ts Outdated
An error the reader cannot act on, about a press they have already replaced,
reads as their current tick having been lost when it has not.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding on the new viewed-files hook: the command-failure path surfaces an error toast for interrupt-only failures, which diverges from the repo's established useAtomCommand failure convention. Everything else in the web scope (Checkbox/Tooltip primitive use, the amber caveat icon matching the adjacent meta-line pattern, header portal render-prop stability via refs, explicit environmentId threading) looks consistent.

Posted via Macroscope — UI Consistency

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…equest
GitLab keeps viewed files in one browser's local storage, so there was
nothing to read or write there. The marks are this environment's instead,
and the surface says whose they are rather than implying gitlab.com will
show them.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 30, 2026
The only signal that GitLab's own site would never show these ticks was a
tooltip on a small icon, and the first reader to use it went looking for
the marks on gitlab.com instead. The count says it now.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

GitLab

Screen.Recording.2026-08-30.at.10.59.33.AM.mov

The server derives a ref's repository from the project identity, and Azure DevOps
is the one host where that is not the recorded path. Clients spelled it the other
way, so the server turned their refs away at the door and the link fell through to
the browser. The rule now lives where both sides can read it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Bitbucket records nothing about what a reviewer has already read, so the marks are
this environment's own. Without a revision to compare against they could not tell a
file still as it was read from one pushed to since, which is the distinction that
makes the marks worth keeping at all.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The adapter never read what a pull request changed, so the panel reported no files
and the Code tab was hidden outright. Azure serves no patch of its own, and its
record of what a reviewer has read sits behind an endpoint it has never released,
so both are answered from what it does state: the files an iteration changed, and
the blob each side holds.
Reading the conversation moved off `az rest` in the process. It mints its own token
against whichever tenant `az` defaults to, which is not the one an organisation
necessarily lives in, so that read had been failing wherever the two differ.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

Copy link
Copy Markdown
ContributorAuthor

Azure DevOps

CleanShot.2026-08-30.at.18.22.41.mp4

@yordis

Copy link
Copy Markdown
ContributorAuthor

Bitbucket

CleanShot.2026-08-30.at.18.30.34.mp4

The marks are this environment's own rows and cost nothing to read, but every read
of them blocked on a host call that only the Changed badge needed, and a press paid
for that call twice over. On Azure, where each one is a process spawn, coming back
to a review left the checkboxes empty for seconds at a time.
Correcting a badge a moment late is cheaper than making a reader wait for it, so a
held answer now stands while the next one is fetched. The press itself still asks
outright, since it stamps what it stores.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestProvider.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts Outdated
Comment threadapps/server/src/pullRequest/BitbucketPullRequestApi.ts Outdated
Comment threadapps/server/src/pullRequest/PullRequestService.ts
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
Azure pages its change list and answers for a binary file in an encoding of its own, so a large pull request came back as part of a change presented as the whole of it, and a file whose contents az would not hand over took the rest of the slice down with it.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A host that answers for part of a change said nothing about the rest, and that silence was read as deletion, so every file past the cut was cleared over a version nobody ever looked at. Two presses on one file could also finish in the other order, and two Azure repositories of the same name shared one row of ticks.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
Comment threadapps/server/src/pullRequest/azureDevOpsPullRequestJson.ts
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 75c0bb8. Configure here.

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestCli.ts Outdated
…f it
A page Azure names but the read stops at was reported as the end of the change, so files it never listed read as removed from the pull request.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/azureDevOpsDiff.ts Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the Azure-safe repository selector is applied to the right-panel branch but not to the sibling /pull-requests navigation in the same function, so an Azure DevOps link still opens a ref the server refuses.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/lib/openPullRequestLink.ts Outdated
… per file
One file's diff was bounded but a slice of them was not, and the page opening a review passed the URL's spelling of a repository where the panel passed the server's.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…th no hunks
A failed side read was degraded to a file listed without its hunks whatever the reason, so a signed-out or throttled host produced a whole change of empty files instead of a failure the app pauses on.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One finding: the new "viewed" segment in the Code tab toolbar cannot shrink, which makes the already-tight meta strip overflow sooner in narrow panels. Everything else in scope looks consistent — the checkbox uses the shared Checkbox primitive with the same label-wrapping pattern as the other call sites, the render props stay identity-stable through refs with the marks folded into item.version, and usePullRequestFilesViewed resolves its environment from the explicit environmentId prop.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/pullRequest/PullRequestCodeTab.tsx Outdated

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One convention finding: a known-tag recovery is expressed with Effect.catchIf instead of Effect.catchTags. Everything else in the new Effect service code (the PullRequestFilesViewed repository module's Context.Service/make/layer shape, namespace imports, dependency acquisition via yield*, and the new structured error mappings) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/pullRequest/AzureDevOpsPullRequestProvider.ts Outdated
…strip
The count was spelled out at a fixed width beside controls that cannot give way, and the Azure per-file recovery named its failures through a predicate where the tags say it plainly.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@yordis