> For the complete documentation index, see [llms.txt](https://docs.kouch.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kouch.dev/docs/early_tests.md).

# Early Tests — go/no-go log

Source of truth for the test definitions: `docs/ARCHITECTURE.md`, "Early Tests" section. Each test is run via `cargo run -p kouch-lab -- <test>`; `kouch-lab` subcommands double as the integration tests for hardware-dependent behavior (per `docs/ARCHITECTURE.md` "Verification").

Fill in **Result** (PASS / PARTIAL / FAIL), **Date**, and **Notes** as each test is actually run. Statuses: PASS / PARTIAL / FAIL / BLOCKED (cannot be run yet for an external reason).

| #  | Test                                                                                                                                                                                    | Pass criteria                                                                                                       | If it fails                                                                                                                                                                                    | Result                                                                          | Date       | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| -- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0  | `steam-input-480` — `Init` + `SetInputActionManifestFilePath` + `RunFrame` under app 480                                                                                                | ≥1 handle from `GetConnectedControllers`, digital/analog actions and `GetMotionData` non-zero on a gyro pad         | Buy Steam Direct slot ($100) → real app ID; continue                                                                                                                                           | PASS                                                                            | 2026-09-17 | 5 controllers (2026 Steam Controller, DualSense, pro-style, Stadia-as-generic, Xbox Series), all bound, buttons+sticks on all, motion 3/3. **Two conditions found the hard way:** (1) Steam only activates Steam Input for a process that has a real top-level window — a console binary never binds; (2) the process must be launched by Steam under an app id flagged for Steam Input API (here: as a non-Steam shortcut, initializing the API as a borrowed flagged id). Spacewar 480 is not flagged. Kouch's own app id replaces the borrowed one once Steam Direct clears.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 1  | `focus-flow` — spawn a child window (notepad / any emulator), give it focus, keep polling                                                                                               | Action data + motion keep updating while the child has focus, for ≥ 60 s                                            | Kouch keeps a hidden always-focused-in-Steam's-eyes window; or run emulator as child of a Steam-launched helper; worst case: Windows only via `SteamInputConfigurationLoaded_t` focus tracking | PARTIAL (measured)                                                              | 2026-09-17 | Steam-launched, real window, 5 pads. Kouch window focused: 65 actions active, motion 4844/4957 ticks, BNewDataAvailable 4759. Child (Notepad) focused: **actions 0/65 and BNewDataAvailable 1 — the action channel dies the instant a child window takes focus** (Steam re-activates the desktop layout, log `Queueing activation … app: 413080` at spawn time); **motion 4860/4960 — GetMotionData keeps flowing at full rate.** Decision: hybrid input — motion via Steam Input → DSU (works), buttons/sticks via the OS gamepad layer (SDL3) read by Kouch, the same layer emulators launched from ES-DE-style frontends already use; Steam Controller-class pads keep the action channel only while Kouch is foreground (overlay approach). See ARCHITECTURE.md "Input sources".                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| 1b | `steam-hybrid` — under Steam, per source and device: Kouch focused, a child process's window focused, Kouch again                                                                       | Some source delivers every pad's buttons while the child has focus                                                  | Override Steam's SDL ignore list; else per-profile fallbacks                                                                                                                                   | PASS (after fix)                                                                | 2026-09-26 | Owner pressing on cue; 3 pads (standard, touchpad, 2026 Steam Controller). **Run 1, Steam's SDL list honoured:** SDL saw 0 pads (`SDL_GAMECONTROLLER_IGNORE_DEVICES` \~12 KB, plus `…ALLOW_STEAM_VIRTUAL_GAMEPAD=1`, `…USE_BUTTON_LABELS=1`). Steam actions ran 7231/7231 ticks with Kouch focused, 10/7231 with the child focused, 3349/3359 after. Motion ran 7231/7231 throughout on both motion pads. So nothing but motion reached a game. **Run 2, list overridden (`KOUCH_SDL_SEE_ALL`):** SDL read the Steam Controller's presses with the child focused (2984 frames non-zero) while Steam delivered none. **Fix:** `b2c1dbb` (override by default under Steam), `a7213f7` (SDL kinds for Valve's pads + pairing); live afterwards, the Steam Controller as P1 advanced a real game with A.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| 2  | `reconnect-order` — unplug/replug 3 pads                                                                                                                                                | Kouch slot map unchanged; Steam handle changes are absorbed by identity heuristics                                  | Tighten heuristics; add "re-claim" prompt                                                                                                                                                      | Logic covered by tests; hardware run pending                                    | 2026-09-26 | `kouch-input/src/scenarios.rs`, real input thread + DSU client: replug within the TTL gets the seat back with the same MAC and no gap on other players; after the TTL the seat goes to the next claimant and the old pad joins as new; three pads of one model replugged in reverse order each find their seat by serial; pads without serials fall back by kind with a VerifyPrompt; a pad's Steam and SDL views leaving in different ticks leave no ghost seat. **Fixed from these:** SDL's per-model GUID counted as an exact identity (identical pads could swap seats); a different-serial pad took a Reserved seat by kind; Steam/SDL pairs were recomputed by position, so one pad's view leaving crossed another pad's motion and left a ghost seat; a TTL-freed seat kept its motion flag.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| 3  | `steam-reorder` — use Steam's Reorder Controllers UI                                                                                                                                    | Document whether it changes anything Kouch sees; ship "Use Steam's order" toggle only if it does                    | Toggle hidden                                                                                                                                                                                  |                                                                                 |            |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 4  | `dsu-probe` / `dsu-client` — 4 servers, 16 slots (2 servers, 8 slots since ADR 0026)                                                                                                    | A test emulator sees 16 slots across 4 server entries, motion on 8; packets ≤ 2 ms after `RunFrame`                 | Fix packet layout; check per-server slot cap                                                                                                                                                   | PASS (loopback + real emulator)                                                 | 2026-09-17 | Loopback: 3334 pkts/5 s, 0 CRC errors, monotonic, idle keep-alive \~117 Hz, server 3 slot 0 = player 12's MAC. **Real emulator (the owner's EmuDeck install of the full-DSU-class emulator):** pointed at all four Kouch servers, it enumerates all 16 devices (`DSUClient/<slot>/Kouch<server>`) with the synthetic feed. Found + fixed an interop bug: that client polls PortInfo every 1.000 s and drops a server whose last PortInfo is older than 1 s, so any drift made it remove and re-add all 16 devices every 2 s (\~150 repopulates/20 s). Kouch now pushes unsolicited PortInfo to recent pollers every 500 ms → 0 repopulates/20 s, 16 devices stable, exactly one re-add after a server restart. Emulator config edits backed up to \~/kouch-backups/.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| 5  | `dsu-reorder` — swap P1↔P5 live in a test emulator                                                                                                                                      | Emulator port mapping unchanged; inputs swap instantly                                                              | Slot policy bug                                                                                                                                                                                | Logic covered by tests; hardware run pending                                    | 2026-09-26 | Scripted P1↔P3 reorder read back by DSU clients: each slot keeps its MAC and switches pads exactly once (nothing reaches a stale slot); the motion flag stays on the seat and the model drops to no-gyro under a pad without motion. Still to run: a real emulator's port mapping.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| 6  | `dsu-disconnect` — unplug P3 mid-game                                                                                                                                                   | `hold_neutral`: slot keeps reporting connected + neutral; `report_disconnected`: slot flips to disconnected         | Policy bug                                                                                                                                                                                     | Logic covered by tests; hardware run pending                                    | 2026-09-26 | Pad unplugged mid-press: `hold_neutral` streams connected + neutral with nothing stuck; `report_disconnected` streams state 0 / connected 0 with nothing held, and the replugged idle pad brings no old press back. **Fixed:** a profile's `on_disconnect` never reached the input thread (always hold-neutral); the shell now sends it at launch and resets it when the session ends.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| 7  | `latency` — timestamp `RunFrame` → DSU send                                                                                                                                             | p99 ≤ 2 ms on Deck at 250 Hz loop; CPU ≤ 5 % one core with 16 pads                                                  | Lower loop rate / batch sends                                                                                                                                                                  |                                                                                 |            |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 8  | `sixteen` — 16 pads (8 since ADR 0026; a ninth waits) (mix BT/USB/phones later)                                                                                                         | All 16 enumerated, no drops for 10 min                                                                              | Document adapter guidance; cap BT per adapter                                                                                                                                                  |                                                                                 |            |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 9  | `overlay-win` — overlay over borderless vs exclusive-fullscreen emulator                                                                                                                | Visible + click-through works over borderless; exclusive documented as unsupported (profiles default to borderless) | Force borderless in profiles                                                                                                                                                                   | PARTIAL                                                                         | 2026-09-18 | Windows, stand-in windowed emulator (a plain Win32 form launched via a profile from the real app). Overlay window positions to the emulator's DWM frame bounds and takes the left 34 % (measured 420×616 over a 1000×625 frame, 125 % DPI), always-on-top, click-through when hidden. Found + fixed: Tauri ignored `set_size` on a non-resizable window and on a hidden one (now resizable, sized after `show()`). Borderless/exclusive-fullscreen emulators not yet tried (no real emulator profile on this run).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| 10 | `overlay-gamescope` — Deck Game Mode, Quick Menu over the running game                                                                                                                  | Panel composited over the game; input reaches it                                                                    | Fall back to Kouch's own fullscreen window swap (hide game, show menu)                                                                                                                         | PASS                                                                            | 2026-09-26 | Real Game Mode on the owner's Deck OLED (gamescope 3.16.23), dev AppImage through a non-Steam shortcut, the xterm stand-in game, the virtual controller's Select+Start chord, and full-composition `gamescopectl` captures. The 435×800 panel is drawn at the left with the game visible beside it; B inside the menu goes back a page, so input reaches it. `GAMESCOPE_EXTERNAL_OVERLAY` (the planned route) turned out to be the wrong tool: gamescope draws external overlays only from Steam's own Xwayland, and it zeroes the marked window's app id. What works is an override-redirect window of the game's own app. Three bugs blocked it: (1) every emulator inherited `SteamAppId=480` from Kouch's Steam init, so gamescope treated the game as another app and the screen stayed black (`9ffbc23`: the launch ids are restored for children); (2) the external mark (removed in `dcc19eb`); (3) GTK/WebKit's 1×1 child window tripped gamescope's SDL-fullscreen heuristic (`ignoreOverrideRedirect`), which pinned min = max size hints avoid (`dcc19eb`, panel-sized in `6b9a3bb`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| 11 | `pause-neutral` — open overlay per emulator                                                                                                                                             | Emulator receives neutral input; pause hotkey or suspend works; no stuck buttons on close                           | Per-profile tuning                                                                                                                                                                             | PASS                                                                            | 2026-09-18 | Real app, real input thread, 4 physical pads seated. `overlay_show` → `Freeze(true)`: DSU slot 0 sticks went from live drift to exactly 0.00 while the panel was up and resumed on `overlay_hide` (checked with `kouch-lab dsu-client`). Players panel keeps all seats listed while frozen (fixed: connectivity was derived from Live output). Pause hotkey/suspend not exercised (stand-in emulator has none).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 12 | `quit-graceful` — WM\_CLOSE/SIGTERM then kill                                                                                                                                           | Save files intact after both paths (hash before/after)                                                              | Longer timeout / profile-specific quit hotkey                                                                                                                                                  | PASS                                                                            | 2026-09-18 | `session_quit graceful` → WM\_CLOSE: stand-in window ran its close path ("closed" written to its log), session back to idle, focus returned to the launched tile. `session_quit force` → process terminated (no close path ran, as intended), window gone. Save-file hashing N/A for the stand-in; repeat with a real emulator profile.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| 13 | `shortcut-handoff` — non-Steam shortcut → `steam://run/480//--launch=<id>`                                                                                                              | Kouch receives the arg (single-instance), launches game, Steam overlay shows Kouch's session                        | Companion tool falls back to a stub `.exe` launcher                                                                                                                                            |                                                                                 |            |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 14 | `slr-flatpak` — from a Steam-launched Kouch on Deck, run `flatpak run <emu>`                                                                                                            | Emulator starts and gets DSU                                                                                        | Use `steam-runtime-launch-client --alongside-steam --host` / `flatpak-spawn --host`; document                                                                                                  | PASS                                                                            | 2026-09-27 | The owner's Deck in Game Mode, dev AppImage through a non-Steam shortcut (no pressure-vessel container, so no escape is needed), one of the owner's EmuDeck Flatpak emulators. Its data folder was backed up first and restored byte-identical afterwards. A Flatpak launched by Kouch exited at once, for two reasons, both fixed: the AppImage's runtime environment leaked into children (`70ba93e`: AppRun snapshots the host environment, and children get it back), and Steam's scout runtime `LD_LIBRARY_PATH`/`PATH` broke `/usr/bin/flatpak` (`88272d3`: `SYSTEM_LD_LIBRARY_PATH`/`SYSTEM_PATH` for host programs). With both corrections applied by hand, the whole chain works in Game Mode: gamescope focuses the emulator; Kouch finds its window although the Flatpak reports a sandbox pid of 2 (X-Resource pid, `ddf54ce`); the Quick Menu is drawn over it; a graceful quit closes it through its window (it saved its settings before the force-kill deadline). **2026-09-27, build `47a37c5`:** a plain `kind: flatpak` profile (no wrapper) launched the emulator from the Steam-launched AppImage in Game Mode. It got focus; its environment has no AppImage or Steam-runtime paths and carries Steam's own launch ids; the Quick Menu was drawn over it; the graceful quit closed it. DSU reachability: the Flatpak shares the host's network namespace (same `net:` inode inside and out), so Kouch's 127.0.0.1 DSU ports are reachable. **DSU from inside a Flatpak, 2026-09-27:** one of the owner's EmuDeck emulator Flatpaks (one with a DSU client), started by the Steam-launched Kouch AppImage with a separate user folder (`-u`, DSU client pointed at 127.0.0.1:26760; the owner's own Flatpak data backed up and restored byte-identical), registered on Kouch's first DSU server (`dsu_clients` 0 → 4). No escape (portal / launch client) is needed for a non-Steam shortcut: it runs outside the pressure-vessel container. |
| 15 | `motion-reassign` — move motion slot P2→P9 mid-game                                                                                                                                     | DSU slot for P9 starts carrying motion within one packet; P2's stops                                                | Mapping bug                                                                                                                                                                                    | Logic covered by tests; hardware run pending                                    | 2026-09-26 | With 9 motion pads: a ninth flag is refused (cap 8); moving P2→P9 flips P9 to full gyro carrying its own samples and P2 to no-gyro, neither flapping back. An unplugged motion pad keeps its flag while it may return; once its seat is freed the next motion pad gets one.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 16 | `rumble-roundtrip` — (a) `dsu-client --rumble` sends `0x110002` to slot 0; (b) Linux: `fftest`-style FF effect on a `UinputPad`; (c) Windows opt-in: XInput `SetState` on the ViGEm pad | Physical controller on that slot vibrates ≤ 50 ms after the request, on all three paths                             | Extension parse bug / FF event drain / driver absent                                                                                                                                           | (a) Delivery verified live; the owner confirms the feel later. (b), (c) not run | 2026-09-26 | Path (a) in `kouch-input/src/scenarios.rs`: a DSU client's motor request for P3 reaches only P3's pad with the right motors; the 5 s motor timeout stops it; after a P1↔P3 reorder the new P1 rumbles and the pad that left is stopped and hears nothing more; an unplugged seat rumbles nobody; the Quick Menu freeze stops it and nothing leaks until it closes. **Fixed:** the requests were parsed but never delivered to any pad, and the app bound DSU with the extension off. **Live 2026-09-26** (no Steam): `KOUCH_NO_STEAM=1 kouch-lab input-live --auto --base-port 26960` seated the three connected pads; `kouch-lab dsu-client --port 26960 --slots 0 --rumble 120` asked P1 (the `pad-trackpad`) for large motor 120 once. The log shows SDL accepting `set_rumble` for that pad (large 30840, 1.5 s) at once and every second after, then a stop 5.6 s after the request (the 5 s motor timeout, checked each second). Still to run: an emulator asking, and the owner feeling it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

## Plan v2 acceptance run (`docs/PLAN_V2.md` "Acceptance run")

A real emulator profile, real games from the owner's library, real pads, Kouch Lab route. Steps as numbered in PLAN\_V2.

| Step | Check                                                                                                              | Result  | Date       | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ---- | ------------------------------------------------------------------------------------------------------------------ | ------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1    | Import the `.kod`; the download queue installs the emulator; version + "Check for updates" in Settings › Emulators | PASS    | 2026-09-26 | Installed from the emulator's release feed (`json_feed` source, 7z archive), `ffa8ea7`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 2    | Owner copies their own keys file (Kouch never touches it)                                                          | N/A     | 2026-09-26 | The reference emulator was switched to one that needs no keys.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| 3    | Scan the games folder; tiles appear                                                                                | PASS    | 2026-09-26 | 42 games from the owner's library. Found + fixed: leftover inner extensions in titles.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| 4    | Claim pads; Steam Input up; DSU servers bound                                                                      | PASS    | 2026-09-26 | Steam route 2026-09-26 (verify build launched by the Kouch Lab shortcut under non-elevated Steam, temp config): Steam Input bring-up succeeded, DSU on 26760–26763, the owner's 3 pads seated with their kinds; the touchpad and trackpad pads got motion slots 0 and 1 automatically.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| 5    | Buttons + sticks reach the game while it has focus, under Steam                                                    | PASS    | 2026-09-26 | Found live with the owner: with the emulator focused Steam stops Kouch's action data entirely (Early Test 1b, `kouch-lab steam-hybrid`), and SDL saw 0 pads because Steam hands launched processes `SDL_GAMECONTROLLER_IGNORE_DEVICES`. Fixed: Kouch overrides that list (`b2c1dbb`) and pairs Steam's and SDL's views of a Steam Controller (`a7213f7`). Verified: the owner's Steam Controller as P1 pressed A in-game and the game advanced past its first screen.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| 5    | Launch: window found, `window_mode` respected, the emulator's DSU client registers                                 | PASS    | 2026-09-26 | Steam route 2026-09-26 (verify build launched by the Kouch Lab shortcut under non-elevated Steam, temp config): launched windowed; `app_diagnostics.dsu_clients` = \[4,4,4,4] — the emulator subscribed on all four servers.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| 5    | Motion: tilt → `kouch-lab dsu-client` shows gyro, the game responds                                                | PARTIAL | 2026-09-26 | Steam route 2026-09-26 (verify build launched by the Kouch Lab shortcut under non-elevated Steam, temp config): Steam motion reaches DSU — resting pads read \|a\| = 1.00 g (touchpad pad \[0.589 0.651 0.483], trackpad pad \[0.005 −0.156 0.991]), gyro ≈ 0. Found: SDL's frame differs from Steam's (steam = (x, −z, y) of SDL), so the SDL fallback was rotated 90° — sent to C. **In game with the dev virtual controller (2026-09-26, P1, pointer on):** the first run showed the pointer only with the pad stood on end — Kouch sent its own frame on the wire instead of the protocol's wire frame (flat landed on the forward axis; yaw and roll swapped). Fixed with `MotionAxisMap::STEAM_TO_WIRE`: at rest P1's pointer sits mid-screen and holds for 12 s+, turning left 2° moves it one file left and back returns it, nose down / up moves it down / up, a 30° roll leaves it in place. Also found: perfectly clean synthetic motion (gravity exactly (0,0,1) plus a pure yaw) makes that emulator's pointer filter divide by zero and lose the pointer for the session; the virtual controller now adds ±0.003 g / ±0.1 °/s sensor noise like real hardware. **Owner:** tilt a real pad in a motion game. |
| 5    | Screenshot via the emulator's hotkey, sent through Kouch, read back                                                | PASS    | 2026-09-26 | Isolated build (below): `emulator_action screenshot` → the emulator saved a frame of the running game, read back. Windowed only: with the monitors powered off an exclusive-fullscreen emulator stalls in present (no display), which is a test-environment limit.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| 6    | Quick Menu over the game: players + motion slots, Resume                                                           | PASS    | 2026-09-26 | Steam route 2026-09-26 (verify build launched by the Kouch Lab shortcut under non-elevated Steam, temp config): Quick Menu over the running game in the active theme, 3 seats with neutral device names and motion slots 0/1; hide + graceful quit 1.0 s. **From a pad (dev virtual controller as P1, 2026-09-26):** holding Select+Start for the combo time opened the Quick Menu over the running game (overlay visible false → true), its d-pad moved the cursor (Players → Game → … → Quit game), and holding A on "Quit game, hold to confirm" for 1.7 s quit the emulator, hid the overlay and ended the session (cloud skipped under the borrowed id). Claim by A on the connect screen with auto-claim off: the unseated pad's white Join box became Player 1. LT on the connect screen: Make Player 1 from seat 5.                                                                                                                                                                                                                                                                                                                                                                                               |
| 7    | Graceful quit: save hash unchanged, idle, focus on the tile, cloud skipped under the borrowed id                   | PARTIAL | 2026-09-26 | Graceful quit twice; saves land in Kouch's folders. Isolated build: graceful quit 0.9–1.0 s back to Home with play history; a stalled emulator still quit in 8.2 s and the session returned to idle. Save hash before/after (isolated build): the saves tree changed only by the emulator's own flush on graceful quit (its play record and system state files), nothing missing — the data was written before exit.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |

**Isolated-build route (2026-09-26, while blocked):** a debug build with `TAURI_CONFIG='{"identifier":"app.kouch.verify","build":{"devUrl":"http://localhost:1421"}}'` runs next to the elevated instance (single-instance is keyed by identifier), with `KOUCH_NO_STEAM=1`, `KOUCH_CONFIG_DIR`/`KOUCH_DATA_DIR` in a temp folder and WebView2 debugging on 9224. Covers everything but Steam Input and motion. Don't finish the first-run wizard there — it recommends the owner's real `R:\Emulation`; use `?setup=skip`.

**Blocked (2026-09-26):** Steam runs as administrator, so the Steam-launched Kouch is elevated and can't be restarted from the agents' shells. The owner closes it (or runs Steam normally) before steps 4–7 are re-run on the rebuilt app. `8e81896` adds a one-time toast when Kouch runs elevated.

## More local test profiles (isolated build, 2026-09-26)

Three more private test profiles in `profiles/local/`, each run on the isolated build (no Steam, temp config and data under a short root, the owner's own game folders added as library roots in the temp config only and scanned read-only; one of the owner's games launched per profile, borderless). `dsu_clients` is the new diagnostics count of clients subscribed to each DSU server. Afterwards, the owner's game folders showed no files changed.

| Profile                                                  | Install                                                   | Scan                                                                                         | Launch + DSU                                                                                                                                                                                                        | Screenshot via Kouch                                       | Quit                                                                                                 | Notes                                                                                                                                                                                                                                                          |
| -------------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 2: games that are folders (`code/*.rpx`), XML config     | PASS (release asset, no published checksum)               | PASS 11/11 launchable folders (4 encrypted install packages and an art folder are not games) | PASS, `dsu_clients` \[1,0,0,0]                                                                                                                                                                                      | PASS, frame read back (the game had just created its save) | PASS graceful                                                                                        | Portable folder is a link to Kouch's `config`; saves under `saves/mlc01/usr/save`; the emulator's own system files under `saves/mlc01/sys` are private.                                                                                                        |
| 3: single-file games, buttons from SDL + motion over DSU | PASS (checksum from the release asset's digest)           | PASS 34/34                                                                                   | PASS, UDP client on Kouch's bound port, `dsu_clients` \[1,0,0,0]                                                                                                                                                    | PASS, title screen read back                               | PASS graceful                                                                                        | Found + fixed: its INI treats `\\` as an escape (new `{key:/}` placeholder form) and it ignores storage paths that don't exist yet (storage is now links into `saves/`, which Kouch creates). Paths past 260 characters crash it (only in a deep test folder). |
| 4: needs the user's own keys (`system_required`)         | PASS (the project's own release host, `json_feed` + glob) | PASS 48/48                                                                                   | Refused cleanly with an empty `system` folder ("copy your own system files into …"). With the guard off in the temp config: links in place (`keys` → `system`, `nand`/`sdmc` → `storage`), `dsu_clients` \[1,0,0,0] | — needs keys                                               | Force-closed at 8 s (its missing-keys dialog blocks a normal close; never reached with the guard on) | Found + fixed: its INI reads a key without a `\\default=false` twin as "use the default". Booting a game needs the owner's keys: **owner-only**.                                                                                                               |

**Steam route (2026-09-26, the Steam-launched verify build, Steam Input up, the owner's 3 pads seated: P1 touchpad pad with motion, P2 standard, P3 trackpad pad with motion).** The three profiles came from the tester pack (`profiles/local/alpha-emulators.kod`, `kod_import`) and installed through the queue; game folders were added as roots in the temp config only and scanned read-only (11 / 34 / 48). Afterwards the owner's game folders again showed no files changed.

| Profile | Launch + DSU                                                                                                                                             | Screenshot via Kouch | Quit                  | Where the game waits                                                                                                                                                                                                                                                        |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 2       | PASS, `dsu_clients` \[1,0,0,0]                                                                                                                           | PASS, read back      | PASS graceful (\~1 s) | "Save data has been created → OK" (needs A)                                                                                                                                                                                                                                 |
| 3       | PASS, UDP client on 26760, `dsu_clients` \[1,0,0,0]                                                                                                      | PASS, read back      | PASS graceful (\~2 s) | File select, with a new save file created during the run and written to Kouch's `saves/sdmc`. That took button presses: this profile reads buttons straight from any SDL game controller, so either a pad was pressed or one sends stray input — to confirm with the owner. |
| 4       | Refused cleanly: "… needs your own system files. Copy them from your console into …\system …"; the emulator never started; `system_folder_present` false | —                    | —                     | — (no keys on this PC for the test)                                                                                                                                                                                                                                         |

Still owner-only for all three: physical buttons and motion from seated pads in the game.

## Regression after data contract v5 (isolated build, 2026-09-27)

The four local test profiles again, end to end, after the day's changes underneath: sessions and playtime, the Quick Menu pause, drive presence, the scan queue, captures, library schema v5. Isolated build (no Steam, temp config and data, CDP on its own port), one instance for all four: each profile imported from `profiles/local/` and installed through the queue, the owner's four game folders added as roots in the temp config only and scanned read-only (43 / 34 / 11 / 48 games), one game launched per profile, then a scratch root for presence. Profiles are numbered as above (1 = the reference profile).

| Profile                       | Install | Launch: window found, `mark_played`                                                                                                                 | DSU                            | Screenshot → `captures_latest`             | Quick Menu open / action / closed                                                                              | Graceful quit → session                                                                             | Result             |
| ----------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------ |
| 1 (pause by hotkey)           | PASS    | PASS (\~4 s)                                                                                                                                        | PASS, `dsu_clients` \[4,4,4,4] | PASS, the right game (after the fix below) | CPU 1,250 → 125 ms per 3 s; save state with the menu open resumes first; 1,484 after closing                   | PASS: kind local, 1 seat, 49 s; `playtime:changed` fired; in `playtime_summary` (game and emulator) | **PASS**           |
| 2 (folder games, suspended)   | PASS    | PASS (\~4 s)                                                                                                                                        | PASS, \[1,0,0,0]               | PASS, the right game (after the fix below) | 57/57 threads suspended, CPU 7,938 → 0; a screenshot with the menu open resumes it (0/57); 7,719 after closing | PASS: local, 1 seat, 47 s; event + summary                                                          | **PASS**           |
| 3 (pause by hotkey)           | PASS    | PASS (\~4 s)                                                                                                                                        | PASS, \[1,0,0,0]               | PASS, the right game                       | CPU 703 → 156; save state with the menu open resumes first; 1,156 after closing                                | PASS: local, 1 seat, 49 s; event + summary                                                          | **PASS**           |
| 4 (needs the user's own keys) | PASS    | Refused cleanly: "… needs your own system files. Copy them from your console into …\system, then start the game again." The emulator never started. | —                              | —                                          | —                                                                                                              | —                                                                                                   | **PASS** (refusal) |

* **Presence** (a scratch root, renamed away and back): `offline` false → true (still not `missing`) → false again 15 s later with no Rescan. PASS.
* **Config restore:** original config files were pre-seeded for profiles 1 (ini) and 2 (xml). Their `.kouch-backup` was taken at the first edit, and `profile_config_restore` put both back byte for byte (`restored: 1` each). PASS.
* **The owner's folders:** a metadata-only fingerprint (names, sizes, times; key and firmware names never listed) of the owner's EmuDeck and emulator config folders and the four game folders was identical before and after every run. Everything Kouch wrote stayed in the temp folders.
* **Found and fixed:**
  * `captures_latest` gave a running game's shots no game: the session row is only written at quit. It now also matches the live session.
  * Profiles 1 and 2 save screenshots in their own user folders (`config/ScreenShots`, `config/screenshots`), which captures never saw. Both profiles now link those folders to `{screenshots}`. The tester pack (`alpha-emulators.kod`) was regenerated, which also picked up an option default it had missed.
  * The session log line now carries seats and peers.
* **Not a Kouch fault:** the first game of profile 1's folder idles on a pre-game screen (about 5 % of a core), so no hotkey has anything to act on there. The run used the next game. Hotkey delivery to that emulator was checked on its own: a save state appeared from Kouch's 20 ms chord.

## Controller types, live (isolated build, 2026-09-30)

CONTROLLER\_TYPES\_PLAN T7 on real emulators. One isolated Kouch (no Steam, temp config and data, muted), the four test profiles imported from `profiles/local/` and installed through the queue, the owner's game folders as read-only roots. Each type was chosen for a game (`game_set_options`), the game launched, and the emulator's own config read back after launch; every session ended with a graceful quit. The owner's emulator and Emulation folders were fingerprinted before and after each run: 0 changes.

| Profile         | Type                                        | Read back from the emulator's config                                                                                     | Result                                        |
| --------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------- |
| Pointer console | remote with attachment (default)            | every remote: the attachment on, its stick and buttons bound; a screenshot of the game running                           | PASS                                          |
|                 | remote                                      | no attachment, not sideways (the emulator drops those defaults when it saves), the remote's buttons as before            | PASS                                          |
|                 | remote held sideways                        | sideways on, the bottom face button on the remote's 2                                                                    | PASS                                          |
|                 | classic pad                                 | the classic pad on, its buttons bound, the remote's own buttons cleared                                                  | PASS                                          |
|                 | a party game, no choice of its own          | its `game_defaults` (by the title id read from the file): sideways on                                                    | PASS                                          |
| Tablet console  | pad with a screen (default) / pro-style pad | player 1's emulated controller type switches between the two                                                             | PASS (no screenshot: the emulator saved none) |
| Handheld        | the one type                                | launched, screenshot read back                                                                                           | PASS                                          |
| Hybrid console  | pro-style / split pair                      | not launched: it refuses without the owner's own keys, as expected; the edits are checked by the committed-profiles test | picks only                                    |

* The id reader found the party game's title id in the owner's copy (read-only); `game_options_get` returned its `game_defaults`, and the launch used them with nothing set for that game.
* Between types, the profile's own `config_edits` put the base bindings back first and the chosen type's edits went last, so no type left a binding behind.

## Dual-screen layout (through Steam, 2026-09-30)

The owner wanted "a big main screen, and small second screen on the side, and this needs to be configurable by kouch" (FINDINGS #44). The dual-screen handheld's test profile ran on the verify build, started by Steam through the Kouch Dev wrapper, with a fresh temp config, muted, and one game from the owner's folder (read-only). Every check below was read back from the emulator's own `qt-config.ini`, or from its own screenshot, which shows the composed frame.

| Check                                                                   | Result    | Notes                                                                                                                                                                                                                                            |
| ----------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Default layout                                                          | PASS      | `layout_option=2`, `large_screen_proportion=4`, `small_screen_position=2`, `swap_screen=false`. The screenshot (2880×1440) shows the main screen large on the left, with the second screen small at its lower right                              |
| Swap mid-game from the Quick Menu (`hotkeys.extra` "swap\_screens", F9) | PASS      | The second screen became the large one (a 2520×1440 frame), with no restart                                                                                                                                                                      |
| Next layout mid-game (`hotkeys.extra` "next\_layout", F10)              | PASS      | Moved to side by side (4320×1440), the next entry in the profile's `layouts_to_cycle` (large, side by side, stacked, main only, large with both small). Separate windows and custom, which break a fullscreen game window, are no longer offered |
| An unknown action                                                       | PASS      | `emulator_action` refuses it ("unknown emulator action")                                                                                                                                                                                         |
| Per-game value (Side by side)                                           | PASS      | Written as `layout_option=3` at the next launch. The screenshot shows the two screens side by side                                                                                                                                               |
| Look at 1920×1080                                                       | by aspect | The same 16:9 as this 2560×1440 monitor, so the same composition scaled. Not run at that size                                                                                                                                                    |
| Look at 1280×800                                                        | pending   | Central's next Deck run                                                                                                                                                                                                                          |

## Emulators launch fullscreen (through Steam, 2026-09-30)

The owner: "make sure emulators launch in full screen". The verify build was started by Steam through the Kouch Dev wrapper, with a fresh temp config, muted. Each test emulator was launched twice. Its game window was measured 8 s and 20 s after Kouch saw it (rect, style and monitor from user32, DPI-aware): whether it covers its monitor, has a caption or thick frame, and is the foreground window. This PC has two 2560×1440 monitors, and every game opened on the primary one.

| Profile                                                                                           | window\_mode                      | Before                                                                                                                                                                                                             | After (see the commit)                                                                                                                                                                                                           |
| ------------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Reference (pointer console)                                                                       | `fullscreen` (the emulator's own) | 2nd launch: covers, no frame, foreground. **1st launch on a fresh config: an 818×647 framed window at +8 s**, fullscreen by +20 s. Its own fullscreen was exclusive-capable, which hides the Quick Menu on Windows | The profile turns on the emulator's borderless fullscreen (GFX.ini). Both launches cover the monitor at +8 s, no frame, foreground                                                                                               |
| Handheld console                                                                                  | `borderless` (Kouch)              | covers, no frame, foreground, both launches                                                                                                                                                                        | same                                                                                                                                                                                                                             |
| Graphic-pack emulator                                                                             | `borderless` (Kouch)              | covers, no frame, foreground, both launches (the 1st at 0 FPS)                                                                                                                                                     | the 2nd launch covers. The 1st exited by itself again on its first Vulkan launch (FINDINGS #34, now 3 of 3)                                                                                                                      |
| Hybrid console                                                                                    | `borderless` (Kouch)              | not launched (it needs the owner's own keys)                                                                                                                                                                       | —                                                                                                                                                                                                                                |
| **Fallback:** handheld console set to `fullscreen` with its own fullscreen off, on a fresh config | `fullscreen`                      | —                                                                                                                                                                                                                  | a 1724×767 framed window at +8 s. The launcher's 20 s check found it didn't cover its monitor and made it borderless ("fullscreen: the game's window didn't cover its monitor; fixed"). At +25 s it covers, no frame, foreground |

**The launcher now checks the window after it's found** (`kouch_launch::fullscreen_fix`, `fullscreen_checks`):

* `borderless` is checked at 3 s and 10 s, and `fullscreen` at 20 s.
* A window that covers its monitor is never touched, including an emulator's own exclusive fullscreen.
* Otherwise Kouch makes it borderless on its monitor, or sends the profile's new `hotkeys.fullscreen` for `fullscreen` mode.
* Checks skip while the Quick Menu holds the game paused.
* **Linux:** under gamescope every game is fullscreen already. On a desktop, the `_NET_WM_STATE_FULLSCREEN` request is sent again for `borderless`; `fullscreen` mode isn't measured there yet.

## Automatic graphics, live (isolated build, 2026-09-30)

CONTROLLER\_TYPES\_PLAN T5/T6 on real emulators. One isolated Kouch (no Steam, temp config and data, muted), the owner's game folders as read-only roots, and the three test profiles that launch without the owner's own files. `device_info`: 2560×1440 at 480 Hz, desktop, a discrete GPU with 16 GB, tier high, 24 threads. Each emulator was launched once in Automatic and once after one hand edit. Every value below was read back from the emulator's own config file after launch, and each session ended with a graceful quit. The owner's emulator and Emulation folders were fingerprinted before and after: 0 changes.

| Profile                         | Automatic (written)                                                                                                                                                                                     | Manual after one hand edit (written)                                                             | Screenshot     | Result                                                                          |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------- | ------------------------------------------------------------------------------- |
| Reference (pointer console)     | renderer Vulkan, internal resolution 2× (the 3× label says 1584 lines, over 1440), MSAA 4×, SSAA off, anisotropic 16×                                                                                   | resolution 3 (the hand value); MSAA and anisotropic back to their defaults (off, the game's own) | both runs      | PASS                                                                            |
| Handheld console                | renderer 1, resolution 6× (1440 lines), texture sampling untouched (its labels have no multiplier)                                                                                                      | resolution 3 (the hand value)                                                                    | both runs      | PASS                                                                            |
| Second emulator (graphic packs) | renderer 1. The resolution pick (`2560x1440`) reaches the emulator only through a resolution graphic-pack mod, which wasn't installed                                                                   | renderer 0 (the hand value)                                                                      | the Manual run | PASS (renderer). The first launch exited by itself: FINDINGS #34, emulator-side |
| Hybrid console                  | not launched (it refuses without the owner's own keys, as expected). Picks: docked, resolution 1.25× (1350 lines of docked 1080), anti-aliasing off (no multiplier labels), anisotropic 16×, renderer 1 | —                                                                                                | —              | picks only                                                                      |

The hand edit switched each emulator to Manual on its own (`graphics_mode: "manual"` returned by `emulators_set_option_values`), and every launch logged "automatic graphics for this launch" with the picks and the device.

## Catalogue profiles, Windows half (through Steam, 2026-09-30)

PROFILES\_CATALOG\_PLAN's verification, Windows half. The setup:

* **Profiles:** the four `catalog/*.kod` files at `5df75a9`, each imported the way a drop is (a `profile:import_request` with source `drop`).
* **Kouch:** a fresh verify build started by Steam through the Kouch Dev wrapper (borrowed app id, muted). Each emulator's own volume was set to 0 in the test config only.
* **Install:** "Take everything" in the import sheet installed each emulator from its Windows source through the queue. The install log lines (start, done with version, path and time) appeared for each.
* **Games:** the owner's game folders as read-only roots; one game per profile, the second in each list.
* **Pad:** the dev virtual pad (pro-style, with motion) in seat 1.
* **The owner's folders:** a metadata fingerprint of their emulator and Emulation folders, before, after each profile and at the end: 0 changes in 118,781 entries.

| Profile                     | Install   | Launch, fullscreen                                                                                                                                     | DSU clients           | Input from the virtual pad                                                                             | Screenshot (the emulator's own, via `emulator_action`)                                                                                      | Quick Menu pause                      | Graceful quit           | Result                                               |
| --------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------------- | ---------------------------------------------------- |
| Reference (pointer console) | 2609, 5 s | 2560×1440 at 0,0 on the primary monitor, no frame                                                                                                      | \[4, 4]: both servers | A moved the game past its title screen                                                                 | the right game; 1920 lines (Automatic's 4×)                                                                                                 | CPU 156 ms per 3 s (its pause hotkey) | 2.2 s; session recorded | **PASS**                                             |
| Tablet console              | v2.6      | 2560×1440 at 0,0, no frame, 60 fps                                                                                                                     | \[1, 0]               | A opened the game's menu                                                                               | the right game; 1280×720, although Automatic shows 2560×1440 (FINDINGS #57)                                                                 | 144 of 144 threads suspended, 0 ms    | 0.6 s                   | **PASS**, with #57 and #58                           |
| Dual-screen handheld        | 2126.1.2  | 2560×1440, popup window (no caption)                                                                                                                   | \[1, 0]: motion only  | not checked: the emulator reads buttons through its own SDL, and the dev pad isn't an SDL device (#59) | the right game, in the default layout (large main screen, small one beside it); "Swap screens" from `emulator_action` swapped them mid-game | 219 ms per 3 s                        | 1.1 s                   | **PASS** (buttons need a real pad), with #58 and #59 |
| Hybrid console              | v0.2.1    | refused before starting: "… needs your own system files. Copy them from your console into …\system, then start the game again." The emulator never ran | —                     | —                                                                                                      | —                                                                                                                                           | —                                     | —                       | **PASS** (the refusal)                               |

* **Written config (reference profile):**
  * the default controller type (remote plus attachment) on players 1–4, each bound to its DSU slot in seat order;
  * both DSU servers listed;
  * the Automatic picks (4×, MSAA 4×, anisotropy 4, Vulkan);
  * the fullscreen key;
  * volume 0.
* **Not covered here:**
  * the reference profile's second system (the older disc console): the owner's folder for it has no games;
  * buttons on the dual-screen emulator (a real pad);
  * the Deck half, which is next.
* **The Deck half, first attempt (build `2027bb2`):** stopped before any install. Steam's own interface took focus on the Deck (docked to the TV), which first looked like someone was using it. The cause was the test tool: its A went to every Kouch window as a broadcast `nav:input`, and the hidden Quick Menu's Resume took it, which in Game Mode hands focus to Steam. No Deck activity followed, and the tools now send to the main window only (TESTING.md §2). The test Kouch was closed and the Deck unmuted. The owner's folders there: 0 changes. To be re-run on a build at current main.

### The first disc-console profile (`c8a4e73`), Windows (through Steam, 2026-09-30)

The same route, on a verify build at `ca10439`. The owner has no games for this system and no system file for it here. The launch was checked with test stand-ins: a zero-filled dummy disc, and a zero-filled dummy of the smallest accepted size, neutrally named, in the test instance's own system folder. Neither is a real game or system file.

| Check                                 | Result                                                                                                                                                                                                                                                                                                                  |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Import like a drop, "Take everything" | PASS: installed `v0.1-11826`, a versioned tag, not the rolling one (`tag: "v*"`)                                                                                                                                                                                                                                        |
| Portable config                       | PASS: `settings.ini` beside the program, in Kouch's install folder                                                                                                                                                                                                                                                      |
| Folders                               | PASS: BIOS search, memory cards, save states, screenshots, videos, game settings, input profiles, textures, patches, cheats, covers, shaders and cache all point into Kouch's user-data layout; SDL input only; the profile's hotkeys                                                                                   |
| Seat binding (`{seat_pad_N}`)         | Pad 1 and 2 written empty, as designed with no Steam pad in those seats: a pad joins only by a press on it, so the owner's pads couldn't be seated remotely. **Hardware check still needed**                                                                                                                            |
| Launch with the dummies               | The emulator crashed after \~4.5 s (0xC0000005), with the default renderer and with "Try with Vulkan". Run directly with the profile's arguments and no system file, it exited cleanly (code 0). So the crash comes from the zero-filled dummy, not the profile. The quick-exit sheet appeared each time (FINDINGS #65) |
| Empty system folder                   | PASS: refused with "… needs your own system files. Copy them from your console into …\system, then start the game again."; the emulator never started                                                                                                                                                                   |
| The owner's folders                   | 0 changes (118,784 entries, including this emulator's usual settings folders)                                                                                                                                                                                                                                           |

### The tablet console's resolution through the game's pack (#57), Windows (through Steam, 2026-09-30)

The emulator's community graphics-pack release (173 pack folders) was unpacked into the test instance's own pack folder. The same tablet-console game was launched from the owner's folder, read-only.

* **`7e2785e`:** the log said "no downloaded pack for this game has that preset", and the screenshot was 1280×720. The game's pack names its category "TV Resolution", as about half the packs do, and its presets carry suffixes ("2560x1440 (2K)").
* **`56d8a43` (profile revision .4):**
  * "the game's own pack carries the chosen preset".
  * During the session, `settings.xml` listed the pack with `<category>TV Resolution</category><preset>2560x1440 (2K)</preset>`.
  * The screenshot is **2560×1440**.
  * After a graceful quit, the entry was gone.
  * **PASS.**

### The second disc-console profile (`818ee04`), Windows (through Steam, 2026-09-30)

The same route, on a verify build at `56d8a43`, with a zero-filled dummy disc. No real game or system file.

| Check                                                    | Result                                                                                                                                                                                                                                         |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Install from the import sheet                            | PASS: `v2.8.2`, the stable release, not a nightly                                                                                                                                                                                              |
| Empty system folder                                      | PASS: refused with the plain message; the emulator never started                                                                                                                                                                               |
| With a 4 MiB zero-filled dummy in the test system folder | Kouch launched it, and the emulator stopped at its own "Startup Error" dialog: it found no valid system file in Kouch's system folder, as expected for a dummy. **No "reset all settings?" dialog**: `PCSX2.ini` carries `SettingsVersion = 1` |
| Written config                                           | PASS: `{config}/PCSX2/inis/PCSX2.ini`; the system-file, memory card, save state and screenshot folders point into Kouch's user-data layout                                                                                                     |
| Graceful quit with the emulator's dialog open            | PASS: the emulator closed in 0.2 s                                                                                                                                                                                                             |
| The owner's folders                                      | 0 changes (118,790 entries, including this emulator's usual settings folders)                                                                                                                                                                  |

## Motion in a real game under Steam (2026-09-29)

The owner's goal item: aim by pointing the pad and have shaking register, with the reference pointer-console profile (profile 1). The verify build ran through the Kouch Lab shortcut (Steam Input on, the borrowed app id), with a temp config and the owner's game folder as a read-only root. The owner played with their 2026 Steam Controller as P1, and the dev virtual controller sat as P2.

* **Kouch's DSU side:** the virtual controller's `shake 2.5 6 1500 z` read on DSU slot 0 with `kouch-lab dsu-client` as −1 ± 2.5 g on DSU Y at exactly 6.00 Hz for 1.5 s: 500 packets/s, no gaps, no CRC errors, packet numbers monotonic. The result was the same without Steam (the isolated build) and under Steam with Kouch focused. Motion reached the emulator while it had focus: its pointer followed the owner's pad.
* **Pointer:** the owner confirmed P1's pointer "works smoothly" (motion pointing on remote 1 through the per-game `pointer_motion` option; remotes 2–4 turned on explicitly and a recenter button on L3, `4985c36`). P2's pointer moved with the owner's pad while it sat in seat 2. One scripted 10° yaw of the virtual controller as P1 didn't visibly move its pointer in a single screenshot; that wasn't followed up. R3 → the emulated Home button wasn't checked on its own.
* **Steam caps acceleration at ±2 g per axis:** `GetMotionData` accel is ±32767 = ±2 g (`kouch-steam` `ACCEL_SCALE`), and gyro is ±2000 °/s. In 60 s of the owner's hard shakes, about 5,000 packets (\~10 s) had an axis at exactly 2.00 g, peaking at |a| = 3.46 g (all three axes at the cap); gyro reached 1,557 °/s. Motion kept arriving: new samples every 2–6 ms while moving, and the longest stale stretch was 30 ms. So the hard shakes the game waits for arrive flattened, and it reacted to some shakes and not others.
* **The emulated attachment must shake too:** with only the main controller shaking, a continuous shake in the rolling platformer stopped and restarted. Moderate shaking kept the trigger below within 0.39 s of its last spike for 26 s straight, so the trigger wasn't the gap. Driving the attachment's shake as well fixed it (owner: "it was that").
* **The mapping (`b5d0427`):** for all four controllers and their attachments, the emulator's own Shake is on while any accel axis is near the cap (> 18 m/s²), held about 0.45 s after the last spike (`smooth(..., 0, 0.9) > 0.5`), or while R1 is held. The owner confirmed rolls are continuous; resting and pointing never trigger it (7 packets over the threshold outside shaking in 40 s, far under the hold). PROFILE\_AUTHORING "Shaking" describes the pattern.
* **Rumble doesn't reach the pad:** the emulator's DSU client has no outputs, so no rumble leaves the game (row 16 needs another path). The planned routes: the emulator rumbling the physical pad through its own SDL (no driver), or Kouch's virtual pad (uinput on the Deck, ViGEmBus on Windows, opt-in).
* **Found and fixed in the test itself:** a staging script decoded the profile as ANSI and showed "6Ã—" in the Graphics sheet; the test copy is now written by Node. Kouch's import kept the UTF-8 bytes.

## LAN, two instances on one PC (2026-09-26)

Two isolated builds (identifiers `app.kouch.verify` / `app.kouch.verify2`, separate temp config/data, no Steam), LAN enabled on both. Covers the protocol end to end; a second physical PC is still untested.

| Check                               | Result | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ----------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| mDNS discovery both ways            | PASS   | After `6214866`: each lists the other at the real LAN address. Before it, both resolved to VPN/VM IPv6 addresses the IPv4 listener never answers.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| Pairing with the 6-digit code       | PASS   | Both sides show the other as paired. Before `6214866` it failed silently (unreachable address, no log).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| Transfer: profile + saves + states  | PASS   | Arrived under the receiver's user data. `system` was requested too and refused: a canary file and the emulator's system storage stayed behind (ground rule 2).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| LAN co-op (guest pads → host seats) | PASS   | Host lists the guest's 3 pads as players 4–6; guest shows the host as `host` (TXT role, new in `6214866`). Open: guest seats report device type `Remote` (the motion-remote class) instead of the pad's own kind + LAN; both sides' `lan_session.players` stay empty. **Fixed and re-run 2026-09-26** with auto-claim *off* on the host (the case that failed: every claim was denied, and the pads were only seated later by a stray press). The host seats the guest's 3 pads as players 1–3 and shows each with its own kind and a LAN badge. `lan_session.players` lists all 3 on both sides.                                                                         |
| Host → guest rumble (FINDINGS #32)  | PASS   | 2026-09-30, after `fc8f8b1`. The guest was the verify build started by Steam through the wrapper (Steam Input on), with the dev virtual pad as its only seated pad (the owner's pads were connected and left unseated there). The host was an isolated build. Pairing, host start, and the guest joining took 6 s from discovery; the host seated the pad as player 1, a LAN seat. 3 of 3 `controller_rumble_test` calls on the host reached the pad: "lan: rumble to a guest" 35.308349 → guest "lan: rumble from the host" 35.308454 → the pad's "dev virtual controller: rumble" 35.308816 (about 0.5 ms), l/r 39321, 200 ms. Both sessions showed ping 0 ms, no loss. |

## Device matrix (Plan v2 Phase 3)

One row per physical pad the owner has. Kinds are Kouch's neutral device classes (`docs/PLAN_V2.md` "Silhouette set"); the concrete model goes in Notes only as the owner describes it. Fill a cell with PASS / PARTIAL / FAIL / — (not supported) and the date in Notes.

| Device class                                                  | Connection       | Seats + buttons/sticks | Motion (Steam → DSU)               | Battery / USB shown | Rumble test | LED test | Split-pair modes                         | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------------------------------------------- | ---------------- | ---------------------- | ---------------------------------- | ------------------- | ----------- | -------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pad-trackpad-2` (2026 Steam Controller)                      | wired (SDL)      | PASS                   | PASS (Steam) / PASS (SDL fallback) | PARTIAL             |             |          | —                                        | Early Test 0, 2026-09-17: bound, buttons + sticks, motion. `kouch-lab os-pads` 2026-09-26: SDL reports it wired with no battery reading, so the box shows no power line. **SDL fallback 2026-09-26:** resting flat, SDL gives accel \[0.00 +0.99 +0.16] g (                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `pad-touchpad`                                                | wired (SDL)      | PASS                   | PASS (Steam) / PASS (SDL fallback) | PASS                |             |          | —                                        | Early Test 0, 2026-09-17. `os-pads` 2026-09-26: SDL power Charged 100 %, link wired. **SDL fallback 2026-09-26:** resting (not flat),                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `pad-pro` (`MotionPro`)                                       |                  | PASS                   | PASS                               |                     |             |          | —                                        | Early Test 0, 2026-09-17.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `pad-standard` (read as generic)                              |                  | PASS                   | —                                  |                     |             |          | —                                        | Early Test 0, 2026-09-17: no motion sensor.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `pad-standard`                                                | — (SDL: unknown) | PASS                   | —                                  | PARTIAL             |             |          | —                                        | Early Test 0, 2026-09-17. `os-pads` 2026-09-26: SDL power Charging 100 %, link unknown. **Identity survey 2026-09-26:** no SDL serial; path is `XInput#0`, the XInput user index, which Windows hands out in connect order. So neither serial nor GUID+path can identify it: since this survey an `XInput#n` path no longer counts, and it returns by the kind heuristic (lowest same-kind Reserved seat, VerifyPrompt when two could match). Steam Input gives no serial either (per-session handles), so preferring the Steam side would not help.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `pad-pair` / `pad-half-left` / `pad-half-right` (`SplitPair`) |                  |                        |                                    |                     |             |          | pair / sideways single / mixed / re-grip | Pairing by Kouch landed in `978812c`; not yet run on hardware.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `handheld` (Deck)                                             | built-in         |                        |                                    |                     |             |          | —                                        | Phase 1 Deck gate: AppImage runs on the Deck OLED (SteamOS 3.8, no host WebKitGTK); perf tour PASS in Desktop Mode (86–90 fps, p95 12–17 ms) and nested gamescope 1280×800 (62 fps, p95 17–18 ms), empty library, 2026-09-26. **2,000 games:** the Library phase fails (p95 21–25 ms, max up to 85 ms), the others pass; the fix is with A. **At the panel's 90 Hz** (owner's target; KDE Wayland, panel on) only the ambient phase holds 90: library 75.5 fps, connect 85.8, sheet 84.7. Under gamescope WebKit runs at a fixed 60 (see PLAN\_V2 Phase 1). **Real Game Mode, 2026-09-26:** WebKit follows the panel's 90 Hz (ADR 0015). Games launched from Kouch show (they were black until `9ffbc23`), and the Quick Menu is drawn over them as a left panel (Early Test 10). SDL reads the built-in controls as `SteamDeck` (vid 0x28DE pid 0x1205) with no Steam running.                                                                                                                                                                                                  |
| `keyboard-mouse`                                              | USB              | PASS                   | — (mouse-as-motion: synthetic)     | —                   | —           | —        | —                                        | Keyboard + mouse seat (`75d6ed3`). `kouch-lab kb-seat --bind F24=a` 2026-09-26: an injected F24 went A down/up and an injected mouse nudge moved the right stick, through Raw Input with another window focused. Not yet seated in the app or tried in an emulator. **In a real game 2026-09-26** (kouch central; Steam-launched verify build, reference emulator, pointer game; keys bound to F15–F24 and injected so nothing typed into the emulator): F24 joined the seat on the connect screen, A+B advanced the title, the pointer appeared, and DSU slot 0 carried the buttons and motion, with mouse right = yaw right and mouse down = pitch down on the wire. **Fixed from it:** perfectly clean motion (gravity exactly (0,0,1) plus a pure yaw) turned that emulator's pointer into NaN for the rest of the session, so the seat now adds sensor jitter like the virtual controller (`source::noise`). Sensitivity 1 was 250 counts per 25° and is now about 2000. The gyro is averaged over 20 ms, so mouse bursts no longer spike one tick; the total turn is kept. |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kouch.dev/docs/early_tests.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
