Skip to content

Surface per-PR CI status in sidebar - #6983

Closed
austinywang wants to merge 19 commits into
mainfrom
issue-5748-surface-per-pr-ci-cd-check-status-in-the-side
Closed

austinywang wants to merge 19 commits into
mainfrom
issue-5748-surface-per-pr-ci-cd-check-status-in-the-side

Conversation

@austinywang

@austinywang austinywang commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #5748

Summary

  • fetch PR CI rollups with one authenticated GraphQL request per repo refresh/cache window
  • thread neutral/success/failure CI status through the PR poller and sidebar row state
  • render localized pending/pass/fail CI glyphs for open PR rows

Testing

  • swift test (Packages/macOS/CmuxGit)
  • swift test (Packages/macOS/CmuxSidebar)
  • swift test (Packages/macOS/CmuxSidebarGit)
  • python3 scripts/check-package-resolved-policy.py
  • python3 scripts/check-workspace-package-groups.py --check
  • python3 -m json.tool Resources/Localizable.xcstrings >/dev/null

Feature work; skipped crash reproduction/failing-regression-first flow. Per request, no reload.sh/dev app build/xcodebuild was run.


Summary by cubic

Shows CI status (pending/pass/fail) beside open PRs in the sidebar. Batch-fetches rollups via GraphQL with a dedicated 3s timeout so badges never wait on CI; threads status through the poller, cache, and UI with localized help and JSON export. Addresses #5748.

  • New Features

    • Batch-fetch statusCheckRollup for candidate open PRs only; dedupe and preserve order; map to neutral/success/failure; embed ciStatus in probe/resolved items, badges, sidebar state, and app bridges; render icons for open rows with localized help; include ciStatus in custom sidebar JSON.
    • For targeted head= lookups, fetch rollups for found PRs and prefer freshly fetched status over cached.
  • Bug Fixes

    • Unknown, missing, unparseable, or future CI values now degrade to neutral instead of suppressing the PR row (including resolved-badge builds); command-hint reconciliation preserves CI status.
    • Restored a bounded test waiter timeout to prevent hangs during PR polling tests.

Written for commit 414ed64. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added end-to-end CI check rollup support: CI status now shows in the sidebar badges and pull-request rows (including a new icon for open PRs) with localized pending/success/failed help.
    • CI status is also included in custom sidebar pull-request values.
  • Bug Fixes
    • CI status is now derived from GitHub check rollups during fetch/refresh and properly propagates through resolution and command-hint badge updates.
    • When CI data is missing or unrecognized, the UI consistently falls back to neutral.

@vercel

vercel Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled Jul 4, 2026 4:57am
cmux-staging Building Building Preview, Comment Jul 4, 2026 4:57am

@coderabbitai

coderabbitai Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds CI check-status models, GraphQL fetch plumbing, workspace/sidebar propagation, sidebar rendering, and related tests and support code.

Changes

CI Check-Status Rollup Feature

