swayfx-mosaic/tooling/probes/step20c-temporal-damage/README.md

6.9 KiB

STEP20C temporal damage fixture — EXPERIMENTAL

This fixture tests repeated popup lifecycle and camera transitions only at HEADLESS-1 (-800,0,800,600) and HEADLESS-2 (0,0,800,600), scale 1, normal transform. The protocol and verdict rules were recorded before this fixture. It does not alter the production build, package, session or SceneFX ABI. It produces sampled PNGs, not every presented frame.

Inputs and preparation

Start from a full Git clone containing Mosaic cd550382 and the preserved STEP20C fixtures. The wrapper invokes the negative-origin prepare.sh, which clones pinned SceneFX 37ccd723bef49e6891156ffafce8f549f01446cc and Mosaic cd550382b311efdbfe3ed892f4e1d281d852e754 into a new temporary lab, applies the unchanged private SceneFX/Mosaic/hidden-owner patches, builds both privately, generates protocol headers and compiles the pointer. client-cycle.patch is the only new C adaptation: it permits explicit A closure and fresh configure/map on later cycles. It is applied to a private copy of the preserved nested client and compiled as C17. No installed library or compositor is modified. The preparation output names both the lab and build log; the lab's temporal-source-sha256.txt records all private patch, client and runner inputs. Compare its hashes before a replay. A full clone containing this fixture can run prepare.sh directly. The source manifest verifies the scripts and patches used by each private lab. Do not copy any generated lab files into Git.

The separate scenefx-timing.patch applies after the preserved SceneFX clip patch and adds only monotonic damage timestamps plus a local output-commit ordinal/result. It touches no public header, rendering buffer or clip rule. An accepted output commit is not proof of a presented frame. The initial uninstrumented campaign remains in its own laboratory for comparison. SwayFX bypasses SceneFX's wlr_scene_output_commit in its normal repaint path, so that SceneFX hook emits no commit records here. The independent mosaic-output-timing.patch logs the actual private SwayFX wlr_output_commit_state call, with the same monotonic clock and an experimental process-local ordinal. It changes neither the decision to commit nor the output state.

New private patch SHA-256
client-cycle.patch 119fa0b61135bb49bf84c42499799f1c75cccbf5842ea5acac9eaaba6ab7b9ca
scenefx-timing.patch 7a7ef1875b559f65a3240a0016592da1da6a8537929d0e96b8aaa2d20ecd46fa
mosaic-output-timing.patch 4419059231e038675f50a6321889f27ba981c5d8df2779ccbc4a61e02f1d6668

The reused SceneFX, Mosaic and hidden-owner patch hashes are recorded in the negative-origin fixture. The fresh lab's source manifest verifies their exact bytes again.

Dependencies are those of the negative-origin fixture, plus Pillow for analysis. Current measured environment: SwayFX 0.6, wlroots 0.20.2, SceneFX 0.5.0, Wayland client 1.26.0. Other versions require separate validation.

prep=$(sh tooling/probes/step20c-temporal-damage/prepare.sh)
printf '%s\n' "$prep"
LAB=$(printf '%s\n' "$prep" | sed -n 's/^LAB=//p')
(cd "$LAB" && sha256sum -c temporal-source-sha256.txt)

Bounded campaign

Every invocation creates a unique LAB/runs/ directory. The three modes are control (unmodified /usr/bin/sway in splith), private_standard (private Mosaic binary in splith) and private_mosaic (same binary in mosaic). Each has its own mode-0700 /tmp/mtd-* runtime and private sockets. The runner removes only its own process groups and runtime, including on failure. It never inherits the daily SWAYSOCK or WAYLAND_DISPLAY; all IPC commands use the discovered swaymsg -s path.

for mode in control private_standard private_mosaic; do
  PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-temporal-damage/run.py \
    "$LAB" "$mode" cycles --cycles 10
done
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-temporal-damage/run.py \
  "$LAB" private_mosaic camera --moves 36
for mode in control private_standard private_mosaic; do
  PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-temporal-damage/run.py \
    "$LAB" "$mode" outside
done
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-temporal-damage/run.py \
  "$LAB" private_mosaic hidden_click
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-temporal-damage/run.py \
  "$LAB" private_mosaic toggle
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-temporal-damage/analyze.py "$LAB"

The command above requests 36 individual camera transitions per mode, or 18 complete outward/return pairs. Defaults cap one run at 900 seconds, 400 captures, 250 MB of PNGs, 30 cycles and 40 camera transitions per mode. --max-seconds, --max-captures and --max-bytes can lower the resource limits. Each run retains config, IPC snapshots, PNGs on both outputs, monotonic action/capture records, XDG/Wayland client log, pointer/wev/compositor logs, exit status and structured analysis. SPIKE_DAMAGE lines are extracted to damage.log; they are output extents, not frame identities. TEMPORAL_DAMAGE and TEMPORAL_OUTPUT_COMMIT add monotonic order without converting sampled PNGs into presented-frame evidence. The analyzer writes per-run damage-analysis.json and summaries under LAB/results/. Full raw logs and captures remain under each run for independent recomputation.

S0/S1/S2/S3/S4/S5/S6/S7 phase names match the protocol. S6 includes an actual A right-button event after B is destroyed. The hidden_click run is separate from camera hiding without clicks: it expects child-first popup_done and no popup button at the hidden point. Immediate and later grim captures are separately named. Camera mode records settled transitions, capture-paced transitions, and a separate burst with no capture between consecutive commands (a capture after each fourth command). They are sampled observations; IPC acceptance and process exit zero alone do not prove render correctness. The analyzer's fixed left ROI (400,90,800,310) and right ROI (0,90,200,310) are output-local and were chosen before inspecting temporal results. Dynamic wev text on HEADLESS-2 prevents whole-image equality there; exact popup colors and client events are evaluated separately. No region is masked after observing an anomaly.

Validation and cleanup

sh -n tooling/probes/step20c-temporal-damage/prepare.sh
PYTHONDONTWRITEBYTECODE=1 python -c 'import ast,pathlib; [ast.parse(p.read_text()) for p in pathlib.Path("tooling/probes/step20c-temporal-damage").glob("*.py")]'
(cd "$LAB" && sha256sum -c temporal-source-sha256.txt)
git diff --check

Inspect each analysis.json, exit-status.json, raw log and sample PNG before accepting its verdict. Keep failed cases and their exact run path. Remove a finished laboratory only by its printed path after preserving needed proof; never perform global /tmp cleanup or touch historical labs.