Skip to content

Add deterministic sidebar ownership and scale gates - #8279

Closed
azooz2003-bit wants to merge 1 commit into
mainfrom
feat-sidebar-ownership-gates
Closed

azooz2003-bit wants to merge 1 commit into
mainfrom
feat-sidebar-ownership-gates

Conversation

@azooz2003-bit

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

Copy link
Copy Markdown
Collaborator

Summary

  • assert viewport resize does not re-enter the sidebar owner during the active layout transaction
  • assert lazy row realization preserves the exact parent-owned observation-token topology
  • render production immutable row snapshots at 1, 10, 100, and 1,000 workspaces and bound work to the viewport
  • cover sidebar snapshot publisher behavior when demand pauses, callbacks re-enter, and AsyncPublisher.values consumes values

This changes no release behavior. The only source change is DEBUG probe plumbing that records which workspace rows SwiftUI realizes.

Verification

  • 25 selected sidebar ownership and scale tests passed
  • hierarchy tests passed 5 repeated in-process runs, 10 test executions total
  • publisher tests passed, 22 of 22
  • strict determinism check passed with 0 findings
  • sidebar lazy-layout guard, its Python tests, project test wiring, and diff checks passed
  • tagged sblife app exercised with 55 workspaces, top-to-bottom scrolling, and selection at both ends; no reentrant-layout, fatal, assertion, crash, or exception log entries

Historical red replay

The two ownership tests were replayed against pre-#8211 sidebar commit 856a18629d8fb5d245aacccdfee37ed4e6d1f514. No publisher fixes were applied.

  • 2 tests executed, 2 failed
  • active viewport resize reevaluated VerticalTabsSidebar.body 8 times, expected 0
  • pure scrolling changed observer identities at all 5 offsets
  • the non-vacuity check passed, proving scrolling realized rows beyond the initial viewport

The historical sidebar implementation remained unchanged. Compatibility adjustments only mapped the probe to the old tab.id name and exposed an existing test helper.

@cursor

cursor Bot commented Jul 16, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates the sidebar workspace-row debug probe to accept workspace identifiers, expands SwiftUI sidebar layout and ownership scale tests, bounds the geometry feedback canary, and adds comprehensive coalesceLatest demand and reentrancy tests.

Changes

Sidebar contract and scale tests

Layer / File(s) Summary
Workspace probe and layout canary
Sources/ContentView.swift, Sources/Debug/SidebarLazyContractProbe.swift, cmuxTests/SidebarLazyLayoutScaleTests.swift
The workspace-row probe receives and records workspaceId, resize invalidations are tracked, and the geometry feedback fixture is bounded inside a lazy stack.
Sidebar ownership boundaries
cmuxTests/SidebarPointerInteractionScaleTests.swift
Serialized tests verify resize behavior and observer identity stability across lazy scrolling.
Immutable row realization scale
cmuxTests/SidebarPointerInteractionScaleTests.swift
A deterministic lazy-stack harness checks viewport-bounded row evaluation and prevents workspace snapshot rebuilds.

CoalesceLatest regression tests

Layer / File(s) Summary
Demand and reentrancy coverage
cmuxTests/WorkspaceSidebarObservationTests.swift
Tests cover demand-gated replay and trailing values, serialized reentrant callbacks, returned demand, completion, and async iteration using manual and reentrant subscribers.

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

Possibly related issues

  • manaflow-ai/cmux#8224 — Adds probes and scale tests for the sidebar lazy-layout virtualization, ownership, and feedback-loop behaviors targeted by this PR.

Possibly related PRs

  • manaflow-ai/cmux#8236 — Directly related coalesceLatest demand-semantics changes covered by the new regression tests.
  • manaflow-ai/cmux#8275 — Overlaps the sidebar lazy-contract and workspace row realization test coverage.
  • manaflow-ai/cmux#7221 — Introduced the sidebar lazy-layout contract probe extended by this PR.

Suggested reviewers: austinywang


Important

