evidence · 7.8 KiB

README.md

Committed at docs/evidence/coherent-shell/overlay-bottom-escape-qemu/README.md. This is what grounds the requirements that cite it.

Open raw source

Bottom-edge overlay escape: paired QEMU injected-touch regression

Observed 2026-09-25 on a headless 568×1232 Pixman output under qemu-riscv64-static, in response to the operator’s literal report: “if in settings swiping up from bottom does nothing it should be like any app really.” Traced by docs/design/shell-ux-critique.md §1.1 to nix/card-shell/adapter.c’s input_down, which ceded every touch to a mapped Drawer/Shade/Settings overlay before the compositor’s own bottom-edge recognizer ever ran. Fixed in nix/card-shell/adapter.c, nix/card-shell/route.c, and nix/rust-shell-client/src/service_ui.rs; see openspec/changes/the-shell-behaves-as-one-coherent-system/ slice E (tasks E.1-E.3) for the full spec/task record.

Positive (fixed) targets:

python3 tests/test_rust_overlay_bottom_escape_runtime.py \
  --sway /nix/store/vysdsfyh2i3k00n6sp8wpfa2hj07qvvc-sway-unwrapped-riscv64-unknown-linux-gnu-1.12/bin/sway \
  --rust /nix/store/3y57vjkizci06plvq8dldqvxdc26yni6-k230-shell-rust-riscv64-unknown-linux-gnu-0.1.0/bin/k230-shell-rust \
  --client /nix/store/03pqadqmfvr2yci8cvq2rf68rx32bf6y-card-composition-probe-client-0.1/bin/card-composition-probe-client \
  --output /tmp/k230-sa-3

PASS (result.json). Four scenarios, all real injected wl_touch via the compositor’s own card_shell test-touch hook (SWAY_K230_CARD_TEST_INPUT), real Sway/Wayland protocol traffic, no board access:

  1. Bottom-edge swipe up from Settings over a running app reaches the overview. With Settings mapped over k230.card.one, a touch down at the bottom edge (284, 1200) followed by an upward motion to (284, 1100) and release is claimed by the compositor: sway.log logs K230_CARD_SHELL mirror id= (the same card-entry mirror an app’s own swipe produces) and settles in state mode=1 (CS_DECK, the overview). rust.log logs unmap — the overlay was dismissed as part of the same gesture, via the pre-existing Route::Hide now reachable from card_shell_launch_surface("hide").
  2. Bottom-edge sideways swipe from Settings switches to the neighbour app. With k230.card.two focused and Settings mapped over it (a second app, k230.card.one, also running), a touch down at (284, 1200), motion up to (284, 1100), then sideways to (420, 1100), then release switches focus directly to k230.card.one (sway.log’s restored focus= incrementing and matching that window’s id; focused() over the Sway IPC tree confirms it) — the same already-approved two-axis quick-switch mechanics (the-handheld-presents-a-coherent-shell design decisions 11/12) an app’s own swipe already used, now reachable from the overlay too.
  3. Settings’ own top-area Close control stays reachable. A plain tap at (520, 50) — well outside the qualified bottom edge band — still reaches the overlay’s own touch handling: rust.log gets a new unmap (the overlay’s own PanelIntent::Hide tap logic fired) with no additional K230_CARD_SHELL mirror id= line in sway.log — confirming the bottom-edge carve-out does not overreach into the overlay’s own controls.
  4. Settings’ local dismiss direction now matches Shade’s. A downward swipe near the top (200, 60) → (200, 400) no longer dismisses Settings (unmap count unchanged); the same swipe reversed — upward, (200, 150) → (200, 40) — does dismiss it, matching Shade’s pre-existing direction.

Negative control: the unmodified pre-fix compositor reproduces the bug

The identical scenario-1 touch sequence against the unmodified origin/master nix/card-shell/adapter.c/route.c (temporarily restored via git show HEAD:..., nix build .#card-shell re-run, then the fixed sources restored — the store path /nix/store/s8r1x1wfhk7ch3z40w7ialcrb7w4br9r-k230-card-shell was not kept) times out after 5s waiting for K230_CARD_SHELL mirror id=. negative-control/rust.log shows the touch reaching the Rust client directly (touch-down 10/touch-move 10/touch-up 10, its own logging), i.e. Sway forwarded the whole gesture to the still-mapped overlay exactly as shell-ux-critique.md §1.1 traced; negative-control/sway.log never logs a K230_CARD_SHELL mirror id= line for this touch. This is the literal “swiping up from the bottom of Settings does nothing” behavior being reproduced under QEMU, not merely inferred from source.

Regression sweep (same fixed binaries unless noted)

Pre-existing, unrelated QEMU pixel-capture issue (not a regression)

tests/test_rust_shade_dismiss_runtime.py and tests/test_rust_drawer_interaction_runtime.py both fail a pixel-comparison assertion (app_shade.getpixel(...) != app.getpixel(...), respectively opened.getpixel(...) != deck.getpixel(...)) in this sandbox. Verified this is not caused by this change: the identical failure reproduces against the unmodified pre-fix adapter.c/route.c binary too. Neither script touches the bottom-edge or dismiss-direction code paths this change edits. Consistent with this repository’s own prior finding of the same class (commit 68796fe8, “Record the QEMU run attempt: environment-blocked, not a code regression”), this is recorded as an environment limitation of this sandbox’s grim/headless capture, not a source regression, and is left for a separate investigation.

Limits

Real Sway/Wayland protocol runtime and real injected touch under QEMU; no physical panel, finger, or board evidence. This proves the compositor routing and Rust surface logic behave as specified; task E.4 (docs/evidence/coherent-shell/overlay-bottom-escape/, not yet captured) remains the required real-glass acceptance gate before slice E can be considered physically verified.