Skip to content

Consolidate workspace extractions into CmuxWorkspaces (no new packages) - #6222

Merged
azooz2003-bit merged 3 commits into
mainfrom
feat-consolidate-workspace
Jun 16, 2026
Merged

azooz2003-bit merged 3 commits into
mainfrom
feat-consolidate-workspace

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 16, 2026 •

Copy link
Copy Markdown
Collaborator

Folds the workspace surface-list extraction into the EXISTING CmuxWorkspaces domain package instead of standing up a new top-level package. The owner rejected the per-sliver micro-packages; the extraction itself is good, so it now lives in the workspace domain package.

Slivers folded

  • feat-workspace-surface-list-model → the new CmuxWorkspaceSurfaceList package is gone; its contents live under Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/SurfaceList/.

Byte-identical

WorkspaceSurfaceListModel.swift (the @MainActor @Observable derivation: orderedPanelIds, focusedPanelId, representativePanelIdForWorkspaceManualUnread, effectiveSelectedPanelId, the tabIdsTo* pane queries, and the paneLayoutVersion reorder bump) and its WorkspaceSurfaceTreeReading.swift seam protocol are byte-identical to the member branch (verified by diff). They import only Foundation/Observation, so CmuxWorkspaces/Package.swift needs no new dependency. The 12 behavior tests moved into CmuxWorkspacesTests with only the @testable import target changed (CmuxWorkspaceSurfaceList → CmuxWorkspaces).

App-side seam is unchanged in shape: Workspace+WorkspaceSurfaceTreeReading.swift conforms Workspace to the seam, Workspace owns the model and is referenced weakly via the seam (no retain cycle), and the legacy accessors stay one-line forwards. Every import CmuxWorkspaceSurfaceList became import CmuxWorkspaces (removed in Workspace.swift, which already imports CmuxWorkspaces).

No new packages

Packages/CmuxWorkspaceSurfaceList/ is deleted and its 6 pbxproj package-reference entries removed. The pbxproj diff only adds the 4 source-file wiring entries for Workspace+WorkspaceSurfaceTreeReading.swift.

Verification

  • scripts/lint-ios-package-conventions.sh: zero new violations (one pre-existing namespace-enum ERROR in CmuxMobileShellUI/ComposerDictationTextMerge.swift is untouched debt already on main).
  • swift build + swift test green in Packages/CmuxWorkspaces: 32 tests across 4 suites pass.
  • Budget for Sources/Workspace.swift ratcheted to 12978.
  • Full-app xcodebuild intentionally left to CI per task instructions.

Supersedes the standalone CmuxWorkspaceSurfaceList package PR from feat-workspace-surface-list-model.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Consolidates the workspace surface-list logic into CmuxWorkspaces and removes CmuxWorkspaceSurfaceList with no behavior changes. Also fixes a pre-existing package-conventions lint to unblock CI.

  • Refactors

    • Added WorkspaceSurfaceListModel and WorkspaceSurfaceTreeReading under Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/SurfaceList/ to own ordered panel ids, focused/representative/selected panel, tabIdsTo*, and the layout-version bump.
    • Workspace now conforms to the seam and forwards legacy accessors; geometry-change handling calls surfaceList.registerGeometryChange().
    • Removed Packages/CmuxWorkspaceSurfaceList/ and replaced import CmuxWorkspaceSurfaceList with import CmuxWorkspaces; moved 12 behavior tests to CmuxWorkspacesTests.
    • No new dependencies; swift build/swift test pass. Sources/Workspace.swift file-length budget set to 12621.
  • Bug Fixes

    • Unblocked package-conventions-lint by adding // lint:allow namespace-enum to ComposerDictationTextMerge.swift (fixes a failure inherited from main).

Written for commit faebd3b. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Refactor
    • Reworked workspace surface and pane ordering logic to improve maintainability and ensure consistent navigation behavior.
  • Bug Fixes
    • Made workspace panel focus/selection and context-menu actions (close left/right/close others) follow the current pane ordering more reliably.
  • Tests
    • Added unit tests covering ordering, selection resolution, navigation helpers, and reorder/layout change detection.

… new package)