Layer / File(s) Summary
CI status models and state
Packages/macOS/CmuxGit/Sources/CmuxGit/Model/*, Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Git/*, Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Model/*, Sources/Workspace.swift, Sources/TabManager+SidebarGitHosting.swift, Sources/Workspace+CustomSidebarPullRequests.swift
Defines CI status enums and adds CI status storage, decoding, and workspace/sidebar state propagation for pull requests.
GraphQL models and fetch pipeline
Packages/macOS/CmuxGit/Sources/CmuxGit/Model/*, Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService+CheckStatusGraphQL.swift, Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService+Fetch.swift, Packages/macOS/CmuxGit/Sources/CmuxGit/PullRequestProbeService.swift, Packages/macOS/CmuxGit/Tests/CmuxGitTests/PullRequestProbeServiceTests.swift
Adds the GraphQL request/response models, decoders, and batched CI-status fetch and cache application logic used by the PR probe service.
Sidebar polling, rendering, and tests
Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/*, Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/*, Sources/ContentView.swift, Resources/Localizable.xcstrings, Packages/macOS/CmuxSidebar/Tests/CmuxSidebarTests/SidebarValueVocabularyTests.swift, cmuxTests/WorkspaceCustomSidebarPullRequestContextTests.swift
Threads CI status through poll-service badge reconstruction, sidebar value projection, and row rendering, with localization and test coverage for badge reconciliation and CI vocabulary.
Test support synchronization
Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/Support/Fakes.swift
Refactors the tracked-path probe wait helper to use queued continuations and timeout-driven wakeups.

Estimated code review effort: 4 (Complex) | ~60 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (2 errors, 3 warnings)

Check name Status Explanation Resolution
Cmux Algorithmic Complexity ❌ Error FAIL: cachedCheckStatus in PullRequestProbeService+CheckStatusGraphQL.swift:123 scans pullRequestsByBranch.values inside foldingBranchLookupResults, making branch-lookup O(B×P). Add a PR-number/status index on the cache entry (or store CI on the keyed branch value) and use direct lookup instead of first(where:).
Cmux Swift @Concurrent ❌ Error New bare nonisolated async network helpers in PullRequestProbeService lack @concurrent; the rule says actor-leaving work needs an explicit boundary. Annotate the new network helpers (pullRequestCheckStatuses, performGraphQLRequest, and any similarly expanded fetch entry points) with @concurrent or move them behind an explicit detached boundary.
Out of Scope Changes check ⚠️ Warning Some support changes look unrelated to the CI-status feature, especially the test waiter refactor in Fakes.swift and import-only visibility tweaks. Remove or justify unrelated support refactors so the PR stays focused on surfacing and rendering per-PR CI status.
Docstring Coverage ⚠️ Warning Docstring coverage is 47.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description covers Summary and Testing, but it omits the Demo Video, Review Trigger, and Checklist sections from the template. Add the missing Demo Video, Review Trigger, and Checklist sections, and include a short video link or note if none is available.
✅ Passed checks (20 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement per-PR CI rollup fetching, propagation, open-row rendering, and localization in line with #5748.
Cmux Swift Actor Isolation ✅ Passed PASS: New CI/status types are plain Sendable value models; the poll service stays @MainActor with detached fetches and a MainActor apply hop, and no mutable Sendable refs were added.
Cmux Swift Blocking Runtime ✅ Passed PASS: New production code is async/network-based; no semaphores, locks, sleeps, or polling were added. The only Task.sleep/continuation timing is in a test fake.
Cmux Browser Automation Off-Main ✅ Passed PASS: The diff only moves ghostty/vendor submodule pointers and touches no browser.* routing, WebKit/AppKit wait paths, or policy tests.
Cmux Expensive Synchronous Load ✅ Passed No agent-history or large-file synchronous load was added to main/interactive paths; new CI work is nonisolated network/JSON parsing, and UI code only maps/renders status.
Cmux Cache Substitution Correctness ✅ Passed CI status is fetched best-effort in the poller, freshness-checked by the 15s repo cache, and only propagated into UI state; no snapshot/history fresh-read substitution found.
Cmux No Hacky Sleeps ✅ Passed PR only changes Swift and localization files; no covered TS/JS/shell/build-runtime code adds sleeps, timers, or polling.
Cmux Swift Concurrency ✅ Passed The PR adds async/await and withTaskGroup-based GraphQL fetches, with no new DispatchQueue/Combine/completion-handler/fire-and-forget Task patterns in the touched code.
Cmux Swift File And Package Boundaries ✅ Passed New CI logic lives in small CmuxGit/CmuxSidebar package files; app-target edits are thin UI/state glue, and no oversized mixed-responsibility file was introduced.
Cmux Swiftpm Lockfiles ✅ Passed No Package.swift/Package.resolved/Xcode-project edits are present, and cmux-owned .gitignore files do not ignore Package.resolved.
Cmux Swift Logging ✅ Passed Added diagnostics use the existing debugLog sink, wired to cmuxDebugLog in DEBUG and no-op in release; no print/NSLog/Logger additions or secret-bearing logs found.
Cmux User-Facing Error Privacy ✅ Passed Only generic CI help text was added; I found no new user-facing errors/alerts or raw upstream/vendor details in the diff.
Cmux Full Internationalization ✅ Passed New CI labels use String(localized:defaultValue:), and the catalog adds all 20 supported locales for the three new keys with no blank/copied-English values.
Cmux Swiftui State Layout ✅ Passed The new CI glyph is pure value-driven SwiftUI; no new ObservableObject/@published, no GeometryReader layout changes, and no render-time mutation or row-store refs appear in the diff.
Cmux Architecture Rethink ✅ Passed Adds CI status via model plumbing in the existing stateless poller; no new timers/locks/observers, only a short-timeout GraphQL call and test-only sync.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only adds CI-status plumbing/UI; no standalone NSWindow/NSPanel/WindowGroup/NSWindowController code or cmuxAuxiliaryWindowIdentifiers changes were introduced.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source, tests, or a localization catalog; no logs, caches, build output, temp/scratch, or dependency checkout artifacts appear.
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS: The changed production CI files add no ForTesting/TestHook seams; the only new #if DEBUG blocks are diagnostic logging, not test-only accessors.
Cmux No Ambient Global State ✅ Passed The PR adds only owned model fields and type/extension methods; no new file-scope API, mutable globals, or singleton-style runtime state appear in the diff.
Title check ✅ Passed The title clearly matches the main change: surfacing per-PR CI status in the sidebar.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-5748-surface-per-pr-ci-cd-check-status-in-the-side

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.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR surfaces per-PR CI check status in the sidebar, threading statusCheckRollup data from a new GraphQL call through the PR poller, cache, and UI. It introduces a dedicated 3s-timeout GraphQL session for CI rollups so a slow GitHub CI endpoint can never gate the authoritative REST PR badge refresh, and degrades unknown/unavailable rollup states to .neutral rather than suppressing the PR row.

  • Adds a batch per-PR-alias GraphQL query (PullRequestProbeService+CheckStatusGraphQL.swift) that builds per-number aliases (pr0, pr1, …) for all open PRs, covering the full REST-fetched window and targeted branch-lookup PRs, and stores the result in GitHubPullRequestProbeItem.ciStatus.
  • Threads ciStatus through WorkspacePullRequestResolvedItem, SidebarPullRequestBadge, SidebarPullRequestState, the apply/command-hint reconciliation path, and custom sidebar JSON, then renders a localized pending/pass/fail icon for open PR rows in ContentView.swift.
  • Adds full string-catalog translations for all 20 supported locales, a bounded-timeout test waiter in Fakes.swift, and targeted unit tests for GraphQL decoding, alias tolerance, and badge degradation.

Confidence Score: 5/5

Safe to merge — CI status is a best-effort cosmetic layer that degrades to neutral on any failure, so no authoritative PR badge data is at risk.

Every edge case in the GraphQL path (timeout, null aliases, unknown rollup states, malformed CI raw values in the resolved item) is handled with a safe neutral fallback and confirmed by tests. The three previously flagged issues (REST/GraphQL coverage mismatch, dual source of truth in the cache, badge suppression on unknown CI values) are all resolved in this revision. Internationalization covers all 20 supported locales. The URLSession-per-call pattern matches existing REST fetch code. No production logic bugs, actor isolation issues, ambient global state, or test seams in production source were found.

No files require special attention.

Important Files Changed

Filename Overview
Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService+CheckStatusGraphQL.swift New file: implements the per-alias GraphQL CI rollup fetch, query builder, response decoder, and apply helpers. Well-structured and fully nonisolated; URLSession pattern matches the existing REST fetch.
Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService+Fetch.swift CI rollup applied after both the recent-window REST fetch and the branch-lookup path; foldingBranchLookupResults extracted cleanly for testability.
Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLRepository.swift Custom decoder handles both the pullRequests connection and dynamic pr0…prN aliases using allKeys iteration with prefix/digit guards; null alias tolerance confirmed by tests.
Packages/macOS/CmuxGit/Sources/CmuxGit/Model/PullRequestCheckStatus.swift Clean enum with case-insensitive GitHub state mapping; default branch maps any unknown/future values to .neutral.
Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/PullRequestPollService+Apply.swift resolvedPullRequestBadge extracted for testability; CI status correctly degrades to .neutral on unknown rawValue without suppressing the PR row; ciStatus propagated in stale-badge path.
Sources/ContentView.swift PullRequestCIStatusIcon added as a private struct; ciStatus rendered only for .open rows with localized help and accessibility label; SidebarWorkspaceSnapshotBuilder.PullRequest gains ciStatus field.
Resources/Localizable.xcstrings Three new CI status strings (pending/success/failed) fully translated across all 20 supported locales.
Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/Support/Fakes.swift waitForTrackedPathEventGenerationProbe replaced its maxYields busy-loop with a proper CheckedContinuation waiter and cancellable timeout Task; correct single-resume guarantee on the actor.
Packages/macOS/CmuxGit/Tests/CmuxGitTests/PullRequestProbeServiceTests.swift Comprehensive new tests: rollup state mapping, aliased/null-alias decoding, branch-lookup CI application, checkStatusPullRequestNumbers filtering, and applyingCheckStatuses by number.
Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/PullRequestPollServiceTests.swift mergeCommandHintReconcilesOpenBadge extended to verify ciStatus preservation; new tests for unknown-CI-value degradation and nil badge on unusable status/URL.

Reviews (17): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

austinywang and others added 3 commits June 29, 2026 16:17
…r-pr-ci-cd-check-status-in-the-side

# Conflicts:
#	.github/swift-file-length-budget.tsv
- Remove `checkStatusesByNormalizedBranch`, which had no production caller
  (the per-branch path reads the embedded `ciStatus` via `cachedCheckStatus`);
  drop its now-orphaned test assertions.
- Document why individual aliased-node decode failures are tolerated so the
  `try?` is intentional rather than silent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the per-branch-lookup fold into a pure `foldingBranchLookupResults`
helper (behavior-preserving: still cached-status-only) and add a regression
test asserting that a PR resolved only via the targeted `head=` lookup — i.e.
outside the recent REST window the window-wide GraphQL fetch covers — gets its
fetched CI rollup applied rather than defaulting to `.neutral`.

This commit is the failing half of the two-commit regression structure; the
fold ignores `fetchedCheckStatuses` here so the new test goes red. The fix
follows in the next commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…imeout

P2 (autoreview): a PR resolved only via the targeted `head=` branch lookup is
absent from the recent REST window, so the window-wide GraphQL rollup fetch
never covered it and its badge defaulted to `.neutral` permanently. Now
`branchLookupOutcome` fetches rollups for the found branch-lookup PRs in one
batched GraphQL call, and `foldingBranchLookupResults` prefers a freshly
fetched status over a cached one. Turns the regression test added in the prior
commit green. (`pullRequestCheckStatuses` skips the network when there are no
open PRs, so the cache-hit fast path stays free.)

P3 (autoreview): restore a bounded timeout to
`GatedMetadataReader.waitForTrackedPathEventGenerationProbe`. The continuation
rewrite dropped the old bounded-yield giveup, so a probe that never arrives
hung the whole suite. The continuation approach is kept (no yield spin loop);
a timeout task resolves the waiter by id so it is resumed exactly once.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/PullRequestPollService+Apply.swift (1)

92-105: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't make CI parsing a hard requirement for resolved PR updates.

If ciStatusRawValue is unknown, this continue drops the entire resolved PR badge update and also skips scheduleNextWorkspacePullRequestPoll(...) for that key on this pass. The PR status and URL are still authoritative here; only the CI glyph should degrade to .neutral, which also matches the fallback already used in the app-side bridge.

As per path instructions, .github/review-bot-rules/reliability-single-source-of-truth.md says the GraphQL-unavailable path must not map to a false state, and the PR objective says unavailable CI should remain neutral/hidden rather than suppress the PR row.

Proposed fix
-                guard let status = PullRequestStatus(rawValue: resolvedPullRequest.statusRawValue),
-                      let ciStatus = PullRequestCheckStatus(rawValue: resolvedPullRequest.ciStatusRawValue),
-                      let url = URL(string: resolvedPullRequest.urlString) else {
+                guard let status = PullRequestStatus(rawValue: resolvedPullRequest.statusRawValue),
+                      let url = URL(string: resolvedPullRequest.urlString) else {
                     continue
                 }
+                let ciStatus = PullRequestCheckStatus(rawValue: resolvedPullRequest.ciStatusRawValue) ?? .neutral
                 host.updatePanelPullRequest(
                     workspaceId: result.workspaceId,
                     panelId: result.panelId,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/PullRequestPollService`+Apply.swift
around lines 92 - 105, The resolved PR update path in
PullRequestPollService+Apply should not abort when ciStatusRawValue cannot be
parsed, since that drops the whole badge update and the next poll scheduling for
that workspace key. Update the logic around the guard in the resolved PR
handling to require only PullRequestStatus and URL, then map an unknown
PullRequestCheckStatus to .neutral before calling host.updatePanelPullRequest
and scheduleNextWorkspacePullRequestPoll, matching the existing fallback
behavior in the app-side bridge.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService`+CheckStatusGraphQL.swift:
- Around line 5-10: The branch-miss fallback in pull request check status lookup
is still doing a linear scan through pullRequestsByBranch.values, which makes
each miss O(n). Update PullRequestProbeService+CheckStatusGraphQL’s
pullRequestCheckStatuses path to build or reuse a second PR-number index (or
equivalent lookup map) alongside the existing branch cache so cachedCheckStatus
can resolve by pull request number in O(1) without re-scanning the whole
repository cache.

In
`@Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService`+Fetch.swift:
- Around line 248-278: The branch-lookup folding path is ignoring the fetched
GraphQL CI rollups, so PRs discovered via head= lookups stay neutral. Update
branchLookupOutcome and foldingBranchLookupResults to pass through and consult
fetchedCheckStatuses before falling back, using the existing cachedCheckStatus
and applyingCheckStatus helpers to attach the authoritative status to found pull
requests.

In `@Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/Support/Fakes.swift`:
- Around line 35-50: Restore a bounded failure path in
`waitForTrackedPathEventGenerationProbe` so test callers do not block
indefinitely when no probe is ever recorded. Update the `Fakes`/`ProbeWaiter`
flow to keep a deterministic timeout or bounded polling fallback (or accept an
explicit deadline) and ensure `probeWaiters` still resumes only within that
bound. Keep the waiting logic in `waitForTrackedPathEventGenerationProbe` and
the resume path in the `probeWaiters` handling aligned so the method returns
`false` on timeout instead of hanging the suite.

---

Outside diff comments:
In
`@Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/PullRequestPollService`+Apply.swift:
- Around line 92-105: The resolved PR update path in
PullRequestPollService+Apply should not abort when ciStatusRawValue cannot be
parsed, since that drops the whole badge update and the next poll scheduling for
that workspace key. Update the logic around the guard in the resolved PR
handling to require only PullRequestStatus and URL, then map an unknown
PullRequestCheckStatus to .neutral before calling host.updatePanelPullRequest
and scheduleNextWorkspacePullRequestPoll, matching the existing fallback
behavior in the app-side bridge.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c3a7f8d4-48bf-4af9-b423-5789893feedc

📥 Commits

Reviewing files that changed from the base of the PR and between a70fcdd and 17f11c6.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (33)
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/GitHubPullRequestProbeItem.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/PullRequestCheckStatus.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLCommit.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLCommitConnection.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLCommitNode.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLData.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLPullRequestConnection.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLPullRequestNode.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLRepository.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLRequestBody.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLResponse.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLStatusCheckRollup.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestGraphQLVariables.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestRepoCacheEntry.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Model/WorkspacePullRequestResolvedItem.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService+CheckStatusGraphQL.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService+Fetch.swift
  • Packages/macOS/CmuxGit/Sources/CmuxGit/PullRequestProbeService.swift
  • Packages/macOS/CmuxGit/Tests/CmuxGitTests/PullRequestProbeServiceTests.swift
  • Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Git/SidebarPullRequestCIStatus.swift
  • Packages/macOS/CmuxSidebar/Sources/CmuxSidebar/Git/SidebarPullRequestState.swift
  • Packages/macOS/CmuxSidebar/Tests/CmuxSidebarTests/SidebarValueVocabularyTests.swift
  • Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Model/SidebarPullRequestBadge.swift
  • Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/PullRequestPollService+Apply.swift
  • Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/PullRequestPollService+CommandHints.swift
  • Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/PullRequestPollServiceTests.swift
  • Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/Support/Fakes.swift
  • Resources/Localizable.xcstrings
  • Sources/ContentView.swift
  • Sources/TabManager+SidebarGitHosting.swift
  • Sources/Workspace+CustomSidebarPullRequests.swift
  • Sources/Workspace.swift
  • cmuxTests/WorkspaceCustomSidebarPullRequestContextTests.swift

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/PullRequestPollService`+Apply.swift:
- Around line 92-98: The PR badge is being dropped when an unrecognized CI value
is encountered because `Self.resolvedPullRequestBadge(from:)` currently fails
the whole badge build; update that path so `ciStatusRawValue` defaults to
`.neutral` instead of returning nil, while keeping the existing fatal handling
for invalid status and URL values. Make the change in
`resolvedPullRequestBadge(from:)` so `PullRequestPollService+Apply` can still
call `host.updatePanelPullRequest(...)` with a badge for resolved PRs even when
CI is unknown.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 71379e25-a206-4a4b-95b4-5230f25bf672

📥 Commits

Reviewing files that changed from the base of the PR and between 17f11c6 and e8c1198.

📒 Files selected for processing (4)
  • Packages/macOS/CmuxGit/Sources/CmuxGit/Probe/PullRequestProbeService+Fetch.swift
  • Packages/macOS/CmuxSidebarGit/Sources/CmuxSidebarGit/Service/PullRequestPollService+Apply.swift
  • Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/PullRequestPollServiceTests.swift
  • Packages/macOS/CmuxSidebarGit/Tests/CmuxSidebarGitTests/Support/Fakes.swift

… PR row

Extract the resolved-badge construction into a pure `resolvedPullRequestBadge`
helper and degrade an unparseable `ciStatusRawValue` to `.neutral` rather than
failing the guard. Previously an unknown CI value made the `.resolved` apply
path `continue`, dropping the entire PR badge update and skipping the next poll
scheduling for that key — even though the PR's status and URL are authoritative.

Aligns with .github/review-bot-rules/reliability-single-source-of-truth.md and
the PR objective (unavailable CI stays neutral, never suppresses the row), and
matches the `.neutral` fallback already used on the app-side bridge. Adds a
regression test for the degrade and the nil-on-unusable-status/URL paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@austinywang
austinywang force-pushed the issue-5748-surface-per-pr-ci-cd-check-status-in-the-side branch from e8c1198 to 8faf7ae Compare June 30, 2026 01:30
…r-pr-ci-cd-check-status-in-the-side

# Conflicts:
#	.github/swift-file-length-budget.tsv
…r-pr-ci-cd-check-status-in-the-side

# Conflicts:
#	.github/swift-file-length-budget.tsv

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/Workspace.swift (1)

4958-4966: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

updatePanelPullRequest should not default CI state to .neutral
Sources/TerminalController+ControlSidebarContext2.swift:114 updates the panel PR without forwarding ciStatus, so a branch/status refresh can silently reset a known pass/fail badge to neutral. Make ciStatus required here or thread through the current panel value instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/Workspace.swift` around lines 4958 - 4966, updatePanelPullRequest is
currently defaulting ciStatus to .neutral, which lets callers like
TerminalController+ControlSidebarContext2.updatePanelPullRequest accidentally
overwrite an existing pass/fail badge during refresh. Make ciStatus required in
Workspace.updatePanelPullRequest, or change the caller to pass through the
panel’s current CI value instead of relying on the default. Update any related
call sites and the updatePanelPullRequest signature so the existing CI state is
preserved.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@Sources/Workspace.swift`:
- Around line 4958-4966: updatePanelPullRequest is currently defaulting ciStatus
to .neutral, which lets callers like
TerminalController+ControlSidebarContext2.updatePanelPullRequest accidentally
overwrite an existing pass/fail badge during refresh. Make ciStatus required in
Workspace.updatePanelPullRequest, or change the caller to pass through the
panel’s current CI value instead of relying on the default. Update any related
call sites and the updatePanelPullRequest signature so the existing CI state is
preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 90eda4af-e1df-4e0a-a972-2218dbea25a3

📥 Commits

Reviewing files that changed from the base of the PR and between 910af2e and 11b393d.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (3)
  • Resources/Localizable.xcstrings
  • Sources/ContentView.swift
  • Sources/Workspace.swift

The per-repo refresh awaited the CI status GraphQL call on the shared REST
session (8s timeout) before building the cache entry and returning any PR
results. Because CI status is optional UI metadata layered on the
authoritative REST PR data, a slow or unavailable rollup should never delay
the core PR status/URL badge update.

Give the CI lookup its own dedicated, much-shorter-timeout session
(checkStatusProbeTimeout = 3s). On timeout it yields no statuses and PRs keep
their neutral/cached CI glyph — the authoritative badge refresh is bounded by
a small fraction of the REST budget instead of the full 8s. No return-contract
change, so branch-lookup PRs still receive fetched CI when it responds
promptly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 34 files

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

Re-trigger cubic

Comment thread Packages/macOS/CmuxGit/Sources/CmuxGit/Model/GitHubPullRequestProbeItem.swift Outdated
…r-pr-ci-cd-check-status-in-the-side

# Conflicts:
#	.github/swift-file-length-budget.tsv
…r-pr-ci-cd-check-status-in-the-side

# Conflicts:
#	.github/swift-file-length-budget.tsv
@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — 414ed645 Deployed Jul 4, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Surface per-PR CI/CD check status in the sidebar (neutral / failed ✕ / success ✓), riding the existing PR poller to stay rate-limit-safe

3 participants