Skip to content

fix(cli): fail the Pi feed when an explicit workspace ref stays unresolved - #14277

Merged
teamleaderleo merged 1 commit into
mainfrom
fix/pi-feed-unresolved-workspace-ref
Sep 24, 2026
Merged

teamleaderleo merged 1 commit into
mainfrom
fix/pi-feed-unresolved-workspace-ref

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

tests/test_pi_compacted_feed.py fails on the CLI regression shard: "Pi feed did not report its missing explicit workspace as an unavailable target". The test was right: the Pi feed leaks events across workspace scope.

Cause

Since #13964, resolveWorkspaceId returns an unmatched ref unchanged when it cannot scan every window, for example when window.list fails, or over a relay, where the host resolves the ref. The Pi feed treated that raw ref as a resolution. Because the ref isn't a UUID, it left workspace_id out of agent.resolve_delivery_target and routed by surface alone. The failing run's frames show the whole sequence:

  • workspace.list
  • window.list returns not_found
  • agent.resolve_delivery_target is called with only surface_id
  • feed.push sends the event to workspace 6666…, which is not the requested workspace:404

Fix

After resolution, an explicit --workspace selector must end as a UUID. If it doesn't, the feed throws its existing unavailable-target error (piHookSurfaceNotFoundError, exit 69, v2 not_found). This follows the file's own rule: a supplied index or ref "cannot be discarded without violating the caller's explicit scope".

Behavior change: over a relay, cmux hooks feed --source pi --workspace workspace:N now fails with 69 instead of silently delivering by surface. This also covers relay runs that pass a ref workspace together with an index or ref surface, or with no surface. Those used to send the ref through surface.list for the host to resolve, and now fail with 69 too. The guard runs in the shared target resolution, so Pi hook events (cmux hooks pi ..., through resolveStrictPiHookTarget) get the same behavior as hooks feed. A caller that passes a workspace UUID is unaffected, and CMUX_WORKSPACE_ID is always a UUID.

Not changed: a full scan that finds no match throws Workspace ref not found without a v2 code, so it exits 1, not 69. That was already true before this PR. Fixing it would mean giving resolveWorkspaceId's errors a not_found code, which also changes error output for its 26 other callers, so it's left for a separate change.

Validation

The CLI regression shard (app-host 4/7) runs tests/test_pi_compacted_feed.py, including test_pi_feed_rejects_missing_explicit_workspace. I did not build the CLI locally (no local cmux builds on this machine), so CI is the proof.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Explicit workspace selections are now rejected when the workspace cannot be resolved, instead of proceeding with surface-only routing. This prevents a request from being routed outside the selected workspace when workspace information is unavailable.

…olved

Since #13964, resolveWorkspaceId returns an unmatched ref unchanged when
it cannot scan every window (a failed window.list, or a relay). The Pi
feed took that as resolved, dropped the non-UUID scope, and routed the
event by surface alone, so an event for a missing --workspace was
delivered to whatever workspace owns the surface. The feed now fails
with its unavailable-target exit code (69) unless an explicit selector
resolves to a UUID.

