swayfx-mosaic/docs/design/STEP20C_ROTATED_PARTIAL_POPUP_CLIP_PROBE.md

13 KiB
Raw Permalink Blame History

STEP20C static R90 partial popup clipping probe

EXPERIMENTAL protocol, before execution. STEP20C is NEXT; production multi-output Mosaic is NOT YET SUPPORTED. The preceding rotation probe was PARTIALLY_FEASIBLE: private standard displayed 15,860 B pixels on H2, but Mosaic B ended at PNG x=903, short of the x=1000 boundary. Its pristine R90 fixture stopped after applying transform 90 because it incorrectly expected IPC 270. This independent campaign tests only a static R90 startup, with no dynamic transform, resize, migration, camera hide/return, effects or algorithm change.

Fixed geometry and model

H1 starts at global (-800,0), physical 750×1000, IPC transform 90, scale 1.25, logical 800×600. H2 starts at (0,0), physical/logical 800×600, normal at scale 1. Read get_outputs before scoring. The expected grim -s 1.25 H1 PNG is logically oriented 1000×750 according to the earlier probe; its actual dimensions and five distinct markers must be measured anew. The internal Wayland transform enum 270, physical buffer and logical PNG are different coordinate systems. Pointer injection uses the measured logical union (-800..800, 0..600), with sent x = global x + 800.

Use one fixed XDG placement rot_cross: TOPLEVEL 420×320; A 480×170 with anchor rect (360,80,1,1); B 300×130 with anchor rect (210,60,1,1). Both anchors fit their parent dimensions. Positioners use TOP_LEFT anchor, BOTTOM_RIGHT gravity and no constraint adjustment requested by the client. Actual xdg_popup.configure x/y/w/h, ack, map and scene placement must be recorded; compositor unconstrain may change them. No alternate placement is authorized in this campaign.

The prior applied Mosaic owner plus camera 640 placed B's right edge near global -78 (PNG x=903). Moving A's anchor +160 and B's -10 predicts B's right edge near +72, enough for a discriminating H2 portion. A's width adds 180, predicting an A right edge near +42. These are predictions, not observations. The original (390,80) candidate would shift B by +180: the earlier standard B left edge near -178 would move to +2, removing its H1 portion. This single pre-run variant shifts B by +150 and predicts standard B left near -28, retaining 28 logical pixels on H1. The owner, workspace, applied camera and popup root scene coordinates must be measured separately per mode. Compute each global popup box from the applied owner/scene origin and configured XDG offsets, then intersect with H1 [-800,0)×[0,600) and H2 [0,800)×[0,600). Partial clipping is exercised only when left < 0 < right and both intersections are nonempty. A crossing less than 16 logical pixels is reported with its actual width before qualification. A box wholly within H1 is NOT EXERCISED, even when H2 contains zero popup pixels.

Runs, observations and decisions

One run each: C0 pristine pinned SwayFX splith, C1 private splith, C2 same private compositor mosaic. Static output config is applied at startup. Each run uses one 0700 runtime and explicit private IPC socket, at most two distinct A/B grab chains, 16 captures and 120 seconds. The entire campaign allows at most 3 runs and 50 captures; failed reservations count. A persistent exclusive ledger is tested offline and reserved before each launch. A single initial Mosaic scroll to 640 is permitted before popup creation, logged once.

Capture a five-marker H1 background and stable H2 reference before popup creation. Record capture monotonic windows, SHA-256, mode/scale/transform, logical rect, PNG dimensions, popup boxes and clips. Compare H2's entire forbidden intersection to its predeclared reference as well as exact A/B colors, without post-hoc ROI exclusions. At least one standard control must show B pixels on both outputs and a real B button on H2. Mosaic must show its own geometric B crossing, B pixels and a delivered button inside H1, zero B contribution and no B delivery on H2. Derive boundary y from the applied popup box and inspect x=-3..3. Keep hover probes in one chain; use a second chain for an exterior click that may dismiss the grab. A is evaluated separately at points outside B when its own box crosses.

