Repository navigation
agent cursor visibility: the rules move to Rust (cmux-focus-core), Swift calls them over the app FFI (B9; waits for the pre-merge FFI release) - #31781
Conversation
…Rust rules (failing) The Rust home of the agent cursor visibility rules (backlog B9) gets its types and the replay of schemas/agent-cursor-visibility/vectors.json, ported from the deleted Swift AgentCursorVisibilityVectorTests, plus the page scale case. The resolver is a stub that answers notDrawn(tabClosed): 25 of 26 vectors fail until the rules move in the next commit.
The rules of CmuxNextAgentCursorVisibility's AgentCursorVisibilityResolver, moved as they are: the window that shows (else lists) the target's workspace, minimized and other-Space windows draw nothing, another workspace anchors at its sidebar row (else the window edge), a pane off the active screen at the window edge, a scrolled-out column or page at the strip edge it left through, a background tab at its chip (else the strip), and a shown page draws in its viewport with its clip, zoom and scale. CGRect semantics: sizes are standardized, intersection is none when the rects do not meet. No behavior change; the Swift copy goes in PR 2.
…SON channel
cmux_layout_reducer_json answers agent_cursor_visibility ({target,
snapshot} in, the visibility in the vectors' expect shape out) from
cmux-focus-core's rules. cmux-app-ffi links this crate already, so the next
CCmuxAppFFI release carries the op; the Swift resolver calls it in PR 2.
The C ABI test sends every vector through the op.
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 2429d60 to compare; do not merge until green; see lane-rules Default changesThis pull request changes 2 defaults at
Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Regenerate the snapshot with |
|
Found 14 test failures on Blacksmith runners: Failures
...and 4 more test failures. View all on Blacksmith: run 41391178939, run 41391178721
|
…ules over the app FFI (B9 PR 2)
AgentCursorVisibilityResolver keeps its signature and becomes a thin call:
it sends {target, snapshot} to cmux_layout_reducer_json
"agent_cursor_visibility" (cmux-focus-core, through CmuxNextFocus's
FocusReducer.call) and decodes the answer into AgentCursorVisibility. The
Swift copy of the rules is deleted (window choice, Space and minimize
checks, sidebar row and window edge anchors, column edges, chip and strip
anchors, the visible clip). AgentCursorAnchor gets its wire name, which
the debug socket now uses instead of its own copy.
CmuxNextAgentCursorVisibilityTests replays the shared vectors through the
call, so the wire between Swift and Rust is proved both ways; it needs the
CCmuxAppFFI re-pin that carries the op (#31781).
…s-core tests embed Also lists schemas/settings/source/agent-retry.json, which acpmux embeds and the key missed on the base (tree-key-embeds.test.sh red at 0511de2).
…ursor-visibility-swift
|
Review (claude-review-subagent): SHIP at 51e3894 What I checked:
Notes (non-blocking):
|
… no new test target
…y wire as strings (failing) The app's JSONEncoder refuses non-finite numbers, and a CGRect.null the snapshot builder converts has infinite x and y. The Swift rules gave a result for such a snapshot; the Rust rules must give the same one.
…y wire as "inf", "-inf", "nan" Every number of the snapshot and of the answer reads and writes the strings the Swift side's JSONEncoder/JSONDecoder convertToString and convertFromString strategies use, so a snapshot with a converted CGRect.null or an infinite scale gets the result the Swift rules gave it.
…ss the Rust call
The resolver encodes and decodes with the convertToString strategies the
Rust wire reads ("inf", "-inf", "nan"), through a new raw-bytes
FocusReducer.call, so a converted CGRect.null or an infinite scale gets the
result the Swift rules gave instead of a refused call. The vector suite
covers it; the vectors file names its three replays.
|
Review (codex gpt-6-astra high, next-review): BLOCK at 78cbd40 BLOCK at 78cbd40 Visual verdict: no images; Leo tries the build.
|
|
Replaced by #31934 (step A: Rust only, the same Rust commits with no Swift history), under the two-step FFI rule (lead 06:37Z). Step B (the Swift thin call, the vector suite, the deletion of the Swift rules) is on branch rust-migration/cursor-visibility-step-b and opens after the CCmuxAppFFI re-pin is on feat-cmux-next. |
… the Swift rules are deleted (B9 step B) (#32028) * test(focus-core): agent cursor visibility vectors replay against the Rust rules (failing) The Rust home of the agent cursor visibility rules (backlog B9) gets its types and the replay of schemas/agent-cursor-visibility/vectors.json, ported from the deleted Swift AgentCursorVisibilityVectorTests, plus the page scale case. The resolver is a stub that answers notDrawn(tabClosed): 25 of 26 vectors fail until the rules move in the next commit. * feat(focus-core): agent cursor visibility rules in Rust (backlog B9) The rules of CmuxNextAgentCursorVisibility's AgentCursorVisibilityResolver, moved as they are: the window that shows (else lists) the target's workspace, minimized and other-Space windows draw nothing, another workspace anchors at its sidebar row (else the window edge), a pane off the active screen at the window edge, a scrolled-out column or page at the strip edge it left through, a background tab at its chip (else the strip), and a shown page draws in its viewport with its clip, zoom and scale. CGRect semantics: sizes are standardized, intersection is none when the rects do not meet. No behavior change; the Swift copy goes in PR 2. * feat(layout-reducer-ffi): agent_cursor_visibility op in the app FFI JSON channel cmux_layout_reducer_json answers agent_cursor_visibility ({target, snapshot} in, the visibility in the vectors' expect shape out) from cmux-focus-core's rules. cmux-app-ffi links this crate already, so the next CCmuxAppFFI release carries the op; the Swift resolver calls it in PR 2. The C ABI test sends every vector through the op. * refactor(next agent cursor): the visibility resolver calls the Rust rules over the app FFI (B9 PR 2) AgentCursorVisibilityResolver keeps its signature and becomes a thin call: it sends {target, snapshot} to cmux_layout_reducer_json "agent_cursor_visibility" (cmux-focus-core, through CmuxNextFocus's FocusReducer.call) and decodes the answer into AgentCursorVisibility. The Swift copy of the rules is deleted (window choice, Space and minimize checks, sidebar row and window edge anchors, column edges, chip and strip anchors, the visible clip). AgentCursorAnchor gets its wire name, which the debug socket now uses instead of its own copy. CmuxNextAgentCursorVisibilityTests replays the shared vectors through the call, so the wire between Swift and Rust is proved both ways; it needs the CCmuxAppFFI re-pin that carries the op (#31781). * cmux-tui tree key: cover the agent cursor visibility vectors the focus-core tests embed Also lists schemas/settings/source/agent-retry.json, which acpmux embeds and the key missed on the base (tree-key-embeds.test.sh red at 0511de2). * test(next agent cursor): the vector replay lives in CmuxNextAppTests, no new test target * test(focus-core): non-finite numbers cross the agent cursor visibility wire as strings (failing) The app's JSONEncoder refuses non-finite numbers, and a CGRect.null the snapshot builder converts has infinite x and y. The Swift rules gave a result for such a snapshot; the Rust rules must give the same one. * feat(focus-core): non-finite numbers cross the agent cursor visibility wire as "inf", "-inf", "nan" Every number of the snapshot and of the answer reads and writes the strings the Swift side's JSONEncoder/JSONDecoder convertToString and convertFromString strategies use, so a snapshot with a converted CGRect.null or an infinite scale gets the result the Swift rules gave it. * next agent cursor: non-finite snapshot numbers keep their result across the Rust call The resolver encodes and decodes with the convertToString strategies the Rust wire reads ("inf", "-inf", "nan"), through a new raw-bytes FocusReducer.call, so a converted CGRect.null or an infinite scale gets the result the Swift rules gave instead of a refused call. The vector suite covers it; the vectors file names its three replays. * CmuxNextFocus: public import Foundation for the raw-bytes FocusReducer.call Its public signature takes and returns Data (InternalImportsByDefault); compile-check 5600d8cb58e1f9195d7e8df1 failed on it. * test(focus-core): no redundant clone of the last null rect (clippy -D warnings) clippy (changed cmux-tui packages), run 41403471881 job 125140181043, failed on redundant_clone at agent_cursor_visibility.rs:158. (cherry picked from commit 0355b6f) * next agent cursor: the FFI glue is its own PLATFORM declarations; the resolver row follows the code The anchor's wire name moves to AgentCursorAnchor+FFI.swift, and AgentCursorVisibilityResolver now only encodes, calls cmux-focus-core and decodes: both are classified PLATFORM in swift-logic-classes.tsv, so the move lowers swift_logic_lines by the deleted rules. * test(next agent cursor): AgentCursorVisibilityResolveBench, ns per resolve over the vectors (off unless CMUX_AGENT_CURSOR_VISIBILITY_BENCH=1) The perf A/B of B9 step B: the per-agent-input-event resolve, Swift rules against the Rust call, run alone by scripts/measure/swift-test-bench.sh. * next agent cursor: the anchor's wire-name extension is nonisolated, as the enum Compile-check 3bcc994ff74702812b1e11a1 failed: the target's default MainActor isolation made init?(wireName:) MainActor, and the resolver's nonisolated decode could not call it. * next agent cursor: the anchor wire names are a MIRROR of the Rust names; doc comments name the Rust rules AgentCursorAnchor+FFI.swift copies cmux-focus-core's Anchor::as_str/parse by hand, as DaemonCapability copies Rust capability names: MIRROR, not PLATFORM (review note on #32028, lead decision). FocusReducer's doc lists the agent_cursor_visibility call; AgentCursorVisibilitySource's no longer names a Swift resolver.
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Waits for the pre-merge FFI release (STATUS 5013). This PR changes an FFI input (
cmux-focus-core,cmux-layout-reducer-ffi) and holds the Swift call in the same PR. The Swift call works only afterCCmuxAppFFIis re-pinned to a release built from this head, and today a release is built only from feat-cmux-next. Do not addready-to-landuntil that release exists and the pin inPackages/macOS/CmuxNext/Package.swiftmoves to it on this branch.The agent cursor's visibility rules now live in Rust. They decide where the cursor for a target browser tab draws: on its page, at an anchor in its window, or nowhere. The app asks them over the app FFI's JSON channel (
agent_cursor_visibility) and keeps only a thin Swift wrapper. This is the whole move of rust-migration backlog B9. No behavior changes.Rust (
cmux-tui/crates/cmux-focus-core/src/agent_cursor_visibility.rs)This is a port of the deleted
AgentCursorVisibilityResolverrules:Rects follow
CGRectrules: sizes are standardized, an intersection is null when the rects don't meet, and "shows" means more than half a point of overlap on both axes.JSON has no non-finite numbers, so they travel as
"inf","-inf"and"nan"in both directions. Both sides use these strings: Swift through its JSONEncoder and JSONDecoder string strategies. So a snapshot with a convertedCGRect.null(infinite x and y) or an infinite scale gets the result the Swift rules gave it.The op is in
cmux-layout-reducer-ffi/src/lib.rs. The request is{"target", "snapshot"}, where the snapshot isAgentCursorVisibilitySnapshot's Codable shape. The answer is the vectors'expectshape plusscale. A malformed request returnsERR_INVALID.The JSON channel, not a typed C ABI: the app resolves once per agent input event, and again on layout or window changes only while a target is tracked. The snapshot holds at most one pane, one chip and one sidebar row per window.
Swift
AgentCursorVisibilityResolver.resolve(target:in:)keeps its signature. It encodes{target, snapshot}, calls the op through the new raw-bytesFocusReducer.call(_:json:), and decodes the answer intoAgentCursorVisibility.AgentCursorVisibilityResolver.swift: 38 new lines replace 83).AgentCursorAnchornow has its wire name. The debug socket (DebugAgentCursor) uses it instead of its own copy (app_lines -10).placement(forWindow:)and the App's snapshot builder stay in Swift.Tests
cmux-focus-core/tests/agent_cursor_visibility.rsreplays all 26 cases ofschemas/agent-cursor-visibility/vectors.json. It is a port of the Swift vector suite deleted on 2026-10-10. It also covers the answer's wire shape, the page scale and non-finite numbers.cmux-layout-reducer-ffi/tests/agent_cursor_visibility.rssends every vector throughcmux_layout_reducer_json("agent_cursor_visibility"), and checks that malformed requests are refused.CmuxNextAppTests/AgentCursorVisibilityVectorTests.swiftreplays the vectors and the non-finite cases through the Swift call, and keeps the old placement tests. It is in an existing target, so no new test target is added.Changelog
none
Observed / Not run
Observed:
cmux-tui-rust-check.sh test agent_cursor_visibility: stepe8bcaea8fadd17bff9d01e80failed. 3 ran, 2 failed: "25 of 26 vectors differ", and the scale case.ff2f9d6976777a31aba6dd0epassed, 3 of 3.f443e12824c30e91ff7c5fe6. PENDING1c9f201aabde9547145ae87c. PENDING30c4eaa5853744cee8d63021passed, 5 of 5 (2 of them incmux-layout-reducer-ffi). It ran on the never-merge proof refrust-migration/cursor-visibility-ffiproof(933db36), which is 51e3894 plus one commit that builds that crate inside the cmux-tui workspace. The crate is its own Cargo workspace, so the fleet script never builds it. Its op and test are unchanged since then.fcc56a985698a6dcbaa2e6aapassed.5600d8cb58e1f9195d7e8df1. PENDINGrust-migration/cursor-visibility-oldswift(4cfb0fc) is this head with the old resolver restored. Compile30c736448ac1883d5410de10, thenAgentCursorVisibilityVectorTestson a Mac. PENDINGtree-key-embeds.test.shpasses (the tree key now lists the vectors file and the base's missingagent-retry.json).prepush-gate.py: no new violations.Not run:
AgentCursorVisibilityVectorTestsat this head: the pinnedCCmuxAppFFIhas noagent_cursor_visibilityop yet, so it can run only after the pre-merge release and re-pin.AgentCursorVisibilitySource.resolvemain-thread time: it needs the re-pinned FFI.Non-green checks, classified:
acpmux tests (lib, hub_integration),tooling-testsdisplay suites, nightly-guards release-notary,rust workspaces/plan(scripts/journeys/tui-kit/rustfrom journeys tui-kit: tk-gradient, the 120 fps gradient in compiled Rust (byte-identical, rate verdict) #31748; its author was told), and the cmux-tui.yml lint reds that base red: plugin update lock opens without truncation (Linux clippy suspicious_open_options, #31462) #31697 fixes.