swayfx-mosaic/docs/design/STEP20C_TEMPORAL_DAMAGE_PROBE.md

297 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# STEP20C temporal rendering and damage probe
**Status: EXPERIMENTAL / PROTOCOL RECORDED BEFORE FIXTURE.** This probe uses
private headless binaries only. STEP20C remains **NEXT** and multi-output
Mosaic remains **NOT YET SUPPORTED**. No UX, production ABI, package or
transaction contract is changed here.
**Measured verdict: PARTIALLY_FEASIBLE for the sampled temporal matrix.**
The stabilized visual and lifecycle assertions passed in the runs below;
frame-by-frame presentation, full input/render synchronization and native
transaction generation remain unproven.
## Question and prior evidence
The [negative-origin probe](STEP20C_NEGATIVE_ORIGIN_NESTED_GRAB_PROBE.md)
found sampled popup clipping and hit testing feasible at stable positions.
It did not capture every presented frame or prove SceneFX damage sufficiency.
This probe asks whether repeated XDG lifecycle and camera transitions expose
stale pixels, wrong input targets or scene/IPC disagreement. A successful
settled screenshot cannot establish correctness during the transition.
## Fixed geometry and three configurations
HEADLESS-1 is `(-800,0,800,600)`, HEADLESS-2 is `(0,0,800,600)`, scale 1,
transform normal, global bounds `[-800,800) × [0,600)`. PNG coordinates are
output-local: HEADLESS-1 local X is global X plus 800, HEADLESS-2 local X is
global X. The virtual pointer receives `sent_x=global_x+800` with extent
`1600×600`; client enter/button events validate actual targeting.
| Mode | Binary | Layout | Camera |
| --- | --- | --- | --- |
| A | unmodified `/usr/bin/sway` | `splith` | N/A |
| B | private Mosaic with private SceneFX | `splith` | N/A |
| C | same private binary, clip and owner guard | `mosaic` | 400 ↔ 1280 |
Each run uses its own mode-0700 runtime, discovered private Wayland display,
explicit `swaymsg -s` socket, bounded children and two-output captures. The
daily session socket is excluded from the subprocess environment. The
ordinary layout controls compare common XDG creation, input and destruction;
they have no invented camera counterpart.
## Hypotheses and XDG lifecycle
H1: hiding the fully off-viewport tiled owner removes its popup pixels.
H2: camera return restores the same mapped A/B objects without old-position
pixels. H3: after B then A are destroyed, their former regions show the
underlying surfaces. H4: applied scene, clip, IPC and pointer targets agree
at observed transitions. H5: SceneFX invalidates the regions actually changed.
H6: private `splith` does not regress against unmodified SwayFX for common
XDG transitions. H7: repetition produces no crash, protocol error, surface
accumulation or ghost pixels. Each hypothesis receives its own verdict.
TOPLEVEL → POPUP_A → POPUP_B is a real parent chain with distinct `wl_surface`,
`xdg_surface` and `xdg_popup` objects. Opening A uses a fresh TOPLEVEL button
serial; opening B uses a fresh A button serial. Every popup gets role
configure, `xdg_surface` ack, then buffer map. Explicit close destroys B
first; A is destroyed after B. An outside click may deliver `popup_done`
B then A and has a different expected outcome from camera hiding without a
click. Serial values are per run, never constants.
## State and observation boundaries
The logical Mosaic `scroll_x` in IPC is distinct from Sway pending/current
container geometry and from the applied scene position. The owner applied
rectangle, clip log and sampled PNGs must corroborate scene placement. An IPC
success reply proves command acceptance, not presentation. The current
private probe exposes no native transaction generation. `SPIKE_DAMAGE`
records an output-local damage **bounding extent** before scheduling a frame
and adding to the damage ring; it is neither an exact region decomposition nor
proof of a presented frame. Any experimental counter must be labelled local.
The run preserves monotonic action/capture times, IPC trees, pointer/client
events, compositor logs and PNG hashes. `grim` produces sampled screenshots;
it cannot guarantee capture of every presented frame or a fixed achieved
frequency. Damage-to-pixel matching is **PARTIAL** unless records can be
associated with the actual presented frame and capture.
## Predefined scenarios and observations
The initial target is ten complete stable cycles per mode, bounded by a
per-run duration and capture/byte limit. Each cycle gets a unique ID and:
| Phase | Action and expected evidence |
| --- | --- |
| S0 | no popup, verified outputs, static reference, IPC, two PNGs |
| S1 | real TOPLEVEL click, A grab/configure/ack/map, two PNGs |
| S2 | real A click, B grab/configure/ack/map, two PNGs |
| S3 | visible A/B, configured/applied positions, interaction without dismissal |
| S4 | C only: `scroll_x` 400 → 1280, fully hidden owner, A/B still mapped, no popup hit |
| S5 | C only: 1280 → 400, same XDG objects, visible pixels restored |
| S6 | explicit B close, A retained, formerly covered region restored |
| S7 | explicit A close or controlled outside dismissal, underlying rendering restored |
| S8 | no old popup objects, owner/client alive, prepare fresh serials |
Separate runs cover controlled outside-click dismissal and Mosaic → `splith`
with open popups. After stable cycles pass, target 15–20 camera back-and-forth
transitions with A/B open, first with observed stabilization and then with
rapid IPC requests. Record both request and observed states; coalescing is
not automatically a failure. A reproducible crash stops the loop for minimal
reproduction. Failed and inconclusive cases remain in the evidence.
## Image and damage analysis protocol
Use the nested client's solid SHM A-yellow `(224,192,32)` and B-green
`(32,208,160)` surfaces as known foreground. Establish stable reference
images of the background and formerly covered A/B rectangles before scoring.
Avoid dynamic `wev` text regions when comparing full pixels; any mask must be
defined before looking at anomalies. Cursor, decorations, text, effects,
capture compression and IPC/capture timing can create unrelated differences.
Record each PNG's dimensions, monotonic capture timestamp, SHA-256, phase,
output-local region of interest, exact popup-color count, whole-region diff
count, diff bounding box and anomalous local coordinates. Compare formerly
covered regions with the appropriate uncovered reference, not just the
decrease of an exact color. Keep signed global conversion separate.
For each transition, compare observed changed regions with time-ordered
`SPIKE_DAMAGE` extents for that output, then with the rendered result. A broad
damage extent alone is not a correctness failure; missing or late invalidation
requires synchronized evidence. When frame association is absent, mark H5
**PARTIAL** even if stabilized images are correct.
## Verdict rules and limits
Each assertion is `PASS` only with the required geometry, XDG serial and
lifecycle traces, mapped identities, client events, PNG pixels and process
status. `FAIL` requires a demonstrated invariant violation. `PARTIAL` means
some required observation exists but coverage or synchronization is limited.
`INCONCLUSIVE` means the fixture cannot identify the behavior; `NOT TESTED`
means it was not run. A zero process exit alone is never `PASS`.
The aggregate is **FEASIBLE for the sampled temporal matrix** only when all
executed required visual/input transitions pass, controls have no blocking
regression, and damage traces support only the precise claims made. Positive
stabilized images with incomplete frame/damage association are
**PARTIALLY_FEASIBLE**. A reproducible leak, protocol violation, destruction
defect or crash is **BLOCKED**. Unusable fixture or captures are
**INCONCLUSIVE**. Untested cells stay **NOT TESTED**. Scaling, rotation,
resize, migration, complete effects and ABI/package maintenance are outside
this experiment. No result authorizes production STEP20C or daily use.
## Measured campaign and retained evidence
The final instrumented lab is `/tmp/swayfx-mosaic-nested-grab-RbwDblky/`
with build log `/tmp/mtd-prepare-Rv5kR9sm`. It contains ten runs: ten
complete cycles each in unmodified SwayFX `splith`, private `splith`, and
private Mosaic; one extra private Mosaic pilot cycle; one camera run; outside
click runs in all three configurations; a distinct hidden-owner click; and a
private Mosaic → `splith` return. The planned 30 cycles all completed.
There are **994 sampled PNGs**
on two outputs. None is labelled a complete presented-frame sequence.
The popup owner and A/B are solid SHM surfaces; supporting Kitty windows ran
with cursor blinking disabled. The predefined HEADLESS-1 ROI
`(400,90,800,310)` was empirically stable across S0 and post-close captures
in the completed cycles. `wev` on HEADLESS-2 can redraw its text, so its
whole image was not treated as a static underlay; right-output popup colors
and events were checked separately. The ROI and this exclusion were fixed
before scoring the campaign.
| Observation | Unmodified `splith` | Private `splith` | Private Mosaic |
| --- | --- | --- | --- |
| Ten A/B open → close B → click A → close A cycles | PASS sampled | PASS sampled | PASS sampled |
| A right-button delivery after B destruction | 10/10 | 10/10 | 10/10 |
| Former A/B left-output ROI restored | 10/10 exact equalities | 10/10 | 10/10 |
| B crossing color at right, cycles 1 and 10 | 15,860 green | 15,860 green | 0 green |
| Fully hidden A/B colors and camera return | N/A | N/A | 10/10 sampled: 0/0 hidden, A/B restored with equal ROI |
| Outside-click `popup_done` and child-first destruction | PASS | PASS | PASS |
| Hidden-owner click: no popup button, B/A dismissal | N/A | N/A | PASS sampled |
| Stable `splith` return with B open | N/A | N/A | 15,860 B pixels and actual B button |
| Damage/frame presentation proof | NOT TESTED | PARTIAL | PARTIAL |
The camera run requested 18 outward/return pairs in each of three pacing
modes: stabilization after every change, capture between accepted commands,
and a four-command burst without intervening captures. The owner stayed IPC
ID 8, A/B were created once each, no `popup_done` occurred before explicit
closure, and the sampled hidden/visible colors followed the observed target
values. All 109 `camera_observed` records, including initial positioning,
reported targets 400 or 1280. No sampled right-output A/B color appeared.
The runner's IPC checks do not prove which intermediate target values were
actually presented. The burst may coalesce them. Input/render consistency
during an unobserved frame is therefore **PARTIAL**, even though the sampled
pointer and pixel outcomes show no reproducible divergence.
The separate hidden-click run sent a right button to a point on HEADLESS-1
after `scroll_x=1280`. The count of popup button presses did not increase;
`popup_done` arrived B then A, and neither popup reappeared after return to
400. This is one controlled hidden point, not a universal input claim.
The private SceneFX `TEMPORAL_DAMAGE` log recorded **4,361** output-local
damage extents across the eight private runs, and the actual SwayFX repaint
path logged **1,432** accepted output commits (zero rejected). The analyzer
compared each pair of sampled captures per output against extents whose
monotonic timestamps fell in that capture interval. It found **zero changed
pixels outside their union** and zero changed intervals without an overlapping
extent. This is interval evidence only: broad bounding extents may hide
over-invalidation, and no screenshot is tied to a unique presented frame.
H5 is **PARTIAL**. The unmodified control has no private damage trace and is
**NOT TESTED** for H5.
An independent audit of the retained PNGs compared all three RGB channels,
rather than relying on the analyzer's grayscale difference. Across 784
private same-output capture intervals, 237 contained changed pixels
(57,451,528 changed pixel positions in total); zero changed positions fell
outside the union of their time-bounded logged damage extents. This confirms
the narrowly stated interval observation despite the grayscale conversion
used by the fixture analyzer. It does not establish minimal damage, exact
pixman regions, a damage-to-commit mapping or intermediate frame correctness.
`results/artifacts-sha256.txt` lists **2,133** raw and derived files, with
manifest SHA-256
`362ba5dc399383ecd7c071b56c144b8bdf9f4dc17fad53b60238a14c750bdf7c`.
The final 12-input source manifest is `temporal-source-sha256.txt`, SHA-256
`ef5596c587372388efedd9319ee0062cf1143e2a7c203ed4c579fc6346753702`.
The preceding instrumented lab
`/tmp/swayfx-mosaic-nested-grab-1u4Q8mE9/` retains its original
`temporal-source-sha256-initial.txt`: after those runs, its analyzer gained
a pixel-wise union check and final matrix. The final lab was rebuilt after
the A-input and hidden-click refinement and carries a single matching source
manifest. `sha256sum -c` passed for all 2,133
listed artifacts and all 12 final source inputs.
A fresh private lab at `/tmp/swayfx-mosaic-nested-grab-u5ZlcX0A/` rebuilt
the pinned source and patches and passed its 12-input source manifest. A
targeted replay completed one A/B open → explicit B/A close cycle in each of
the three configurations, plus private Mosaic hide/click/return, one
two-move camera run and a separate outside-click dismissal. All six runs had
no runner failure, valid XDG button serials and no failing targeted
assertions. Their 124 sampled PNGs, 1,457 private timed damage extents and
289 accepted private output commits reproduce the sampled outcome; they do
not add frame identity. This fresh lab is retained outside Git.
The independent uninstrumented lab
`/tmp/swayfx-mosaic-nested-grab-36Cbn4JP/` had the same ten-cycle sampled
outcomes in each configuration. The first instrumented lab
`/tmp/swayfx-mosaic-nested-grab-M5uSSO6U/` and the later
`/tmp/swayfx-mosaic-nested-grab-1u4Q8mE9/` also repeated them. No
probe-induced visual difference was observed in these sampled runs; timing
perturbation outside them remains possible. No compositor crash, Wayland
protocol error, failed grab, stale popup object or residual popup-colored
pixel was detected in the completed final matrix. The initial toggle
sampling failure and its correction are recorded in the history below.
This result does not settle popup UX while an owner is hidden, full
transaction-generation consistency, all presented frames, effects/decorations,
saved buffers, scaling/rotation, output migration/resize or SceneFX ABI/package
maintenance. The next bounded STEP20C experiment should instrument an actual
headless output presentation event together with applied camera/clip state
and pointer target for one repeated hide/return transition. It should test
the unobserved interval directly; it does not authorize a production fix.
## Protocol history
- 2026-10-11: protocol written before the temporal fixture; targets and
verdict rules above are prospective. Subsequent changes and measured
results must be recorded here with their date and run paths.
- 2026-10-11: first private campaign in
`/tmp/swayfx-mosaic-nested-grab-36Cbn4JP/` completed ten cycles in each
configuration, plus 18 camera transitions per mode, outside clicks and a
layout-return pilot. The original runner/analyzer sources are retained in
that lab's `source-snapshot-v1/`. Its immediate `layout splith` capture
contained no right-output B pixels; the protocol now adds a stabilized
capture and B click before classification. The camera runner also adds a
separate command burst without captures between every accepted scroll.
These changes affect measurement timing, not the private clip algorithm.
- 2026-10-11: `SPIKE_DAMAGE` lacks monotonic timestamps and an output commit
marker. A separate private SceneFX logging patch is therefore planned for
the next lab. It may log `CLOCK_MONOTONIC` nanoseconds, the damage extent,
and a **local experimental** output-commit ordinal/result. It will not
expose a native transaction generation, alter public headers or prove
presentation by itself. Compare the instrumented result with the
uninstrumented campaign for probe-induced changes.
- 2026-10-11: the first instrumented lab
`/tmp/swayfx-mosaic-nested-grab-M5uSSO6U/` retained 10 cycles per mode,
18 camera round trips in each of three pacing modes, outside clicks and a
successful stable layout-return check. It logged damage but zero SceneFX
commit-hook calls. Source audit found the actual call in private SwayFX
`sway/desktop/output.c`; a separate logging-only Mosaic patch is now added
to the next private lab. The initial toggle runner failure in
`/tmp/swayfx-mosaic-nested-grab-pX0BTADM/` was a left-side fixture sample
after stable right-side pixels had already been captured; it was not a
compositor or XDG failure. Its logs and exit code are retained.
- 2026-10-11: the private SwayFX commit-hook patch logged the repaint path
actually used. Pixel-wise unions and `matrix.json` were added to the
analyzer after the first complete instrumented campaign; its original
analyzer hash was retained in `temporal-source-sha256-initial.txt` under
that lab. Its own source and artifact manifests remain available.
- 2026-10-11: a final protocol refinement adds an explicit A right-button
interaction after B's destruction in each cycle, and a separate hidden-owner
outside-click run. Earlier cycles demonstrated A mapping and B creation via
an A click, but did not directly recheck A input after B closed. The new
run must not erase or relabel earlier evidence; its own manifest and run IDs
will distinguish this stronger input check from the previous matrix.
- 2026-10-11: the refined campaign in
`/tmp/swayfx-mosaic-nested-grab-RbwDblky/` completed the 30-cycle matrix,
camera modes and both outside-click contexts. Ten post-B A interactions per
configuration and the separate hidden-click non-hit assertion passed. Its
final source and artifact manifests validate the finished analysis. The
verdict remains **PARTIALLY_FEASIBLE** because frames and native transaction
generations remain unobserved.