docs(mosaic): preserve static nested grab geometry fixture failure evidence

This commit is contained in:
fy59 2026-10-13 12:53:12 +02:00
parent d0fa8c5c9e
commit 899c007c37
16 changed files with 1623 additions and 0 deletions

View file

@ -4,6 +4,8 @@
### STEP20C experimental evidence
- Preserved static nested-grab fixture failure: sole unchanged-binary run confirms identity/output/camera/tiled clip and exact whole-H2 pre-popup references, then fails before any click/grab on a native-SHM versus painted-height assertion. INCONCLUSIVE / UNDECIDED; additional IPC-y/titlebar assumption invalid, offline assertion audit insufficient. Raw runner exit1 and compositor exit0 retained; popup/standard gates NOT TESTED, no retry/build/production change. Historical runner and sealed artifacts preserved.
- Preserved independent static RGB/input/standard retest: corrected shared predicate and real replay pass; exact whole-H2 RGB, H1 retained/H2 forbidden pixels, real target/reference clicks and targeted splith clip removal/input pass. FEASIBLE for this matrix. Terminal exit IPC makes runner exit 1 after measured gates and compositor exit 0; raw failure retained and offline diagnosis passes. No new compositor/library build or production change.
- Preserved static focus/input/standard fixture failure: exact static binary and loaded pair verified; one run stopped before captures/input on an incorrect border-width fixture assertion. INCONCLUSIVE / UNDECIDED; camera and clip traces retained, RGB/clicks/splith NOT TESTED, no retry or production change.

View file

@ -430,3 +430,16 @@ and separately diagnosed/revalidated offline. No algorithm, build, production,
package or UX change follows. Wider static popup/effect/lifecycle, complete
damage/generation, ABI/maintenance/notices gates remain open. D1–D4 persist;
STEP20C stays NEXT and production multi-output remains NOT YET SUPPORTED.
The preserved [static nested valid-grab probe](design/STEP20C_STATIC_NESTED_VALID_GRAB_PROBE.md)
is **EXPERIMENTAL / INCONCLUSIVE**, architecture UNDECIDED. The sole unchanged-
static-binary run verified actual identity, outputs, applied camera/tiled clip
and two exact whole-H2 references, then stopped before any click or popup on
an invalid painted-height assertion (573 vs native SHM320). An additional
IPC-y/titlebar assertion was also invalid. The recorded offline test PASS had
an insufficient source-assertion audit; raw runner exit1 and all evidence remain
immutable. Root/nested grabs, geometry, popup pixels/input/dismissal and splith
are NOT TESTED in this campaign. No algorithm/production/UX/package change or
retry; budget exhausted. Correct/replay geometry predicates offline before a
separately authorized fresh static popup gate. Historical failure evidence is frozen;
STEP20C NEXT, production multi-output NOT YET SUPPORTED.

View file

@ -371,3 +371,16 @@ and separately diagnosed/revalidated offline. No algorithm, build, production,
package or UX change follows. Wider static popup/effect/lifecycle, complete
damage/generation, ABI/maintenance/notices gates remain open. D1–D4 persist;
STEP20C stays NEXT and production multi-output remains NOT YET SUPPORTED.
The preserved [static nested valid-grab probe](design/STEP20C_STATIC_NESTED_VALID_GRAB_PROBE.md)
is **EXPERIMENTAL / INCONCLUSIVE**, architecture UNDECIDED. The sole unchanged-
static-binary run verified actual identity, outputs, applied camera/tiled clip
and two exact whole-H2 references, then stopped before any click or popup on
an invalid painted-height assertion (573 vs native SHM320). An additional
IPC-y/titlebar assertion was also invalid. The recorded offline test PASS had
an insufficient source-assertion audit; raw runner exit1 and all evidence remain
immutable. Root/nested grabs, geometry, popup pixels/input/dismissal and splith
are NOT TESTED in this campaign. No algorithm/production/UX/package change or
retry; budget exhausted. Correct/replay geometry predicates offline before a
separately authorized fresh static popup gate. Historical failure evidence is frozen;
STEP20C NEXT, production multi-output NOT YET SUPPORTED.

View file

@ -289,3 +289,16 @@ and separately diagnosed/revalidated offline. No algorithm, build, production,
package or UX change follows. Wider static popup/effect/lifecycle, complete
damage/generation, ABI/maintenance/notices gates remain open. D1–D4 persist;
STEP20C stays NEXT and production multi-output remains NOT YET SUPPORTED.
The preserved [static nested valid-grab probe](design/STEP20C_STATIC_NESTED_VALID_GRAB_PROBE.md)
is **EXPERIMENTAL / INCONCLUSIVE**, architecture UNDECIDED. The sole unchanged-
static-binary run verified actual identity, outputs, applied camera/tiled clip
and two exact whole-H2 references, then stopped before any click or popup on
an invalid painted-height assertion (573 vs native SHM320). An additional
IPC-y/titlebar assertion was also invalid. The recorded offline test PASS had
an insufficient source-assertion audit; raw runner exit1 and all evidence remain
immutable. Root/nested grabs, geometry, popup pixels/input/dismissal and splith
are NOT TESTED in this campaign. No algorithm/production/UX/package change or
retry; budget exhausted. Correct/replay geometry predicates offline before a
separately authorized fresh static popup gate. Historical failure evidence is frozen;
STEP20C NEXT, production multi-output NOT YET SUPPORTED.

View file

@ -375,3 +375,16 @@ and separately diagnosed/revalidated offline. No algorithm, build, production,
package or UX change follows. Wider static popup/effect/lifecycle, complete
damage/generation, ABI/maintenance/notices gates remain open. D1–D4 persist;
STEP20C stays NEXT and production multi-output remains NOT YET SUPPORTED.
The preserved [static nested valid-grab probe](design/STEP20C_STATIC_NESTED_VALID_GRAB_PROBE.md)
is **EXPERIMENTAL / INCONCLUSIVE**, architecture UNDECIDED. The sole unchanged-
static-binary run verified actual identity, outputs, applied camera/tiled clip
and two exact whole-H2 references, then stopped before any click or popup on
an invalid painted-height assertion (573 vs native SHM320). An additional
IPC-y/titlebar assertion was also invalid. The recorded offline test PASS had
an insufficient source-assertion audit; raw runner exit1 and all evidence remain
immutable. Root/nested grabs, geometry, popup pixels/input/dismissal and splith
are NOT TESTED in this campaign. No algorithm/production/UX/package change or
retry; budget exhausted. Correct/replay geometry predicates offline before a
separately authorized fresh static popup gate. Historical failure evidence is frozen;
STEP20C NEXT, production multi-output NOT YET SUPPORTED.

View file