Folds the per-workspace surface-list derivation from
feat-workspace-surface-list-model into the EXISTING CmuxWorkspaces domain
package instead of standing up a new top-level CmuxWorkspaceSurfaceList
package. The owner rejected the per-sliver micro-packages; the extraction is
good, so it lives in the workspace domain package.

What moved (byte-identical logic):
- WorkspaceSurfaceListModel (the @mainactor @observable derivation model:
  orderedPanelIds, focusedPanelId, representativePanelIdForWorkspaceManualUnread,
  effectiveSelectedPanelId, the tabIdsTo* pane queries, and the paneLayoutVersion
  reorder bump) and its WorkspaceSurfaceTreeReading seam protocol now live in
  Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/SurfaceList/. Both files are
  byte-identical to the member branch; they only import Foundation/Observation,
  so CmuxWorkspaces's Package.swift needs no new dependency.
- The 12 behavior tests move into CmuxWorkspacesTests (only the @testable
  import target changed from CmuxWorkspaceSurfaceList to CmuxWorkspaces).

App-side seam unchanged in shape: Workspace+WorkspaceSurfaceTreeReading.swift
conforms Workspace to the seam and Workspace holds the model (weak back-ref via
the seam to avoid a retain cycle), with the legacy accessors as one-line
forwards. Every `import CmuxWorkspaceSurfaceList` became `import CmuxWorkspaces`
(removed in Workspace.swift, which already imports CmuxWorkspaces).

No new top-level package: Packages/CmuxWorkspaceSurfaceList/ is deleted and its
6 pbxproj package-reference entries are removed. The pbxproj only gains the
4 source-file wiring entries for Workspace+WorkspaceSurfaceTreeReading.swift.

Verified: scripts/lint-ios-package-conventions.sh adds zero new violations (the
one pre-existing namespace-enum ERROR in CmuxMobileShellUI is untouched debt on
main); swift build + swift test green in Packages/CmuxWorkspaces (32 tests, 4
suites). Budget for Sources/Workspace.swift ratcheted to 12978.

Supersedes the standalone CmuxWorkspaceSurfaceList package PR from
feat-workspace-surface-list-model.

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

vercel Bot commented Jun 16, 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 16, 2026 7:48am
cmux-staging Building Building Preview, Comment Jun 16, 2026 7:48am

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 46711876-dfc5-48c5-a10e-73ec1f66da23

📥 Commits

Reviewing files that changed from the base of the PR and between 45fed5a and faebd3b.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (2)
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj

📝 Walkthrough

Walkthrough

Introduces WorkspaceSurfaceListModel (an @Observable @MainActor`` class) and a WorkspaceSurfaceTreeReading protocol seam. `Workspace` conforms to the protocol and attaches the model at init, delegating all surface/panel ordering, selection, and tab-navigation computations to the new model instead of computing them inline.

Changes

WorkspaceSurfaceListModel extraction

Layer / File(s) Summary
WorkspaceSurfaceTreeReading protocol
Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/SurfaceList/WorkspaceSurfaceTreeReading.swift
Defines the @MainActor AnyObject protocol with UUID-based read-only accessors for pane/tab/surface geometry and panel registry, plus mutable reorder bookkeeping (lastOrderedPanelIds, bumpPaneLayoutVersion()).
WorkspaceSurfaceListModel implementation
Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/SurfaceList/WorkspaceSurfaceListModel.swift
Adds WorkspaceSurfaceListModel with a weak tree reference, attach(tree:), orderedPanelIds (deduped + orphan-appended), focusedPanelId, representativePanelIdForWorkspaceManualUnread (fallback chain), effectiveSelectedPanelId, left/right/close-others surface navigation, and registerGeometryChange() that conditionally bumps paneLayoutVersion.
Workspace conforms to WorkspaceSurfaceTreeReading
Sources/Workspace+WorkspaceSurfaceTreeReading.swift, cmux.xcodeproj/project.pbxproj
New file implementing the protocol on Workspace by reading bonsplitController pane/tab structure, mapping TabID/PaneID to UUID, forwarding panel registry, and delegating lastOrderedPanelIds/bumpPaneLayoutVersion() to paneTree. Registered in the Xcode project.
Workspace delegates to surfaceList
Sources/Workspace.swift
Adds surfaceList stored property and attach(tree: self) at init; replaces inline focusedPanelId, orderedPanelIds, representativePanelIdForWorkspaceManualUnread, effectiveSelectedPanelId, and tab left/right/close-others with forwarding calls into surfaceList; calls registerGeometryChange() in didChangeGeometry and removes the old lastOrderedPanelIds gate.
FakeTree and test suite
Packages/CmuxWorkspaces/Tests/CmuxWorkspacesTests/WorkspaceSurfaceListModelTests.swift
Adds FakeTree (in-memory WorkspaceSurfaceTreeReading) and tests covering ordered panel ID derivation, deduplication, orphan ordering, focused/representative/effective panel selection fallback chains, surface navigation helpers, registerGeometryChange() bump semantics, and detached model defaults.