Pre-merge checks failed

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

❌ Failed checks (2 errors)

Check name Status Explanation Resolution
Cmux Swiftui State Layout ❌ Error FAIL: cmuxTests/SidebarLazyLayoutScaleTests.swift adds a new GeometryReader→@State row-height feedback fixture that mutates layout from measurement, matching the banned SwiftUI pattern. Remove or isolate the feedback-loop canary from the SwiftUI diff; use a non-layout-mutating measurement harness or a pure mock instead.
Cmux No Test Or Debug Seam In Production Source ❌ Error Sources/ContentView.swift’s TabItemView keeps a DEBUG-only workspaceRowBody probe in shipping source and now passes workspaceId to it for tests. Move the observation into the test target via @testable import, or isolate any unavoidable debug-only probe in a dedicated debug file/folder (cf. PR #6452).
✅ Passed checks (23 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 Production diff only changes DEBUG probe plumbing in a SwiftUI view; no new isolation debt, protocols, or shared Sendable references were introduced.
Cmux Swift Blocking Runtime ✅ Passed PASS: The only production diffs thread a UUID through a DEBUG-only probe; the new tests use deterministic run-loop draining, with no semaphores, sync waits, sleeps, or locks in the touched files.
Cmux Browser Automation Off-Main ✅ Passed The commit only changes sidebar DEBUG probes and tests; no browser socket commands, worker routing, or policy tests were modified.
Cmux Expensive Synchronous Load ✅ Passed Only DEBUG probe plumbing and tests changed; TabItemView.body now passes a UUID to a test probe, with no new agent-history load/parse on main or interactive paths.
Cmux Cache Substitution Correctness ✅ Passed Only DEBUG probe plumbing and tests changed; no production persistence/history/undo/snapshot path swapped authoritative reads for cached values.
Cmux No Hacky Sleeps ✅ Passed PASS: The PR only changes Swift debug/test code; no TypeScript/JS/shell/build runtime files or new fixed sleeps/timers were introduced.
Cmux Algorithmic Complexity ✅ Passed PASS: The only production-code change is a DEBUG-only probe signature/value pass-through; no scalable collection scans, rescans, or hot-path sorting/filtering were introduced.
Cmux Swift Concurrency ✅ Passed Diff only adds DEBUG probe UUID plumbing and XCTest/Combine test scaffolding; no new background queues, detached Tasks, or completion-handler APIs were introduced.
Cmux Swift @Concurrent ✅ Passed Touched Swift files add only @MainActor UI-bound async tests and a DEBUG probe closure; no missing/invalid @concurrent or off-actor heavy async work found.
Cmux Swift Package Boundaries ✅ Passed Only production code change is DEBUG-only probe plumbing in app glue; the rest are tests, so no reusable domain logic was kept in the app target.
Cmux Swiftpm Lockfiles ✅ Passed Diff touches only Swift sources/tests; no Package.swift, .gitignore, workflow, project, or Package.resolved changes appear.
Cmux Swift Logging ✅ Passed No new production Swift logging was added; the only added print is in a test file, and the Sources changes are DEBUG probe plumbing only.
Cmux User-Facing Error Privacy ✅ Passed No user-facing error/alert/recovery copy changed; the only source change is a DEBUG-only probe signature and the rest are tests.
Cmux Full Internationalization ✅ Passed Only DEBUG-gated probe plumbing changed in production code; no locale/catalog/plist files or web i18n assets were touched.
Cmux Architecture Rethink ✅ Passed DEBUG-only probe plumbing and test coverage only; no production timing, observer, or split-ownership behavior was introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed Diff only changes DEBUG probe plumbing and test-only fixtures; no new standalone NSWindow/WindowGroup/NSPanel code or cmuxAuxiliaryWindowIdentifiers changes.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/test files; no logs, caches, build output, temp dirs, or other artifact paths were added.
Cmux No Ambient Global State ✅ Passed Production diff only changes an existing debug probe closure signature and its call site; no new top-level funcs, globals, namespaces, or singletons were added.
Title check ✅ Passed The title is concise and accurately summarizes the main change: deterministic sidebar ownership and scale gates.
Description check ✅ Passed The description covers summary and verification well, but omits the demo video, review trigger block, and checklist details from the template.
✨ 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-sidebar-ownership-gates

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 Jul 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds deterministic sidebar ownership and scale gates: a one-line production change threads workspaceId through the existing #if DEBUG probe, and the test layer gains three new suites verifying that viewport resizing doesn't re-enter the sidebar owner, that lazy row realization preserves observation-token topology through scroll, and that immutable row rendering stays viewport-bounded at 1–1 000 workspaces. Four new coalesceLatest Combine publisher tests cover demand-pause, reentrant callbacks, returned-demand forwarding, and AsyncPublisher.values.

  • Production change (compiled-out): SidebarLazyContractProbe.workspaceRowBody widens from () → Void to (UUID) → Void; TabItemView.body passes workspaceId into the existing #if DEBUG block — no Release behavior change.
  • New test suites: SidebarHierarchyOwnershipTests (causal, not timing-based checks against the pre-Fix sidebar scroll layout livelock #8211 publish-during-layout regression), SidebarImmutableRowScaleTests (renderer-neutral scale fixture at 1/10/100/1 000 workspaces), and four coalesceLatest variants in WorkspaceSidebarObservationTests.
  • Fixture hardening: DivergentGeometryFeedbackRowFixture replaced with BoundedGeometryFeedbackRowFixture (5-iteration feedback cap) to prevent the canary from trapping the test host in a permanent layout loop.

Confidence Score: 4/5

Safe to merge: the only production source change is a one-character DEBUG probe signature update that is compiled out of Release builds entirely, leaving runtime behaviour unchanged.

The production diff is minimal and correct. The test additions are well-structured causal checks. The one gap worth noting is that SidebarImmutableRowScaleTests.realizedRowCeiling = 150 does not catch an O(n) regression at the 100-workspace level — all 100 rows could be eagerly realized and the assertion would still pass — so that scale point is not meaningfully guarded. The ceiling is effective only at 1 000 workspaces.

cmuxTests/SidebarPointerInteractionScaleTests.swift — the realizedRowCeiling = 150 assertion in SidebarImmutableRowScaleTests and the SIDEBAR_SCALE_BASELINE print statement.

Important Files Changed

Filename Overview
Sources/ContentView.swift One-line change: passes workspaceId to the existing #if DEBUG-gated probe call site; modifies existing seam only, no logic change in Release builds.
Sources/Debug/SidebarLazyContractProbe.swift Widens the workspaceRowBody callback from () -> Void to (UUID) -> Void; the probe lives in the canonical Sources/Debug/ folder behind #if DEBUG — an existing seam with no production caller, compiled out of Release.
cmuxTests/SidebarLazyLayoutScaleTests.swift Adds realizedWorkspaceIds, isViewportResizeActive, and verticalSidebarBodiesDuringViewportResize tracking to RowBodyCounter; replaces the unbounded divergent feedback fixture with a 5-iteration-capped bounded one; injects MinimalModeInvalidationProbe. The realizedRowCeiling = 150 ceiling is shared across the 1–1,000 workspace loop, leaving the 100-workspace O(n) regression invisible.
cmuxTests/SidebarPointerInteractionScaleTests.swift Adds SidebarHierarchyOwnershipTests (viewport-resize and pure-scroll topology tests) and SidebarImmutableRowScaleTests (1/10/100/1000 scale fixture with realizedRowCeiling = 150); the ceiling does not catch O(n) at 100 workspaces.
cmuxTests/WorkspaceSidebarObservationTests.swift Adds four new coalesceLatest tests covering demand-paused retention, reentrant callbacks, returned-demand consumption, and AsyncPublisher.values interop; adds ManualDemandSubscriber and ReentrantDemandSubscriber helpers — all test-only scaffolding, no production impact.

Reviews (1): Last reviewed commit: "test: guard sidebar ownership at scale" | Re-trigger Greptile

/// An AppKit renderer can reuse these exact row values and operation bounds.
@Suite(.serialized)
final class SidebarImmutableRowScaleTests {
private static let realizedRowCeiling = 150

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 realizedRowCeiling = 150 does not protect the 100-workspace scale point

SidebarImmutableRowScaleTests iterates over [1, 10, 100, 1_000] and checks initialRowBodies < 150 at every step, but the threshold was sized to catch O(n) at 1 000 workspaces. At 100 workspaces a full-list realization (the regression being guarded) produces 100 bodies, which still satisfies 100 < 150, so the test silently passes even if LazyVStack virtualisation is defeated. Only the 1 000-workspace iteration would fail. A per-scale effective ceiling (e.g. min(workspaceCount, realizedRowCeiling)) would close the gap.

Comment on lines +428 to +434
"""
)
}

let newlyRealizedWorkspaceIds = harness.counter.realizedWorkspaceIds
.subtracting(initiallyRealizedWorkspaceIds)
#expect(

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 print() emits structured baseline data to stdout

The SIDEBAR_SCALE_BASELINE JSON lines are written with print(). Test code is exempt from the unified-logging rule, but if this output is intended for CI tooling or trend tracking, it would be more reliably captured via os_log / Logger at a debug level, or written to a named file from the test, rather than mixed into the test runner's stdout stream where it competes with framework output.

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!

@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)
cmuxTests/SidebarLazyLayoutScaleTests.swift (1)

457-485: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the realization thresholds discriminate the behavior under test.

Both gates can pass without proving viewport-bounded or feedback-driven realization.

  • cmuxTests/SidebarLazyLayoutScaleTests.swift#L457-L485: compare the feedback fixture with an identical no-feedback baseline.
  • cmuxTests/SidebarPointerInteractionScaleTests.swift#L450-L507: bound unique realized workspace IDs below the total row count for overflowing fixtures.
🤖 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 `@cmuxTests/SidebarLazyLayoutScaleTests.swift` around lines 457 - 485,
Strengthen the realization assertions at
cmuxTests/SidebarLazyLayoutScaleTests.swift:457-485 by rendering an identical
no-feedback baseline alongside BoundedGeometryFeedbackRowFixture and comparing
their realization counts, so the test proves feedback-driven behavior rather
than merely exceeding a fixed threshold. At
cmuxTests/SidebarPointerInteractionScaleTests.swift:450-507, track unique
realized workspace IDs for the overflowing fixtures and assert that their count
remains below the total row count, preserving the existing interaction coverage
while proving viewport-bounded realization.
🤖 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 `@cmuxTests/SidebarLazyLayoutScaleTests.swift`:
- Around line 457-485: Strengthen the realization assertions at
cmuxTests/SidebarLazyLayoutScaleTests.swift:457-485 by rendering an identical
no-feedback baseline alongside BoundedGeometryFeedbackRowFixture and comparing
their realization counts, so the test proves feedback-driven behavior rather
than merely exceeding a fixed threshold. At
cmuxTests/SidebarPointerInteractionScaleTests.swift:450-507, track unique
realized workspace IDs for the overflowing fixtures and assert that their count
remains below the total row count, preserving the existing interaction coverage
while proving viewport-bounded realization.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 83fe2b0c-baba-46e4-9f4f-8e1d46e217aa

📥 Commits

Reviewing files that changed from the base of the PR and between 25dc913 and a829f7f.

📒 Files selected for processing (5)
  • Sources/ContentView.swift
  • Sources/Debug/SidebarLazyContractProbe.swift
  • cmuxTests/SidebarLazyLayoutScaleTests.swift
  • cmuxTests/SidebarPointerInteractionScaleTests.swift
  • cmuxTests/WorkspaceSidebarObservationTests.swift

@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
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.

3 participants