a73x

docs/superpowers/plans/2026-09-05-native-interaction-debt.md

Ref:   Size: 6.9 KiB   History

# Native interaction ownership — debt sprint

The user authorized this sprint after the completed SSH follow-up. Sprint 5
remains accepted; the SSH recording's acceptance remains pending. Advancing to
this sprint does not imply acceptance of that recording.

Status: implementation, review and all required validation complete.
Recorded-demo acceptance is pending. The user authorized the
[component-separation sprint](2026-09-05-component-separation.md) before this
recording was accepted; that authorization is not demo approval.

## Scope and acceptance

Give native command modes, menu transitions, held input and captured pending End
actions a clear owner outside SDL window handling and painting. Preserve current
controls, labels, attachment identity rules, persistence and test-observation
schema. `Ctrl+\\`, then `p` remains Pane actions; Enter opens insertion, while
Choose session replaces the captured pane through the same picker.

Luna began the extraction but returned an unwired state-only seam. Root completed
the controller migration and focused regressions; Terra independently reviewed
the final controller, SDL adapter, shared navigation and tests. Root owns the
validation, delivery record and promoted `test/native_scale.py` fixture.
Workspace geometry, attachment runtime, persistence and SSH retry policy retain
their existing boundaries. A generic menu framework and terminal CLI redesign
are outside this sprint.

Opening assessment: no preparatory cleanup is needed. The substantial interaction
refactor is the deliverable itself. Luna and Terra were reused; their recorded
session `turn_context.model` values were checked immediately on resuming and
confirm `gpt-5.6-luna` and `gpt-5.6-terra` respectively.

Acceptance uses real multi-pane/host fixtures: insertion and replacement; held
keys and modal text; delayed End through command, focus, picker, resize, drag,
replacement and detach transitions; recovery and explicit Retry; resize and DPI
changes with independent PTY and framebuffer checks. Run the real SSH gate to
exercise recovery through the new controller. Preserve the terminal layout
sentinel. Record the actual GUI and keep demo approval distinct from automation.

## Delivery evidence

The final change moves command/resize modes, held-key and text suppression,
picker/recovery lifetimes, captured pending End actions, pointer resizing and
intent saves into `src/gui/interaction.zig`. `frame.zig` translates SDL events,
measures geometry, synchronizes mouse capture and paints snapshots. A small shared
menu-key mapping preserves navigation aliases while leaving j/k as editor text.
The existing observation JSON and SDL regression scenarios remain intact.

Closing review found no remaining correctness issue. The preliminary unused
Effect API was removed. Two direct controller tests pin exact key release,
post-dismissal repeats, text suppression reset, command-to-resize, focus loss,
and modal precedence over the prefix. Existing SDL tests retain adapter coverage.
No workspace, runtime, transport or terminal-client behavior changed.

Final source was frozen before these commands, using the pinned compiler and
`ZIG_GLOBAL_CACHE_DIR=/tmp/muxg-zig-cache`; local socket/PTY checks ran with the
required authorized permissions:

| Gate | Result |
| --- | --- |
| `deps/zig/zig build install native native-test -Doptimize=ReleaseSafe -p dist/native-interaction-release` | Passed; both release binaries from one build, 46 native test blocks |
| `make native-e2e` | Passed; 62 real-boundary scenarios |
| `native_picker.old_daemon` with `/tmp/muxg-sprint2-old-mux` | Passed separately; 63 total native integration scenarios |
| `test/native_ssh.py` with both release binaries, Wayland at 200% | All five real OpenSSH groups passed |
| `test/native_scale.py` with both release binaries and `--output HEADLESS-1` | Passed 200%/100%/150%/200%, drag cancellation, nested resize, PTYs and pixels |
| `make native-stress`, Wayland on isolated GPU compositor | Passed unchanged budgets |
| `make check` | Passed before commit |
| `make ci` | Full retry passed, including all e2e, agent and throughput gates |

The initial CI failure was `test/e2e_09_hosts.sh` waiting 15 seconds for the born
session's selected row (`2> 1`). The unchanged terminal host group passed all 15
scenarios when rerun with `E2E_ONLY=09_hosts make e2e`. The precise cause of that
first timeout is not established; its failure log is retained. The subsequent
full CI run passed without source or test changes.

Stress used a headless Sway output backed by NVIDIA GeForce RTX 3080, GLES2,
with no concurrent GUI fixture or recording. In 30.3 seconds the flooded daemon
read 105.7 MB. Sampled input-to-painted maxima were 55.4 ms on the shared daemon
and 55.5 ms on the separate daemon (94 samples each); final frame p99 was 18.1 ms.
The 5 ms polling interval and snapshot observation overhead make those input
numbers upper bounds, not exact input latency. These are Linux results; no new
macOS performance or compatibility claim is made.

The 57-second actual GUI recording uses the final release at 200%, H.264
1100×700 with no audio. It shows insertion cancellation, keyboard resize,
delayed shared-session End, Pane actions, close/reopen, unavailable-host return,
missing-session replacement, Detach and End. Three continuous clips have two
restart cuts. Input is injected through ordinary SDL events; this recording does
not claim a new compositor mouse-path trial. The owned compositor and fixtures
were stopped. Recording acceptance remains pending.

Retained local recording:
`/home/xanderle/.codex/visualizations/2026/09/05/01a071c2-5767-7790-a335-1a84536c9ca5/native-interaction-trial.mp4`.
Evidence is in the sibling `interaction-evidence/` directory: final logs, the
initial CI failure and targeted rerun, release/source hashes, stress JSON,
recording driver and model metadata. This recording has not been published to
Tailscale; prior demo routes retain their existing approved payloads.

## Retained debt and next actions

- `frame.zig` still contains painting and test-observation hooks. They stay together
  for this bounded ownership change; the next painter/test-protocol change should
  assess extracting those hooks without changing passive observation semantics.
- The general screen recorder remains an artifact helper rather than a repository
  tool. The scale gate is now durable. A future recording-tooling package owns
  parameterizing capture, process cleanup and clip composition; no further
  production refactor depends on it.
- Use a fresh task-specific agent context for the next substantial extraction.
  Reused Luna stopped before wiring, and root completed implementation. Terra
  provided useful concrete review. Recorded models and cumulative counters are
  retained, with cached input separate; this sprint establishes no cost saving.
- Record this demo's approval separately from the earlier SSH demo and any
  hands-on feedback. Start further production work only when authorized.