Skip to content

Fix sidebar lag regression since v0.64.16 (#6612): cut per-row font-modifier + pin-state work - #6613

Merged
austinywang merged 12 commits into
mainfrom
issue-6612-sidebar-lag-regression
Jun 23, 2026
Merged

austinywang merged 12 commits into
mainfrom
issue-6612-sidebar-lag-regression

Conversation

@austinywang

@austinywang austinywang commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #6612

Fixes the sidebar lag regression that landed after v0.64.16 (5321becb6) with 100+ workspaces under continuous agent-status churn.

This PR makes three reductions to the per-row work the sidebar performs on every render pass:

  1. Cut the per-row font-modifier cost (primary, root-cause fix). Each sidebar row applied ~20 .cmuxFont(...) modifiers — each a custom @Environment-reading CmuxFontModifier ViewModifier introduced by the global font-magnification feature (Add global font magnification #6554). The row now reads the magnification percent once via the existing @Environment(\.cmuxGlobalFontMagnificationPercent) and applies a primitive .font(...) resolved with GlobalFontMagnification.scaledSize(_:percent:) (identical math to CmuxFontModifier, so magnification is unchanged).
  2. Build a WorkspaceActionDispatcher.PinResolutionContext once per VerticalTabsSidebar render pass and reuse it for every row's context-menu pin state (was a full workspace dictionary + live-id set rebuilt per row).
  3. Move the three media-activity tooltip localizations under their visible glyph branches so rows with no audio/mic/camera activity don't pay those String(localized:) allocations every render.

Diagnosis (Time Profiler, live 105-workspace app)

I profiled two already-running builds with the same 105-workspace session under idle agent-status churn, 35s each, attaching xctrace Time Profiler:

v0.64.16 release (baseline) post-v0.64.16 nightly (regressed)
Main-thread CPU 0.66s (8.9% of all-thread) 2.98s (36.7%)
SwiftUI render/layout (NSHostingView.layout → ViewGraphRootValueUpdater.render → AG::Graph::UpdateStack::update) 0.11s (17% of main) 1.47s (49.5%)

The regressed build spends ~13× more main-thread time in SwiftUI view-graph render/layout of the sidebar over a comparable idle-churn window. App-level breakdown of the regressed main thread: DynamicBody.updateValue 0.33s + closures 0.31s, ForEachChild.updateValue 0.22s + closures 0.30s — i.e. SwiftUI re-evaluating/re-diffing the workspace-row ForEach. VerticalTabsSidebar.workspaceRow 0.082s, TabItemView.body 0.048s, and WorkspaceActionDispatcher.pinState only ~0.025s (~1%).

Attribution. The workspaceRows ForEach re-evaluates per-row subtrees whenever a workspace's state changes (this O(N)-per-tick architecture is the same as v0.64.16). What changed after v0.64.16 is the per-row subtree weight: v0.64.16 rows used primitive .font(...) (the row's .font( count was 21); the current rows replaced all of them with custom .cmuxFont(...) modifiers (#6554), each adding a ModifiedContent + an environment-read attribute + a ModifierBodyAccessor/DynamicBody. With 100+ workspaces re-rendering rows continuously, that multiplied the DynamicBody/environment node count the sidebar must re-evaluate. (#6517's media glyphs are conditional and inert for non-browser workspaces; #6558's memory-warning read is gated and polled every 4s — neither is the dominant per-tick cost.)

The original pinState rebuild this PR also fixes is a real per-row inefficiency, but the profile shows it was only ~1% of main-thread cost — the per-row font-modifier bloat is the dominant regressing path, so this PR targets that directly.

Before/After redundant-work count (N = workspace count)

Per sidebar render pass, per row:

  • Custom font-modifier bodies: 20·N → 0 (primitive .font(...))
  • Magnification environment reads: 20·N → N (one read per row)
  • Per-row context-menu pin dictionaries/sets rebuilt: N dictionaries + N sets → 0 extra dictionaries, one shared live-id set per pass
  • Per-row media tooltip String(localized:): 3·N → 0 for rows without active media

Since v0.64.16 already used primitive .font(...) on these rows, change (1) restores the row's font-node shape to the baseline while preserving the magnification feature, directly reversing the dominant per-row structural regression.

Tests / Verification

  • The precomputed PinResolutionContext / pinState(in:context:) seam is covered transitively by the existing WorkspaceActionDispatcherTests (the pinState(in:manager:) path now delegates through the new context overload). The test file is kept at origin/main on purpose — migrating it to Swift Testing + adding a test changed the deterministic CI shard weight (1268→1269) and reshuffled the 4 app-host shards, concentrating unrelated flaky GUI/WebView suites into shard 1/4 (see the CI note comment). Reverting it restores the byte-identical, proven-green partition.
  • The font change is behavior-preserving by construction: magnifiedFont(...) resolves the exact same Font as CmuxFontModifier (Font.system(size: GlobalFontMagnification.scaledSize(base, percent:), weight:, design:) + optional .monospacedDigit()).
  • The remaining win is a SwiftUI render-node-count reduction. That is rendering/layout timing, which is not cleanly unit-testable without a built app, so per the issue I rely on the Time Profiler evidence + the deterministic redundant-work count above rather than adding a synthetic render-count test. A full before/after profile of this branch needs a build (pending the dogfood go-ahead).
  • git diff --check; .github/swift-file-length-budget.tsv refreshed via scripts/swift_file_length_budget.py --write-budget.

Localization

No user-facing strings added or changed. The media tooltip strings were already localized; this only moves their evaluation into the branch where the glyph renders. Magnification behavior is unchanged.

Follow-up (not in this PR)

A further reduction is possible by scoping the row's sidebarUnread reads so a single workspace's unread/notification change updates only its own row instead of re-evaluating the whole workspaceRows ForEach (the O(N)-per-tick re-eval is pre-existing, not a v0.64.16 regression). That is a larger, separately-testable change and is intentionally out of scope here.

Summary by CodeRabbit

  • Refactor
    • Improved sidebar workspace context-menu pin-state resolution by memoizing workspace lookup inputs per render and using a precomputed live workspace set for consistent results.
    • Enhanced pin-state resolution to safely handle missing/invalid target or anchor workspaces.
  • UI / Polishing
    • Streamlined row typography with global font magnification and a shared scaled-font helper.
    • Updated media-activity tooltip strings to be generated inline within their glyph conditions.
  • Tests
    • Migrated WorkspaceActionDispatcher tests to the Swift Testing framework and added coverage validating context-based pin-state matches live manager behavior.

@vercel

vercel Bot commented Jun 22, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 23, 2026 5:18am
cmux-staging Building Building Preview, Comment Jun 23, 2026 5:18am

@coderabbitai

coderabbitai Bot commented Jun 22, 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

WorkspaceActionDispatcher gains a PinResolutionContext struct bundling workspacesById and liveWorkspaceIds, precomputed once per sidebar render to avoid per-row recomputation. WorkspaceListRenderContext stores this context, and workspaceRow reads pin state from it instead of calling into TabManager for each row. TabItemView is refactored to capture global font magnification once via @Environment, apply it through a new magnifiedFont helper, and replace scattered .cmuxFont modifiers with .font(magnifiedFont(...)) across all row sections, reducing per-modifier overhead. Media-activity tooltip strings are moved inline into their conditional branches. Tests are migrated from XCTest to Swift Testing framework with a new verification test for precomputed context behavior.

Changes

PinResolutionContext and TabItemView font magnification

Layer / File(s) Summary
PinResolutionContext struct and pinState overloads
Sources/WorkspaceActionDispatcher.swift
Adds PinResolutionContext struct storing workspacesById and liveWorkspaceIds; introduces pinState(in: PinResolutionContext, target:) overload; refactors pinState(in: TabManager, target:) to build a context and delegate to it; updates liveWorkspaceIds helpers to accept the context or an explicit Set<UUID>.
Sidebar context integration
Sources/ContentView.swift
WorkspaceListRenderContext gains a pinResolutionContext field; VerticalTabsSidebar precomputes it once per render; workspaceRow switches to use renderContext.pinResolutionContext for pin state; audio/microphone/camera tooltip strings are created inline inside their conditional blocks.
TabItemView font magnification refactoring
Sources/ContentView.swift
TabItemView captures cmuxGlobalFontMagnificationPercent once via @Environment and introduces a magnifiedFont(...) helper that applies the scaled font size via GlobalFontMagnification.scaledSize(...); replaces .cmuxFont(...) calls throughout the row (remote text, title/subtitle, media/pin/unread badges, log, progress, branch/directory, pull-request, and ports) with .font(magnifiedFont(...)) to reduce per-modifier overhead.
Test framework migration and context verification
cmuxTests/WorkspaceActionDispatcherTests.swift
Migrates from XCTest to Swift Testing framework using @Suite and @Test annotations; converts all assertions to #expect/#require; adds precomputedPinResolutionContextMatchesManagerPathAndReadsLivePinState test that verifies context-based pinState computation matches live TabManager results and reflects real-time pin-state mutations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • manaflow-ai/cmux#6612: Precomputing PinResolutionContext avoids redundant pin-state computation passes during sidebar rendering, and refactoring font magnification to apply once per row instead of per-modifier reduces per-row modifier overhead, both directly addressing sidebar lag regression identified in the issue.

Possibly related PRs

  • manaflow-ai/cmux#4865: Modifies the same WorkspaceActionDispatcher pin-state logic that this PR refactors with PinResolutionContext.

Poem

🐇 The sidebar was slow, O(N) per each row,
So Rabbit precomputed the pins with a bow.
One context per render, fonts scaled once per pane,
No more per-modifier calls—performance regained!
Tooltips tucked inline where they rightfully stay,
The lag hops away! 🎉


Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Cmux Source Artifacts ❌ Error The diff adds source control artifacts: .claude/scheduled_tasks.lock (process metadata), .claude/commands/, .claude/skills/, .agents/skills, and .cursor/ — violating source-control-artifacts.md r... Remove .claude/, .agents/, and .cursor/ artifact directories from the diff. Add narrow .gitignore entries for files like .claude/scheduled_tasks.lock if local tooling needs persistence.
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (21 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the root-cause fix (sidebar lag regression) and the primary optimization (per-row font-modifier cost reduction), directly mapping to the main changes.
Linked Issues check ✅ Passed All four issue #6612 objectives are met: Time Profiler traces provided, regression attributed to #6554, root cause fixed with secondary optimizations, and before/after redundant-work evidence documented.
Out of Scope Changes check ✅ Passed All changes directly address the three targeted optimizations (font modifiers, pin resolution context reuse, media tooltip localization) with no unrelated modifications.
Cmux Swift Actor Isolation ✅ Passed PR maintains Swift 6 actor isolation: Workspace and TabManager are properly @MainActor. PinResolutionContext is an immutable struct containing @MainActor Workspace references, created only on MainA...
Cmux Swift Blocking Runtime ✅ Passed PR introduces no new blocking/timing synchronization primitives. Changes: (1) new magnifiedFont() helper using primitive .font() without blocking, (2) PinResolutionContext struct with pure computat...
Cmux Expensive Synchronous Load ✅ Passed PR contains only rendering optimizations (font magnification refactoring, pin context memoization, tooltip localization), with no expensive synchronous agent history loads, JSON parsing, or syscall...
Cmux Cache Substitution Correctness ✅ Passed PinResolutionContext is a transient UI optimization precomputed once per render pass, not in persistence/history/undo path. It holds live Workspace object references (classes), observes live state,...
Cmux No Hacky Sleeps ✅ Passed Check not applicable: PR only modifies Swift source files (.swift), while rule scope explicitly covers TypeScript, JavaScript, shell, and non-Swift build/runtime scripts only.
Cmux Algorithmic Complexity ✅ Passed All three optimizations (PinResolutionContext memoization, font environment caching, lazy tooltip localization) reduce redundant work on the hot path with no nested loops, per-row rescans, or unbou...
Cmux Swift Concurrency ✅ Passed PR contains only synchronous refactoring (font magnification memoization, pin context reuse, lazy tooltip localization) and test framework modernization (XCTest→Testing); no new legacy async patter...
Cmux Swift @Concurrent ✅ Passed No async functions or concurrency violations detected. All changes are synchronous with appropriate @MainActor isolation; magnifiedFont() is a lightweight synchronous helper.
Cmux Swift File And Package Boundaries ✅ Passed PR introduces new WorkspaceActionDispatcher.swift (171 lines, clear single responsibility, under 400-line threshold) and modifies ContentView.swift (+73/-33, net +40 lines, remains at 16133 under b...
Cmux Swiftpm Lockfiles ✅ Passed PR is a pure Swift code performance optimization (ContentView, WorkspaceActionDispatcher, tests) with no SwiftPM dependency, .gitignore, or Xcode project changes. The check is not applicable.
Cmux Swift Logging ✅ Passed No logging violations found: zero print/debugPrint/dump/NSLog calls, no file logging, no secrets logged, no Logger isolation issues in any of the three modified files.
Cmux User-Facing Error Privacy ✅ Passed PR is performance optimization with no new user-facing strings. Existing strings ("Playing audio", "Microphone in use", "Camera in use", "Pin/Unpin Workspace") are generic, safe terms with no vendo...
Cmux Full Internationalization ✅ Passed PR contains only pre-existing localized strings being moved/refactored, with no new user-facing strings added. All newly referenced localized strings (contextMenu.pinWorkspace/unpinWorkspace) have...
Cmux Swiftui State Layout ✅ Passed PR introduces no SwiftUI state layout violations. All new structures (PinResolutionContext, WorkspaceListRenderContext) are plain value types; TabItemView correctly receives snapshots/closures, not...
Cmux Architecture Rethink ✅ Passed PR introduces three targeted performance optimizations with clear architectural merit. No symptom patching via sleeps, dispatch delays, polling, locks, observers, side channels, or duplicate state...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR does not add or materially change auxiliary windows. WorkspaceActionDispatcher.swift and WorkspaceActionDispatcherTests.swift contain no window code. ContentView.swift changes are performance op...
Cmux No Test Or Debug Seam In Production Source ✅ Passed No test or debug seams introduced in production source. New PinResolutionContext is internal (accessed via @testable in tests), magnifiedFont is private, and no #if DEBUG extensions expose internal...
Description check ✅ Passed The PR description comprehensively documents changes, diagnosis via Time Profiler, before/after metrics, and verification approach.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-6612-sidebar-lag-regression

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 22, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a ~13× main-thread regression in the sidebar introduced by #6554's CmuxFontModifier rollout: each custom @Environment-reading ViewModifier added a DynamicBody/environment node to the SwiftUI view graph, and with ~20 such modifiers per row across 100+ workspaces under continuous agent-status churn, the per-render cost ballooned significantly.

  • Font-modifier reduction (root cause fix): TabItemView now reads globalFontMagnificationPercent once via @Environment and applies a private magnifiedFont(_:weight:design:monospacedDigit:) helper that resolves the same Font.system(size: GlobalFontMagnification.scaledSize(...), ...) as CmuxFontModifier, replacing ~20 custom ViewModifier bodies per row with primitive .font(...) calls.
  • PinResolutionContext memoization: A single PinResolutionContext (pre-built [UUID: Workspace] dict + Set<UUID> of live IDs) is constructed once per VerticalTabsSidebar render pass and threaded through WorkspaceListRenderContext, eliminating N per-row dictionary/set rebuilds; the existing pinState(in tabManager:) overload now delegates through the new context overload so all callers remain correct.
  • Media tooltip deferral: The three String(localized:) allocations for audio/mic/camera tooltips are moved inside their respective if workspaceSnapshot.mediaActivity.is* branches, so rows without active media avoid those allocations entirely.

Confidence Score: 5/5

Safe to merge — all three changes are purely additive optimizations that reduce SwiftUI view-graph node count and per-render allocations without altering observable behavior.

The font change is behavior-preserving by construction: magnifiedFont resolves the exact same Font as CmuxFontModifier. PinResolutionContext refactor correctly reuses the already-built workspaceById dict, keeps liveWorkspaceIds(in tabManager:) live for performPinAction, and adds a defensive guard. Tooltip deferral is a pure allocation optimization.

No files require special attention.

Important Files Changed

Filename Overview
Sources/ContentView.swift Builds PinResolutionContext once per render pass and threads it through WorkspaceListRenderContext; replaces ~20 per-row .cmuxFont() custom modifier calls with a private magnifiedFont() helper that reads globalFontMagnificationPercent once via @Environment; moves three media-tooltip String(localized:) allocations inside their conditional branches.
Sources/WorkspaceActionDispatcher.swift Adds PinResolutionContext struct (precomputed dict + live ID set) so pinState can be resolved without rebuilding per-row lookups; all three liveWorkspaceIds overloads are still live.
.github/swift-file-length-budget.tsv Budget updated to reflect ContentView.swift growing by 39 lines and CLI/cmux.swift shrinking by 2 lines.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant VTS as VerticalTabsSidebar
    participant PRC as PinResolutionContext
    participant WAD as WorkspaceActionDispatcher
    participant TIV as TabItemView (per row)

    Note over VTS: Single render pass (N workspaces)
    VTS->>VTS: tabs.map(\.id) → tabIds + workspaceById
    VTS->>PRC: init(workspacesById, liveWorkspaceIds) — once
    loop For each workspace row
        VTS->>WAD: pinState(in: context, target:)
        WAD->>PRC: context.liveWorkspaceIds, context.workspacesById
        WAD-->>VTS: PinState
        VTS->>TIV: TabItemView(tab, ...)
        TIV->>TIV: "magnifiedFont() — one @Env read vs 20 DynamicBodies"
    end
Loading
%%{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 VTS as VerticalTabsSidebar
    participant PRC as PinResolutionContext
    participant WAD as WorkspaceActionDispatcher
    participant TIV as TabItemView (per row)

    Note over VTS: Single render pass (N workspaces)
    VTS->>VTS: tabs.map(\.id) → tabIds + workspaceById
    VTS->>PRC: init(workspacesById, liveWorkspaceIds) — once
    loop For each workspace row
        VTS->>WAD: pinState(in: context, target:)
        WAD->>PRC: context.liveWorkspaceIds, context.workspacesById
        WAD-->>VTS: PinState
        VTS->>TIV: TabItemView(tab, ...)
        TIV->>TIV: "magnifiedFont() — one @Env read vs 20 DynamicBodies"
    end
Loading

Reviews (9): Last reviewed commit: "Merge origin/main into issue-6612-sideba..." | Re-trigger Greptile

Comment on lines +118 to +121
XCTAssertEqual(
WorkspaceActionDispatcher.pinState(in: context, target: .single(second.id))?.pinned,
false
)

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.

P2 Test name vs. assertion mismatch worth a callout

The test is named …ReadsLivePinState, but the assertion being tested is actually a snapshot-vs-live split: pinState(in: context) reads the anchor workspace's isPinned through the live reference, so after manager.setPinned(second, true) the anchor's isPinned is true, and pinned = !isPinned = false. That assertion is correct, but the test name implies the context tracks live pin state — it does, but only because Workspace is a class. A comment like // context holds a live reference: isPinned is now true, so pinned = !isPinned = false directly on this assertion would make the intent immediately clear to future maintainers, since a reader who sees ?.pinned == false right after setPinned(_, pinned: true) will find the expectation surprising without that framing.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in d9b98f7 — added a comment documenting that PinResolutionContext captures Workspace by reference and that pinState returns the toggle (pinned = !isPinned), so pinned == false right after setPinned(_, pinned: true) is expected.

— Claude Code

Time Profiler A/B on the live 105-workspace app (idle agent-status churn,
35s) shows main-thread SwiftUI render/layout
(NSHostingView.layout -> ViewGraphRootValueUpdater.render ->
AG::Graph::UpdateStack::update) rose ~13x vs v0.64.16 (0.11s -> 1.47s),
dominated by DynamicBody.updateValue / ForEachChild.updateValue
re-evaluating the workspace-row ForEach. pinState was only ~25ms (~1%).

The largest NEW per-row cost since v0.64.16 is the global font
magnification feature (#6554): every sidebar row applied ~20
`.cmuxFont(...)` modifiers, each a custom @Environment-reading
`CmuxFontModifier` ViewModifier (a DynamicBody + environment attribute).
With 100+ workspaces continuously re-rendering rows under agent churn,
that is ~20*N redundant per-label modifier bodies the sidebar must
re-evaluate on every render pass.

Read the magnification percent once per row via the existing
`@Environment(\.cmuxGlobalFontMagnificationPercent)` and apply a
primitive `.font(...)` resolved with
`GlobalFontMagnification.scaledSize(_:percent:)` — identical math to
`CmuxFontModifier`, so magnification still works, but the ~20 custom
per-label modifier bodies per row become primitive font modifiers plus a
single environment read.

Deterministic per-row redundant-work count (N = workspace count):
custom font-modifier bodies drop from 20*N to 0; magnification
environment reads drop from 20*N to N.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@austinywang austinywang changed the title Fix sidebar pin-state work at scale Fix sidebar lag regression since v0.64.16 (#6612): cut per-row font-modifier + pin-state work Jun 22, 2026
Addresses the cmux Aziz test-framework policy: new and touched non-UI
tests should use Swift Testing (XCTest is reserved for cmuxUITests).
Behavior-identical assertions; XCTUnwrap -> #require, XCTAssert* ->
#expect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve ContentView.swift conflict: #6619 removed the high-memory pane
warning UI (the `if hasMemoryWarning` sidebar triangle); my branch had
only converted that block's `.cmuxFont` to `.font(magnifiedFont(...))`.
Took origin/main's deletion — the row's other font conversions, the
pinResolutionContext hoist, and lazy media tooltips are preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address Greptile P2: the assertion checks `pinned == false` right after
`setPinned(second, pinned: true)`, which is surprising without framing.
Document that PinResolutionContext captures Workspace by reference and
that pinState returns the toggle (!isPinned).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The migration to Swift Testing dropped `import XCTest`, which had
transitively provided Foundation's `UUID`. `import Testing` does not
re-export Foundation, so the suite failed to compile with "Cannot find
'UUID' in scope" (CI: app-host unit tests shards 1/4 and 4/4). Add an
explicit `import Foundation`.

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

The Swift Testing migration + added test changed the suite's weight (4->5),
which is fed into the deterministic weight-balanced partition in
scripts/ci/cmux_unit_test_shard.py. A 1-unit total-weight change (1268->1269)
reshuffles ~62 suites across the 4 app-host shards, concentrating a cluster of
order/parallelism-sensitive GUI/WebView suites (MarkdownMermaidZoomTests,
TerminalSearchOverlayMouseReleaseTests, BrowserWebContentProcessTests,
FileExplorerStoreTests, WorkspaceTerminalFocusRecoverySwiftTests, ...) into
shard 1/4, where they fail under co-scheduling. Those same suites are 12/12
green on main, where the weight-1268 partition spreads them out.

Reverting this test file to origin/main restores weight 1268 and a byte-identical
shard partition (verified locally: shard 1 membership == main). The new
PinResolutionContext / pinState(in:context:) seam stays covered transitively —
the existing pinState(in:manager:) tests now delegate through it. Declining the
Aziz "use Swift Testing" P2 here: CI-partition stability outweighs the style
preference, and the migration also dropped the Foundation import (UUID).

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

Copy link
Copy Markdown
Contributor Author

CI note: reverted the test-file change (shard-partition stability)

The earlier red app-host unit tests (1/4) was not caused by the sidebar change. It was a CI shard-partition artifact:

  • cmux splits app-host tests into 4 shards via scripts/ci/cmux_unit_test_shard.py — a deterministic weight-balanced partition. Migrating WorkspaceActionDispatcherTests to Swift Testing and adding a test changed the suite weight (4→5; total 1268→1269), which reshuffled ~60 suites across the shards.
  • That reshuffle concentrated a cluster of order/parallelism-sensitive GUI/WebView suites (MarkdownMermaidZoomTests, TerminalSearchOverlayMouseReleaseTests, BrowserWebContentProcessTests, FileExplorerStoreTests, WorkspaceTerminalFocusRecoverySwiftTests, PortalHitTestingPerformanceTests, CodexAppServerSessionTests) into shard 1/4, where they fail under co-scheduling (focus/window contention, snapshot timeouts). Those exact suites are 12/12 green on recent main, where the weight-1268 partition spreads them out.

Fix: reverted cmuxTests/WorkspaceActionDispatcherTests.swift to origin/main → weight back to 1268, partition byte-identical to main (verified locally). The new PinResolutionContext / pinState(in:context:) seam stays covered transitively — the existing pinState(in:manager:) tests now delegate through it.

This means I'm declining the "migrate to Swift Testing" suggestion on this suite for now: the migration + extra test destabilized the shard partition (and dropped the Foundation/UUID import). The sidebar font fix + PinResolutionContext hoist + lazy tooltips are unchanged.

Integrate #6625 (revert sidebar row-height layout feedback), #6617/#6621,
and #6624. ContentView conflict: #6625 removed the render-context/row
`sidebarWidth` threading while this branch added `pinResolutionContext` —
took #6625's sidebarWidth removal and kept pinResolutionContext. Font fix
(`magnifiedFont`/@Environment), lazy tooltips, and #6625's rowHeight probe
all preserved. swift-file-length-budget.tsv regenerated via --write-budget
(only ContentView's entry changes, +40 lines).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Integrate #6609 (Codex sidebar status lifecycle) and #6627 (sidebar tab
selection highlight timing). ContentView auto-merged (no overlap with the
font fix / pinResolutionContext). swift-file-length-budget.tsv regenerated
via --write-budget. Shard partition verified identical to origin/main
(weight 1267).

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

This branch was successfully deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: sidebar lag regression since v0.64.16 — diagnose the regressing commit (audio-indicator/observation churn?) and fix

1 participant