Hover rules in Rust, step A: the hover card machine, tooltip intent, safe triangle, row card placement and group summary, with their C ABI (no Swift change)
Step A of the hover FFI move (B8): the hover rules in Rust, with their C ABI and JSON op. No Swift change and no behavior change: the app keeps its Swift rules until step B (#31836) switches it to these, after the bot's CCmuxAppFFI re-pin is on feat.
What lands:
cmux-motionhover: the hover card state machine (phases, delays, aiming, bridging, pins, an owner's card), the tooltip hover intent, the safe triangle (CGRect.isAimedAt), the sidebar row card's placement and zones (HoverCardEscapeGeometry, room, row band) and the hover timing tokens. Leo's and Lawrence's values are copied unchanged, each with its history, intohover/timing.rs.cmux-layout-reducergroup_hover_summary: the group card summary (GroupHoverCardSummary.make) as typed lines; the app keeps the localized words. It keeps Swift's String rules: values are equal after NFC, and port lists split on grapheme clusters that are exactly ",".unicode-normalizationandunicode-segmentationare already in the app FFI lock (cmux-palette-ranker, cmux-focus-core), so no new package reaches the app.- The C ABI:
cmux-app-ffi/src/hover.rsand the Hover section ofcmux_motion_ffi.h(ABI version 4). The machine is a plain C struct the app keeps; one call applies a batch of typed events and writes the effects into a caller buffer (no JSON, no allocation per pointer move). The struct forms and their total conversions arecmux_motion::hover::c, so the workspace tests cover them, layouts included. The group summary is the JSON opgroup_hover_summaryoncmux_layout_reducer_json(once per card show).
The Swift tests of these rules are ported as Rust tests: WorkspaceHoverCardBehaviorTests, HoverCardEscapeGeometryTests, HoverCardRowAlignmentTests, HoverCardWindowClampTests, GroupHoverCardSummaryTests and the machine and intent halves of TabHoverCardTimingTests and TooltipHoverIntentTests, plus the branches only AppKit tests reached (pins, an owner's card, removed targets, lingering cards), a 20 000-event walk that bounds effects per event, and the C forms.
Check the app FFI pin: expected, step A of a two-step FFI move.
Tests
scripts/ci/cmux-tui-rust-check.sh on the fleet (Linux):
- Red,
test hoverat 9512791bb149 (rule bodies stubbed, on rust-migration/hover): job 9651cf0dfca75b673f29a7a8, 75 run, 63 failed (assertions; it built). - Red,
test group_summaryat c4776fd2125a (the two Unicode tests before the fix): job 41fb34bc3f1df61721789c48, exactly those 2 failed, also on their rerun. - Green,
test hoverat 4ead4a4c830d: job 6d821e84132797854e9b7bcf, 77 of 77, no FLAKY notice. - Clippy at 4b073d17fea9: job df9bf645ec81bf01dc66a491, pass.
- At bb5b54e7ee6a (the same Rust files on feat 5a56d58c646b): green
test hoverjob 5f4372cafaf6ef6bab14dad4, 77 of 77, no FLAKY notice; clippy job 19cb9b13e0c07ef265257654 failed only on the base redcmux-tui-core/src/mux/agent_chat_notices.rs:147,:209,:1462(fixed on feat by #31907). - At 40ff7fd0fb2a (a clean merge of feat with #31907; no hover file changed): green
test hoverjob cfbeba60fc3b15012eda75a2, 77 of 77; clippy job 6e4bf63e7637fd7006a4fddd, pass. - At 25747875f798 (the duration cast's
#[allow]names its reason, as the panic ratchet requires): jobs cancelled, the head was replaced. - At 9393b2faa2da ( feat 13fd3f48bcb0 merged, both module lines kept in cmux-layout-reducer/src/lib.rs; the suppression bits written as literals): panic ratchet job 896a63176e7ac3cf6271bbfb pass (no deny-lint hit; the tracked arithmetic warning on cmux-layout-reducer is base, see the classification comment); green
test hoverjob 6a1858911ebc8d265dbc39b8, 77 of 77, no FLAKY notice; clippy job 2b54803968b3e9dfc5f044d3 red only on the base findingcmux-tui-core/src/output_store/snapshot.rs:537(fixed on feat by #32092). - At this head (f4eb46c3f265: feat d5e0073cb09 merged, which includes #32092; both doc lines kept in cmux-layout-reducer-ffi/src/lib.rs): panic ratchet job 4d1c5067f1245b205789994f, green
test hoverjob 8629062088bba65d9921af2b, clippy job 158f4e6fa9f3e328783e2b95; results go here when they end.
Risk
risk:normal. Nothing calls the new symbols yet; the app links them only after the re-pin.
Changelog
none
Observed / Not run
Observed: the fleet red and green runs and clippy above; the pre-push gate (no new violations).
Not run:
- Fmt: base finding.
cmux-tui-rust-check.sh fmt(jobs eed2d3a4f24560587d3079ce, b6392995e2e2a3e64abcadbc) fails only onacpmux/src/hub/list_guard.rs:837,:925andhub/mod.rs:1372, which this PR does not touch; the hover files are clean. cmux-layout-reducer-ffiworkspace tests (tests/group_hover_summary.rs): not in the fleet script; the cmux-tui CI job runs them.- Swift: nothing changes here. Step B (#31836) runs the Swift suites on a Mac and the perf A/B of a sidebar hover sweep.
- No capture: no UI changes.