Sequence Diagram(s)

sequenceDiagram
  participant Workspace
  participant WorkspaceSurfaceListModel
  participant WorkspaceSurfaceTreeReading

  Note over Workspace: init
  Workspace->>WorkspaceSurfaceListModel: attach(tree: self)

  Note over Workspace: query orderedPanelIds
  Workspace->>WorkspaceSurfaceListModel: orderedPanelIds
  WorkspaceSurfaceListModel->>WorkspaceSurfaceTreeReading: surfaceIdsInTabOrderAcrossAllPanes
  WorkspaceSurfaceListModel->>WorkspaceSurfaceTreeReading: panelId(forSurfaceId:), panelExists(_:), allPanelIds
  WorkspaceSurfaceListModel-->>Workspace: deduped + orphan-appended [UUID]

  Note over Workspace: didChangeGeometry
  Workspace->>WorkspaceSurfaceListModel: registerGeometryChange()
  WorkspaceSurfaceListModel->>WorkspaceSurfaceTreeReading: lastOrderedPanelIds (read)
  alt panel order changed
    WorkspaceSurfaceListModel->>WorkspaceSurfaceTreeReading: lastOrderedPanelIds = new (write)
    WorkspaceSurfaceListModel->>WorkspaceSurfaceTreeReading: bumpPaneLayoutVersion()
    WorkspaceSurfaceListModel-->>Workspace: true
  else unchanged
    WorkspaceSurfaceListModel-->>Workspace: false
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 A protocol seam, a model so neat,
The tree reads the panes — no inline repeat!
Orphan panels sorted by UUID string,
registerGeometryChange does its thing.
The workspace just forwards, clean and bright,
Extracted with tests — everything's right! 🌿

