You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Once a session has an open PR, its sidebar dot and kanban badge are locked to the PR lifecycle color (blue/"pending") regardless of whether the agent is actively working or idle. Users lose the ability to see real-time activity state from the sidebar/kanban — the dot never shows "working" (orange) again.
The gtm-strategy session is actively Working (orange pill in topbar, "Working — just now" in activity feed), but its sidebar dot is blue — indistinguishable from an idle session with an open PR.
Reproduction
Spawn a worker session and let it open a PR (status derives to pr_open or review_pending).
While the PR is open, send the agent another task or have it continue working (activity state → active).
Observe the sidebar dot: it stays blue (pending zone) even though the agent is actively working.
Compare with the topbar, which correctly shows orange "Working" (from session.activity.state, decoupled in PR fix: sync topbar activity pill #2541).
Same behavior on the kanban board — the card badge reflects PR status, not activity.
Root Cause
backend/internal/service/session/status.go, deriveStatus() checks for open PRs before checking agent activity:
// line 35-37: needs_input wins (correct)ifrec.Activity.State.NeedsInput() {
returndomain.StatusNeedsInput
}
// line 39-42: open-PR check runs FIRST — short-circuits activityopen:=openPRs(prs)
iflen(open) >0 {
returnaggregatePRStatus(open) // ← returns review_pending/pr_open/etc.
}
// line 47-49: activity check only reached if NO open PRifrec.Activity.State==domain.ActivityActive {
returndomain.StatusWorking// ← unreachable when a PR exists
}
Once openPRs() returns non-empty, deriveStatus() returns a PR-based status and never evaluates ActivityActive. So pr_open + active and pr_open + idle produce the same status — the sidebar dot and kanban badge are identical in both cases.
The frontend consumes this in two places, both reading only session.status (never activity.state):
Sidebar (Sidebar.tsx:125-127): getSessionDotView(session) → getAttentionZoneView(session.status) → attentionZone() → blue "pending" dot for any PR-derived status
Kanban (SessionsBoard.tsx:92, 467): column placement via attentionZone(session) + badge via getSessionStatusView(session.status)
The topbar was already fixed to read session.activity.state directly (PR #2541), so it correctly shows "Working" — but the sidebar and kanban were not decoupled, creating the disagreement visible in the screenshot.
#2345 describes the opposite symptom: the topbar showing "working" for idle+PR sessions. Both bugs stem from the same architectural tension — status and activity are derived independently, and different surfaces pick different signals — but the root causes are in different layers:
Result: agent actively working → orange dot / "Working" column, regardless of PR. Agent goes idle → status falls back to PR lifecycle (blue review_pending, red ci_failed, green approved). The PR lifecycle remains visible in the right panel and board card PR groups — no information loss, just no longer competing with the real-time working signal.
Consistent with existing design: needs_input already takes precedence over PR status for the same reason — it's the signal that most needs the user's attention right now.
Impact
Severity: Medium — no data loss, but the primary navigation surfaces (sidebar, kanban) lose a real-time signal users rely on to know which agents are actively working. This defeats the purpose of the multi-session dashboard.
Scope: Every session that has an open PR and is still doing work (addressing reviews, fixing CI, iterating). With Claude Code's tool-use hooks keeping activity accurate, this is a large fraction of active sessions.
Bug
Once a session has an open PR, its sidebar dot and kanban badge are locked to the PR lifecycle color (blue/"pending") regardless of whether the agent is actively working or idle. Users lose the ability to see real-time activity state from the sidebar/kanban — the dot never shows "working" (orange) again.
Source: Discord —
#🧑🔧-bug-triage| Reported by: @prateek | Analyzed against:cabf6610(main, 2026-07-21)Confidence: High
Screenshot
The
gtm-strategysession is actively Working (orange pill in topbar, "Working — just now" in activity feed), but its sidebar dot is blue — indistinguishable from an idle session with an open PR.Reproduction
pr_openorreview_pending).active).session.activity.state, decoupled in PR fix: sync topbar activity pill #2541).Root Cause
backend/internal/service/session/status.go,deriveStatus()checks for open PRs before checking agent activity:Once
openPRs()returns non-empty,deriveStatus()returns a PR-based status and never evaluatesActivityActive. Sopr_open + activeandpr_open + idleproduce the same status — the sidebar dot and kanban badge are identical in both cases.The frontend consumes this in two places, both reading only
session.status(neveractivity.state):Sidebar.tsx:125-127):getSessionDotView(session)→getAttentionZoneView(session.status)→attentionZone()→ blue "pending" dot for any PR-derived statusSessionsBoard.tsx:92, 467): column placement viaattentionZone(session)+ badge viagetSessionStatusView(session.status)The topbar was already fixed to read
session.activity.statedirectly (PR #2541), so it correctly shows "Working" — but the sidebar and kanban were not decoupled, creating the disagreement visible in the screenshot.Note: this is the inverse of #2345
#2345 describes the opposite symptom: the topbar showing "working" for idle+PR sessions. Both bugs stem from the same architectural tension —
statusandactivityare derived independently, and different surfaces pick different signals — but the root causes are in different layers:workerDisplayStatushad nopr_open/draftcase → fell through to "working"deriveStatus()returns PR-based status even when agent is active → sidebar/kanban can't show "working"Fix
Move the
ActivityActivecheck before the PR aggregation — same precedence thatNeedsInput()already enjoys (line 35). InderiveStatus():Result: agent actively working → orange dot / "Working" column, regardless of PR. Agent goes idle → status falls back to PR lifecycle (blue
review_pending, redci_failed, greenapproved). The PR lifecycle remains visible in the right panel and board card PR groups — no information loss, just no longer competing with the real-time working signal.Consistent with existing design:
needs_inputalready takes precedence over PR status for the same reason — it's the signal that most needs the user's attention right now.Impact
Related
session.activity.statedirectly (the half of this fix that already landed)