test_pi_feed_rejects_missing_explicit_workspace caught this once the
CLI regression shard got past its earlier failures (#14246, #14263).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 0c04f43c-a199-4e11-816c-5835e12ef89b

📥 Commits

Reviewing files that changed from the base of the PR and between 2d821f1 and 6e66f25.

📒 Files selected for processing (1)
  • CLI/CMUXCLI+PiCompactedFeed.swift

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The Pi hook target resolver now rejects an explicitly supplied workspace selector when it does not resolve to a UUID. It throws the surface-not-found error instead of continuing with surface-only routing.

Changes

Pi hook routing

Layer / File(s) Summary
Reject unresolved workspace selectors
CLI/CMUXCLI+PiCompactedFeed.swift
When the caller supplies a workspace selector and its resolved ID is missing or not a UUID, resolveStrictPiHookTarget throws piHookSurfaceNotFoundError(workspace).

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Suggested reviewers: austinywang

Merge Risk: ⚪ Minimal · up to 6e66f

Unresolved explicit workspace selectors now return the unavailable-target error without routing by surface alone. The inspected change leaves resolved UUID selectors and full-scan no-match behavior unchanged, with no actionable merge risk identified.

🚥 Pre-merge checks | ✅ 25
✅ Passed checks (25 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files.
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 Cloud Persistent Session And Early Input ✅ Passed PASS: The pull request changes only CLI/CMUXCLI+PiCompactedFeed.swift. The diff adds validation that an explicit workspace selector resolves to a UUID before Pi feed routing. It does not change Clou…
Cmux Swift Actor Isolation ✅ Passed The PR adds only a synchronous guard and error path inside the existing CMUXCLI.resolveStrictPiHookTarget method. The diff adds no @MainActor, async, Sendable, model, protocol, shared reference, o…
Cmux Swift Blocking Runtime ✅ Passed PASS. The PR adds only a UUID validation guard and comments in resolveStrictPiHookTarget. It adds no semaphore, blocking wait, sleep, delayed dispatch, polling, synchronous queue dispatch, or manual…
Cmux Browser Automation Off-Main ✅ Passed PASS: The PR changes only CLI/CMUXCLI+PiCompactedFeed.swift, adding workspace-resolution validation for the Pi feed. It does not change a browser.* socket command, socketWorkerMethods, the worke…
Cmux Expensive Synchronous Load ✅ Passed PASS. The PR changes only CLI/CMUXCLI+PiCompactedFeed.swift and adds a UUID validation guard plus comments in resolveStrictPiHookTarget. It adds no RestorableAgentSessionIndex.load(), agent-hist…
Cmux Cache Substitution Correctness ✅ Passed PASS. The PR adds only a UUID validation guard in CLI/CMUXCLI+PiCompactedFeed.swift. It rejects an unresolved workspace reference instead of using it for surface-only routing. It does not replace a …
Cmux No Hacky Sleeps ✅ Passed PASS. The pull request changes only CLI/CMUXCLI+PiCompactedFeed.swift. It adds a UUID validation guard and an error path. It does not add sleeps, timers, polling, delays, or wall-clock waits. The re…
Cmux Algorithmic Complexity ✅ Passed PASS. The PR adds one isUUID check and one conditional throw in CLI/CMUXCLI+PiCompactedFeed.swift (added lines 228–234). isUUID calls UUID(uuidString:) and performs no collection scan. The exi…
Cmux Swift Concurrency ✅ Passed PASS. The PR adds only a synchronous validation guard in resolveStrictPiHookTarget. The diff introduces no Dispatch, Task, Combine, completion-handler, or other legacy async pattern covered by t…
Cmux Swift @Concurrent ✅ Passed The PR changes only synchronous Swift code in resolveStrictPiHookTarget; it adds a UUID guard and no async, nonisolated, @concurrent, or actor-isolation annotation. The surrounding CLI type is…
Cmux Swift Package Boundaries ✅ Passed PASS. The diff adds only seven lines to the existing CLI target resolver in CLI/CMUXCLI+PiCompactedFeed.swift. The guard is tightly coupled to CMUXCLI, SocketClient, resolveWorkspaceId, and ex…
Cmux Swiftpm Lockfiles ✅ Passed PASS — The authoritative PR diff changes only CLI/CMUXCLI+PiCompactedFeed.swift (+7 lines). It changes Swift CLI logic only; it does not change a Package.swift, Package.resolved, .gitignore, w…
Cmux Swift Logging ✅ Passed PASS. The PR changes only workspace-resolution control flow and comments in CLI/CMUXCLI+PiCompactedFeed.swift. The diff adds no print, debugPrint, dump, NSLog, file logging, Logger declarati…
Cmux User-Facing Error Privacy ✅ Passed The changed path is the product CLI cmux hooks feed --source pi, and failures reach the end user through the top-level Error: ... stderr printer. The new branch calls the existing `piHookSurfaceNo…
Cmux Full Internationalization ✅ Passed The PR adds only developer comments and a UUID guard in CLI/CMUXCLI+PiCompactedFeed.swift. The new error path reuses the existing piHookSurfaceNotFoundError helper, which uses `String(localized:de…
Cmux Swiftui State Layout ✅ Passed PASS. The PR changes only CLI/CMUXCLI+PiCompactedFeed.swift. The seven added lines add workspace-resolution validation in an extension CMUXCLI. They do not add SwiftUI views, state wrappers, `Obse…
Cmux Architecture Rethink ✅ Passed PASS. The PR adds only a local seven-line guard in resolveStrictPiHookTarget. It uses no sleeps, polling, locks, observers, flags, caches, side channels, duplicate wiring, or UI lifecycle ownership.…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR changes only workspace/surface target resolution in CLI/CMUXCLI+PiCompactedFeed.swift. The diff adds validation and error handling; it does not add or materially change NSWindow, NSPanel,…
Cmux Source Artifacts ✅ Passed The pull request changes only the tracked hand-written Swift source file CLI/CMUXCLI+PiCompactedFeed.swift. The seven added lines are product logic in resolveStrictPiHookTarget. No logs, caches, b…
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS: The PR changes only CLI/CMUXCLI+PiCompactedFeed.swift. No changed Swift file is under a production Sources/ path, so this check does not apply.
Title check ✅ Passed The title clearly identifies the main change: failing the Pi feed when an explicit workspace reference remains unresolved.
Description check ✅ Passed The description clearly explains the problem, cause, fix, behavior changes, unchanged behavior, and validation. It does not use the template headings or include the checklist or a demo video, but it p…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@teamleaderleo
teamleaderleo enabled auto-merge (squash) September 24, 2026 19:40
@teamleaderleo
teamleaderleo merged commit 2ef659a into main Sep 24, 2026
59 of 60 checks passed
rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 24, 2026
2ef659a fix(cli): fail the Pi feed when an explicit workspace ref stays unresolved (manaflow-ai#14277)
2d821f1 Track per-hop mobile keystroke latency and pacer rate in the existing Axiom window (manaflow-ai#14270)
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