Repository navigation
Fix stale sidebar agent status refresh - #6804
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 2 minutes and 53 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughWorkspace agent runtime tracking now flows through a shared observation model, sidebar observation state includes the runtime fields, the tab row refreshes from runtime changes, and tests were migrated to ChangesSidebar agent runtime observation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 24 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (24 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR fixes a stale sidebar agent status visibility bug by moving agent runtime maps (
Confidence Score: 5/5Safe to merge. The change is well-scoped: it encapsulates agent runtime maps in a dedicated @mainactor model, uses @ObservationIgnored to prevent broad view invalidation, and fans change signals to per-workspace AsyncStreams. The @mainactor isolation guarantees consumers always see fully-settled map state even when a single recordAgentPID call triggers multiple notifyChanged() yields. The architecture directly addresses the root cause rather than patching symptoms. Computed property delegation in Workspace+PanelLifecycle means all existing call sites — recordAgentPID, clearAgentPID, removeAgentPIDOwnership, recordAgentPIDOwnership — route through the new equality-guarded setters without any call-site changes. The regression test is deterministic and covers both the visibility fix and the isolation from Workspace.objectWillChange. No new global state, no timing-based synchronization, and no broad invalidation path is introduced. No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Hook as Agent Hook
participant WS as Workspace
participant Model as WorkspaceSidebarAgentRuntimeObservationModel
participant Stream as AsyncStream<Void>
participant Row as TabItemView (Sidebar Row)
Hook->>WS: recordAgentPID(key:pid:panelId:)
WS->>Model: setAgentPIDs(newValue)
Model->>Model: "guard != newValue"
Model->>Model: "agentPIDs = newValue, changeGeneration &+= 1"
Model->>Stream: continuation.yield(()) [bufferingNewest(1)]
Note over WS,Model: Additional map mutations (ownership, lifecycle) also call notifyChanged() — all synchronous on @MainActor
Note over Stream: Task won't resume until current @MainActor turn completes — consumer always sees fully-settled map state
Stream-->>Row: for await _ in model.changes()
Row->>Row: refreshWorkspaceSnapshot()
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Hook as Agent Hook
participant WS as Workspace
participant Model as WorkspaceSidebarAgentRuntimeObservationModel
participant Stream as AsyncStream<Void>
participant Row as TabItemView (Sidebar Row)
Hook->>WS: recordAgentPID(key:pid:panelId:)
WS->>Model: setAgentPIDs(newValue)
Model->>Model: "guard != newValue"
Model->>Model: "agentPIDs = newValue, changeGeneration &+= 1"
Model->>Stream: continuation.yield(()) [bufferingNewest(1)]
Note over WS,Model: Additional map mutations (ownership, lifecycle) also call notifyChanged() — all synchronous on @MainActor
Note over Stream: Task won't resume until current @MainActor turn completes — consumer always sees fully-settled map state
Stream-->>Row: for await _ in model.changes()
Row->>Row: refreshWorkspaceSnapshot()
Reviews (10): Last reviewed commit: "Avoid observing sidebar runtime maps fro..." | Re-trigger Greptile |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…ation Agent lifecycle transitions drove sidebar state coloring by calling objectWillChange.send() on the whole Workspace from recordAgentLifecycleChange. Workspace is a large ObservableObject on a hot agent-monitoring path, so that broad fan-out invalidates every unrelated observer per transition — the sidebar CPU-spin class called out in CLAUDE.md, and the exact invariant the runtime observation model (PR #6804) enforces for agent PID churn. Route the lifecycle color refresh through a dedicated PassthroughSubject that only the sidebar observation pipeline subscribes to. The lifecycle state itself already lives on WorkspaceSidebarAgentRuntimeObservationModel (its setter bumps changeGeneration / .changes()), so per-row coloring still refreshes via the existing narrow stream, and group-header coloring still refreshes via the sidebar observation publisher. Adds a regression test asserting an agent lifecycle change notifies the narrow stream and refreshes the sidebar publisher without firing Workspace.objectWillChange. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
@Observableruntime model with anAsyncStreamchange signalWorkspace.objectWillChangeFixes #6799
Testing
python3 scripts/normalize-pbxproj.py cmux.xcodeproj/project.pbxproj && scripts/check-pbxproj.sh && git diff --checkDemo Video
N/A. This is an intermittent state-observation race; the deterministic regression test is the useful proof, and the issue instructions say not to build or launch the app before CI is green.
Review Trigger
Please focus on the sidebar observation path for agent runtime visibility: hook/status metadata can already exist while PID ownership/lifecycle state changes later, and each workspace must refresh independently without broad workspace invalidation.
Checklist
Fixes #6799.Summary by CodeRabbit
New Features
Bug Fixes