@ -0,0 +1,389 @@
# STEP20C static root/nested valid-grab continuity probe
**EXPERIMENTAL / INCONCLUSIVE; architecture UNDECIDED. Frozen failure evidence.** The protocol below was written before fixture implementation
and graphical launch; completed observations are appended separately.
Canonical [architecture](../ARCHITECTURE.md), [UX](../UX.md),
[limitations](../KNOWN_LIMITATIONS.md) and [roadmap](../ROADMAP.md) govern.
STEP20A DONE, STEP20B EXPERIMENTAL, STEP20C NEXT, STEP20D–G PLANNED;
production multi-output NOT YET SUPPORTED. No algorithm or UX change.
## Prior evidence and exact question
Phase A froze the [static tiled RGB/input/standard evidence](STEP20C_STATIC_RGB_INPUT_STANDARD_RETEST.md)
in commit d0fa8c5c9e6f878a0cf30c16c5ce006392838791, verified directly on
Forgejo and GitHub with clean worktree. Its scientific verdict is FEASIBLE
only for its tested tiled matrix; its runner exit 1 / runtime INCONCLUSIVE
and compositor exit 0 remain immutable. No historical run is repeated.
The [popup ownership](STEP20C_POPUP_OWNERSHIP_PROBE.md),
[valid-grab hidden-owner](STEP20C_VALID_GRAB_HIDDEN_OWNER_PROBE.md),
[nested-grab](STEP20C_NESTED_VALID_GRAB_PROBE.md),
[vertical](STEP20C_VERTICAL_OUTPUT_NESTED_GRAB_PROBE.md) and
[R90 partial-popup](STEP20C_ROTATED_PARTIAL_POPUP_CLIP_PROBE.md) reports
establish sampled shared-private behavior and controls, not static continuity.
They distinguish invisible hits from legitimate outside-grab dismissal.
No new pristine control run is authorized; comparison uses those retained
controls. Static/shared exhaustive equivalence is NOT PROVEN.
Reuse only static candidate
`/home/fy59/swayfx-mosaic-static-runtime-hm5kbdkt/stage-static/usr/bin/swayfx-mosaic`,
SHA-256 `f82557c1a9978a5e9665b9b4291b74880253725359e3df1c5b8d554921f7603b`,
build ID `942db64269640778ee433e5970ba1100bc60f94c`. Verify private identical
0755 copy, ELF64 x86-64, ordinary clip definitions, no SceneFX DT_NEEDED,
no missing relocation, and actual loaded system wlroots 0.20.2 SHA-256
`7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837`.
No compositor/library builds, binary modifications, system install or daily IPC.
## Client and XDG contract
Historical `step20c-nested-grab/nested-client.c` must remain byte-identical,
SHA-256 `2e40c98af72a0df8b316810589a0be8f4425a763db1de448b49a7813956b6f7d`.
Retain it separately from the adapted copy and private placement patch.
Reuse the exact valid-grab pointer daemon and static-reference/saved-client
sources. Reuse manifest-verified generated protocol files; retain XML hashes
and verify regeneration byte-for-byte. Compile only clients as C17 with
-Werror (-Wno-unused-parameter for existing listener signatures).
The [XDG protocol](https://raw.githubusercontent.com/wayland-mirror/wayland-protocols/main/stable/xdg-shell/xdg-shell.xml)
and installed XML require a user-action serial, mapped parent, grabbing popup
parent for B, pre-map grab, bufferless initial commit, configure/ACK before
buffer attachment, and reverse destruction. Client binds wm_base v3. A uses
the exact TOPLEVEL left press serial; B uses a new POPUP_A left press serial.
Both logs and WAYLAND_DEBUG requests must agree; nonzero serial alone fails.
A/B have distinct wl_surface, xdg_surface and popup roles, with B.parent=A.xdg.
No arbitrary serial, forced grab or protocol workaround is permitted.
The only private C delta adds placement `static_cross`: A anchor (100,80),
size 350×170; B anchor (100,60), size 300×130. Both 1×1 anchors are inside
parent effective SHM geometry (TOPLEVEL 420×320; A 350×170). Anchor top-left,
gravity bottom-right, default constraint adjustment none. No draw/grab/serial/
ACK/map/dismissal/destruction change. The toplevel keeps historical 420×320
buffer; assigned container content is measured separately. Source constants
and actual wl_surface.attach/protocol sizes qualify drawn dimensions.
For applied top content near (-318,25), predicted A=(-218,105,350,170),
B=(-118,165,300,130). Predictions are not evidence. Parse actual role configure,
measure owner scene and content offset, then independently correlate solid
paint and pointer-local coordinates. Require A.left<0<A.right and
B.left<0<B.right. Never vary anchors empirically after launch.
## Scene contract and observability
Exact candidate source parents root popup wrapper under root->layers.popup,
positions it from the applied view content tree, and derives its local clip
from current workspace's already-applied tiling clip and output intersection.
B's scene wrapper descends from A's XDG tree, retaining the same owner.
Source trace PI_OWNER distinguishes logical/current rectangle from scene;
PI_SCENE reports applied tiling clip; PI_POPUP reports root wrapper clip;
PROBE_POPUP_CLIP records owner pointer/local clip. Root wrapper origin differs
from A's configured painted origin. Correlate root local clip + applied content
origin with global [-800,0,800,600]. Child effective clip is inherited, backed
by exact source hierarchy and measured B pixels/input; no new child-node or
atomic-generation instrumentation may be claimed. Standard root clip removal
must appear in PI_POPUP, and B standard rendering/input must exercise inheritance
removal. Missing direct child trace is documented, not manufactured.
## Offline preflight and resource ledger
Before run reservation: source/protocol manifests, C17 syntax/build, binary/
loader identity, AST/shell/links, source audit (XDG hierarchy, input mapping,
configure/ACK/map, child-first destruction, clipping and shutdown), deterministic
color/coordinate/geometry/button predicates and negative cases, dismissal
classification and exit-classification tests all PASS. Live predicates are the
same functions used offline. Record `STATIC_NESTED_GRAB_FIXTURE_PREFLIGHT=PASS`.
No graphical launch to discover an offline-detectable error.
One exclusive persistent campaign owner file and one LAB outside Git. Stable
flock serializes fsync/atomic ledger updates; reservations persist before run,
chain, grab, click, pointer positioning, PNG, camera and transition. Failures
consume reservations; no refunds/reset/second LAB. Limits: run 1, pristine 0,
SceneFX/Mosaic builds 0, chains 2, grabs 4, camera 2 (at most one per chain),
Mosaic→splith 1, complete clicks 9, PNG 16, positioning/injection actions 24,
run duration 150 seconds. Planned 8 clicks and 15 PNGs; every click includes
and consumes one positioning action. No hide/return, scale/rotation/resize/
migration or additional campaign. Watchdog bounds owned process groups/logs;
all command timeouts and cleanup fit inside 150 seconds.
## Ordered runtime protocol
One headless compositor, private short runtime mode 0700, private Wayland and
explicit swaymsg -s socket. Clear inherited display/IPC/library/session overrides.
H1=(-800,0,800,600); H2=(0,0,800,600); scale1/normal. focus_follows_mouse no.
Create static H2 reference, discover PID/con_id, apply only its `[con_id=ID]
border none. Validate empty deco_rect, 800×600 content, visible XDG identity,
output/workspace; stored border width need not be zero. H1 filler may share
App ID, but never identity/PID/ancestor. Establish Mosaic, owner and H1 focus
before two H2 baselines separated by >=500 ms. Park private pointer and require
all 480,000 RGB pixels #303038 and exact equality. Stop dependents if unstable.
E1: reserve a fresh chain, map owner; compute signed relative camera delta from
actual PI_OWNER/content rectangle to center assigned content at x=0. Reserve
at most one correction; validate applied camera, same owner/workspace and clip.
Capture actual blue pixels, choose interior point, reserve grab and full left
click, open A using received press. Require configure/ACK/map; capture A, select
actual yellow interior, reserve second grab/left click to open B. Capture H1/H2;
require both crossings, positive A/B paint H1, zero A/B H2 and whole-H2 equality.
Choose B visible point from actual green pixels and inject right; require B pair,
no reference/filler event, no prior popup_done. Choose H2 point within measured
B continuation and actual reference, inject right; no invisible A/B button may
arrive. Observe reference pair and topmost-first popup_done separately; legitimate
dismissal is not an invisible hit. Verify clean H2, close E1 owner normally.
E2: new process, owner IDs and serials in the same compositor. Reserve chain,
verify Mosaic workspace, recompute sole possible camera correction, open A/B
with new actual left presses. Capture clipped state and whole H2, then send
`[con_id=E2] layout splith` without exterior click. Verify same workspace,
actual applied splith, both still mapped, no prior popup_done, tile/root clip
absent. Capture both outputs: require actual A/B crossings and positive A/B
colors H2, not empty-reference equality during intentional popup spill. Right
click actual green H2 interior must go to B. Send historical `close_b` command;
require B destruction, A survives, capture H2 and right click actual yellow
interior to A. Close owner normally; final H2 must fully equal baseline with
zero A/B residue. No stale IDs or points are reused across stages.
## Closure, classification and preservation
Record completion of all scientific gates before terminal exit. Audit
sway/commands/exit.c, ipc-server.c and main.c: termination may close socket before
queued writable reply. Keep swaymsg stdout, stderr and real code separately;
wait for compositor code and shutdown log, clients and residual groups/sockets.
Nonzero exit IPC is nonblocking transport only when all prior measures pass,
server handled exit, compositor=0, no crash/protocol error or rescue cleanup.
Never force code0 or claim IPC success when transport failed. Earlier functional
failure remains fatal to scientific qualification, regardless of shutdown.
FEASIBLE requires all listed identity/reference/XDG/grab/crossing/render/input/
dismissal/standard/cleanup gates in this matrix. PARTIALLY_FEASIBLE retains a
working main chain with missing secondary measurements; INCONCLUSIVE means
fixture attribution, geometry or protocol sequence not exercised. BLOCKED needs
actual visual/input leak, grab violation, runtime ABI/crash or standard regression.
Architecture is STATIC_NESTED_VALID_GRAB_FEASIBLE_FOR_TESTED_MATRIX,
STATIC_NESTED_VALID_GRAB_REQUIRES_REDESIGN, or UNDECIDED respectively.
Retain raw exact source/patch/runner/config, WAYLAND_DEBUG, timestamps/injections,
IPC/scene/client logs, actual codes, PNGs, dependency maps and source/evidence
SHA-256 inventories. Seal only after collection; verify every entry read-only.
Available damage extents and stabilized capture changes are partial evidence:
no intermediate-frame/minimal-damage/native-buffer/GPU-texture guarantee.
Hidden owner, scaling/rotation, migration/resize, saved buffers, effects,
complete damage/transactions and exhaustive ABI are NOT TESTED in this campaign.
Synchronize this report, fixture README, architecture, limitations, roadmap,
document index and changelog. B stays local and uncommitted, never pushed.
## Offline preparation completed before run reservation
LAB `/home/fy59/swayfx-mosaic-static-nested-grab-m0a5e2qh`, exclusive owner
`/home/fy59/swayfx-mosaic-static-nested-grab-v1.owner`. Exact candidate/0755/
ELF/build ID/ordinary symbols/ldd -r/system wlroots 0.20.2 pass. Three client-only
C17 syntax and executable builds pass with -Werror; both protocol regenerations
are byte-identical to manifest-verified inputs. Original nested SHA matches.
Private placement patch SHA-256
`e0e87fb0cb3d6e7dafb1cd59ccb50f323f2934e65247526199da1695487d3e4a`;
adapted C SHA-256
`6eafb8ad63b0b06b8297e7e72711056a6d42bdf33ccf795793eeda77f98221c7`.
Exact frozen live runner SHA-256
`e2bde767036096e4633f9dd4fe3deb1b147f6415dc550a46802a6a90c4bd6486`.
First offline check stopped on a negative with the original button deliberately
removed: the shared predicate correctly rejected it via ValueError, but the
test harness initially counted only assertion/runtime errors. Correct only
that harness in `LAB/preflight-correction/check.py`; retain immutable original
`LAB/fixture/check.py` and the incident JSON. No live predicate/runner change,
no budget reservation or graphical launch occurred. The corrected checker
then passes retained actual standard-control protocol, actual historical
border-none/stored-width2 reference, labelled synthetic geometry/paint/input,
16 negatives, ledger concurrency/exhaustion/corruption and terminal outcome
positives/five negatives. AST/shell/links and exact frozen inventory pass.
All live predicates are the same frozen functions exercised offline.
`STATIC_NESTED_GRAB_FIXTURE_PREFLIGHT=PASS`.
Runtime remains NOT TESTED at this point; reserve the sole run only afterward.
## Completed single runtime — 2026-10-13
`SWAYFX_MOSAIC_STATIC_NESTED_VALID_GRAB_PROBE=INCONCLUSIVE`.
Architecture: **UNDECIDED**. This is a fixture geometry failure before the first
popup, not a demonstrated clipping, grab, ABI or standard-layout defect.
The sole compositor run is consumed; no retry or second laboratory. The
intended two-chain experiment was **not completed** and must not be described
as popup evidence. No new Mosaic/SceneFX build, binary/algorithm/shader change,
production/UX/package change or installation occurred.
### Actual identity, output, focus and reference
Original and private executable retain SHA-256
`f82557c1a9978a5e9665b9b4291b74880253725359e3df1c5b8d554921f7603b`,
build ID `942db64269640778ee433e5970ba1100bc60f94c`, mode0755, ELF64 x86-64.
Ordinary clip definitions and ldd -r pass; no SceneFX DT_NEEDED/RPATH/RUNPATH
or loaded shared SceneFX. /proc/exe resolves to the private copy; actual /proc
maps show system wlroots 0.20.2 SHA-256
`7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837`.
All protected production/system/package/UX/AGENTS/binary hashes pass afterward.
Actual outputs match H1=(-800,0,800,600), H2=(0,0,800,600), scale1/normal.
Reference ID7/PID1737643 belongs to workspace2 ID5/H2; only its discovered
con_id receives border none. Stored width2 persists, deco_rect empty,
rect/window_rect 800×600, visible xdg_shell, correct app_id/PID/output.
Filler PID1737649 is distinct despite the same app_id. E1 owner ID9/PID1737655
belongs to workspace1 ID6/H1, focused and mapped. IDs were discovered, not
hard-coded. Only one chain instance was reserved/mapped.
After E1 map, applied camera was 480. PI_OWNER measured scene(-640,0,640,600),
content x=-638, assigned content636×573. Desired content x=-318 yields the
sole relative correction **-320**, resulting in camera160, applied owner
scene(-320,0,640,600), content x=-318. PI_SCENE reports local tile(-160,0),
clip(160,0,800,600); with H1 origin this gives [-800,0)×[0,600).
H2 tiling clip is absent. No popup root or child clip was measured.
Two independent 800×600 reference PNGs were captured after setup/H1 focus and
pointer parking, >=500ms apart (requested extra delay600ms). Every RGB pixel
is #303038; zero differences, no mask or tolerance. Both PNG SHA-256:
`4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a`.
This establishes pre-popup reference stability only. No popup-phase whole-H2
capture exists. The third PNG, E1-top, has 182,214 actual blue pixels, box
[482,25,800,598) in H1 local coordinates, giving global visible x[-318,0),
y[25,598). It does not establish popup clipping or popup geometry.
### Runtime fixture failure and source-based diagnosis
The frozen runner stops at `E1-open-A`, **before any click/grab reservation**.
Line182 asserts painted height320 from the native SHM constants. The actual
client creates a 420×320 SHM buffer, then receives and ACKs configure636×573
without redrawing (historical client behavior). SwayFX
`output_configure_scene` in the exact candidate's sway/desktop/output.c:331
sets the tiled scene buffer destination from applied content width/height.
The captured blue height is573, consistent with this source path, not320.
The failed assertion is therefore an invalid fixture assumption.
An additional assertion at line183 was not reached: it requires painted y
= owner scene y + IPC window_rect.y. Exact sway/ipc-json.c intentionally
sets window_rect.y=0 when a titlebar is enabled; actual IPC has that0,
deco height25 and painted y25. The prior static retest already distinguished
native buffer y from window_rect.y. This source-visible error should also
have been caught before the run. No rendered-buffer/IPC equivalence contract
is invented to make the fixture pass.
The recorded preflight marker remains PASS for its actually executed tests.
Its assertion/source audit was **INSUFFICIENT / retrospective FAIL** for these
two live assertions; it did not satisfy the full intended offline gate.
No retrospective rewrite of offline-gate.json, runtime.json, frozen runner,
protocol or budget is made. Preparation's missing-origin negative-case harness
incident and this runtime geometry incident are separate. The full client
protocol buffer/configure/ACK/map, IPC, PI_OWNER/PI_SCENE and PNG are retained.
`geometry_audit.py` reproduces both invalid assumptions read-only, verifies
actual reference/camera/clip/paint/codes and confirms zero popup creation,
zero pointer button and zero grab. This offline diagnosis is not graphical
qualification. The original runner remains byte-identical and is preserved
as failed experimental evidence; it is not a ready replay fixture.
### Unexercised protocol, geometry and input
The historical nested C source remains byte-identical; the sole private delta
is the legal static_cross placement. Original C and adapted C/patch are retained
with distinct hashes. The source hierarchy and historical control/replay show
correct XDG parentage, real button serial use and child-first destruction.
In this new runtime, however, **A and B were never created**. No A/B configure,
ACK, MAP, grab request, serial, enter/button, popup_done or destruction exists.
Neither predicted crossing is a measurement. E2 was never reserved or spawned;
no standard transition, standard popup pixels/input or popup residue cleanup
sample was exercised. All those matrix cells are NOT TESTED.
### Terminal exit and owned cleanup
Runtime duration5.485246415s; actual runner exit1, runtime INCONCLUSIVE,
measurements_completed=false, watchdog=false. The finally path explicitly sends
exit on /tmp/msng-jfnc_v3o's private IPC socket; stdout empty, stderr
`Unable to receive IPC response`, actual swaymsg code1. Server log records
Handling command exit and Shutting down sway; compositor exits0. E1, filler,
reference and pointer all exit0, with normal owned cleanup and no rescue signal.
No wl_display.error/protocol-error event appears. Ordinary startup backend
errors/noise are retained; no compositor crash is observed.
The command's queued response may have been lost at socket closure, compatible
with audited source. It is **not accepted as a nonblocking scientific exception**:
the earlier geometry failure occurred before measurements completed. The
terminal classifier correctly retains scientific_cleanup_pass=false. Composite
shutdown/cleanup success does not turn this campaign into FEASIBLE.
All owned PIDs/process groups are gone; short runtime removed, no sockets left.
No daily compositor/socket/process was touched.
### Budget, damage and retained inventories
| Resource | Consumed / ceiling |
| --- | --- |
| Static compositor runs | 1/1 |
| Pristine / SceneFX build / Mosaic build | 0/0 each |
| Chain instances | 1/2; E1 toplevel only |
| Valid-grab reservations | 0/4 |
| Camera corrections | 1/2; E1 only |
| Mosaic→splith | 0/1 |
| Complete clicks | 0/9 |
| Pointer positioning | 1/24 |
| PNGs | 3/16 |
| Runtime seconds | 5.485246415/150 |
Unused chain/click/PNG counters cannot authorize another compositor run.
The durable ledger remains consumed, with no refund/reset/retry. Available
TEMPORAL_DAMAGE extents cover only setup, camera, captures and shutdown;
A/B appearance, partial popup clipping, outside dismissal/destruction, standard
return and disappearance damage are NOT TESTED. Only stabilized reference
RGB is compared. No all-frame/minimal-damage/native-PNG/GPU guarantee.
Frozen pre-run fixture and source inventories remain immutable. Collector and
read-only diagnostic are preserved separately in LAB/postrun-fixture; corrected
offline harness in LAB/preflight-correction. Both are included in source sealing.
Source:30 entries, SHA-256
`9b76aae162faa631bf1930677d484359dfc3e29ace237b9aee2daa3d5cd68dc4`.
Evidence:96 entries, SHA-256
`5750d1e74636c2d276800f795ed0214c3e12999908149855af0b382a2da9bfb4`.
Every entry is verified read-only; reports and closeout receipts live outside
the sealed inventories to avoid circular hashes. No generated binary/PNG/JSON/
protocol/build/socket/log is added to Git.
### Architectural answers for this campaign
| Question | Evidence-backed answer |
| --- | --- |
| Q1 A/B real button serial? | NOT TESTED; zero runtime buttons or grabs. Historical source/control passed offline. |
| Q2 distinct compliant grabs? | NOT TESTED; no A/B objects in the new run. |
| Q3 hierarchy correct? | Correct in exact source and retained historical control; runtime A→B NOT TESTED. |
| Q4 both really cross x=0? | NOT EXERCISED. Requested anchors and predicted boxes are not configured geometry. |
| Q5 clip from applied owner? | Tiled applied viewport measured; popup root/child NOT TESTED. |
| Q6 permitted A/B pixels? | NOT TESTED; only toplevel blue182214 measured. |
| Q7 forbidden popup pixels absent H2? | NOT TESTED; two pre-popup H2 references stable. |
| Q8 visible B input? | NOT TESTED. |
| Q9 invisible B events? | NOT TESTED; no popup/input exists, not proof of exclusion. |
| Q10 outside grab behavior? | NOT TESTED; historical controls distinguish dismissal from hit. |
| Q11 popup_done distinct from invisible button? | Yes as protocol/measurement categories; no new dismissal or button sample. |
| Q12 A/B survive splith E2? | NOT TESTED; E2 and transition not executed. |
| Q13 clips removed? | NOT TESTED for popup or standard transition. |
| Q14 standard popup colors on H2? | NOT TESTED. |
| Q15 standard A/B buttons? | NOT TESTED. |
| Q16 popup residues after closure? | NOT TESTED because none opened; process/socket cleanup PASS separately. |
| Q17 static regression versus private shared controls? | UNDECIDED for popups; no valid static comparison was obtained. |
| Q18 algorithm change justified? | No. Confirmed errors are fixture assertions; no clipping defect demonstrated. |
| Q19 matrices open? | Static hidden-owner, scale, rotation, resize/migration, saved-buffer/effects, full damage/transactions and exhaustive ABI. Historical sampled evidence is not replayed or promoted. |
| Q20 smallest next gate? | First correct and replay all geometry predicates offline against actual native/configured/painted/IPC observations, including titlebar and standard states; then a separately authorized fresh one-run static two-chain gate. Current run budget is exhausted. |
Validation PASS: original nested hash, placement-only delta, C17/client builds,
protocol byte identity, binary/loader/maps, outputs/focus/camera/tiled clip,
reference whole RGB, actual paint diagnosis, owned codes/cleanup, protected
hashes, manifests, AST/shell/links and diff. FAIL: full preflight assertion audit
and the exact runtime geometry assertion; runner code1. NOT RUN/NOT TESTED:
new pristine/compositor/library builds and all new popup/input/standard gates.
No subagent review is claimed; final local delta/source/evidence audit is by the
parent. This historical report and source fixture are now frozen for publication
in the failure-freeze phase. A separate offline geometry gate remains local
and cannot change this historical verdict or authorize another run.
STEP20C remains NEXT, production multi-output NOT YET SUPPORTED.
## Failure evidence freeze — 2026-10-13
Read-only revalidation verifies all24/30/96 entries of the historical inventories
and reproduces both invalid assertions without launching a compositor. AST,
Shell blocks, Markdown links, source-only Git content and exact distinctions
between executed, corrected-checker and postrun sources pass. The executed
runner SHA and raw runtime/terminal codes remain unchanged. The single commit
for this freeze preserves INCONCLUSIVE / UNDECIDED and all NOT TESTED cells.
No historical run, ledger, manifest, client source or binary is modified.

View file

@ -0,0 +1,87 @@
# Static nested valid-grab fixture
EXPERIMENTAL / FROZEN FAILURE EVIDENCE. No production integration.
Read the [protocol](../../../docs/design/STEP20C_STATIC_NESTED_VALID_GRAB_PROBE.md).
One exclusive laboratory, one existing immutable static binary, client-only
C17 builds; no SceneFX/Mosaic build or pristine run. Original nested source is
retained separately; `placement.patch` adds only legal static_cross anchors.
`prepare.py` verifies identity/provenance and compiles clients outside Git.
`check.py` exercises actual historical observations and labelled synthetic
negative fixtures, ledger concurrency/exhaustion/corruption, lifecycle and exit
classification before run reservation. `run.py` shares those predicates,
consumes reservations before every action, and preserves real terminal codes.
`collect.py` records only measured states and seals inventories once.
```sh
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-static-nested-grab/prepare.py
# Use only the LAB printed and registered by prepare; no second LAB or reset.
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-static-nested-grab/check.py "$LAB"
# Only after STATIC_NESTED_GRAB_FIXTURE_PREFLIGHT=PASS:
PYTHONDONTWRITEBYTECODE=1 python "$LAB/fixture/run.py" "$LAB"
PYTHONDONTWRITEBYTECODE=1 python "$LAB/fixture/collect.py" "$LAB"
```
Budgets: 1 run, 2 chains, 4 grabs, 2 calculated camera corrections (one per
chain), 1 splith transition, 9 complete clicks, 16 PNGs, 24 positions, 150 s.
Failed actions consume budget. Private sockets/groups only, no desktop IPC.
Generated protocol/client binaries/logs/JSON/PNG/build files stay outside Git.
Fixture preflight success is not graphical evidence. Results appended after
collection; every unexecuted matrix cell remains NOT TESTED.
## Completed campaign: INCONCLUSIVE, do not rerun
LAB `/home/fy59/swayfx-mosaic-static-nested-grab-m0a5e2qh`; run exhausted1/1.
Only E1 toplevel mapped: two stable full #303038 H2 images, computed camera
480→160 by -320, measured applied tiled clip, H1 blue182214 pixels. No popup,
click or grab occurred. Runner exits1 on its painted-height320 assertion;
actual height573. A further IPC window_rect.y=0/titlebar y25 assertion was
invalid but unreached. The original run.py here and LAB/fixture remain exact
failed evidence, **not a qualified replay runner**. Before any fresh separately
authorized campaign, repair/replay all geometric assertions offline. No runtime
retry is permitted by this ticket; unused chain/click/capture capacity is not
a new run authorization. The recipes above describe the preparation/run that
was attempted, not permission to repeat it.
`check.py` now counts ValueError from a deliberately removed-button negative
as rejection; the initial immutable checker is retained in LAB/fixture and the
corrected preflight checker in LAB/preflight-correction. Recorded preflight PASS
covers its tests, but the full geometric source/assertion audit was insufficient.
No historical gate/runtime status or manifest is rewritten. `geometry_audit.py`
rechecks actual SHM/configure/ACK/map, scene/IPC/paint, reference RGB, zero
popup/button/grab and terminal codes without launching a graphical process.
Post-run collector/diagnostic copies are in LAB/postrun-fixture, separate from
the executed fixture. Source/evidence inventories include these distinctions.
Terminal swaymsg actual1 (response receive failure), compositor0, all four
clients/injector0, no rescue or residual process/socket. Earlier measurement
failure is preserved; shutdown success cannot qualify scientific success.
Budget: run1, chain1, grab0, camera1, transition0, click0, move1, PNG3,
5.485246415 seconds. New Mosaic/SceneFX builds0, pristine runs0.
Source30 entries SHA256
`9b76aae162faa631bf1930677d484359dfc3e29ace237b9aee2daa3d5cd68dc4`;
evidence96 entries SHA256
`5750d1e74636c2d276800f795ed0214c3e12999908149855af0b382a2da9bfb4`.
Both are sealed once and verified. Root/nested input, crossings, dismissal,
standard-return/input/residues and related damage remain NOT TESTED.
Read-only completed-lab checks (never rerun collect or regenerate manifests):
```sh
PYTHONDONTWRITEBYTECODE=1 python "$LAB/postrun-fixture/geometry_audit.py" "$LAB"
PYTHONDONTWRITEBYTECODE=1 python - "$LAB" <<'PYCODE'
import sys
from pathlib import Path
lab = Path(sys.argv[1])
sys.path.insert(0, str(lab / 'postrun-fixture'))
from support import verify
for name in ['fixture-freeze', 'source', 'evidence']:
print(name, verify(lab / 'results' / (name + '-sha256.txt')))
PYCODE
```
Verdict SWAYFX_MOSAIC_STATIC_NESTED_VALID_GRAB_PROBE=INCONCLUSIVE.
Architecture UNDECIDED. STEP20C NEXT; multi-output NOT YET SUPPORTED.
This historical failure fixture is frozen for publication. The separate new
offline geometry-review fixture remains local, uncommitted and unpublished.

View file

@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""Offline protocol/pixel/ledger/terminal tests; never starts a compositor.
Historical observations and synthetic negative cases are explicitly labelled.
"""
import ast
import concurrent.futures
import copy
import json
from pathlib import Path
import re
import subprocess
import sys
import tempfile
from PIL import Image
from support import initial,reserve,LIMITS,save,sha,verify,OWNER,REPO,NESTED_SHA
from predicates import protocol,geometry,pair,dismissal,terminal,point,reference,root_clip,popup_pixels,Defect
from ipc_predicates import validate_reference,validate_outputs
def attempt(args):
lab,k=args
try:reserve(lab,k);return True
except RuntimeError:return False
def rejected(name,func):
try:func()
except (AssertionError,Defect,RuntimeError,ValueError):return name
raise AssertionError('negative accepted: '+name)
if __name__=='__main__':
lab=Path(sys.argv[1]);assert OWNER.read_text().strip()==str(lab)
verify(lab/'results/fixture-freeze-sha256.txt')
assert json.loads((lab/'results/budget.json').read_text())['used']==dict.fromkeys(LIMITS,0)
for p in (lab/'fixture').glob('*.py'):ast.parse(p.read_text(),filename=str(p))
for p in [lab/'protocol-before-run.md',lab/'fixture/README.md']:
for s in re.findall(r'```(?:sh|bash)\n(.*?)```',p.read_text(),re.S):subprocess.run(['sh','-n'],input=s,text=True,check=True)
with tempfile.TemporaryDirectory(prefix='static-nested-ledger-offline-') as tmp:
test=Path(tmp);(test/'results').mkdir();initial(test)
with concurrent.futures.ProcessPoolExecutor(max_workers=4) as pool:
assert sum(pool.map(attempt,[(test,'capture')]*24))==16
for k,n in LIMITS.items():
if k=='capture':continue
for _ in range(n):reserve(test,k)
assert not attempt((test,k))
before=(test/'results/budget.json').read_bytes()
assert not attempt((test,'run')) and (test/'results/budget.json').read_bytes()==before
state=json.loads(before);state['used']['run']=-1
(test/'results/budget.json').write_text(json.dumps(state));assert not attempt((test,'run'))
# Use the retained actual unmodified nested control, stopping while mapped.
old=Path('/tmp/swayfx-mosaic-nested-grab-If8ofeUu/run-control-open-visible/client.log')
text=old.read_text().split('TOPLEVEL DESTROY')[0]
cuts=[text.find(s) for s in ['POPUP_B DESTROY','POPUP_B POPUP_DONE'] if s in text]
if cuts:text=text[:min(cuts)]
good=protocol(text);negative=[]
for name,wrong in [('serial',text.replace('used=61','used=62')),
('parent',text.replace('parent_xdg=12','parent_xdg=9')),
('button origin',text.replace('target=TOPLEVEL serial=61 button=272 state=1','target=OTHER serial=61 button=272 state=1')),
('protocol error',text+'\nwl_display#1.error(1, 1, "bad")'),
('premature dismissal',text+'\nPOPUP_B POPUP_DONE role=17')]:
negative.append(rejected(name,lambda t=wrong:protocol(t)))
snap=json.loads((Path('/home/fy59/swayfx-mosaic-static-rgb-input-retest-hn67lnhq/results/preflight-snapshot.json')).read_text())
ref=validate_reference(snap,7,1700453);validate_outputs(snap['outputs']);assert ref['stored_border_width']==2
negative.append(rejected('wrong reference identity',lambda:validate_reference(snap,8,1700459)))
synthetic='POPUP_A ROLE_CONFIGURE x=100 y=80 w=350 h=170\nPOPUP_B ROLE_CONFIGURE x=100 y=60 w=300 h=130'
g=geometry(synthetic,[-318,25]);assert g['A']==[-218,105,350,170] and g['B']==[-118,165,300,130]
negative.append(rejected('no crossing',lambda:geometry(synthetic,[-700,25])))
# Labelled synthetic color regions challenge exact rectangle/occlusion predicates.
from PIL import ImageDraw
baseline=Image.new('RGB',(800,600),(48,48,56))
def synthetic_pixels(mosaic):
images=[]
for ox in [-800,0]:
im=baseline.copy();draw=ImageDraw.Draw(im)
if not mosaic or ox==-800:
for key,color in [('A',(224,192,32)),('B',(32,208,160))]:
x,y,w,h=g[key];draw.rectangle((x-ox,y,x+w-ox-1,y+h-1),fill=color)
images.append(im)
return images
left,right=synthetic_pixels(True);popup_pixels(left,right,g,True,baseline)
badright=right.copy();badright.putpixel((1,200),(32,208,160))
negative.append(rejected('actual forbidden color',lambda:popup_pixels(left,badright,g,True,baseline)))
lstd,rstd=synthetic_pixels(False);popup_pixels(lstd,rstd,g,False,baseline)
negative.append(rejected('standard B missing',lambda:popup_pixels(lstd,right,g,False,baseline)))
assert point(left,'POPUP_B',-800)[0]<0
# Initial synthetic protocol must reject missing/early ACK and buffer attachment.
cfg=good['grabs'][0]['ack'];role=good['grabs'][0]['ids'][1]
negative.append(rejected('missing real ACK',lambda:protocol(text.replace(f'xdg_surface#{role}.ack_configure({cfg})',f'xdg_surface#{role}.ack_configure(999)'))))
assert 100+1<=420 and 80+1<=320 and 100+1<=350 and 60+1<=170
assert -800+800==0 and 799+800==1599 # Signed global -> verified output-layout fraction.
im=Image.new('RGB',(800,600),(48,48,56));reference(im,im.copy())
bad=im.copy();bad.putpixel((799,599),(48,48,57))
negative.append(rejected('one changed RGB',lambda:reference(im,bad)))
negative.append(rejected('sparse paint point',lambda:point(im,'POPUP_B',0)))
lines=['POINTER_BUTTON target=POPUP_B serial=70 button=273 state=1','POINTER_BUTTON target=POPUP_B serial=71 button=273 state=0']
pair(lines,'POPUP_B')
negative.append(rejected('wrong delivered target',lambda:pair(lines,'POPUP_A')))
d='POPUP_B POPUP_DONE role=17\nPOPUP_A POPUP_DONE role=14\nPOPUP_B DESTROY role=17\nPOPUP_A DESTROY role=14'
dismissal(d,[])
negative.append(rejected('invisible delivery',lambda:dismissal(d,lines)))
negative.append(rejected('wrong dismissal order',lambda:dismissal(d.replace('POPUP_B POPUP_DONE','POPUP_A POPUP_DONE'),[])))
sc='PI_POPUP output=HEADLESS-1 ns=1 local_index=1 tree=0x123 enabled=1 clip_valid=1 clip=-482,-25,800,600'
root_clip(sc,[-318,25],True)
negative.append(rejected('wrong applied clip',lambda:root_clip(sc,[-317,25],True)))
log="Handling command 'exit'\nShutting down sway"
assert terminal(True,1,0,log,False,False)['transport_incident']
for args in [(False,1,0,log,False,False),(True,1,1,log,False,False),(True,1,0,'',False,False),(True,1,0,log,True,False),(True,1,0,log,False,True)]:
assert not terminal(*args)['scientific_cleanup_pass']
src=(lab/'historical-source/nested-client.c').read_text();assert sha(lab/'historical-source/nested-client.c')==NESTED_SHA
patched=(lab/'client-source/nested-client.c').read_text()
# CONTRACT: remove precisely the sole new placement branch, recover original bytes.
expected=src.replace(' if (!strcmp(placement,"visible")) {',' /* EXPERIMENTAL: only placement changes; serial/grab/lifecycle stay historical.\n * Both 1x1 anchors lie inside their parent SHM window geometry. */\n if (!strcmp(placement,"static_cross")) {\n a.anchor_x=100; a.anchor_y=80; a.width=350;\n b.anchor_x=100; b.anchor_y=60; b.width=300;\n } else if (!strcmp(placement,"visible")) {')
assert patched==expected,'unauthorized client behavior change'
for tokens in ['xdg_popup_grab(s->popup,seat,serial)','parent->xdg','if (!s->mapped && !s->done) draw(s)','destroy_popup(&b); destroy_popup(&a);']:
assert tokens in src
candidate=Path('/home/fy59/swayfx-mosaic-static-runtime-hm5kbdkt/mosaic-source')
token_files={'sway/desktop/transaction.c':['con->current.workspace','wlr_scene_tree_get_clip(ws->layers.tiling','wlr_scene_tree_set_clip(popup_tree, NULL)'],
'sway/desktop/xdg_shell.c':['popup->xdg_surface_tree, popup->image_capture_tree','popup->desc.relative = &view->content_tree->node'],
'sway/commands/exit.c':['sway_terminate(0)'],
'sway/main.c':['wl_display_terminate(server.wl_display)','Shutting down sway','return exit_value'],
'sway/ipc-server.c':['WL_EVENT_WRITABLE','ipc_send_reply']}
for file,tokens in token_files.items():assert all(t in (candidate/file).read_text() for t in tokens),(file,tokens)
save(lab,'offline-gate',dict(marker='STATIC_NESTED_GRAB_FIXTURE_PREFLIGHT=PASS',status='PASS',fixture_sha256=sha(lab/'results/fixture-freeze-sha256.txt'),historical_control=str(old),historical_protocol=good,synthetic_geometry=g,negative_cases=negative,ledger='PASS concurrency/exhaustion/corruption',terminal='PASS synthetic success and five failures',client_delta='placement only',AST='PASS',shell='PASS',source_audit='PASS',C17='PASS from preparation',runtime='NOT TESTED'))
print('STATIC_NESTED_GRAB_FIXTURE_PREFLIGHT=PASS')
print('PASS historical control, reference width2, labelled synthetic predicates,',len(negative),'negative cases, ledger and terminal classification')

View file

@ -0,0 +1,92 @@
#!/usr/bin/env python3
"""Seal retained one-run observations without manufacturing missing evidence.
CONTRACT: runtime failures and real IPC codes stay immutable. No graphical replay.
INVARIANT: source/evidence manifests are created once and checked read-only.
"""
import argparse
import json
from pathlib import Path
import re
from PIL import Image
from support import OWNER,sha,save,verify,inventory
from predicates import protocol,mapped,geometry,popup_pixels,paint,pair,dismissal,root_clip,equal
from ipc_predicates import nodes,workspace,validate_outputs,validate_reference,scene_from_log
from geometry_audit import diagnose
p=argparse.ArgumentParser();p.add_argument('lab',type=Path);lab=p.parse_args().lab.resolve()
assert OWNER.read_text().strip()==str(lab)
assert not (lab/'results/evidence-sha256.txt').exists(),'already sealed'
verify(lab/'results/fixture-freeze-sha256.txt')
def read(n):return json.loads((lab/'results'/(n+'.json')).read_text())
run=lab/'run';runtime=read('runtime');terminal=read('terminal-exit');cleanup=read('cleanup')
protected=read('protected-before');assert all(sha(p)==h for p,h in protected.items()),'protected source/system change'
save(lab,'protected-after',dict(status='PASS',hashes=protected))
assert cleanup['runtime_removed'] and not Path(cleanup['runtime']).exists()
assert all(not Path('/proc',str(p['pid'])).exists() for p in cleanup['owned_processes'])
text=(run/'compositor.log').read_text();events=[json.loads(s) for s in (run/'events.jsonl').read_text().splitlines()]
full=runtime['status']=='PASS' and runtime['measurements_completed'] and terminal['scientific_cleanup_pass']
independent={}
if not full and runtime['stage']=='E1-open-A':
diagnostic=diagnose(lab);save(lab,'geometry-fixture-diagnostic',diagnostic)
save(lab,'applied-owner-geometry',dict(status='PARTIAL',E1=diagnostic['applied_owner'],painted_content_origin=diagnostic['painted_content_origin'],SHM_size=diagnostic['SHM_size'],assigned_content=diagnostic['assigned_content'],painted=diagnostic['painted_TOPLEVEL'],popups='NOT TESTED'))
save(lab,'applied-clips',dict(status='PARTIAL',tiled=diagnostic['tiled_clip'],root='NOT TESTED',child='NOT TESTED'))
save(lab,'mosaic-pixels',dict(status='PARTIAL',toplevel_H1=diagnostic['painted_TOPLEVEL'],H2=diagnostic['H2'],root='NOT TESTED',nested='NOT TESTED'))
if full:
baseline=Image.open(run/'H2-reference-1.png').convert('RGB')
owners=read('applied-owner-geometry');clips=read('applied-clips');grab_serials=[]
for name in ['E1','E2']:
client=(run/(name+'.log')).read_text();cut=client.index('POPUP_B MAP ');prefix=client[:client.index('\n',cut)+1]
pr=protocol(prefix);grab_serials += [g['serial'] for g in pr['grabs']]
g=geometry(prefix,owners[name]['content_origin'])
independent[name]=dict(protocol=pr,geometry=g,pixels=popup_pixels(Image.open(run/(name+'-mosaic-H1.png')).convert('RGB'),Image.open(run/(name+'-mosaic-H2.png')).convert('RGB'),g,True,baseline))
assert clips[name]['root']['raw'] in text
root_clip(clips[name]['root']['raw'],owners[name]['content_origin'],True)
assert len(set(grab_serials))==4 and grab_serials==sorted(grab_serials)
for file in ['H2-reference-2.png','E1-mosaic-H2.png','E1-dismissed-H2.png','E2-mosaic-H2.png','final-H2.png']:
assert equal(baseline,Image.open(run/file).convert('RGB'))['equal'],('full H2',file)
returns=read('standard-return');assert returns['root_clip']['raw'] in text
root_clip(returns['root_clip']['raw'],returns['geometry']['origin'],False)
stdsnap=read('standard-snapshot');ws=workspace(stdsnap['tree'],'1');assert ws['id']==owners['E2']['workspace'] and ws['layout']=='splith'
validate_reference(stdsnap,read('reference-stability')['reference']['con_id'],read('reference-stability')['reference']['pid'])
std=popup_pixels(Image.open(run/'standard-H1.png').convert('RGB'),Image.open(run/'standard-H2.png').convert('RGB'),returns['geometry'],False,baseline)
client=(run/'E2.log').read_text();cut=next(e['ns'] for e in events if e['kind']=='measurements-completed')
# Delivery must exist in actual retained recipient logs, not just summary JSON.
for row in read('clicks'):
for name,lines in row['events'].items():
actual=(run/(name+'.log')).read_text()
assert all(line in actual for line in lines)
for name,target in [('E1-visible-B','POPUP_B'),('E2-standard-B','POPUP_B'),('E2-standard-A','POPUP_A')]:
row=next(r for r in read('clicks') if r['tag']==name);who='E1' if name.startswith('E1') else 'E2'
pair(row['events'][who],target)
assert not row['events']['reference'] and not row['events']['filler']
forbidden=read('forbidden-input');dismissal((run/'E1.log').read_text(),forbidden['popup_events'])
assert client.index('POPUP_B DESTROY ')<client.index('COMMAND close_b DONE')<client.index('POPUP_A DESTROY ')
assert not re.search(r'wl_display[^\n]*\.error\(|protocol error',client,re.I)
assert runtime['duration_seconds']<=150 and not runtime['rescue_cleanup']
independent['standard']=std
save(lab,'independent-validation',dict(status='PASS',historical_status_unchanged=True,actual=independent,serials=grab_serials))
# Trace extents + capture diffs are retained as partial damage observations.
damage=[s for s in text.splitlines() if 'TEMPORAL_DAMAGE' in s]
save(lab,'damage-analysis',dict(status='PARTIAL',trace_count=len(damage),raw_extents=damage,
capture_windows=[e for e in events if e['kind']=='capture'],
changed_regions={n:independent[n]['pixels'] for n in ['E1','E2'] if n in independent},
limitations=['not every intermediate frame','not minimal damage','no native buffer/PNG identity','no exhaustive GPU lifetime']))
source=Path('/home/fy59/swayfx-mosaic-static-runtime-hm5kbdkt/mosaic-source/sway/desktop/xdg_shell.c')
save(lab,'scene-parentage',dict(status='PASS source-backed' if full else 'NOT TESTED runtime',source=str(source),source_sha256=sha(source),root='global popup layer; positioned from applied view content tree',nested='B wrapper under A xdg_surface_tree; same view',direct_child_trace='NOT AVAILABLE in immutable binary',runtime_XDG=read('xdg-protocol-order') if (lab/'results/xdg-protocol-order.json').exists() else None))
required=['applied-owner-geometry','popup-root-geometry','popup-nested-geometry','grab-serials','xdg-protocol-order','applied-clips','mosaic-pixels','mosaic-input','forbidden-input','dismissal','standard-return','standard-popup-pixels','standard-popup-input','reference-stability']
for n in required:
if not (lab/'results'/(n+'.json')).exists():save(lab,n,dict(status='NOT TESTED',stopping_stage=runtime['stage'],reason=runtime['failure']))
verdict='FEASIBLE' if full else (runtime.get('failure') or {}).get('verdict','INCONCLUSIVE')
architecture='STATIC_NESTED_VALID_GRAB_FEASIBLE_FOR_TESTED_MATRIX' if full else 'STATIC_NESTED_VALID_GRAB_REQUIRES_REDESIGN' if verdict=='BLOCKED' else 'UNDECIDED'
matrix={n:'PASS' if full else 'NOT TESTED: inspect individual retained observations' for n in required}
if not full:
matrix.update(binary_identity='PASS',loaded_libraries='PASS',client_provenance='PASS',C17='PASS',outputs='PASS',H1_focus='PASS',applied_camera='PASS relative -320, 480 to 160',H2_reference='PASS whole RGB; before any popup',tiled_clip='PASS global [-800,0,800,600]',toplevel_paint='PASS measured 182214 pixels; no popup',root_grab='NOT TESTED',nested_grab='NOT TESTED',E2='NOT TESTED',terminal_IPC='FAIL actual exit1; completed=false, no scientific exception',compositor_exit='PASS actual code0',cleanup='PASS no rescue',offline_gate='PASS recorded tests; INSUFFICIENT assertion audit, see diagnostic')
matrix.update(damage='PARTIAL',direct_child_clip_trace='NOT AVAILABLE; runtime NOT TESTED' if not full else 'NOT AVAILABLE; inherited source + pixels/input',hidden_owner='NOT TESTED',scale='NOT TESTED',rotation='NOT TESTED',output_migration='NOT TESTED',saved_buffer='NOT TESTED',effects='NOT TESTED',atomic_generation='NOT PROVEN',exhaustive_ABI='NOT TESTED',new_pristine='NOT RUN; historical controls only')
save(lab,'matrix',matrix)
save(lab,'summary',dict(verdict=verdict,architecture=architecture,runtime=runtime,terminal=terminal,budget=read('budget'),marker='SWAYFX_MOSAIC_STATIC_NESTED_VALID_GRAB_PROBE='+verdict,STEP20C='NEXT',production_multi_output='NOT YET SUPPORTED',new_Mosaic_builds=0,new_SceneFX_builds=0,pristine_runs=0))
sources=[p for root in ['fixture','preflight-correction','postrun-fixture','client-source','historical-source'] for p in (lab/root).rglob('*') if p.is_file()]+[lab/'protocol-before-run.md']
evidence=[p for root in ['raw','run','results'] for p in (lab/root).rglob('*') if p.is_file()]+[lab/n for n in ['swayfx-mosaic','nested-client','static-reference','pointer-daemon','campaign-owner']]
# Both lists fixed before writing either manifest, avoiding circular digests.
for name,paths in [('source',sources),('evidence',evidence)]:
print(name,inventory(lab/'results'/(name+'-sha256.txt'),paths))
print('SWAYFX_MOSAIC_STATIC_NESTED_VALID_GRAB_PROBE='+verdict)

View file

@ -0,0 +1,80 @@
#!/usr/bin/env python3
"""Read-only post-run diagnosis of failed geometry assertions; no graphical retry.
WHY: SHM/native geometry, rendered destination and IPC window_rect differ.
CONTRACT: preserve the executed runner and diagnose against actual PNG/protocol.
INVARIANT: a successful diagnosis cannot qualify uncreated popup grabs or input.
"""
import argparse
import ast
import json
from pathlib import Path
import re
from PIL import Image
from predicates import paint,equal,reference
from ipc_predicates import validate_reference,measure_owner,scene_from_log
from support import sha,save,verify
def diagnose(lab):
lab=Path(lab);run=lab/'run'
runtime=json.loads((lab/'results/runtime.json').read_text());budget=json.loads((lab/'results/budget.json').read_text())
assert runtime['status']=='INCONCLUSIVE' and runtime['stage']=='E1-open-A' and not runtime['measurements_completed']
assert budget['used']==dict(run=1,chain=1,grab=0,click=0,capture=3,camera=1,transition=0,move=1)
client=(run/'E1.log').read_text();assert 'GRAB_REQUEST' not in client and 'POPUP_A CREATE' not in client and 'POINTER_BUTTON' not in client
assert 'create_buffer(new id wl_buffer#12, 0, 420, 320, 1680, 1)' in client
assert 'TOPLEVEL ROLE_CONFIGURE w=636 h=573' in client
assert client.index('xdg_surface#9.ack_configure(20)')<client.index('wl_surface#3.attach(')<client.index('TOPLEVEL MAP ')
snap=json.loads((lab/'results/E1-applied-snapshot.json').read_text())
cal=json.loads((lab/'results/camera-calibration.json').read_text())[-1];owner=cal['after_owner']['IPC']
measure=measure_owner((run/'compositor.log').read_text(),owner)
# Use the recorded applied sample before shutdown, never the later teardown scene.
assert cal['after_owner']['raw'] in (run/'compositor.log').read_text()
applied=measure_owner(cal['after_owner']['raw'],owner)
scene=scene_from_log(cal['scene']['raw'],'HEADLESS-1')
assert scene['global_clip']==[-800,0,800,600] and scene['clip_valid'] and scene['scroll']==160
assert cal['before']==480 and cal['delta']==-320 and cal['after']==160
value=paint(Image.open(run/'E1-top.png').convert('RGB'),'TOPLEVEL');assert value==dict(count=182214,bbox=(482,25,800,598))
x1,y1,x2,y2=value['bbox'];assert x1-800==applied['horizontal_content'][0]==-318
assert value['count']==(x2-x1)*(y2-y1) and y2-y1==owner['window_rect']['height']==573
assert owner['geometry']==dict(x=0,y=0,width=420,height=320)
old_height_ok=(y2-y1==320)
old_y_ok=(y1==applied['scene'][1]+owner['window_rect']['y'])
assert not old_height_ok and not old_y_ok, 'must reproduce both invalid assumptions'
assert owner['window_rect']['y']==0 and owner['deco_rect']['height']==25 and applied['scene'][1]==0
ref=json.loads((lab/'results/reference-stability.json').read_text())['reference']
validate_reference(snap,ref['con_id'],ref['pid'])
a=Image.open(run/'H2-reference-1.png').convert('RGB');b=Image.open(run/'H2-reference-2.png').convert('RGB');reference(a,b)
assert paint(a,'TOPLEVEL')['count']==0 and paint(b,'TOPLEVEL')['count']==0
events=[json.loads(s) for s in (run/'events.jsonl').read_text().splitlines()]
cap=[e for e in events if e['kind']=='capture']
assert len(cap)==3 and cap[1]['start_ns']-cap[0]['start_ns']>=500000000
exact=Path('/home/fy59/swayfx-mosaic-static-runtime-hm5kbdkt/mosaic-source')
output=(exact/'sway/desktop/output.c').read_text();ipc=(exact/'sway/ipc-json.c').read_text();trans=(exact/'sway/desktop/transaction.c').read_text()
assert 'wlr_scene_buffer_set_dest_size(buffer, MAX(content_width, 0), MAX(content_height, 0))' in output
assert 'has_titlebar ? 0 : c->pending.content_y - c->pending.y' in ipc
assert 'border_left, border_top' in trans
runner=(lab/'fixture/run.py').read_text();assert 'topbox[3]-topbox[1]==320' in runner
assert "origin[1]==after['scene'][1]+owner['window_rect']['y']" in runner
terminal=json.loads((lab/'results/terminal-exit.json').read_text())
assert terminal['ipc_exit']==1 and terminal['compositor_exit']==0 and not terminal['scientific_cleanup_pass']
assert 'Unable to receive IPC response' in terminal['stderr']
text=(run/'compositor.log').read_text();assert "Handling command 'exit'" in text and 'Shutting down sway' in text
assert all(row['exit']==0 and not Path('/proc',str(row['pid'])).exists() for row in terminal['owned_process_codes'])
assert not re.search(r'wl_display[^\n]*\.error\(|protocol error',client,re.I)
return dict(status='PASS offline diagnosis; runtime remains INCONCLUSIVE',runner_sha256=sha(lab/'fixture/run.py'),
executed_assertion_line=182,first_failure='rendered blue height 573 != immutable SHM height 320',
additional_unreached_assertion_line=183,additional_failure='titlebar-enabled IPC window_rect.y=0 does not give painted/content y=25',
applied_owner=applied,painted_TOPLEVEL=value,SHM_size=[420,320],assigned_content=[636,573],painted_content_origin=[-318,25],
applied_camera=dict(before=480,relative_delta=-320,after=160),tiled_clip=scene,
H2=dict(whole_RGB='PASS two references',color='#303038',changed_pixels=0,PNG_sha256=sha(run/'H2-reference-1.png')),
source_locations={'destination':'sway/desktop/output.c:331','window_rect_y':'sway/ipc-json.c:712','content_origin':'sway/desktop/transaction.c:705'},
origin_diagnosis='actual paint supplies y; IPC window_rect excludes enabled titlebar; rendered destination is separate from native SHM',
offline_preflight_limit='recorded PASS did not audit these two live assertions against the source/available prior IPC; it was insufficient',
popup_geometry='NOT EXERCISED',grabs='NOT TESTED',input='NOT TESTED',standard='NOT TESTED',new_runs=0,
correction_scope='offline fixture geometry revalidation required; no clipping algorithm change justified')
if __name__=='__main__':
p=argparse.ArgumentParser();p.add_argument('lab',type=Path);p.add_argument('--record',action='store_true');a=p.parse_args()
verify(a.lab/'results/fixture-freeze-sha256.txt');result=diagnose(a.lab)
if a.record:save(a.lab,'geometry-fixture-diagnostic',result)
print('PASS reproduce failed height assertion and additional invalid IPC-y assumption; no popup evidence manufactured')

View file

@ -0,0 +1,139 @@
"""Pure validators for replay and live observations, never desktop IPC.
WHY: stored border thickness and container IPC geometry are not rendered pixels.
CONTRACT: callers supply measured identities; validate ancestors and applied scene.
INVARIANT: no width-zero predicate, hard-coded runtime IDs, or native buffer y.
"""
import re
OUTPUTS = {'HEADLESS-1': (-800, 0, 800, 600, 1.0, 'normal'),
'HEADLESS-2': (0, 0, 800, 600, 1.0, 'normal')}
ZERO = dict(x=0, y=0, width=0, height=0)
FULL = dict(x=0, y=0, width=800, height=600)
def nodes(node):
yield node
for child in node.get('nodes', []) + node.get('floating_nodes', []):
yield from nodes(child)
def workspace(tree, name):
rows = [n for n in nodes(tree) if n.get('type') == 'workspace' and n.get('name') == name]
assert len(rows) == 1, 'workspace identity'
return rows[0]
def ancestry(tree, con_id, path=()):
if tree.get('id') == con_id:
return path + (tree,)
for child in tree.get('nodes', []) + tree.get('floating_nodes', []):
found = ancestry(child, con_id, path + (tree,))
if found:
return found
return ()
def validate_outputs(outputs):
actual = {o['name']: (*[o['rect'][k] for k in ('x', 'y', 'width', 'height')],
o['scale'], o['transform']) for o in outputs if o['active']}
assert actual == OUTPUTS, ('output geometry', actual)
assert len([o for o in outputs if o['active']]) == 2, 'duplicate output'
return actual
def validate_reference(snapshot, con_id, pid, workspace_name='2', output_name='HEADLESS-2'):
"""B_NONE may retain width 2; require actual empty decoration/full content.
IPC visibility means view_is_visible, not proof of SHM coverage. RGB is
independently required by the runner. Width is returned only as metadata.
"""
validate_outputs(snapshot['outputs'])
path = ancestry(snapshot['tree'], con_id)
assert path, 'reference surface absent'
ref = path[-1]
ws = next((n for n in path if n.get('type') == 'workspace'), None)
out = next((n for n in path if n.get('type') == 'output'), None)
assert ref.get('type') == 'con' and ref.get('shell') == 'xdg_shell', 'reference view absent'
assert ref.get('app_id') == 'org.mosaic.StaticReference', 'reference App ID'
assert ref.get('pid') == pid and pid > 0 and ref['id'] == con_id, 'reference PID/ID'
assert ws and ws['name'] == workspace_name and ws.get('output') == output_name, 'reference workspace'
assert out and out['name'] == output_name and out['rect'] == FULL, 'reference output'
assert ref.get('visible') is True, 'reference visibility'
assert ref.get('border') == 'none', 'reference border mode'
assert ref.get('rect') == FULL and ref.get('window_rect') == FULL, 'reference full content'
assert ref.get('deco_rect') == ZERO, 'effective reference decoration'
return {'status': 'PASS', 'con_id': con_id, 'pid': pid, 'workspace': ws['id'],
'output': output_name, 'stored_border_width': ref.get('current_border_width'),
'reference': ref}
def scene_from_log(text, output):
rows = [s for s in text.splitlines() if 'PI_SCENE output=' + output + ' ' in s
and 'workspace=none' not in s]
assert rows, 'applied scene trace absent'
line = rows[-1]
m = re.search(r'workspace=(\d+) layout=(\d+) scroll=(-?[\d.]+) tile_scene=(-?\d+),(-?\d+) clip_valid=(\d+) clip=(-?\d+),(-?\d+),(\d+),(\d+)', line)
assert m, 'scene trace format'
v = list(map(float, m.groups()))
origin = OUTPUTS[output][:2]
return {'workspace': int(v[0]), 'layout_enum': int(v[1]), 'scroll': v[2],
'tile_local': v[3:5], 'clip_valid': bool(v[5]), 'clip_local': v[6:10],
'global_clip': [origin[0] + v[3] + v[6], origin[1] + v[4] + v[7], v[8], v[9]],
'raw': line}
def measure_owner(text, owner):
rows = [x for x in text.splitlines() if 'PI_OWNER output=HEADLESS-1 ' in x
and f' id={owner["id"]} ' in x]
assert rows, 'applied owner trace absent'
line = rows[-1]
m = re.search(r'scene_valid=1 scene=(-?\d+),(-?\d+) applied_size=(\d+),(\d+)', line)
assert m, 'owner trace format'
x, y, w, h = map(int, m.groups())
win = owner['window_rect']
return {'id': owner['id'], 'scene': [x, y, w, h], 'window_rect': win,
'horizontal_content': [x + win['x'], win['width']], 'raw': line, 'IPC': owner}
def client_commit(text):
rows = [s for s in text.splitlines() if s.startswith('COMMIT ')]
assert rows, 'no real client commit'
m = re.fullmatch(r'COMMIT ns=(\d+) serial=(\d+) size=(\d+)x(\d+) color=([0-9a-f]{8})', rows[-1])
assert m, 'client commit format'
ns, serial, w, h = map(int, m.groups()[:4])
assert ns > 0 and 0 < serial <= 0xffffffff and 0 < w <= 4096 and 0 < h <= 4096
return {'ns': ns, 'serial': serial, 'width': w, 'height': h, 'color': m[5], 'raw': rows[-1]}
def validate_preflight(snapshot, con_id, pid, target_id, target_pid, scene, h2_scene, measured, commit):
reference = validate_reference(snapshot, con_id, pid)
ws = workspace(snapshot['tree'], '1')
path = ancestry(snapshot['tree'], target_id)
assert path and ws in path, 'target workspace ownership'
owner = path[-1]
assert owner.get('app_id') == 'org.mosaic.SavedBufferProbe' and owner.get('pid') == target_pid
assert owner.get('shell') == 'xdg_shell' and owner.get('visible') is True, 'target mapped'
assert ws['output'] == 'HEADLESS-1' and ws['layout'] == 'mosaic', 'H1 Mosaic'
assert owner.get('focused') is True and reference['reference']['focused'] is False, 'initial focus'
assert [z['name'] for z in snapshot['workspaces'] if z['focused']] == ['1'], 'workspace focus'
scroll = ws['mosaic']['rows'][0]['scroll_x']
assert scene['workspace'] == ws['id'] and scene['layout_enum'] == 5, 'applied Mosaic owner'
assert scene['scroll'] == scroll and scene['tile_local'] == [-scroll, 0], 'applied camera'
assert scene['clip_valid'] and scene['global_clip'] == [-800, 0, 800, 600], 'viewport clip'
assert scene['clip_local'] == [scroll, 0, 800, 600], 'local clip'
h2ws = workspace(snapshot['tree'], '2')
assert h2_scene['workspace'] == h2ws['id'] and not h2_scene['clip_valid'], 'H2 ordinary clip'
assert measured['id'] == target_id and measured['IPC'] == owner, 'measured owner identity'
x, w = measured['horizontal_content']
assert -800 < x < 0 < x + w, 'target continuation crosses boundary'
assert w == commit['width'] == owner['window_rect']['width'], 'configured content width'
assert commit['height'] == owner['window_rect']['height'] and commit['color'] in ('002344cc', '0020d0a0')
return {'status': 'PASS', 'reference': reference, 'workspace': ws['id'],
'target': target_id, 'scroll': scroll, 'scene': scene, 'H2_scene': h2_scene,
'measured': measured, 'commit': commit}
def validate_camera(before_scroll, after_scroll, delta, scene):
assert type(delta) is int and -2147483647 <= delta <= 2147483647
assert after_scroll == before_scroll + delta and scene['scroll'] == after_scroll, 'camera correction applied'

View file

@ -0,0 +1,16 @@
--- a/nested-client.c
+++ b/nested-client.c
@@ -205,7 +205,12 @@
int main(int argc,char **argv) {
signal(SIGTERM,stop);
const char *placement=argc>1?argv[1]:"b_cross";
- if (!strcmp(placement,"visible")) {
+ /* EXPERIMENTAL: only placement changes; serial/grab/lifecycle stay historical.
+ * Both 1x1 anchors lie inside their parent SHM window geometry. */
+ if (!strcmp(placement,"static_cross")) {
+ a.anchor_x=100; a.anchor_y=80; a.width=350;
+ b.anchor_x=100; b.anchor_y=60; b.width=300;
+ } else if (!strcmp(placement,"visible")) {
a.anchor_x=50; a.anchor_y=80; a.width=250;
b.anchor_x=20; b.anchor_y=60; b.width=170;
} else if (!strcmp(placement,"both_cross")) {

View file

@ -0,0 +1,146 @@
"""Shared offline/live predicates: facts precede scientific classification.
CONTRACT: full RGB comparisons have no mask/tolerance; grabs require real logs.
INVARIANT: dismissal, client destruction, clipping and layout remain distinct.
"""
import re
from PIL import Image,ImageChops
COLORS=dict(TOPLEVEL=(35,68,204),POPUP_A=(224,192,32),POPUP_B=(32,208,160))
class Defect(RuntimeError):
"""A directly measured scientific contract failure, distinct from fixture ambiguity."""
def paint(im,target):
im=im.convert('RGB');assert im.size==(800,600)
mask=Image.new('L',im.size);mask.putdata([255 if p==COLORS[target] else 0 for p in im.get_flattened_data()])
return dict(count=sum(mask.histogram()[1:]),bbox=mask.getbbox())
def point(im,target,origin):
box=paint(im,target)['bbox'];assert box,('no measured paint',target)
# WHY: A may be occluded by B; bbox center alone is not a valid hit point.
x1,y1,x2,y2=box
for y in range(y1+10,y2-10,5):
for x in range(x1+10,x2-10,5):
if all(im.getpixel((xx,yy))==COLORS[target] for yy in range(y-8,y+9) for xx in range(x-8,x+9)):
return [x+origin,y]
raise AssertionError('no solid measured interior '+target)
def equal(a,b):
assert a.size==b.size==(800,600)
rows=[(i%800,i//800,x,y) for i,(x,y) in enumerate(zip(a.get_flattened_data(),b.get_flattened_data())) if x!=y]
return dict(equal=not rows,changed=len(rows),bbox=ImageChops.difference(a,b).getbbox(),pixels=rows)
def reference(a,b):
result=equal(a,b)
assert result['equal'] and all(c==(48,48,56) for c in a.get_flattened_data()),'unstable reference'
return result
def configured(text,name):
rows=re.findall(rf'{name} ROLE_CONFIGURE x=(-?\d+) y=(-?\d+) w=(\d+) h=(\d+)',text)
assert rows,(name,'no configure')
return list(map(int,rows[-1]))
def geometry(text,origin):
a=configured(text,'POPUP_A');b=configured(text,'POPUP_B')
A=[origin[0]+a[0],origin[1]+a[1],a[2],a[3]]
B=[A[0]+b[0],A[1]+b[1],b[2],b[3]]
assert all(r[0]<0<r[0]+r[2] for r in [A,B]),'popup crossing NOT EXERCISED'
return dict(A=A,B=B,configured_A=a,configured_B=b,origin=origin)
def mapped(text):
for name in ['POPUP_A','POPUP_B']:
assert text.count(name+' MAP ')==1 and name+' POPUP_DONE ' not in text and name+' DESTROY ' not in text,(name,'not mapped')
def protocol(text):
assert not re.search(r'wl_display[^\n]*\.error\(|protocol error|invalid_popup_parent|not_the_topmost_popup',text,re.I),'protocol error'
mapped(text)
ids={}
for name in ['TOPLEVEL','POPUP_A','POPUP_B']:
m=re.search(rf'{name} CREATE wl=(\d+) xdg=(\d+) role=(\d+)',text);assert m
ids[name]=list(map(int,m.groups()))
assert len({n for v in ids.values() for n in v})==9,'object identities reused'
grabs=[]
for name,parent in [('POPUP_A','TOPLEVEL'),('POPUP_B','POPUP_A')]:
create=re.search(rf'{name} CREATE .*parent={parent} parent_xdg=(\d+)',text);assert create
assert int(create[1])==ids[parent][1], 'wrong XDG parent'
m=re.search(rf'{name} GRAB_REQUEST origin=wl_pointer.button target={parent} serial=(\d+) used=(\d+)',text);assert m
serial,used=map(int,m.groups());assert serial==used and 0<serial<=0xffffffff
button=f'POINTER_BUTTON target={parent} serial={serial} button=272 state=1'
assert text.index(button)<m.start(),'grab serial not from earlier button'
role=text.index(name+' ROLE_CONFIGURE ');cfg=re.search(rf'{name} XDG_CONFIGURE serial=(\d+) ack',text);assert cfg
mp=text.index(name+' MAP ')
assert m.start()<role<cfg.start()<mp,'configure ACK map order'
popup_role=ids[name][2];xdg=ids[name][1];wl=ids[name][0]
# WAYLAND_DEBUG is independent corroboration, not just fixture claims.
request=re.search(rf'xdg_popup#{popup_role}\.grab\(wl_seat#\d+, {serial}\)',text);assert request
ack=re.search(rf'xdg_surface#{xdg}\.ack_configure\({cfg[1]}\)',text);assert ack
attach=re.search(rf'wl_surface#{wl}\.attach\(',text);assert attach
commits=list(re.finditer(rf'wl_surface#{wl}\.commit\(\)',text));assert len(commits)>=2
assert request.start()<commits[0].start()<role<ack.start()<attach.start()<commits[1].start()<mp
if parent=='POPUP_A':assert text.index('POPUP_A MAP ')<text.index(button)
grabs.append(dict(popup=name,parent=parent,serial=serial,used=used,origin='wl_pointer.button',ids=ids[name],ack=int(cfg[1])))
assert grabs[0]['serial']<grabs[1]['serial'], 'distinct ordered serials'
return dict(ids=ids,grabs=grabs,hierarchy='TOPLEVEL -> POPUP_A -> POPUP_B',status='PASS')
def pair(lines,target):
events=[]
for line in lines:
m=re.fullmatch(r'POINTER_BUTTON target=(\w+) serial=(\d+) button=(\d+) state=(\d+)',line);assert m
events.append([m[1],*map(int,m.groups()[1:])])
if len(events)!=2 or any(e[0]!=target for e in events) or [e[2:] for e in events]!=[[273,1],[273,0]]:
raise Defect('wrong actual button recipient/pair: '+str(events))
assert 0<events[0][1]<events[1][1]<=0xffffffff
return events
def dismissal(text,buttons):
if any('target=POPUP_A ' in b or 'target=POPUP_B ' in b for b in buttons):
raise Defect('invisible popup received actual button')
done=re.findall(r'(POPUP_[AB]) POPUP_DONE ',text)
destroyed=re.findall(r'(POPUP_[AB]) DESTROY ',text)
assert done==['POPUP_B','POPUP_A'] and destroyed==['POPUP_B','POPUP_A'],('dismissal order',done,destroyed)
return dict(done=done,destroyed=destroyed,invisible_buttons=buttons,status='PASS',meaning='outside dismissal distinct from invisible hit')
def root_clip(text,origin,mosaic):
rows=[s for s in text.splitlines() if 'PI_POPUP output=HEADLESS-1 ' in s]
assert rows,'no root clip trace'
row=rows[-1]
m=re.search(r'local_index=(\d+) tree=(\S+) enabled=(\d+) clip_valid=(\d+) clip=(-?\d+),(-?\d+),(\d+),(\d+)',row);assert m
index,tree,enabled,valid,*box=m.groups();box=list(map(int,box))
assert int(index)==1 and int(enabled)==1
if bool(int(valid))!=mosaic:raise Defect('root clip state mismatch')
if mosaic:
assert [origin[0]+box[0],origin[1]+box[1],box[2],box[3]]==[-800,0,800,600], 'root/owner applied clip relationship'
return dict(tree=tree,clip_valid=bool(int(valid)),local=box,origin=origin,raw=row,child='inherited; source hierarchy plus measured B render/input')
def popup_pixels(left,right,g,mosaic,baseline):
result={side:{n:paint(im,n) for n in COLORS} for side,im in [('H1',left),('H2',right)]}
for key,name in [('A','POPUP_A'),('B','POPUP_B')]:
rect=g[key]
assert result['H1'][name]['count']>0,'permitted popup color absent'
if mosaic and result['H2'][name]['count']:
raise Defect('forbidden popup pixels '+name)
if not mosaic and not result['H2'][name]['count']:
raise AssertionError('standard popup continuation absent '+name)
# CONTRACT: compare the exact color region against configured geometry,
# subtracting B's occlusion of A, not against a predicted painted bbox.
for side,im,ox in [('H1',left,-800),('H2',right,0)]:
for y in range(600):
for x in range(800):
gx=x+ox
inside=rect[0]<=gx<rect[0]+rect[2] and rect[1]<=y<rect[1]+rect[3]
if key=='A':
B=g['B'];inside=inside and not (B[0]<=gx<B[0]+B[2] and B[1]<=y<B[1]+B[3])
expected=inside and (not mosaic or side=='H1')
if (im.getpixel((x,y))==COLORS[name])!=expected:
raise AssertionError(('paint/configured position mismatch',name,side,x,y))
if mosaic:
result['whole_H2']=equal(baseline,right)
if not result['whole_H2']['equal']:raise Defect('whole-H2 changed under Mosaic')
return result
def terminal(measures,ipc_code,compositor_code,log,protocol_error,rescue):
ok=bool(measures and compositor_code==0 and "Handling command 'exit'" in log
and 'Shutting down sway' in log and not protocol_error and not rescue)
return dict(scientific_cleanup_pass=ok,ipc_exit=ipc_code,compositor_exit=compositor_code,
ipc_success=ipc_code==0,transport_incident=bool(ok and ipc_code!=0),
interpretation=('compatible queued-response loss, not proven packet causality' if ok and ipc_code!=0 else 'actual recorded IPC outcome'))

View file

@ -0,0 +1,77 @@
#!/usr/bin/env python3
"""Create one exclusive LAB; copy an immutable compositor and build clients only.
CONTRACT: never launch a graphical process from preparation. No LAB retry/reset.
INVARIANT: retained historical source and manifests are read-only.
"""
import ast
import json
import os
from pathlib import Path
import shutil
import stat
import subprocess
import tempfile
from support import REPO,OWNER,BINARY,BINARY_SHA,WLROOTS_SHA,NESTED_SHA,sha,save,command,initial,inventory,verify
fd=os.open(OWNER,os.O_CREAT|os.O_EXCL|os.O_WRONLY,0o600)
with os.fdopen(fd,'w') as out:
lab=Path(tempfile.mkdtemp(prefix='swayfx-mosaic-static-nested-grab-',dir=Path.home()))
out.write(str(lab)+'\n');out.flush();os.fsync(out.fileno())
for n in ['raw','results','client-source','historical-source','fixture']:(lab/n).mkdir()
(lab/'campaign-owner').write_text(str(OWNER)+'\n');initial(lab)
prior=Path('/home/fy59/swayfx-mosaic-static-rgb-input-retest-hn67lnhq')
receipts={n:verify(prior/'results'/(n+'-sha256.txt')) for n in ['fixture-freeze','source','evidence']}
assert sha(BINARY)==BINARY_SHA and not BINARY.is_symlink() and stat.S_IMODE(BINARY.stat().st_mode)==0o755
shutil.copy2(BINARY,lab/'swayfx-mosaic');assert sha(lab/'swayfx-mosaic')==BINARY_SHA
elf=command(lab,'ELF',['readelf','-hW','-nW','-dW',lab/'swayfx-mosaic'])
assert 'ELF64' in elf and 'Advanced Micro Devices X86-64' in elf and '942db64269640778ee433e5970ba1100bc60f94c' in elf
assert 'libscenefx' not in elf and '(RPATH)' not in elf and '(RUNPATH)' not in elf
symbols=command(lab,'symbols',['nm',lab/'swayfx-mosaic'])
assert all(' T '+s in symbols for s in ['wlr_scene_tree_set_clip','wlr_scene_tree_get_clip'])
loader=command(lab,'loader',['ldd','-r',lab/'swayfx-mosaic'])
assert not any(s in loader for s in ['undefined symbol','not found','libscenefx'])
wl=Path('/usr/lib/libwlroots-0.20.so').resolve();assert sha(wl)==WLROOTS_SHA and str(wl) in loader
version=command(lab,'wlroots-version',['pkg-config','--modversion','wlroots-0.20']).strip();assert version=='0.20.2'
save(lab,'binary-identity',dict(status='PASS',sha256=BINARY_SHA,build_id='942db64269640778ee433e5970ba1100bc60f94c',mode='0755',ELF='ELF64 x86-64',SceneFX_dynamic=False,wlroots_sha256=WLROOTS_SHA,wlroots_version=version,source=str(BINARY),copy=str(lab/'swayfx-mosaic')))
src=lab/'client-source';inputs=[]
for name,rel in [('nested-client.c','step20c-nested-grab/nested-client.c'),('pointer-daemon.c','step20c-valid-grab/pointer-daemon.c'),('static-reference.c','step20c-saved-target-timeout-input/static-reference.c'),('saved-client.c','step20c-saved-target-timeout-input/saved-client.c')]:
p=REPO/'tooling/probes'/rel;shutil.copy2(p,src/name);shutil.copy2(p,lab/'historical-source'/name)
inputs.append(dict(source=str(p),sha256=sha(p),copy=str(src/name)))
assert sha(src/'nested-client.c')==NESTED_SHA
patch=REPO/'tooling/probes/step20c-static-nested-grab/placement.patch'
command(lab,'placement-check',['git','apply','--check',patch],cwd=src)
command(lab,'placement-apply',['git','apply',patch],cwd=src)
# Protocol byte identity is independently checked by regeneration, outside Git.
for name in ['xdg-shell-client.h','xdg-shell-protocol.c','virtual-pointer-client.h','virtual-pointer-protocol.c']:
shutil.copy2(prior/'client-source'/name,src/name)
xml=Path('/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml');shutil.copy2(xml,src/'xdg-shell.xml')
vxml=REPO/'tooling/probes/step20c-valid-grab/wlr-virtual-pointer-unstable-v1.xml';shutil.copy2(vxml,src/'virtual-pointer.xml')
assert sha(vxml)=='3ff6d540be0bc5228195bf072bde42117ea17945a5c2061add5d3cf97d6bb524'
for stem in ['xdg-shell','virtual-pointer']:
for mode,suffix in [('client-header','-client.h'),('private-code','-protocol.c')]:
dest=lab/'raw'/(stem+suffix)
command(lab,stem+'-'+mode,['wayland-scanner',mode,src/(stem+'.xml'),dest])
assert dest.read_bytes()==(src/(stem+suffix)).read_bytes(),'generated protocol differs'
flags=command(lab,'wayland-flags',['pkg-config','--cflags','--libs','wayland-client']).split()
builds=[]
for name,proto in [('nested-client','xdg-shell'),('static-reference','xdg-shell'),('pointer-daemon','virtual-pointer')]:
args=['cc','-std=c17','-Wall','-Wextra','-Werror','-Wno-unused-parameter','-I'+str(src),src/(name+'.c'),src/(proto+'-protocol.c'),*flags]
command(lab,name+'-syntax',args+['-fsyntax-only']);command(lab,name+'-build',args+['-o',lab/name])
builds.append(dict(name=name,source_sha256=sha(src/(name+'.c')),binary_sha256=sha(lab/name)))
save(lab,'client-provenance',dict(inputs=inputs,historical_nested_sha256=NESTED_SHA,adapted_nested_sha256=sha(src/'nested-client.c'),patch_sha256=sha(patch),protocol_regeneration='byte-identical',protocols={p.name:sha(p) for p in src.glob('*') if p.suffix in ['.h','.xml'] or p.name.endswith('-protocol.c')},C17='PASS',builds=builds,prior_manifests=receipts))
for p in Path(__file__).parent.iterdir():
assert p.suffix in ['.py','.md','.patch'],('generated repository file',p)
shutil.copy2(p,lab/'fixture'/p.name)
if p.suffix=='.py':ast.parse(p.read_text(),filename=str(p))
shutil.copy2(REPO/'docs/design/STEP20C_STATIC_NESTED_VALID_GRAB_PROBE.md',lab/'protocol-before-run.md')
protected=[REPO/p for p in ['AGENTS.md','docs/UX.md','docs/PACKAGING.md','PKGBUILD','patches/0001-mosaic-layout-viewport.patch']]
protected+=[Path('/usr/bin/sway'),wl,Path('/usr/lib/libscenefx-0.5.so').resolve(),BINARY]
protected+=list((REPO/'sway').rglob('*.c'))+list((REPO/'include').rglob('*.h'))
save(lab,'protected-before',{str(p):sha(p) for p in protected})
source=Path('/home/fy59/swayfx-mosaic-static-runtime-hm5kbdkt/mosaic-source')
files=['sway/desktop/transaction.c','sway/desktop/xdg_shell.c','sway/desktop/output.c','sway/tree/view.c','sway/commands/exit.c','sway/ipc-server.c','sway/main.c','sway/commands/layout.c']
save(lab,'candidate-source-audit',{str(source/p):sha(source/p) for p in files})
freeze=[p for root in ['fixture','client-source','historical-source'] for p in (lab/root).rglob('*') if p.is_file()]+[lab/'protocol-before-run.md']
save(lab,'fixture-inventory',inventory(lab/'results/fixture-freeze-sha256.txt',freeze))
print('LAB='+str(lab))

View file

@ -0,0 +1,319 @@
#!/usr/bin/env python3
"""One immutable-static headless process, two genuinely grabbed XDG chains.
WHY: outside dismissal must not preclude standard-return measurements.
CONTRACT: every mutation/injection/capture consumes a persistent reservation.
INVARIANT: only owned groups/sockets; actual codes survive terminal IPC failure.
"""
import argparse
import fcntl
import json
import os
from pathlib import Path
import re
import shutil
import signal
import subprocess
import tempfile
import threading
import time
from PIL import Image
from support import OWNER,BINARY,BINARY_SHA,WLROOTS_SHA,LIMITS,sha,save,reserve,environment,verify
from ipc_predicates import nodes,workspace,validate_outputs,validate_reference,measure_owner,scene_from_log,validate_camera
from predicates import Defect,COLORS,paint,point,equal,reference,protocol,geometry,mapped,pair,dismissal,root_clip,popup_pixels,terminal
p=argparse.ArgumentParser();p.add_argument('lab',type=Path);lab=p.parse_args().lab.resolve()
assert not __import__('sys').flags.optimize,'assertions required'
assert OWNER.read_text().strip()==str(lab) and (lab/'campaign-owner').read_text().strip()==str(OWNER)
lock=(lab/'run.lock').open('a+');fcntl.flock(lock,fcntl.LOCK_EX|fcntl.LOCK_NB)
freeze=verify(lab/'results/fixture-freeze-sha256.txt');gate=json.loads((lab/'results/offline-gate.json').read_text())
assert gate['marker']=='STATIC_NESTED_GRAB_FIXTURE_PREFLIGHT=PASS' and gate['fixture_sha256']==freeze['sha256']
assert json.loads((lab/'results/binary-identity.json').read_text())['status']=='PASS'
assert sha(BINARY)==sha(lab/'swayfx-mosaic')==BINARY_SHA
assert not (lab/'run').exists(),'run path already used'
reserve(lab,'run')
run=lab/'run';run.mkdir();runtime=Path(tempfile.mkdtemp(prefix='msng-',dir='/tmp'));runtime.chmod(0o700)
assert len(os.fsencode(str(runtime/'sway-ipc.4294967295.2147483647.sock')))<108
(run/'runtime-path').write_text(str(runtime)+'\n')
config='output HEADLESS-1 resolution 800x600 scale 1 transform normal position -800 0\noutput HEADLESS-2 resolution 800x600 scale 1 transform normal position 0 0\nworkspace 1 output HEADLESS-1\nworkspace 2 output HEADLESS-2\nfocus_follows_mouse no\nseat seat0 hide_cursor 100\n'
(run/'config').write_text(config)
env=environment();env.update(XDG_RUNTIME_DIR=str(runtime),WLR_BACKENDS='headless',WLR_HEADLESS_OUTPUTS='2',WLR_RENDERER='pixman')
processes=[];files=[];comp=None;pointer=None;failure=None;stage='startup';measures=False;rescue=False
started=time.monotonic();finished=threading.Event();expired=threading.Event();chains={};clips={};captures=[];clicks=[];owners={};camera_rows=[]
def event(kind,**data):
with (run/'events.jsonl').open('a') as out:out.write(json.dumps(dict(ns=time.monotonic_ns(),kind=kind,**data))+'\n')
def spawn(name,argv,debug=False):
assert not expired.is_set()
out=(run/(name+'.log')).open('w');files.append(out)
proc=subprocess.Popen(list(map(str,argv)),stdin=subprocess.PIPE,stdout=out,stderr=subprocess.STDOUT,
text=True,start_new_session=True,env={**env,**({'WAYLAND_DEBUG':'1'} if debug else {})})
processes.append((name,proc));event('spawn',name=name,pid=proc.pid,argv=list(map(str,argv)));return proc
def stop_owned(sig=signal.SIGTERM):
for name,proc in list(processes):
try:os.killpg(proc.pid,sig)
except ProcessLookupError:pass
def watchdog():
while not finished.wait(.1):
if time.monotonic()-started>150 or any(p.stat().st_size>32*1024*1024 for p in run.glob('*.log')):
expired.set();stop_owned();return
thread=threading.Thread(target=watchdog,daemon=True);thread.start()
def log(name):return (run/(name+'.log')).read_text(errors='replace')
def wait(fn,seconds=6):
end=min(time.monotonic()+seconds,started+143)
while time.monotonic()<end:
if expired.is_set():raise RuntimeError('deadline/log bound exceeded')
if comp is not None and comp.poll() is not None:raise RuntimeError('unexpected compositor exit '+str(comp.returncode))
value=fn()
if value:return value
time.sleep(.025)
raise RuntimeError('fixture wait timeout at '+stage)
def ipc(*args):
assert sock.is_relative_to(runtime) and sock.is_socket()
r=subprocess.run(['swaymsg','-s',str(sock),*args],env=env,capture_output=True,text=True,timeout=4)
event('ipc',args=args,exit=r.returncode,stdout=r.stdout,stderr=r.stderr)
assert r.returncode==0,('IPC failure',args,r.returncode)
return json.loads(r.stdout)
def cmd(text):
assert all(x['success'] for x in ipc(text)),text
def snapshot(tag):
tree=ipc('-t','get_tree');outputs=ipc('-t','get_outputs');ws=ipc('-t','get_workspaces')
data=dict(ns=time.monotonic_ns(),tree=tree,outputs=outputs,workspaces=ws,focused=[n['id'] for n in nodes(tree) if n.get('focused')])
save(lab,tag+'-snapshot',data);return data
def find(app,pid):
candidates=[n for n in nodes(ipc('-t','get_tree')) if n.get('app_id')==app and n.get('pid')==pid]
assert len(candidates)<=1
return candidates[0] if candidates else None
def capture(tag,output):
reserve(lab,'capture');time.sleep(.20)
path=run/(tag+'.png');assert not path.exists()
before=time.monotonic_ns()
r=subprocess.run(['grim','-s','1','-o',output,str(path)],env=env,capture_output=True,text=True,timeout=4)
event('capture',file=path.name,output=output,start_ns=before,exit=r.returncode,stderr=r.stderr)
assert r.returncode==0
im=Image.open(path).convert('RGB');assert im.size==(800,600)
captures.append(dict(file=path.name,output=output,sha256=sha(path),ns=time.monotonic_ns()))
save(lab,'captures',captures);return im
def inject(action,xy,grab=False):
assert action in ['left','right','move'] and len(xy)==2
x,y=xy;assert type(x) is int and type(y) is int and -800<=x<800 and 0<=y<600
kinds=['move'] if action=='move' else ['click','move']+(['grab'] if grab else [])
reserve(lab,*kinds)
marker=f'INJECT_DONE {action} {x+800},{y}';before=log('pointer').count(marker)
pointer.stdin.write(f'{action} {x+800} {y}\n');pointer.stdin.flush()
wait(lambda:log('pointer').count(marker)>before);time.sleep(.18)
event('injection',action=action,global_point=xy,sent=[x+800,y],extent=[1600,600],grab=grab)
def buttons(name):
return [s for s in log(name).splitlines() if s.startswith(('POINTER_BUTTON ','BUTTON '))]
def click(tag,name,xy,grab=False,action='right'):
before={n:len(buttons(n)) for n in [name,'reference','filler']}
t0=time.monotonic_ns();inject(action,xy,grab)
row=dict(tag=tag,global_point=xy,action=action,start_ns=t0,end_ns=time.monotonic_ns(),events={n:buttons(n)[before[n]:] for n in before})
clicks.append(row);save(lab,'clicks',clicks);return row
def delivery(row,name,target):
assert not row['events']['reference'] and not row['events']['filler'],'other client received visible popup button'
return pair(row['events'][name],target)
def correlate_pointer(name,xy,rect,target):
# WHY: an injection request alone does not identify applied popup origin.
rows=re.findall(rf'POINTER_(?:ENTER|MOTION) target={target} .*?x=([\d.-]+) y=([\d.-]+)',log(name))
assert rows,'missing pointer local coordinates'
local=list(map(float,rows[-1]));expected=[xy[0]-rect[0],xy[1]-rect[1]]
assert local==expected,('pointer/global geometry mismatch',target,local,expected)
return dict(global_point=xy,local=local,rectangle=rect)
def close_client(proc,name,value):
proc.stdin.write(value+'\n');proc.stdin.flush()
code=proc.wait(timeout=3);assert code==0,(name,code)
assert 'TOPLEVEL DESTROY' in log(name)
wait(lambda:find('org.mosaic.NestedGrabProbe',proc.pid) is None)
# CONTRACT: applied owner, paint and XDG surface size are distinct measurements.
def owner_state(name,proc,tag):
snap=snapshot(tag);ws=workspace(snap['tree'],'1');owner=next(n for n in nodes(ws) if n.get('pid')==proc.pid)
assert owner['app_id']=='org.mosaic.NestedGrabProbe' and owner['shell']=='xdg_shell' and owner['visible']
assert ws['output']=='HEADLESS-1' and owner['focused'] and snap['focused']==[owner['id']]
measured=measure_owner(log('compositor'),owner);scene=scene_from_log(log('compositor'),'HEADLESS-1')
assert scene['workspace']==ws['id']
return snap,ws,owner,measured,scene
def open_chain(name):
global stage
reserve(lab,'chain');cmd('workspace 1');proc=spawn(name,[lab/'nested-client','static_cross'],debug=True)
wait(lambda:find('org.mosaic.NestedGrabProbe',proc.pid) and 'TOPLEVEL MAP ' in log(name));time.sleep(.6)
snap,ws,owner,before,sc=owner_state(name,proc,name+'-before-camera')
assert ws['layout']=='mosaic'
current=ws['mosaic']['rows'][0]['scroll_x'];x,w=before['horizontal_content'];desired=-w//2;delta=int(x-desired)
if delta:
reserve(lab,'camera');cmd(f'[con_id={owner["id"]}] layout mosaic scroll {delta}');time.sleep(.6)
snap,ws,owner,after,scene=owner_state(name,proc,name+'-applied')
validate_camera(current,ws['mosaic']['rows'][0]['scroll_x'],delta,scene)
assert scene['clip_valid'] and scene['global_clip']==[-800,0,800,600]
assert not scene_from_log(log('compositor'),'HEADLESS-2')['clip_valid']
refstate=validate_reference(snap,refid,ref.pid)
camera_rows.append(dict(chain=name,before=current,delta=delta,after=scene['scroll'],before_owner=before,after_owner=after,scene=scene,reference=refstate))
save(lab,'camera-calibration',camera_rows)
if name=='E1':
stage='reference';inject('move',[-790,590]);time.sleep(.5)
first=capture('H2-reference-1','HEADLESS-2');time.sleep(.6)
second=capture('H2-reference-2','HEADLESS-2');cmp=reference(first,second)
save(lab,'reference-stability',dict(status='PASS',comparison=cmp,reference=refstate,interval='>=600ms',focus=snap['focused']))
global baseline
baseline=first
stage=name+'-open-A';topim=capture(name+'-top','HEADLESS-1')
topbox=paint(topim,'TOPLEVEL')['bbox'];assert topbox
# Tiled scene+window offset is checked against actual painted blue origin.
origin=[after['horizontal_content'][0],topbox[1]]
assert topbox[0]-800==origin[0] and topbox[3]-topbox[1]==320
assert origin[1]==after['scene'][1]+owner['window_rect']['y']
owners[name]=dict(id=owner['id'],pid=proc.pid,workspace=ws['id'],logical_rect=owner['rect'],applied=after,drawn_size=[420,320],paint=paint(topim,'TOPLEVEL'),content_origin=origin)
save(lab,'applied-owner-geometry',owners)
cp=click(name+'-open-A',name,point(topim,'TOPLEVEL',-800),True,'left')
wait(lambda:'POPUP_A MAP ' in log(name));time.sleep(.25)
aim=capture(name+'-A','HEADLESS-1');ap=point(aim,'POPUP_A',-800)
stage=name+'-open-B';click(name+'-open-B',name,ap,True,'left')
wait(lambda:'POPUP_B MAP ' in log(name));time.sleep(.3)
prot=protocol(log(name));g=geometry(log(name),origin)
assert g['configured_A']==[100,80,350,170] and g['configured_B']==[100,60,300,130]
correlate_pointer(name,ap,g['A'],'POPUP_A')
left=capture(name+'-mosaic-H1','HEADLESS-1');right=capture(name+'-mosaic-H2','HEADLESS-2')
rgb=popup_pixels(left,right,g,True,baseline)
clip=root_clip(log('compositor'),origin,True)
chains[name]=dict(protocol=prot,geometry=g,pixels=rgb,owner=owners[name])
clips[name]=dict(tile=scene,root=clip,child=clip['child'])
save(lab,'grab-serials',{n:v['protocol']['grabs'] for n,v in chains.items()})
save(lab,'xdg-protocol-order',{n:v['protocol'] for n,v in chains.items()})
save(lab,'popup-root-geometry',{n:v['geometry']['A'] for n,v in chains.items()})
save(lab,'popup-nested-geometry',{n:v['geometry']['B'] for n,v in chains.items()})
save(lab,'applied-clips',clips);save(lab,'mosaic-pixels',{n:v['pixels'] for n,v in chains.items()})
return proc,owner,g,left
try:
comp=spawn('compositor',[lab/'swayfx-mosaic','-d','-c',run/'config'])
sock=wait(lambda:next(iter(runtime.glob('sway-ipc.*.sock')),None))
display=wait(lambda:next((x for x in runtime.glob('wayland-*') if x.is_socket()),None))
env.update(WAYLAND_DISPLAY=display.name,SWAYSOCK=str(sock))
assert Path(f'/proc/{comp.pid}/exe').resolve()==lab/'swayfx-mosaic'
maps=Path(f'/proc/{comp.pid}/maps').read_text();(run/'proc-maps.txt').write_text(maps)
paths=sorted({s.split()[-1] for s in maps.splitlines() if len(s.split())>=6 and s.split()[-1].startswith('/')})
wl=Path('/usr/lib/libwlroots-0.20.so').resolve()
assert [Path(x).resolve() for x in paths if 'libwlroots' in x]==[wl] and sha(wl)==WLROOTS_SHA
assert not any('libscenefx' in x for x in paths)
save(lab,'dependency-mappings',dict(status='PASS',paths=paths,wlroots=str(wl),wlroots_sha256=sha(wl),SceneFX_shared=False))
outputs=ipc('-t','get_outputs');validate_outputs(outputs);save(lab,'output-geometry',outputs)
pointer=spawn('pointer',[lab/'pointer-daemon']);wait(lambda:'POINTER_READY' in log('pointer'))
cmd('workspace 2');ref=spawn('reference',[lab/'static-reference'],debug=True)
rn=wait(lambda:find('org.mosaic.StaticReference',ref.pid));refid=rn['id'];cmd(f'[con_id={refid}] border none')
cmd('workspace 1');filler=spawn('filler',[lab/'static-reference'],debug=True)
wait(lambda:find('org.mosaic.StaticReference',filler.pid));cmd('layout mosaic')
E1,owner1,g1,im1=open_chain('E1')
stage='E1-visible-B';xy=point(im1,'POPUP_B',-800);row=click(stage,'E1',xy)
result=delivery(row,'E1','POPUP_B');coords=correlate_pointer('E1',xy,g1['B'],'POPUP_B');mapped(log('E1'))
save(lab,'mosaic-input',dict(status='PASS',pair=result,coordinates=coords,click=row))
stage='E1-forbidden-B';B=g1['B'];xy=[int((max(0,B[0])+min(800,B[0]+B[2]))//2),B[1]+30]
assert B[0]<=xy[0]<B[0]+B[2] and 8<=xy[0]<792
cut=len(log('E1'));row=click(stage,'E1',xy);time.sleep(.3)
ds=dismissal(log('E1')[cut:],row['events']['E1']);save(lab,'dismissal',ds)
refpair=row['events']['reference'];assert len(refpair) in [0,2]
save(lab,'forbidden-input',dict(status='PASS',click=row,popup_events=row['events']['E1'],reference_events=refpair,dismissal=ds))
inject('move',[-790,590]);clean=capture('E1-dismissed-H2','HEADLESS-2')
assert equal(baseline,clean)['equal'],'E1 dismissal residue'
close_client(E1,'E1','close_owner')
E2,owner2,g2,im2=open_chain('E2');assert owner2['id']!=owner1['id'] and E2.pid!=E1.pid
s1=[g['serial'] for g in chains['E1']['protocol']['grabs']];s2=[g['serial'] for g in chains['E2']['protocol']['grabs']]
assert len(set(s1+s2))==4 and max(s1)<min(s2),'serial reuse across chains'
stage='E2-standard';mapped(log('E2'));reserve(lab,'transition');cmd(f'[con_id={owner2["id"]}] layout splith');time.sleep(.6)
snap,ws,std_owner,std_measure,std_scene=owner_state('E2',E2,'standard')
assert ws['id']==owners['E2']['workspace'] and ws['layout']=='splith'
if std_scene['clip_valid'] or std_scene['layout_enum']!=1:raise Defect('standard tiled clip retained')
mapped(log('E2'))
stdleft=capture('standard-H1','HEADLESS-1');stdright=capture('standard-H2','HEADLESS-2')
blue=paint(stdleft,'TOPLEVEL')['bbox'];assert blue
stdorigin=[std_measure['horizontal_content'][0],blue[1]];assert blue[0]-800==stdorigin[0]
stdg=geometry(log('E2'),stdorigin);stdclip=root_clip(log('compositor'),stdorigin,False)
stdrgb=popup_pixels(stdleft,stdright,stdg,False,baseline)
save(lab,'standard-return',dict(status='PASS',same_workspace=ws['id'],owner=std_owner,applied=std_measure,scene=std_scene,root_clip=stdclip,child_clip='no independent clip in exact source; standard B pixels/input exercise removed inherited boundary',geometry=stdg,mapped_before_and_after=True,no_prior_popup_done=True))
save(lab,'standard-popup-pixels',stdrgb)
stage='E2-standard-B';xy=point(stdright,'POPUP_B',0);row=click(stage,'E2',xy)
Bpair=delivery(row,'E2','POPUP_B');Bcoords=correlate_pointer('E2',xy,stdg['B'],'POPUP_B');mapped(log('E2'))
E2.stdin.write('close_b\n');E2.stdin.flush();wait(lambda:'COMMAND close_b DONE' in log('E2'))
assert 'POPUP_B DESTROY ' in log('E2') and 'POPUP_A DESTROY ' not in log('E2') and 'POPUP_A POPUP_DONE ' not in log('E2')
stage='E2-standard-A';Aimage=capture('standard-A-H2','HEADLESS-2');assert paint(Aimage,'POPUP_B')['count']==0
xy=point(Aimage,'POPUP_A',0);rowA=click(stage,'E2',xy);Apair=delivery(rowA,'E2','POPUP_A')
Acoords=correlate_pointer('E2',xy,stdg['A'],'POPUP_A')
save(lab,'standard-popup-input',dict(status='PASS',B=Bpair,A=Apair,B_coordinates=Bcoords,A_coordinates=Acoords,explicit_B_close=True,A_survived=True))
stage='E2-cleanup';close_client(E2,'E2','close_owner');time.sleep(.35)
final=capture('final-H2','HEADLESS-2');assert equal(baseline,final)['equal'],'final H2 residue'
assert not any(paint(final,n)['count'] for n in ['POPUP_A','POPUP_B'])
snap=snapshot('final');validate_reference(snap,refid,ref.pid)
assert filler.poll() is None and ref.poll() is None
measures=True;event('measurements-completed',status='PASS');stage='completed'
except Exception as exc:
failure=dict(type=type(exc).__name__,message=str(exc),stage=stage,verdict='BLOCKED' if isinstance(exc,Defect) else 'INCONCLUSIVE')
event('failure',**failure)
finally:
# WHY: shutdown transport outcome is not folded into check=True scientific gates.
exit_data=None
if comp is not None and comp.poll() is None and 'sock' in globals() and sock.is_socket():
try:
r=subprocess.run(['swaymsg','-s',str(sock),'exit'],env=env,capture_output=True,text=True,timeout=3)
(run/'terminal-exit.stdout').write_text(r.stdout);(run/'terminal-exit.stderr').write_text(r.stderr)
comp_code=comp.wait(timeout=3)
bad_protocol=any(re.search(r'wl_display[^\n]*\.error\(|protocol error',log(n),re.I) for n,_ in processes if n not in ['compositor','pointer'])
exit_data=terminal(measures,r.returncode,comp_code,log('compositor'),bad_protocol,expired.is_set())
exit_data.update(stdout=r.stdout,stderr=r.stderr,measurements_completed=measures)
except Exception as exc:
exit_data=dict(scientific_cleanup_pass=False,error=repr(exc),measurements_completed=measures)
if exit_data is None:exit_data=dict(scientific_cleanup_pass=False,compositor_exit=comp.poll() if comp else None,measurements_completed=measures)
codes=[]
for name,proc in reversed(processes):
if proc.poll() is None:
try:proc.wait(timeout=.7)
except subprocess.TimeoutExpired:
if name=='pointer':proc.stdin.close() # normal EOF destroys virtual pointer
else:
rescue=True
try:os.killpg(proc.pid,signal.SIGTERM)
except ProcessLookupError:pass
try:proc.wait(timeout=.7)
except subprocess.TimeoutExpired:
rescue=True
try:os.killpg(proc.pid,signal.SIGKILL)
except ProcessLookupError:pass
proc.wait(timeout=.7)
codes.append(dict(name=name,pid=proc.pid,exit=proc.returncode))
if proc.stdin and not proc.stdin.closed:proc.stdin.close()
finished.set();thread.join(timeout=1)
for out in files:out.close()
for name,proc in processes:
try:os.killpg(proc.pid,0)
except ProcessLookupError:pass
else:rescue=True;os.killpg(proc.pid,signal.SIGKILL)
assert all(not Path('/proc',str(row['pid'])).exists() for row in codes),'owned process residual'
private_sockets=[str(p) for p in runtime.iterdir() if p.is_socket()]
shutil.rmtree(runtime)
exit_data.update(rescue_cleanup=rescue,owned_process_codes=codes)
if rescue:exit_data['scientific_cleanup_pass']=False
if measures and (not exit_data['scientific_cleanup_pass'] or any(r['exit']!=0 for r in codes)):
failure=dict(type='TerminalCleanupFailure',message='terminal/process evidence failed',stage='completed',verdict='INCONCLUSIVE')
save(lab,'terminal-exit',exit_data)
save(lab,'cleanup',dict(status='PASS' if not rescue else 'RESCUE',runtime=str(runtime),runtime_removed=not runtime.exists(),owned_processes=codes,sockets_before_owned_directory_removal=private_sockets,private_socket_residual=False))
save(lab,'runtime',dict(status='PASS' if failure is None else failure['verdict'],failure=failure,stage=stage,measurements_completed=measures,duration_seconds=time.monotonic()-started,watchdog=expired.is_set(),rescue_cleanup=rescue,runner_exit=0 if failure is None else 1))
verify(lab/'results/fixture-freeze-sha256.txt')
print('RUNTIME', 'PASS' if failure is None else failure)
raise SystemExit(0 if failure is None else 1)

View file

@ -0,0 +1,100 @@
"""Private probe ownership, durable budgets and bounded argv execution.
WHY: an exhausted experiment must not be restarted by replacing its LAB.
CONTRACT: stable exclusive owner and lock files; fsync precedes every action.
INVARIANT: failures consume all reservations, never refund or reset counters.
"""
import fcntl
import hashlib
import json
import os
from pathlib import Path
import subprocess
import tempfile
import time
REPO = Path('/home/fy59/Documents/Development/swayfx-mosaic')
OWNER = Path.home() / 'swayfx-mosaic-static-nested-grab-v1.owner'
BINARY = Path('/home/fy59/swayfx-mosaic-static-runtime-hm5kbdkt/stage-static/usr/bin/swayfx-mosaic')
BINARY_SHA = 'f82557c1a9978a5e9665b9b4291b74880253725359e3df1c5b8d554921f7603b'
WLROOTS_SHA = '7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837'
NESTED_SHA = '2e40c98af72a0df8b316810589a0be8f4425a763db1de448b49a7813956b6f7d'
LIMITS = dict(run=1, chain=2, grab=4, click=9, capture=16, camera=2, transition=1, move=24)
def sha(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def save(lab, name, data):
(Path(lab)/'results'/(name+'.json')).write_text(json.dumps(data,indent=2)+'\n')
def durable(path, data):
fd,tmp=tempfile.mkstemp(prefix='.ledger-',dir=path.parent)
with os.fdopen(fd,'w') as out:
json.dump(data,out,indent=2);out.write('\n');out.flush();os.fsync(out.fileno())
os.replace(tmp,path)
fd=os.open(path.parent,os.O_RDONLY|os.O_DIRECTORY)
try:os.fsync(fd)
finally:os.close(fd)
def initial(lab):
path=Path(lab)/'results/budget.json'
with path.open('x') as out:
json.dump(dict(limits=LIMITS,used=dict.fromkeys(LIMITS,0),events=[]),out,indent=2)
out.write('\n');out.flush();os.fsync(out.fileno())
fd=os.open(path.parent,os.O_RDONLY|os.O_DIRECTORY)
try:os.fsync(fd)
finally:os.close(fd)
def reserve(lab, *kinds):
lab=Path(lab)
with (lab/'budget.lock').open('a+') as lock:
fcntl.flock(lock,fcntl.LOCK_EX)
path=lab/'results/budget.json';state=json.loads(path.read_text())
valid=(state.get('limits')==LIMITS and set(state.get('used',{}))==set(LIMITS)
and all(type(state['used'][k]) is int and 0<=state['used'][k]<=LIMITS[k] for k in LIMITS)
and len(state.get('events',[]))==sum(state['used'].values())
and all(e.get('seq')==i and e.get('kind') in LIMITS for i,e in enumerate(state.get('events',[])))
and all(sum(e['kind']==k for e in state['events'])==state['used'][k] for k in LIMITS))
if not valid or not kinds or any(k not in LIMITS for k in kinds):
raise RuntimeError('corrupt/invalid ledger')
if any(state['used'][k]+kinds.count(k)>LIMITS[k] for k in kinds):
raise RuntimeError('budget exhausted')
for k in kinds:
state['used'][k]+=1
state['events'].append(dict(seq=len(state['events']),kind=k,ns=time.monotonic_ns()))
durable(path,state)
return state
def environment():
# WHY: inherited desktop/loader settings must not select a daily socket.
excluded={'DISPLAY','WAYLAND_DISPLAY','SWAYSOCK','I3SOCK','XDG_RUNTIME_DIR',
'WAYLAND_DEBUG','DBUS_SESSION_BUS_ADDRESS','XDG_SESSION_ID','XDG_SEAT',
'XDG_VTNR','XDG_SESSION_TYPE','XDG_CURRENT_DESKTOP','XDG_SESSION_DESKTOP',
'LD_LIBRARY_PATH','LD_PRELOAD','LD_AUDIT','PKG_CONFIG_PATH','WLR_BACKENDS',
'WLR_RENDERER','WLR_HEADLESS_OUTPUTS','WLR_DRM_DEVICES','WLR_LIBINPUT_NO_DEVICES'}
env={k:v for k,v in os.environ.items() if k not in excluded and not k.startswith('WLR_')}
env.update(LC_ALL='C',PYTHONDONTWRITEBYTECODE='1')
return env
def command(lab,label,argv,cwd=None):
result=subprocess.run(list(map(str,argv)),cwd=cwd,env=environment(),capture_output=True,text=True,timeout=30)
(lab/'raw'/(label+'.stdout')).write_text(result.stdout)
(lab/'raw'/(label+'.stderr')).write_text(result.stderr)
with (lab/'raw/commands.jsonl').open('a') as out:
out.write(json.dumps(dict(label=label,argv=list(map(str,argv)),exit=result.returncode,cwd=str(cwd)))+'\n')
assert result.returncode==0,(label,result.returncode,result.stderr)
return result.stdout
def verify(manifest):
seen=set()
for row in Path(manifest).read_text().splitlines():
digest,p=row.split(' ',1)
assert p not in seen and sha(p)==digest,(manifest,p)
seen.add(p)
assert seen
return dict(entries=len(seen),sha256=sha(manifest))
def inventory(path, files):
with Path(path).open('x') as out:
for p in sorted(files):out.write(f'{sha(p)} {p}\n')
return verify(path)