The client must log a real button serial on TOPLEVEL before A's grab and on A before B's grab, each configure/ack/map and protocol error. The runner records applied tiled/root/child clips, owner output, damage in buffer-local physical coordinates, commits/presents and actual client delivery. Damage from the inherited TEMPORAL_DAMAGE path is already physical: do not apply scale twice. Settled PNG differences do not prove every intermediate frame or an atomic render/input generation.

FEASIBLE requires valid crossing B in Mosaic, standard overflow controls, retained H1 pixels/input, excluded H2 pixels/input, correct owner clips and completed pristine R90. PARTIALLY_FEASIBLE preserves a crossing with missing secondary proof. INCONCLUSIVE covers absent crossing, invalid fixture or incomparable controls. BLOCKED requires a reproducible forbidden pixel/hit, wrong owner clip, crash or standard regression. A confirmed leak stops the affected campaign; no clipping algorithm is changed to obtain a pass. R270, saved buffers, optimized blur cache, inner shadow, raw framebuffer, all intermediate frames and ABI/package maintenance remain NOT TESTED.

The source fixture retains only reviewed scripts and the client placement patch. Generated builds, binaries, captures, sockets, logs and structured results stay in a private LAB.

Measured static-R90 campaign — 2026-10-12

EXPERIMENTAL / PARTIALLY_FEASIBLE. LAB: /tmp/swayfx-mosaic-nested-grab-PioJ5X43. The new preparer rebuilt the pinned pristine SwayFX, private Mosaic/SceneFX and strict C17 clients from the prior published source chain, then applied only the dedicated rot_cross client patch. The clipping algorithm and installed libraries were untouched. One main run each of pristine splith, private splith and private mosaic completed normally, with 14 captures and about 14.6 seconds per run. The new locked ledger consumed 3/3 runs; dynamic transitions, migrations, resize, camera hide/return and R270 each consumed 0. Mosaic made one pre-popup static camera placement to scroll 640, recorded in the raw events.

All three get_outputs states reported H1 physical 750×1000, IPC transform 90, scale 1.25 and logical (-800,0,800,600). H2 remained 800×600, normal/scale 1 at (0,0). Every H1 grim -s 1.25 PNG was 1000×750 and the five marker centers established the logical PNG orientation. The control pristine therefore completed the R90 capture and input matrix missed by the historical fixture; no dynamic R90→R0 action occurred. Its two grabs used real button serials 121/126, configured, acked, mapped, and exited without protocol error. Private standard used 123/128; Mosaic used 105/110. The configured XDG offsets were A (360,80,480,170) and B (210,60,300,130) in all modes, matching the fixed legal 1×1 anchors. The actual source scene and owner positions produced these global half-open boxes:

Mode Applied owner x / camera A global A∩H1 / A∩H2 widths B global B∩H1 / B∩H2 widths
Pristine splith -600 / 0 [-238,242)×[105,275) 238 / 242 [-28,272)×[165,295) 28 / 272
Private splith -600 / 0 [-238,242)×[105,275) 238 / 242 [-28,272)×[165,295) 28 / 272
Private Mosaic -160 / 640 [-438,42)×[105,275) 438 / 42 [-228,72)×[165,295) 228 / 72

The Mosaic owner current rect was x=-160 with width 640, while its applied scene origin was x=-800 after scroll 640. Its content/window x offset was 2, giving root-popup global (-798,25). A starts there plus configured (360,80), B starts at A plus configured (210,60). The sampled DO_STATE reported internal transform 3 (WL_OUTPUT_TRANSFORM_270), physical 750×1000 and logical 800×600. PI_SCENE held tile global -1440 and local clip (640,0,800,600), hence viewport [-800,0)×[0,600). DO_POPUP identified owner 8 on H1 and local root clip (-2,-25,800,600), which yields the same global viewport. B remained a scene descendant of A and inherited that root clip. The scene and configured XDG offsets agree at the sampled applied state; this does not establish an atomic generation over all frames.

