From 33b1e350cf9eb6a0d7e8219c69492028f707edbd Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Mon, 30 Mar 2026 23:30:11 -0500 Subject: [PATCH 1/3] fix: Re-check PR badge when session becomes active When clicking a session in the sidebar or switching expanded views, invalidate the PrLinkService cache and re-fetch if no PR was found previously. This ensures PR badges appear promptly after creating a PR or switching branches, without aggressive polling. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Components/ExpandedSessionView.razor | 15 +++++++++++--- .../Components/Layout/SessionListItem.razor | 20 ++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/PolyPilot/Components/ExpandedSessionView.razor b/PolyPilot/Components/ExpandedSessionView.razor index 5461e14b71..e39ed5f6ff 100644 --- a/PolyPilot/Components/ExpandedSessionView.razor +++ b/PolyPilot/Components/ExpandedSessionView.razor @@ -772,10 +772,19 @@ if (PlatformHelper.IsDesktop) { var dir = Session.WorkingDirectory; - if (!string.IsNullOrEmpty(dir) && dir != _lastPrCheckedDir) + if (!string.IsNullOrEmpty(dir)) { - _lastPrCheckedDir = dir; - _ = FetchPrUrlAsync(dir); + if (dir != _lastPrCheckedDir) + { + _lastPrCheckedDir = dir; + _ = FetchPrUrlAsync(dir); + } + else if (_prUrl == null) + { + // Session switched back or PR may have been created — re-check + PrLinkService.Invalidate(dir); + _ = FetchPrUrlAsync(dir); + } } } } diff --git a/PolyPilot/Components/Layout/SessionListItem.razor b/PolyPilot/Components/Layout/SessionListItem.razor index 6d1eda3cad..25b6257446 100644 --- a/PolyPilot/Components/Layout/SessionListItem.razor +++ b/PolyPilot/Components/Layout/SessionListItem.razor @@ -352,15 +352,29 @@ private string _prLabel = "PR"; private string? _lastPrCheckedDir; private string? _renderSignature; + private bool _wasActive; protected override void OnParametersSet() { if (!PlatformHelper.IsDesktop) return; var dir = GetSessionDirectory(); - if (!string.IsNullOrEmpty(dir) && dir != _lastPrCheckedDir) + + // Re-check PR when session becomes active (user clicks it) and we don't have a PR yet + var becameActive = IsActive && !_wasActive; + _wasActive = IsActive; + + if (!string.IsNullOrEmpty(dir)) { - _lastPrCheckedDir = dir; - _ = FetchPrUrlAsync(dir); + if (dir != _lastPrCheckedDir) + { + _lastPrCheckedDir = dir; + _ = FetchPrUrlAsync(dir); + } + else if (becameActive && _prUrl == null) + { + PrLinkService.Invalidate(dir); + _ = FetchPrUrlAsync(dir); + } } } From 71ca4e2b669b1fc53f1213653d02a736693b7538 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Fri, 3 Apr 2026 20:49:16 -0500 Subject: [PATCH 2/3] fix: add activation guard for PR fetch and remove cache-busting Invalidate calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ExpandedSessionView: track session identity via _lastExpandedSessionId to only re-check PR badge on session switch, not every render cycle (fixes fetch storm during streaming — gh pr view was spawned 10-20x/sec) - ExpandedSessionView: remove PrLinkService.Invalidate() call that defeated the 5-minute cache TTL on every render - SessionListItem: remove PrLinkService.Invalidate() call for consistency (becameActive guard already limits re-checks to activation transitions) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- PolyPilot/Components/ExpandedSessionView.razor | 9 ++++++--- PolyPilot/Components/Layout/SessionListItem.razor | 1 - 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/PolyPilot/Components/ExpandedSessionView.razor b/PolyPilot/Components/ExpandedSessionView.razor index e39ed5f6ff..70c4de21c8 100644 --- a/PolyPilot/Components/ExpandedSessionView.razor +++ b/PolyPilot/Components/ExpandedSessionView.razor @@ -683,6 +683,7 @@ private string? _prUrl; private string _prLabel = "PR"; private string? _lastPrCheckedDir; + private string? _lastExpandedSessionId; private List? availableSkills; private List? availableAgents; @@ -772,6 +773,9 @@ if (PlatformHelper.IsDesktop) { var dir = Session.WorkingDirectory; + var sessionSwitched = Session.SessionId != _lastExpandedSessionId; + _lastExpandedSessionId = Session.SessionId; + if (!string.IsNullOrEmpty(dir)) { if (dir != _lastPrCheckedDir) @@ -779,10 +783,9 @@ _lastPrCheckedDir = dir; _ = FetchPrUrlAsync(dir); } - else if (_prUrl == null) + else if (sessionSwitched && _prUrl == null) { - // Session switched back or PR may have been created — re-check - PrLinkService.Invalidate(dir); + // Only re-check when user switches to this session, not on every render _ = FetchPrUrlAsync(dir); } } diff --git a/PolyPilot/Components/Layout/SessionListItem.razor b/PolyPilot/Components/Layout/SessionListItem.razor index 25b6257446..127fcc9789 100644 --- a/PolyPilot/Components/Layout/SessionListItem.razor +++ b/PolyPilot/Components/Layout/SessionListItem.razor @@ -372,7 +372,6 @@ } else if (becameActive && _prUrl == null) { - PrLinkService.Invalidate(dir); _ = FetchPrUrlAsync(dir); } } From 1e14508ee3eef2fa056a5457b7e2c672c6f91da2 Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Fri, 3 Apr 2026 20:56:10 -0500 Subject: [PATCH 3/3] fix: clear stale PR state on session switch and guard against async race - Clear _prUrl and _prLabel when session identity changes, preventing stale PR badges from session A appearing on session B (same-dir case) - Capture Session.SessionId before await in FetchPrUrlAsync and discard results if session changed during the async operation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- PolyPilot/Components/ExpandedSessionView.razor | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/PolyPilot/Components/ExpandedSessionView.razor b/PolyPilot/Components/ExpandedSessionView.razor index 70c4de21c8..1f759932ff 100644 --- a/PolyPilot/Components/ExpandedSessionView.razor +++ b/PolyPilot/Components/ExpandedSessionView.razor @@ -776,6 +776,12 @@ var sessionSwitched = Session.SessionId != _lastExpandedSessionId; _lastExpandedSessionId = Session.SessionId; + if (sessionSwitched) + { + _prUrl = null; + _prLabel = "PR"; + } + if (!string.IsNullOrEmpty(dir)) { if (dir != _lastPrCheckedDir) @@ -794,7 +800,10 @@ private async Task FetchPrUrlAsync(string dir) { - _prUrl = await PrLinkService.GetPrUrlForDirectoryAsync(dir); + var capturedId = Session.SessionId; + var url = await PrLinkService.GetPrUrlForDirectoryAsync(dir); + if (Session.SessionId != capturedId) return; + _prUrl = url; if (_prUrl != null) { var lastSlash = _prUrl.LastIndexOf('/');