🚥 Pre-merge checks | ✅ 20 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: consolidating workspace surface-list logic from a new micro-package into the existing CmuxWorkspaces package, which aligns with the PR's primary objective.
Description check ✅ Passed The description includes all required template sections: Summary (what changed and why), Testing (verification steps taken), and Checklist items are addressed throughout the detailed description. Some checklist items are not explicitly marked but are substantively covered.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed WorkspaceSurfaceListModel and WorkspaceSurfaceTreeReading are both properly marked @MainActor and used only in MainActor contexts. Workspace (already @MainActor) owns the model with weak protocol r...
Cmux Swift Blocking Runtime ✅ Passed No blocking runtime patterns introduced: new code contains pure MainActor computations over live state, protocol definitions, and simple property forwarding with zero semaphores, locks, sleeps, or...
Cmux Expensive Synchronous Load ✅ Passed PR only moves existing @MainActor properties into a separate model; all operations remain in-memory (array iteration, Set ops, string sorting, dict lookups). No disk I/O, syscalls, or expensive loa...
Cmux Cache Substitution Correctness ✅ Passed All properties and methods forwarded via WorkspaceSurfaceListModel are computed (not cached); they read fresh from live sources (bonsplitController, panels registry) with no cached values substitut...
Cmux No Hacky Sleeps ✅ Passed This PR contains only Swift and Xcode project files. The custom check applies only to TypeScript, JavaScript, shell, or build/runtime scripts (per the rule's explicit scope which excludes Swift), s...
Cmux Algorithmic Complexity ✅ Passed All production code (WorkspaceSurfaceListModel, WorkspaceSurfaceTreeReading, Workspace+WorkspaceSurfaceTreeReading, Workspace) is byte-identical to HEAD. PR is a package reorganization, not introdu...
Cmux Swift Concurrency ✅ Passed The PR introduces modern Swift concurrency patterns. WorkspaceSurfaceListModel uses @Observable and @MainActor with Observation framework (not Combine); all APIs are synchronous read-only; no Dispa...
Cmux Swift @Concurrent ✅ Passed All code is synchronous with proper @MainActor annotations on class and protocol; no async functions, @concurrent misuse, or CPU/IO-heavy operations without explicit hops detected.
Cmux Swift File And Package Boundaries ✅ Passed All new files are under size limits (156/86/65 lines), have clear single responsibility (navigation state derivation), contain no mixed concerns, and code is properly placed in existing domain pack...
Cmux Swift Logging ✅ Passed No logging violations found. New source files contain no print/debugPrint/dump/NSLog statements, file logging, MainActor-coupled Logger declarations, or sensitive data logging. Code is pure derivat...
Cmux User-Facing Error Privacy ✅ Passed PR introduces no user-facing error messages or privacy-violating content. Changes consolidate internal navigation-state derivation code into CmuxWorkspaces package with no new error strings, creden...
Cmux Full Internationalization ✅ Passed PR contains no user-facing text requiring localization. Changes are refactoring-only: moving internal workspace surface-list model/protocol code from new package to existing CmuxWorkspaces package...
Cmux Swiftui State Layout ✅ Passed PR introduces WorkspaceSurfaceListModel using @Observable (modern shape, not @Published/@observableobject), with computed read-only properties and geometry bookkeeping called from proper event ha...
Cmux Architecture Rethink ✅ Passed PR extracts navigation-state derivations into WorkspaceSurfaceListModel with @MainActor sync reads through protocol seam, no timing/dispatch/locks/observers, single unified owner with weak backrefe...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds only data-model/state-management classes (WorkspaceSurfaceListModel, WorkspaceSurfaceTreeReading protocol, conformance extension) with zero window code; not subject to auxiliary-window-clos...
Cmux Source Artifacts ✅ Passed All 7 changed files are intentional source, test, or config files: 4 new Swift sources, 1 refactored Swift file, and 2 legitimate config updates. No local artifacts, generated files, caches, build...

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feat-consolidate-workspace

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 and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Consolidates the workspace surface-list extraction into the existing CmuxWorkspaces package instead of standing up a separate CmuxWorkspaceSurfaceList top-level package. No behavioral changes — WorkspaceSurfaceListModel and WorkspaceSurfaceTreeReading are moved to Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/SurfaceList/, Workspace conforms to the seam and forwards its legacy accessors, and the 12 behavior tests land in CmuxWorkspacesTests.

  • Extraction: WorkspaceSurfaceListModel (@MainActor @Observable) derives orderedPanelIds, focusedPanelId, the representative-panel fallback, per-pane selection, the tabIdsTo* queries, and the paneLayoutVersion reorder bump; Workspace holds one instance, attaches itself as the weak tree-reading host, and delegates all legacy computed properties here.
  • Cleanup: Packages/CmuxWorkspaceSurfaceList/ is deleted, its 6 pbxproj package-reference entries removed, and all import CmuxWorkspaceSurfaceList call-sites updated to import CmuxWorkspaces.
  • CI fix: A pre-existing namespace-enum lint violation in ComposerDictationTextMerge.swift is suppressed with // lint:allow namespace-enum to unblock the package-conventions lint gate.

Confidence Score: 4/5

The consolidation is faithful and well-tested, but two open design questions on this PR — the @observable observation no-op in WorkspaceSurfaceListModel and the compactMap UUID conversion in the seam — should be resolved before merging.

The logic extraction is behavior-preserving: the 12 tests cover all derivation paths, the delegation chain in Workspace.swift is straightforward, and the pbxproj delta is minimal. The two concerns already active in the PR thread — that WorkspaceSurfaceListModel's @observable fires no updates (all properties compute from an @ObservationIgnored field), and that spatiallyOrderedPaneIds silently drops panes via compactMap(UUID.init(uuidString:)) — remain unresolved and affect correctness for any callers that bypass the Workspace forwarding wrappers or encounter a UUID format edge case.

WorkspaceSurfaceListModel.swift (observation design) and Workspace+WorkspaceSurfaceTreeReading.swift (spatiallyOrderedPaneIds UUID conversion)

Important Files Changed

Filename Overview
Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/SurfaceList/WorkspaceSurfaceListModel.swift New derivation model; all public computed properties read exclusively from an @ObservationIgnored weak reference, so the @observable annotation generates no observation access calls and views reading surfaceList directly will register no dependency. Open design discussion on the PR.
Packages/CmuxWorkspaces/Sources/CmuxWorkspaces/SurfaceList/WorkspaceSurfaceTreeReading.swift Clean @mainactor protocol seam erasing Bonsplit's opaque TabID/PaneID types to UUID at the package boundary; API surface is minimal and well-documented.
Packages/CmuxWorkspaces/Tests/CmuxWorkspacesTests/WorkspaceSurfaceListModelTests.swift 12 behavior tests covering ordered-panel derivation, deduplication, orphan sort, focused/representative/per-pane selection, left/right/close-others queries, geometry-change bump gating, and detached defaults — comprehensive coverage of all model paths.
Sources/Workspace+WorkspaceSurfaceTreeReading.swift Conformance file correctly erases Bonsplit types; spatiallyOrderedPaneIds uses compactMap(UUID.init(uuidString:)) to convert snapshot strings — silent-drop behavior under UUID format divergence is an open discussion on the PR.
Sources/Workspace.swift Legacy computed properties (orderedPanelIds, focusedPanelId, representativePanelIdForWorkspaceManualUnread, effectiveSelectedPanelId, tabIdsTo*) cleanly delegated to surfaceList; attach(tree: self) wired in init; lastOrderedPanelIds private property removed. Budget correctly ratcheted down.
.github/swift-file-length-budget.tsv Workspace.swift budget reduced from 12660 to 12621, reflecting lines removed by the delegation refactor.
cmux.xcodeproj/project.pbxproj Adds only the 4 entries for Workspace+WorkspaceSurfaceTreeReading.swift (PBXBuildFile, PBXFileReference, group membership, Sources phase); matches the PR description of no new package references added.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant SwiftUI as SwiftUI View
    participant WS as Workspace (ObservableObject)
    participant SL as WorkspaceSurfaceListModel (@Observable)
    participant Seam as WorkspaceSurfaceTreeReading (protocol)
    participant BC as BonsplitController
    participant PT as PaneTreeModel

    Note over WS,SL: init() — attach(tree: self)

    SwiftUI->>WS: orderedPanelIds
    WS->>SL: surfaceList.orderedPanelIds
    SL->>Seam: surfaceIdsInTabOrderAcrossAllPanes
    Seam->>BC: allTabIds.map(\.uuid)
    BC-->>Seam: [UUID]
    Seam-->>SL: [UUID]
    SL->>Seam: panelId(forSurfaceId:) / panelExists(_:)
    Seam->>WS: panelIdFromSurfaceId / panels[panelId]
    WS-->>Seam: UUID?
    SL-->>WS: [UUID]
    WS-->>SwiftUI: [UUID]

    Note over WS,SL: geometry change callback

    WS->>SL: surfaceList.registerGeometryChange()
    SL->>SL: compute orderedPanelIds
    SL->>Seam: lastOrderedPanelIds (compare)
    Seam->>PT: paneTree.lastOrderedPanelIds
    PT-->>Seam: [UUID]
    alt order changed
        SL->>Seam: "lastOrderedPanelIds = currentOrder"
        SL->>Seam: bumpPaneLayoutVersion()
        Seam->>WS: "paneLayoutVersion &+= 1"
        WS-->>SwiftUI: objectWillChange fires
    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 SwiftUI as SwiftUI View
    participant WS as Workspace (ObservableObject)
    participant SL as WorkspaceSurfaceListModel (@Observable)
    participant Seam as WorkspaceSurfaceTreeReading (protocol)
    participant BC as BonsplitController
    participant PT as PaneTreeModel

    Note over WS,SL: init() — attach(tree: self)

    SwiftUI->>WS: orderedPanelIds
    WS->>SL: surfaceList.orderedPanelIds
    SL->>Seam: surfaceIdsInTabOrderAcrossAllPanes
    Seam->>BC: allTabIds.map(\.uuid)
    BC-->>Seam: [UUID]
    Seam-->>SL: [UUID]
    SL->>Seam: panelId(forSurfaceId:) / panelExists(_:)
    Seam->>WS: panelIdFromSurfaceId / panels[panelId]
    WS-->>Seam: UUID?
    SL-->>WS: [UUID]
    WS-->>SwiftUI: [UUID]

    Note over WS,SL: geometry change callback

    WS->>SL: surfaceList.registerGeometryChange()
    SL->>SL: compute orderedPanelIds
    SL->>Seam: lastOrderedPanelIds (compare)
    Seam->>PT: paneTree.lastOrderedPanelIds
    PT-->>Seam: [UUID]
    alt order changed
        SL->>Seam: "lastOrderedPanelIds = currentOrder"
        SL->>Seam: bumpPaneLayoutVersion()
        Seam->>WS: "paneLayoutVersion &+= 1"
        WS-->>SwiftUI: objectWillChange fires
    end
Loading

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

Comment on lines +22 to +26
@MainActor
@Observable
public final class WorkspaceSurfaceListModel {
@ObservationIgnored
private weak var tree: (any WorkspaceSurfaceTreeReading)?

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 @Observable with no tracked storage — observation silently no-ops

WorkspaceSurfaceListModel is @Observable, but its only stored property (tree) is @ObservationIgnored. Every computed property (orderedPanelIds, focusedPanelId, representativePanelIdForWorkspaceManualUnread, etc.) reads exclusively from tree. The @Observable macro generates _$observationRegistrar.access calls only for stored properties that are NOT @ObservationIgnored; computed properties that read only ignored storage register no observation dependency at all.

The consequence: any SwiftUI view body that reads workspace.surfaceList.orderedPanelIds (or any other derived property) via the @Observable machinery registers no dependency, will never be re-invalidated when tree data changes, and silently shows stale data. surfaceList is internal let (not private), so it is accessible to all SwiftUI views in the app target — the missing-update footgun is live.

Current callers route through workspace.orderedPanelIds (the ObservableObject forwarding path), so nothing is broken today. But the @Observable annotation advertises an observability contract the model cannot honour for any of its useful properties. Either drop @Observable here (and document that callers must observe through Workspace), or add a stored cached snapshot that IS tracked and that the registerGeometryChange() path invalidates.

Comment on lines +29 to +31
var spatiallyOrderedPaneIds: [UUID] {
bonsplitController.treeSnapshot().orderedPaneIds.compactMap(UUID.init(uuidString:))
}

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 Silent pane drop if orderedPaneIds strings don't round-trip through UUID

spatiallyOrderedPaneIds uses compactMap(UUID.init(uuidString:)) to convert bonsplit's treeSnapshot().orderedPaneIds strings. compactMap silently drops any string that fails UUID parsing, whereas the original code keyed its dictionary by paneId.id.uuidString and looked up by the same string type — a mismatch just missed the key, but every pane was iterated. If bonsplit ever emits a pane id string in a format that UUID.init(uuidString:) rejects (e.g., non-standard casing or extra wrapper characters), the representative-panel fallback will silently skip that pane. allPaneIds takes \.id directly from PaneID, so the two UUID sources are structurally different; a precondition or an assertion that the parsed count equals allPaneIds.count would catch any future format divergence early.

ComposerDictationTextMerge (landed in #6197) is a caseless static-member
enum with no lint:allow marker, so package-conventions-lint (a required
check) has been red on main and on every PR branched off it. It is a
genuine stateless pure-function namespace with no instance state to own,
so the sanctioned inline lint:allow escape hatch is the correct fix rather
than reshaping it into an instantiated type.

Unblocks this consolidation PR's required CI; the consolidation diff
itself is unchanged.

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

# Conflicts:
#	.github/swift-file-length-budget.tsv
#	Packages/CmuxMobileShellUI/Sources/CmuxMobileShellUI/ComposerDictationTextMerge.swift
@azooz2003-bit
azooz2003-bit merged commit 6c96623 into main Jun 16, 2026
23 of 24 checks passed
@azooz2003-bit
azooz2003-bit deleted the feat-consolidate-workspace branch June 16, 2026 08:25

This branch was successfully deployed

1 active deployment
Preview – cmux — faebd3b5 Deployed Jun 16, 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.

1 participant