The predefined reference was each mode's right-reference.png, captured before A/B creation. At the mapped-B capture, pristine and private standard each had 5,705 exact B pixels on H1 and 35,360 on H2; their H2 full-image difference from reference contained 49,880 pixels, with box [0,105,272,295). Mosaic retained 46,455 B pixels on H1, including 163/489/815 pixels in its last 1/3/5 PNG columns, and zero B pixels on H2. Its H2 whole PNG was pixel-identical to the predeclared reference: zero differing pixels, not merely zero exact SHM colors. A itself also crossed: Mosaic showed 77,181 A pixels on H1 and zero on H2; the standards showed 58,431 on H1 and 14,520 on H2. The A count includes occlusion by B where their rectangles overlap; it is not a full theoretical A-area count. The measured B geometry, unlike the old probe, genuinely challenged the clip by 72 logical pixels on H2.

For B's y=230 boundary grid, the pristine and private-standard clients reported B local motions x=25..31 for global x=-3..3 and delivered right buttons on B at (-14,230) and (30,230). The Mosaic client reported B local motions x=225,226,227 at global x=-3,-2,-1, then a B leave at x=0; no B enter/motion followed for x=0..3. A right button at (-30,230) was delivered to B with serial 119. At forbidden (30,230), B received no button; the valid grab produced popup_done for B and A. The button on visible A that created B was genuinely delivered (serial 110). An independent click on the clipped-away portion of A was not made; P2 root-popup input is therefore PARTIAL even though A's geometry and pixels cross. No universal click-through contract is inferred from the dismissal.

Available TEMPORAL_DAMAGE extents for the settled reference→mapped-B Mosaic H1 pair covered all 123,636 changed logical-PNG pixels after mapping (x,y) to physical (749-y,x): 10 physical extents, zero uncovered. H2 changed zero pixels. The private-standard pair likewise had zero uncovered changed pixels on both outputs (10 H1 and 6 H2 extents). The pristine control had no passive damage trace; its nonzero screenshot diff cannot be scored against absent extents. These broad damage observations cover only the settled pair, not minimal invalidation, all intermediate frames, saved buffers or render/input generation identity. Private Mosaic logged 126 native commits and 124 presents during the whole run; private standard logged 119/117. Startup, pointer and teardown activity are included.

LAB/results/ retains geometry, positions/intersections, output transform, grab, applied clip, input, pixels, damage, matrix and summary JSON. Raw client/protocol, compositor, pointer, get_outputs/tree, PNG and capture windows remain under each LAB/runs/ directory. The final source and evidence manifest entry counts and SHA-256 values are recorded below after documentation synchronization: 910 source entries, 3e6930c46dd9abf50aa2720357ccbdd47ac3fdd0f1106a47734383cb281b41a5; 146 evidence entries, e3c13e4fc02f6b66b59b87407ef7b91f5b7cd67430cc1142252098ef3885a949. The dedicated placement patch SHA-256 is 0f45d48625c062ca05f36849068aedecd02e4480a98f3e0bafe98c1f1c529089, based on nested client SHA-256 2e40c98af72a0df8b316810589a0be8f4425a763db1de448b49a7813956b6f7d. Both manifest files passed entry-by-entry verification after the fixture README was synchronized and the CLI limits were made non-overridable above 120 seconds / 16 captures / 30 MB. Each run retains its executed fixture-source.py; that exact source precedes this post-run limit hardening. The hardening was tested offline with an over-limit argument and caused no fourth run or ledger change. The ledger is separate from the historical 5/6 rotation and 1/1 camera budget, which were not reopened. Every run used a private 0700 runtime and explicit private IPC; exit status and cleanup were retained. No production, package or UX change was made.

Verdict: SWAYFX_MOSAIC_ROTATED_PARTIAL_POPUP_CLIP_PROBE=PARTIALLY_FEASIBLE. The central B crossing/visible/clipped/input distinction passed this one static-R90 matrix, including a complete pristine control. The scored clipped-away A input point, all-frame damage and applied generation are still open. Architectural conclusion: ROTATED_PARTIAL_POPUP_CLIP_FEASIBLE_FOR_TESTED_MATRIX, without production STEP20C qualification. Saved transaction buffers are the next priority: they can reintroduce pixels from an earlier scene at the same viewport even when the live popup tree clips correctly. Optimized blur cache, interior shadow and SceneFX/wlroots ABI/package maintenance remain separate gates.