evidence · 4.9 KiB

README.md

Committed at docs/evidence/card-shell/runtime-tap-after-drag-race/README.md. This is what grounds the requirements that cite it.

Open raw source

tests/card_shell_runtime.py pre-existing flake: tap-after-drag race

Evidence class: host-only (QEMU-injected input under qemu-riscv64-static, real cross-built Sway; no board, no physical touch). This fixes a test-harness bug found while closing out the-card-shell-has-no-video-special-case’s task 4.2, not a compositor behavior change.

What was reported

Task 4.2 recorded that tests/card_shell_runtime.py’s wait_for(lambda:focused()=='k230.card.two') assertion (after a full horizontal deck drag followed by an immediate tap) was already failing against the pre-change baseline (commit 59e0eb78), unrelated to that change’s own diff.

Root cause

Confirmed by reproducing directly (python3 tests/card_shell_runtime.py --sway <sway> --client <client> --rgb565, no board):

  1. cs_up (nix/card-shell-policy/card-shell-policy.c) resolves a released horizontal drag by updating p->selected to the new card synchronously, but deliberately does not re-center that card: scroll_from_dx is chosen so the newly selected card’s on-screen position stays continuous with wherever the drag left it, then eases to center under its own momentum over up to config.reduced_motion== false’s 760ms bound (cs_up’s own comment: “the settled card’s on-screen x must not jump at the instant of release”).
  2. cs_down (same file) hit-tests a fresh touch against the current, still-animating geometry: on a coast, it calls cs_tick(p, time_ms) using the real wall-clock time of the IPC call before hit-testing.
  3. The test fired command('down 2 284 450'); command('up 2') (a tap at the panel’s horizontal center) immediately after command('up 1') ended the drag, with no wait for the coast. Depending on scheduler timing (worse under shared-host load), the tap could land while the just-selected card was still off-center, so it either missed or hit a different card than the one cs_up had already selected.

This is real, intentional product physics (cs_up’s continuity design), not a compositor bug, and reproducing it does not require the video special-case removal — it was present at commit 59e0eb78 already.

A second, independent flake was found while reproducing this one: the during-drag.png capture at x==184 in the same drag loop (subprocess.run(['grim', ...]) immediately after an IPC motion command) could run before the compositor’s next scheduled frame had actually been composited, especially under the heavily loaded shared host this session ran on (uptime showed ~18-19 load average across 32 cores while reproducing this). docs/evidence/brightness-slider/README.md already documents the same class of host-load sensitivity for a different QEMU harness.

Fix

tests/card_shell_runtime.py:

Neither change touches compositor source (nix/card-shell*); both are confined to test synchronization in tests/card_shell_runtime.py.

Verification

Narrow proof command (from tests/, matching the task’s own required invocation):

python3 -m unittest test_card_shell_scaled_cache_runtime -v

Result: PASS, both the SWAY_K230_CARD_SCALED_CACHE=0 and =1 runs (off and on), reusing the cached .#card-shell build (/nix/store/j57c5im42d3rq5gxdar2ikmh22717zvc-k230-card-shell, unwrapped Sway /nix/store/0a2f857nc1rz65gnjdfn46h32zsyxm18-sway-unwrapped- riscv64-unknown-linux-gnu-1.12) and the native card-composition-probe-client (/nix/store/yjb89ap4bq5vb29szdzkr5sv9lpw1sz6-card-composition-probe- client-0.1). Also reproduced clean twice more by invoking tests/card_shell_runtime.py directly with the same binaries and --rgb565 (no unittest wrapper).

Unaffected suites confirmed unchanged by inspection: --two-axis and --touch-first both return before reaching the edited code path, so test_card_shell_two_axis_runtime.py, test_card_shell_touch_first_ runtime.py and test_card_shell_home_bleed.py (which drives --home-layer-client through the two-axis path) exercise different lines entirely. Both of those suites were observed independently flaking on this same shared, loaded host during this session (different assertions, earlier in their own paths) — that is the same pre-existing host-load class documented in docs/evidence/brightness-slider/README.md, not a regression from this diff, and is out of this task’s scope.

Limits

QEMU-injected-input proof only; no board, no real finger, no panel. This fix makes the existing host regression deterministic again; it makes no claim about physical drag/tap timing.