The gaps were prose in TASK-43 and a summary message. They are tasks now. 50 is the one that matters: every scene intent dispatches except touch, so she can move and dim a window and cannot press anything in one — and the workaround is the uinput bridge, which launders her intent into a physical touch inside the kernel where nothing can undo it. That is the conflation input.rs was written to prevent, and it is live every day this stays open. 51 is the punch list found by using the phone rather than reading it: stacked windows, capture written-and-unmerged so nothing visual can be verified, volume recognised and dropped, and the named holes.
5 KiB
TASK 50 — Her hand on the glass: synthesized touch, and the pose that must map back
Status: open, and it is the highest-value bridge left in viewtop. Created
2026-08-02, when the rest of ToCompositor landed (276bb3e) and these were
the two intents that had to be refused. Repo: souveraine-viewtop.
Why this one matters more than it looks
Doctrine §13: "tap the thing on screen" is a verb, and a verb she cannot reach
is a defect. Every other scene intent now reaches the compositor — place,
pose, expose, raise, lower, set_visible, focus, close are live and
proven on hardware. The four touch intents are refused with unavailable.
So today she can move a window, scale it, dim it, close it — and cannot press anything inside it. The one thing she reaches for most is the one thing routed around.
Worse: the workaround is the thing input.rs was written to replace. She
reaches touch through the uinput bridge, which launders agent intent into a
physical touch inside the kernel, where nothing above it can undo the
conflation. TOUCH-AND-EVIDENCE.md is entirely about that: a finger is a
sensor reading (§4, if touch.active: confidence += 0.1), an agent tap is an
action, and the whole reason viewtop exists is that provenance has to start at
the source. Every day this stays open, observed_confidence is being raised by
her own taps.
The receiving end is already built
This is a bridge, not a design. input.rs has all of it:
Origin::Agentcarried from the event source, never from a field a caller could set.AGENT_SLOT_BASE(1 << 16) so a synthesized contact cannot land on a slot a thumb already owns.Origin::is_evidence()— the single predicate that keeps her taps out ofinputandsensor_input.Viewtop::touch_down/motion/up/cancelalready takeOriginas their first argument and already return theEvidencethe caller owes sessiond.
Tests for all of it pass and have since 458a354. Nothing calls them with
Origin::Agent.
What to build
- Dispatch the four intents in
Viewtop::serve_intent(wayland.rs), where they currently refuse.TouchDown { slot, at }→touch_down( Origin::Agent, slot, at, SERIAL_COUNTER.next_serial(), time). Thetimeis the wrinkle: touch events carry a millisecond clock a client uses to compute velocity, andclock_now()is already there for presentation timestamps. - Refuse a motion or up for a slot she does not hold.
Router::motionalready answersRoute::Withheldfor an unknown slot, so this is reading its answer rather than adding a check — but the reply must say so, or a chain cannot tell "dropped" from "delivered". TouchCancelclears only her slots.Router::cancel(Origin::Agent)does this already and has a test (cancelling_the_agent_leaves_the_finger_down).
The half that is genuinely unbuilt: inverse mapping through pose
pose is live and applied in the render — scale about the pivot, exposure as
alpha. The hit test does not know about it. A surface painted at scale 0.8
is still touched at its placed rectangle, by a finger and by her.
That is currently honest rather than broken (the module says so in as many words), and it stops being honest the moment either of these is true:
- she poses a surface and then taps inside it — her own coordinates would be in posed space and the client would receive them in placed space;
- a person taps a posed surface, which is already reachable today.
TASK-43's scene-composition section named this as the real cost of "spin and twirl": "a touch on a rotated surface has to land back in the client's own coordinates, or the surface is a picture rather than a window."
The mapping is the inverse of pose_origin plus the scale, and rotation when it
lands: client = (screen - origin) / scale, about the same pivot. It belongs
next to pose_origin in wayland.rs so the two cannot drift, with a test that
round-trips a point through pose-then-unpose for a spread of scales and anchors.
Acceptance
{"op":"scene","intent":"touch_down","slot":0,"at":{"x":…,"y":…}}presses a button in a real client on the phone, and the client cannot tell it from a finger.sessiond device_stateshows no change inobserved_confidenceand noinputtrail entry across a hundred synthesized taps — the property the whole provenance design exists for, and the one that fails silently ifOriginis ever recovered downstream instead of carried.- A physical finger during the same run still moves both.
- A point posed at
scale 0.5and tapped at its visual centre reaches the client's centre, not its top-left quadrant.
Connects to
TASK-43 (viewtop; this is its "nothing dispatches ToCompositor" item, now
narrowed to touch), TOUCH-AND-EVIDENCE.md (why provenance starts at the
source), doctrine §13 and §4, TASK-41 (nothing yet proves which caller is
asking — the control socket admits every uid-1000 process, same hole as
may_take_lock).