docs(mosaic): preserve optimized blur edge causality evidence
This commit is contained in:
parent
e749653ccd
commit
7c22b4020e
18 changed files with 1867 additions and 0 deletions
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
### STEP20C experimental evidence
|
### STEP20C experimental evidence
|
||||||
|
|
||||||
|
- Preserved optimized-edge gate: four completed controls reproduce the same boundary differences in pristine SceneFX, private splith and Mosaic without OPT traces. Same-binary Mosaic trace-off/on and pristine/private standard match full RGB at six states; central freshness, H2 stability and sampled clipping hold. PARTIALLY_FEASIBLE, architecture UNDECIDED: reduced-domain FBO history has source/model support but no native causal observation. Separate ABI/package audit justified; optional bounded GPU study remains unexecuted. No production change; historical graphical campaign closed.
|
||||||
|
|
||||||
- Preserved optimized blur cache probe: private splith/Mosaic used a real background source and output-scoped GPU cache, naturally reconstructed A/B/A and restored exact central filtered pixels with stable whole H2 RGB. Boundary equivalence still differs by up to six RGB levels in both private modes. Pristine C0 failed before captures; its duplicate initial image was charged after observation, with no retry or numerical budget overrun. PARTIALLY_FEASIBLE, architecture UNDECIDED; neutrality and whole-cache correctness unqualified. No production change; the historical campaign is closed.
|
- Preserved optimized blur cache probe: private splith/Mosaic used a real background source and output-scoped GPU cache, naturally reconstructed A/B/A and restored exact central filtered pixels with stable whole H2 RGB. Boundary equivalence still differs by up to six RGB levels in both private modes. Pristine C0 failed before captures; its duplicate initial image was charged after observation, with no retry or numerical budget overrun. PARTIALLY_FEASIBLE, architecture UNDECIDED; neutrality and whole-cache correctness unqualified. No production change; the historical campaign is closed.
|
||||||
|
|
||||||
- Preserved saved-target natural timeout gate: one Mosaic run used a static SHM H2 reference with four identical whole-RGB captures. The measured target saved node crossed x=0, rendered 182,214 retained-color pixels on H1, contributed no H2 pixels and was removed after a real 2500 ms timeout while the client held serial 50 alive. Two sampled pointer points found the H2 reference and visible H1 saved node. PARTIALLY_FEASIBLE because complete damage, broader input and GPU/texture lifetime remain unqualified; no production change.
|
- Preserved saved-target natural timeout gate: one Mosaic run used a static SHM H2 reference with four identical whole-RGB captures. The measured target saved node crossed x=0, rendered 182,214 retained-color pixels on H1, contributed no H2 pixels and was removed after a real 2500 ms timeout while the client held serial 50 alive. Two sampled pointer points found the H2 reference and visible H1 saved node. PARTIALLY_FEASIBLE because complete damage, broader input and GPU/texture lifetime remain unqualified; no production change.
|
||||||
|
|
|
||||||
|
|
@ -329,3 +329,16 @@ whole-cache equivalence and intermediate frames remain unqualified. A
|
||||||
separate pristine/untraced boundary-sampling gate should precede ABI/package
|
separate pristine/untraced boundary-sampling gate should precede ABI/package
|
||||||
qualification. This evidence freeze changes no production or UX contract.
|
qualification. This evidence freeze changes no production or UX contract.
|
||||||
STEP20C stays **NEXT**, multi-output **NOT YET SUPPORTED**.
|
STEP20C stays **NEXT**, multi-output **NOT YET SUPPORTED**.
|
||||||
|
|
||||||
|
The preserved [optimized edge causality gate](design/STEP20C_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE.md)
|
||||||
|
is **PARTIALLY_FEASIBLE**, architecture **UNDECIDED**. Four completed fixed
|
||||||
|
negative-origin runs qualify pristine/private splith and same-binary Mosaic
|
||||||
|
OPT-off/on controls. Pristine/private full images and Mosaic trace-off/on
|
||||||
|
full images are exact at six homologous states; common glass across layouts
|
||||||
|
is also exact. Historical right/bottom differences persist without new traces,
|
||||||
|
with max RGB delta 6, fresh central pixels and stable whole H2. Native FBO
|
||||||
|
history causality remains unproved despite source/model support. R3 damage
|
||||||
|
extents cover stabilized differences only. No clipping regression or required
|
||||||
|
invariant violation is established. A separate SceneFX ABI/package audit is
|
||||||
|
now justified, retaining this shared rendering limitation; optional selective
|
||||||
|
GPU observation requires a new scoped ticket. This evidence is preserved without a production change. STEP20C stays NEXT, production multi-output NOT YET SUPPORTED.
|
||||||
|
|
|
||||||
|
|
@ -270,3 +270,16 @@ whole-cache equivalence and intermediate frames remain unqualified. A
|
||||||
separate pristine/untraced boundary-sampling gate should precede ABI/package
|
separate pristine/untraced boundary-sampling gate should precede ABI/package
|
||||||
qualification. This evidence freeze changes no production or UX contract.
|
qualification. This evidence freeze changes no production or UX contract.
|
||||||
STEP20C stays **NEXT**, multi-output **NOT YET SUPPORTED**.
|
STEP20C stays **NEXT**, multi-output **NOT YET SUPPORTED**.
|
||||||
|
|
||||||
|
The preserved [optimized edge causality gate](design/STEP20C_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE.md)
|
||||||
|
is **PARTIALLY_FEASIBLE**, architecture **UNDECIDED**. Four completed fixed
|
||||||
|
negative-origin runs qualify pristine/private splith and same-binary Mosaic
|
||||||
|
OPT-off/on controls. Pristine/private full images and Mosaic trace-off/on
|
||||||
|
full images are exact at six homologous states; common glass across layouts
|
||||||
|
is also exact. Historical right/bottom differences persist without new traces,
|
||||||
|
with max RGB delta 6, fresh central pixels and stable whole H2. Native FBO
|
||||||
|
history causality remains unproved despite source/model support. R3 damage
|
||||||
|
extents cover stabilized differences only. No clipping regression or required
|
||||||
|
invariant violation is established. A separate SceneFX ABI/package audit is
|
||||||
|
now justified, retaining this shared rendering limitation; optional selective
|
||||||
|
GPU observation requires a new scoped ticket. This evidence is preserved without a production change. STEP20C stays NEXT, production multi-output NOT YET SUPPORTED.
|
||||||
|
|
|
||||||
|
|
@ -179,3 +179,19 @@ whole-cache equivalence and intermediate frames remain unqualified. A
|
||||||
separate pristine/untraced boundary-sampling gate should precede ABI/package
|
separate pristine/untraced boundary-sampling gate should precede ABI/package
|
||||||
qualification. This evidence freeze changes no production or UX contract.
|
qualification. This evidence freeze changes no production or UX contract.
|
||||||
STEP20C stays **NEXT**, multi-output **NOT YET SUPPORTED**.
|
STEP20C stays **NEXT**, multi-output **NOT YET SUPPORTED**.
|
||||||
|
|
||||||
|
The preserved [optimized edge causality gate](design/STEP20C_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE.md)
|
||||||
|
is **PARTIALLY_FEASIBLE**, architecture **UNDECIDED**. Four completed fixed
|
||||||
|
negative-origin runs qualify pristine/private splith and same-binary Mosaic
|
||||||
|
OPT-off/on controls. Pristine/private full images and Mosaic trace-off/on
|
||||||
|
full images are exact at six homologous states; common glass across layouts
|
||||||
|
is also exact. Historical right/bottom differences persist without new traces,
|
||||||
|
with max RGB delta 6, fresh central pixels and stable whole H2. Native FBO
|
||||||
|
history causality remains unproved despite source/model support. R3 damage
|
||||||
|
extents cover stabilized differences only. No clipping regression or required
|
||||||
|
invariant violation is established. A separate SceneFX ABI/package audit is
|
||||||
|
now justified, retaining this shared rendering limitation; optional selective
|
||||||
|
GPU observation requires a new scoped ticket. This evidence is preserved without a production change. STEP20C stays NEXT, production multi-output NOT YET SUPPORTED.
|
||||||
|
|
||||||
|
The [preserved edge source fixture](../tooling/probes/step20c-optimized-blur-edge/README.md)
|
||||||
|
records pinned reconstruction, offline checks and the exhausted four-slot ledger.
|
||||||
|
|
|
||||||
|
|
@ -274,3 +274,16 @@ whole-cache equivalence and intermediate frames remain unqualified. A
|
||||||
separate pristine/untraced boundary-sampling gate should precede ABI/package
|
separate pristine/untraced boundary-sampling gate should precede ABI/package
|
||||||
qualification. This evidence freeze changes no production or UX contract.
|
qualification. This evidence freeze changes no production or UX contract.
|
||||||
STEP20C stays **NEXT**, multi-output **NOT YET SUPPORTED**.
|
STEP20C stays **NEXT**, multi-output **NOT YET SUPPORTED**.
|
||||||
|
|
||||||
|
The preserved [optimized edge causality gate](design/STEP20C_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE.md)
|
||||||
|
is **PARTIALLY_FEASIBLE**, architecture **UNDECIDED**. Four completed fixed
|
||||||
|
negative-origin runs qualify pristine/private splith and same-binary Mosaic
|
||||||
|
OPT-off/on controls. Pristine/private full images and Mosaic trace-off/on
|
||||||
|
full images are exact at six homologous states; common glass across layouts
|
||||||
|
is also exact. Historical right/bottom differences persist without new traces,
|
||||||
|
with max RGB delta 6, fresh central pixels and stable whole H2. Native FBO
|
||||||
|
history causality remains unproved despite source/model support. R3 damage
|
||||||
|
extents cover stabilized differences only. No clipping regression or required
|
||||||
|
invariant violation is established. A separate SceneFX ABI/package audit is
|
||||||
|
now justified, retaining this shared rendering limitation; optional selective
|
||||||
|
GPU observation requires a new scoped ticket. This evidence is preserved without a production change. STEP20C stays NEXT, production multi-output NOT YET SUPPORTED.
|
||||||
|
|
|
||||||
500
docs/design/STEP20C_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE.md
Normal file
500
docs/design/STEP20C_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE.md
Normal file
|
|
@ -0,0 +1,500 @@
|
||||||
|
# STEP20C optimized blur edge history and instrumentation gate
|
||||||
|
|
||||||
|
**EXPERIMENTAL / protocol recorded before new fixture development.**
|
||||||
|
The separate cache evidence freeze passed at
|
||||||
|
`e749653ccda42abad9a66a11009be6043b5b6f62`, directly verified on Forgejo
|
||||||
|
and GitHub with a clean main. The completed experimental evidence is preserved for publication. STEP20A DONE, STEP20B EXPERIMENTAL, STEP20C NEXT, STEP20D–G
|
||||||
|
PLANNED. Production multi-output Mosaic is NOT YET SUPPORTED.
|
||||||
|
No UX, production source, cumulative patch, PKGBUILD, system dependency,
|
||||||
|
shader, rendering algorithm or ABI change is authorized.
|
||||||
|
|
||||||
|
## Evidence and competing hypotheses
|
||||||
|
|
||||||
|
The [V1 cache probe](STEP20C_OPTIMIZED_BLUR_CACHE_PROBE.md) already established
|
||||||
|
actual FX/GLES 3.2, BACKGROUND cache source, optimized selection, natural
|
||||||
|
A/B/A dirty/rebuild/copy, fresh central 80,000 pixels, stable whole H2,
|
||||||
|
sampled clipping/damage/teardown. Its whole-H1 B-natural/B-explicit differences
|
||||||
|
were 36,776 private splith and 33,915 Mosaic; A-initial/A-return differences
|
||||||
|
38,308 and 35,340, maximum RGB delta 6. Common boundary ROI counts were
|
||||||
|
19,007 and 20,486. These are not excluded or dismissed as rounding.
|
||||||
|
C0 failed before captures through duplicate configure-driven initial images;
|
||||||
|
its second image was charged after observation, a reservation deviation.
|
||||||
|
The corrected client ACKs configures without drawing. Historical sources,
|
||||||
|
PNGs, logs, manifests and ledger stay intact; no V1 run is repeated.
|
||||||
|
Instrumentation neutrality and pristine graphical behavior were NOT TESTED.
|
||||||
|
|
||||||
|
| Hypothesis | Discriminating evidence | Limit |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| H1 reduced-domain FBO history | Source-domain audit, spatial distributions, offline pinned-kernel predictions, identical-source repeat | Native tail content is not read; correlation cannot establish GPU causality |
|
||||||
|
| H2 new cache traces | R2/R3 same source/library/binary/client/config, OPT_TRACE alone varies | Independent timing; equality is sampled neutrality, not universal proof |
|
||||||
|
| H3 shared SceneFX property | Completed R0 pristine versus R1 private splith and R2/R3 | Private clipping and older passive traces differ from pristine |
|
||||||
|
| H4 blur command cycle state | B unchanged during one disable/enable, client events, configuration, native R3 dirty/rebuild | Cycle rearranges blur and dirties all outputs; not identical to source-only commit |
|
||||||
|
| H5 another observed rendering factor | Geometry, alpha, source colors, renderer, timing, filtering, presentation evidence | Do not invent an unobserved explanation |
|
||||||
|
|
||||||
|
## Fixed comparative matrix and binary differences
|
||||||
|
|
||||||
|
| Run | Compositor / layout | New cache traces |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| R0 | pristine SwayFX 0.6 / splith + pristine SceneFX 0.5 | absent, no private patches |
|
||||||
|
| R1 | private historical compositor / splith | OPT_TRACE absent |
|
||||||
|
| R2 | same private compositor / mosaic | OPT_TRACE absent |
|
||||||
|
| R3 | identical private compositor / mosaic | OPT_TRACE=1 |
|
||||||
|
|
||||||
|
Pinned pristine SwayFX `fd71a6bdc061bd633b488ae7b83e8a6981d22f86`, Mosaic
|
||||||
|
`cd550382b311efdbfe3ed892f4e1d281d852e754`, SceneFX
|
||||||
|
`37ccd723bef49e6891156ffafce8f549f01446cc`, compatible installed wlroots 0.20.
|
||||||
|
Private builds apply unchanged inherited clip/popup/guard/timing/presentation
|
||||||
|
patches and the exact V1 cache/source trace patches. R1/R2/R3 load the same
|
||||||
|
library and binary. Their old SPIKE/TEMPORAL/PI traces are always active;
|
||||||
|
"trace-off" means the new OPT cache/source logs are disabled, not all logging.
|
||||||
|
OPT_LOG tests getenv presence, so OPT_TRACE=0 is not trace-off. Only presence
|
||||||
|
changes for R2/R3. Borrowed trace-only reads outside OPT_LOG remain in both.
|
||||||
|
No neutral instrumentation claim precedes the graphics. B does not modify
|
||||||
|
those patches or add renderer instrumentation.
|
||||||
|
|
||||||
|
## Geometry, graphical inputs and parameters
|
||||||
|
|
||||||
|
Two headless outputs only: H1 HEADLESS-1 at (-800,0), H2 HEADLESS-2 at (0,0),
|
||||||
|
both 800×600 physical/logical, scale=1, transform=normal. Record actual IPC
|
||||||
|
rect/mode/scale/transform and PNG dimensions. No rotation, scaling, hotplug,
|
||||||
|
resize, migration, popup, saved-buffer episode, animation or stress test.
|
||||||
|
At most one initial Mosaic camera correction calculated from actual applied
|
||||||
|
camera and glass geometry; no hide/return pair or P1–P3 camera change.
|
||||||
|
|
||||||
|
Reuse V1 deterministic SHM patterns exactly: BACKGROUND layer on H1, opaque
|
||||||
|
8-pixel stripes A=(245,245,245)/(15,25,45), B=(32,192,224)/(176,32,64).
|
||||||
|
Same 800×600 XRGB image for each reserved commit. Glass premultiplied ARGB
|
||||||
|
0x88442010, transparent ARGB filler, static XDG SHM reference H2. No terminal
|
||||||
|
cursor or animation. XDG configure-driven size submissions are logged separately
|
||||||
|
from the three explicitly reserved background images. No background configure
|
||||||
|
may submit pixels. Require two independent whole-H2 captures equal before FX2.
|
||||||
|
|
||||||
|
Fixed blur radius=5, passes=3, noise=0, brightness=contrast=saturation=1,
|
||||||
|
xray=off, shadows=off, corners=0, compositor opacity=1. Audit pinned command
|
||||||
|
syntax/source; save applied container/tree and startup config. Acceptance is
|
||||||
|
not effect evidence: exposed stripe colors calibrate the source; FX0/FX2
|
||||||
|
central contrast reduction demonstrates actual filtering. R3 must additionally
|
||||||
|
show FX renderer, optimized node under blur_tree, BACKGROUND path, optimized=1,
|
||||||
|
selected FBO, successful rebuild and cache copies. Other runs provide config,
|
||||||
|
source and pixel evidence without fabricated absent OPT traces.
|
||||||
|
|
||||||
|
## Pre-registered regions and comparisons
|
||||||
|
|
||||||
|
All coordinates below are output-local half-open physical rectangles:
|
||||||
|
|
||||||
|
| Region | Rectangle |
|
||||||
|
| --- | --- |
|
||||||
|
| glass center | (520,100,720,500), 80,000 pixels |
|
||||||
|
| exposed source | (20,100,160,500) |
|
||||||
|
| historical right boundary | (720,50,800,550) |
|
||||||
|
| physical right diagnostic | (750,0,800,600) |
|
||||||
|
| physical bottom diagnostic | (0,550,800,600) |
|
||||||
|
| whole H1 / whole H2 | (0,0,800,600) |
|
||||||
|
|
||||||
|
No diagnostic region is an exclusion. Every full-equality comparison uses all
|
||||||
|
800×600 RGB pixels. Intra-run full images always remain reported. Inter-layout
|
||||||
|
comparisons use only actually homologous source/common glass rectangles and
|
||||||
|
explicitly retain distinct glass extents (historically splith x=400, Mosaic
|
||||||
|
x=480); R0/R1 and R2/R3 full-image equality requires matching applied geometry.
|
||||||
|
Measure changed pixels, max channel delta, mean absolute channel delta,
|
||||||
|
per-channel amplitude histogram, bounding box, changed-pixel count per column
|
||||||
|
and per row, every ROI, H2 full differences, capture hashes and timestamps.
|
||||||
|
|
||||||
|
## One deterministic sequence per reserved run
|
||||||
|
|
||||||
|
P0: connect and map background with initial bufferless commit; wait/ACK all
|
||||||
|
layer configures, assert no image submitted, reserve then command A once.
|
||||||
|
Map filler/glass/static H2, settle actual geometry/focus and initial camera.
|
||||||
|
Capture FX0 H1/H2, later independent H2. Assert source colors and stable H2.
|
||||||
|
Enable scoped glass blur, settle, capture FX2 H1/H2; verify filtering.
|
||||||
|
P1: reserve and command B exactly once, keep blur/geometry unchanged, settle,
|
||||||
|
capture H1/H2. P2: no client image; reserve one explicit cycle, scoped blur
|
||||||
|
disable then enable with ordinary commands, settle and capture H1/H2.
|
||||||
|
P3: reserve and command A once, keep all else fixed, settle, capture H1/H2;
|
||||||
|
one later H1 confirmation must match whole RGB. Total 12 PNG per run.
|
||||||
|
|
||||||
|
Settling uses client command receipt, unchanged applied IPC geometry, at least
|
||||||
|
350 ms without intentional mutation before each measured capture; last H1
|
||||||
|
has an independent 350 ms confirmation. Native R3 logs are checked for source
|
||||||
|
commit/rebuild before capture and competing events in capture windows. Earlier
|
||||||
|
states lack duplicate H1 PNGs under the finite budget; that limits claims of
|
||||||
|
stability, especially if event/capture windows disagree. No screenshot gains
|
||||||
|
a native output-buffer identity from proximity to a commit or present.
|
||||||
|
|
||||||
|
Comparisons: FX0 A/FX2 A, P0 FX2/P3 A, P1 B/P2 B, R0/R1 homologous states,
|
||||||
|
R2/R3 homologous states, and common edge regions across layouts. Inspect
|
||||||
|
source A/B/A submission order, sizes, events and frame timing before attribution.
|
||||||
|
No deliberate focus, resize, camera, alpha, radius, passes or source mutation
|
||||||
|
outside this sequence. If a second unreserved A submission appears: abort,
|
||||||
|
retain evidence, consume reservation, no rerun, dependent results INCONCLUSIVE.
|
||||||
|
|
||||||
|
## Sampling and command audit before graphics
|
||||||
|
|
||||||
|
Inspect pinned render_blur_segments/get_main_buffer_blur, blur1.frag/blur2.frag,
|
||||||
|
texture filter/wrap, FBO allocation and written/sampled regions. For each of
|
||||||
|
six passes document full framebuffer size, freshly written domain, mapping,
|
||||||
|
radius/taps, bilinear texels beyond the valid domain, possible historical value
|
||||||
|
and expected final influence. Domain sizes for 800×600 are down 400×300,
|
||||||
|
200×150,100×75 then up 200×150,400×300,800×600, inside full-size FBOs.
|
||||||
|
Full-texture GL_CLAMP_TO_EDGE is distinct from reduced valid-domain clamp.
|
||||||
|
The offline model uses ideal bilinear sampling and 8-bit rounding, not native
|
||||||
|
mediump GLES precision, and must be reported as hypothesis only.
|
||||||
|
|
||||||
|
Audit cmd_blur: scoped container blur flag and arrange_container, then dirty
|
||||||
|
all output nodes. Natural BACKGROUND commit dirties its own output. Therefore
|
||||||
|
P1 and P2 need not traverse identical scene/rebuild sequences. Preserve native
|
||||||
|
R3 evidence of H1/H2 counts and scene/damage. No shader modification, forced
|
||||||
|
FBO clearing or GPU readback is authorized. If needed, propose only a later
|
||||||
|
bounded selective-readback protocol after results; do not execute it here.
|
||||||
|
|
||||||
|
## Budgets, isolation and preflight gate
|
||||||
|
|
||||||
|
One new LAB, one persistent campaign ledger in the home directory, exclusive
|
||||||
|
flock, atomic durable replacement, exact schema validation. Four run slots
|
||||||
|
R0–R3, each once; at most 3 background images, 1 blur cycle, 12 PNG, 150 s.
|
||||||
|
Global max 12 images,4 cycles,48 PNG; one initial calibration per Mosaic run,
|
||||||
|
zero camera pairs. Reserve before every launch/action; failed reservations
|
||||||
|
remain consumed, no refund/reset/new-LAB bypass/fifth run.
|
||||||
|
|
||||||
|
Before any compositor launch: Python AST, shell syntax if applicable, offline
|
||||||
|
ledger exhaustion/corruption/concurrency/cross-LAB tests, actual layer callback
|
||||||
|
ACK/no-draw harness, explicit-command audit, SHM widths/formats/bounds/lifetimes,
|
||||||
|
Wayland globals/listeners/output naming/protocol hashes, C17 -Werror, both
|
||||||
|
SceneFX and compositor builds, Meson mosaic-model, all pinned patch checks,
|
||||||
|
private linker identities, cleanup/timeouts. Fixtures are standalone and
|
||||||
|
corrected; C0 originals and historical LAB remain untouched.
|
||||||
|
|
||||||
|
Each run has private mode-0700 XDG_RUNTIME_DIR, private WAYLAND_DISPLAY,
|
||||||
|
explicit SWAYSOCK and swaymsg -s, WLR_BACKENDS=headless. Strip inherited daily
|
||||||
|
socket/display/library/trace variables; use private SceneFX LD_LIBRARY_PATH.
|
||||||
|
Record binary/library hashes, /proc/PID/maps, renderer logs, IPC, configs,
|
||||||
|
client sources, runner exact source, PNGs, capture windows, logs and exits.
|
||||||
|
Terminate only owned process groups; controlled IPC exit first, preserve
|
||||||
|
return codes, reap clients, remove only owned runtime/socket directory.
|
||||||
|
25 MB per raw log and watchdog bound resource use. No live desktop IPC,
|
||||||
|
killall/pkill, install, sudo, dotfiles, QuickShell or Codex changes.
|
||||||
|
|
||||||
|
Stop consumed failing controls; continue other predefined independent slots
|
||||||
|
only if safe/meaningful, never relaunch to get a favorable result. Critical
|
||||||
|
fixture/budget/isolation violation stops affected dependent execution. Compiler
|
||||||
|
or offline preflight issues may be corrected before the first reserved run.
|
||||||
|
|
||||||
|
## Result evidence and classification
|
||||||
|
|
||||||
|
Keep build/renderer-identities, private-trace-comparison, pristine-control,
|
||||||
|
source-commits, graphic-states, output-geometries, blur-settings, cache-use,
|
||||||
|
dirty-events, regeneration-events, edge-pixel-analysis, column/row-distribution,
|
||||||
|
sampling-domain-audit, edge-model-comparison, damage-analysis, capture-windows,
|
||||||
|
campaign-budget, matrix, summary and source/evidence SHA-256 manifests in
|
||||||
|
LAB/results. Generated files/builds/logs/PNG/socket/bytecode never enter Git.
|
||||||
|
The source-only fixture must rebuild from the pinned versions.
|
||||||
|
|
||||||
|
FEASIBLE requires complete comparable pristine and trace controls, coherent
|
||||||
|
cache contract, absent or natively explained compatible edges, correct allowed
|
||||||
|
Mosaic pixels and no forbidden contribution/regression. PARTIALLY_FEASIBLE
|
||||||
|
means valid majority of controls but native cause or edge property remains
|
||||||
|
open. INCONCLUSIVE means controls/fixture cannot distinguish hypotheses.
|
||||||
|
BLOCKED needs a demonstrated required invariant violation, reproducible crash,
|
||||||
|
forbidden contribution or blocking standard regression; low RGB amplitude
|
||||||
|
alone is insufficient. Architecture: OPTIMIZED_EDGE_CACHE_FEASIBLE_FOR_TESTED_MATRIX,
|
||||||
|
OPTIMIZED_EDGE_CACHE_REQUIRES_REDESIGN or UNDECIDED. Distinguish a shared SceneFX
|
||||||
|
issue from Mosaic clipping. Answer Q1–Q17 from the retained evidence after
|
||||||
|
execution; recommend minimal GPU study or ABI/package gate explicitly.
|
||||||
|
|
||||||
|
## Retained execution and measured result (2026-10-13)
|
||||||
|
|
||||||
|
`SWAYFX_MOSAIC_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE=PARTIALLY_FEASIBLE`.
|
||||||
|
Architecture: **UNDECIDED**. LAB:
|
||||||
|
`/home/fy59/swayfx-mosaic-optimized-edge-a55yjb8n/`.
|
||||||
|
All four controls completed and were comparable in their defined domains.
|
||||||
|
The old pristine failure did not recur: duplicate layer configures were ACKed
|
||||||
|
without another image. No run failed, was repeated or exceeded a budget.
|
||||||
|
The original pre-result protocol is retained as LAB/protocol-before-results.md.
|
||||||
|
|
||||||
|
| Run | Duration | A/B images | PNG | Blur cycles | Initial camera corrections | Compositor exit |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| R0 pristine splith | 4.995 s | 3 | 12 | 1 | 0 | 0 |
|
||||||
|
| R1 private splith, OPT absent | 4.293 s | 3 | 12 | 1 | 0 | 0 |
|
||||||
|
| R2 private Mosaic, OPT absent | 4.638 s | 3 | 12 | 1 | 1 | 0 |
|
||||||
|
| R3 same private Mosaic, OPT=1 | 4.652 s | 3 | 12 | 1 | 1 | 0 |
|
||||||
|
|
||||||
|
Total 4/4 runs,12/12 images,48/48 PNG,4/4 cycles,2/2 initial corrections,
|
||||||
|
zero camera pairs. The home-directory ledger is permanently exhausted for
|
||||||
|
run slots. Every mutation/capture/cycle/calibration reservation preceded its
|
||||||
|
operation; failed-reservation tests used independent offline temporary ledgers.
|
||||||
|
Clients report Wayland EPIPE=32/code 1 after controlled compositor exit; these
|
||||||
|
teardown statuses are retained, not compositor crashes. Owned children were
|
||||||
|
reaped and all four runtime/socket directories removed.
|
||||||
|
|
||||||
|
### Actual sources, geometry and rendering
|
||||||
|
|
||||||
|
Every run uses the real FX renderer, OpenGL ES 3.2, Mesa 26.2.4-arch1.1,
|
||||||
|
AMD Radeon 780M. /proc/PID/maps establishes the private pristine SceneFX in R0
|
||||||
|
and the same private patched SceneFX in R1/R2/R3, together with installed
|
||||||
|
wlroots 0.20.2. Installed package/library series are SceneFX 0.5.0, Wayland
|
||||||
|
client 1.26.0 and wayland-protocols 1.49. The build-identity JSON records
|
||||||
|
all archive revisions, exact patch hashes, library and executable digests.
|
||||||
|
Private compositor SHA-256:
|
||||||
|
`0c87ece70aa012207de951e9d558c81c5c4b3ea78548b943477bf12543264042`;
|
||||||
|
private SceneFX:
|
||||||
|
`78daf506d9aacdd0b1a05605f73b4103ee48cd0b5900a3574671b5ec11f07fe7`.
|
||||||
|
Pristine compositor:
|
||||||
|
`8ac865481bc0487344210cd0e16d8e6c7655b29db887cd58ddc11b0ca22fe494`;
|
||||||
|
pristine SceneFX:
|
||||||
|
`7a07c1f239043f7910039670006a2f6e9bb15608bf2a840576476c5f7b1378b3`.
|
||||||
|
|
||||||
|
IPC/output records and all PNGs confirm fixed 800×600 scale-1 normal outputs
|
||||||
|
at (-800,0)/(0,0). Standard glass is 400×600, global x=-400; Mosaic source
|
||||||
|
scene glass is 640×600 at global x=-320, crossing x=0 by 320. Mosaic's initial
|
||||||
|
camera 480 receives the measured delta -320 and becomes 160. Tiled scene
|
||||||
|
translation/clip and regular blur final draw yield output-local
|
||||||
|
[480,800)×[0,600); no target regular blur draw is seen on H2 in R3. The
|
||||||
|
private scene-state traces in R2 agree. Neither P1–P3 focus, camera, geometry,
|
||||||
|
alpha nor blur parameters are deliberately changed. Stored IPC trees confirm
|
||||||
|
stable applied geometry/focus/camera during measured states.
|
||||||
|
|
||||||
|
Exposed source ROI matches every stripe pixel exactly for A/B/B/A; glass
|
||||||
|
ARGB, source image dimensions and SHM lifetime remain fixed. Container opacity
|
||||||
|
1 is source-defined (container_create alpha=1), with no opacity mutation;
|
||||||
|
ordinary IPC here does not expose an opacity/blur-parameter getter. R3 actual
|
||||||
|
regular-blur strength=1, radius=5, passes=3 and optimized=1/selected FBO=11
|
||||||
|
corroborate source/config/pixel evidence. No getter observation is fabricated.
|
||||||
|
FX0/FX2 central luminance standard deviation falls 51.165618→0.132211 and
|
||||||
|
adjacent luminance contrast 12.351341→0.015453 in every run. Actual filtering
|
||||||
|
is visible beyond alpha compositing. Source mutation changes the central
|
||||||
|
80,000 pixels and whole 480,000 H1 pixels; B's center equals explicit B exactly,
|
||||||
|
and returned A's center equals initial A exactly. Six whole-H2 captures in
|
||||||
|
each run, including two independent preflight images, are pixel-identical.
|
||||||
|
All 24 H2 PNG hashes equal the historical static-reference hash
|
||||||
|
`4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a`.
|
||||||
|
|
||||||
|
### Full-image and pre-registered edge comparisons
|
||||||
|
|
||||||
|
| Comparison | R0 pristine | R1 private splith | R2 Mosaic OPT absent | R3 Mosaic OPT=1 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: |
|
||||||
|
| B natural → B explicit, whole H1 | 36,776 | 36,776 | 33,915 | 33,915 |
|
||||||
|
| A initial → A returned, whole H1 | 38,308 | 38,308 | 35,340 | 35,340 |
|
||||||
|
| Maximum channel delta, both comparisons | 6 | 6 | 6 | 6 |
|
||||||
|
| Center changed pixels, both comparisons | 0 | 0 | 0 | 0 |
|
||||||
|
| H2 changed pixels, every comparison | 0 | 0 | 0 | 0 |
|
||||||
|
| Last A → independent H1 confirmation | 0 | 0 | 0 | 0 |
|
||||||
|
|
||||||
|
R0/R1 have zero whole-H1 RGB differences at all six homologous capture states.
|
||||||
|
R2/R3 likewise have zero at all six states; H2 also matches across runs.
|
||||||
|
Runner bytes, config, compiled client, private binary and loaded private library
|
||||||
|
are identical in R2/R3. New OPT logs are absent in R0/R1/R2 and present in R3;
|
||||||
|
old private logs remain active in R1/R2/R3. Thus no measured graphical effect
|
||||||
|
of activating new traces exists in this matrix. Different frame timing remains
|
||||||
|
observable, and universal instrumentation neutrality is not established.
|
||||||
|
Standard/Mosaic whole-H1 differs by 48,000 pixels at every state because glass
|
||||||
|
coverage is x=[400,800) versus [480,800). The entire common glass
|
||||||
|
[480,800)×[0,600) and exposed source are exact across layouts at every state.
|
||||||
|
This comparison does not exclude any intra-run full-image difference.
|
||||||
|
|
||||||
|
| Pre-registered edge region | B natural/explicit standard | B natural/explicit Mosaic | A initial/return standard | A initial/return Mosaic |
|
||||||
|
| --- | ---: | ---: | ---: | ---: |
|
||||||
|
| Historical boundary (720,50,800,550) | 19,007 | 19,007 | 20,486 | 20,486 |
|
||||||
|
| Physical right x=[750,800) | 23,119 | 23,119 | 22,948 | 22,948 |
|
||||||
|
| Physical bottom y=[550,600) | 15,992 | 13,139 | 15,793 | 12,825 |
|
||||||
|
|
||||||
|
Historical boundary max delta is 4 for B and 5 for A; physical bands reach 6.
|
||||||
|
Whole-H1 mean absolute channel error is 0.083278/0.083215 standard (B/A) and
|
||||||
|
0.076682/0.076858 Mosaic. Right-band means are 0.866344/0.857756; historical
|
||||||
|
boundary means 0.515933/0.524808. These small per-channel means do not erase
|
||||||
|
the tens of thousands of different pixels. Whole-image bounding boxes are
|
||||||
|
[400,800)×[0,600) standard and [480,800)×[0,600) Mosaic. Column/row arrays
|
||||||
|
and amplitude histograms retain every changed pixel. In Mosaic only 103 B
|
||||||
|
and 1,963 A differences lie outside the union of the pre-registered right
|
||||||
|
50 columns and bottom 50 rows; no pixels are discarded. Rows near the bottom
|
||||||
|
and columns near the right reach all visible glass pixels; fine quantization
|
||||||
|
also leaves sparse differences just inside the bands.
|
||||||
|
|
||||||
|
For Mosaic B, changed-pixel maximum amplitudes 1/2/3/4/5/6 occur
|
||||||
|
17,174/8,705/3,825/4,073/130/8 times. For Mosaic A return they occur
|
||||||
|
19,009/8,177/5,093/2,394/652/15 times. Channel-level histograms and standard
|
||||||
|
counts are in edge-pixel-analysis.json; this is not an assertion of ordinary
|
||||||
|
rounding as the cause. No perceptual or daily-session assessment was run.
|
||||||
|
|
||||||
|
### Natural versus explicit path, native timing and damage
|
||||||
|
|
||||||
|
R3 P1 B and P3 A each contain one mapped BACKGROUND source commit,
|
||||||
|
one H1 dirty/rebuild/result=1, two completed cache texture-copy draw calls,
|
||||||
|
one dirty clear and optimized glass use. H2 has zero reconstruction in those
|
||||||
|
windows. P2 contains no background image commit, six dirty-set observations,
|
||||||
|
two successful H1 and two successful H2 reconstructions, eight completed copy
|
||||||
|
draw calls and four dirty clears. This is consistent with scoped cmd_blur
|
||||||
|
arrangement and its unconditional all-output invalidation, not a claim that
|
||||||
|
natural and explicit updates execute the same GPU sequence. The fixed cache
|
||||||
|
objects/FBO sizes are reused; source/configuration do not change radius/passes.
|
||||||
|
Copy draw completion is not a driver fence or per-pixel intermediate readback.
|
||||||
|
|
||||||
|
All R3 relevant reconstructions finish at least 357.899 ms before H1 capture;
|
||||||
|
no source commit/reconstruction trace occurs inside the measured capture
|
||||||
|
windows. The final H1 confirmation is identical after another 350 ms.
|
||||||
|
Earlier states do not have duplicate H1 PNGs under the finite budget, and
|
||||||
|
untraced controls lack OPT quiescence evidence. Their deterministic inputs,
|
||||||
|
stable applied state, settled windows and exact cross-run pixels support the
|
||||||
|
comparisons without claiming every intervening frame.
|
||||||
|
|
||||||
|
For four stabilized R3 H1 transitions, union of available native output-state
|
||||||
|
damage extents leaves zero changed pixels uncovered. Old private scene damage
|
||||||
|
in R1/R2 is retained separately and is not promoted to equivalent output-buffer
|
||||||
|
damage proof. Pristine has no new native damage trace. Commit/present traces
|
||||||
|
keep their own IDs; no screenshot is assigned an exact native presented buffer.
|
||||||
|
No all-frame, minimum-damage, physical-presentation or input claim follows.
|
||||||
|
|
||||||
|
### Sampling domain and fixed offline model
|
||||||
|
|
||||||
|
Pinned shaders are byte-identical pristine/private. FBOs stay 800×600; the
|
||||||
|
written domains are down 400×300,200×150,100×75 and up
|
||||||
|
200×150,400×300,800×600. Down taps use 2*(p+0.5)-0.5 with ±5-pixel offsets;
|
||||||
|
up taps use (p+0.5)/2-0.5 with axial ±2.5 and diagonal ±1.25. GL_LINEAR
|
||||||
|
requires neighboring texels. First downpass sees a complete source, with
|
||||||
|
full-texture clamp; later downpasses and all upsample passes can reach past
|
||||||
|
the fresh reduced domain while remaining inside the texture. No full color
|
||||||
|
clear appears between these blur passes. Alternating full-size ping-pong FBOs
|
||||||
|
can retain earlier regions. The audited source demonstrates this possibility;
|
||||||
|
it does not identify the native value actually read there.
|
||||||
|
|
||||||
|
The exact V1 functions are reused without executing its historical writer,
|
||||||
|
with the actual eight H1 R3 rebuild timestamps and source order. No kernel,
|
||||||
|
offset or rounding fitting is performed. Model/native historical-edge mean
|
||||||
|
absolute channel error spans 0.198700–0.518242; 96.668–97.911% of channels
|
||||||
|
are within one level, maximum residual 4 in that ROI. The broader physical
|
||||||
|
right and glass-bottom domains reach model/native residual 6. For B, model
|
||||||
|
predicts 32,129 changed visible-glass pixels versus native 33,915, mask Jaccard
|
||||||
|
0.861863. For A, 37,701 versus 35,340, Jaccard 0.805086; predicted maximum
|
||||||
|
7 versus native 6. Delta residual means in visible glass are 0.049901 and
|
||||||
|
0.056941. The residual and spatial distributions are preserved, not hidden.
|
||||||
|
This is strong history compatibility, not equivalence to native mediump GLSL
|
||||||
|
or a causal measurement of intermediate FBO contents.
|
||||||
|
|
||||||
|
| Hypothesis | Result for tested matrix |
|
||||||
|
| --- | --- |
|
||||||
|
| H1 reduced-domain history | Supported by source possibility and fixed-model spatial/amplitude agreement; native causality UNDECIDED |
|
||||||
|
| H2 new trace activation causes these edge differences | Not needed to reproduce: pristine and private OPT-off show them; R2/R3 graphical effect zero; universal neutrality NOT PROVEN |
|
||||||
|
| H3 shared rendering property | Supported: pristine/private splith complete RGB identical; common glass across layouts identical |
|
||||||
|
| H4 blur cycle alters more than source cache content | Demonstrated arrangement/all-output dirty and additional reconstructions; exact RGB contribution of each side effect remains unresolved |
|
||||||
|
| H5 another observed rendering factor | Native mediump versus ideal-model residual and timing differences remain limits; geometry/source/alpha/parameters are controlled; no alternate native cause demonstrated |
|
||||||
|
|
||||||
|
### Required architectural answers
|
||||||
|
|
||||||
|
| Question | Evidence-backed answer |
|
||||||
|
| --- | --- |
|
||||||
|
| Q1 pristine edges? | Yes: R0 reproduces exact standard counts and full images of R1. |
|
||||||
|
| Q2 standard and Mosaic? | Yes: common visible glass is exact; full counts differ with coverage. |
|
||||||
|
| Q3 without new traces? | Yes: R0, R1 and R2 reproduce the edge differences. |
|
||||||
|
| Q4 measurable trace effect? | Zero RGB difference in six R2/R3 states; timing differs. Neutrality is sampled, not universal. |
|
||||||
|
| Q5 same reconstruction steps? | Same source-defined blur/copy functions, different trigger/scene/output sequence: natural 1 H1 versus explicit 2 H1+2 H2. No intermediate GPU state equivalence proved. |
|
||||||
|
| Q6 blur-command contribution? | Container blur flag/arrangement and all-output dirty, with extra reconstructions observed. Their separate pixel effects cannot be isolated here. |
|
||||||
|
| Q7 central freshness? | Yes for the predefined 80,000 pixels: changes with B, exact explicit B and exact returned A in all four runs. |
|
||||||
|
| Q8 domains localize anomalies? | Right/bottom bands contain most differences; fixed model overlaps strongly but imperfectly. Not an exact causal localization. |
|
||||||
|
| Q9 source permits stale-domain sampling? | Yes: later down and up supports cross reduced fresh bounds inside full-size textures. Actual sampled old value remains unobserved. |
|
||||||
|
| Q10 level of proof? | Source possibility plus offline prediction and native final pixels; no intermediate native causality. |
|
||||||
|
| Q11 amplitude/distribution? | Max channel 6, tens of thousands of pixels, detailed rows/columns/ROIs/histograms above and in JSON. Not dismissed as rounding. |
|
||||||
|
| Q12 Mosaic clip? | Correct for sampled final draw: H1 x=[480,800), no target draw on H2, whole H2 exact. Not a universal clipping/input proof. |
|
||||||
|
| Q13 damage? | R3 extent union covers every stabilized changed pixel in four transitions; no all-frame or screenshot/native-buffer identity claim. |
|
||||||
|
| Q14 correction justified? | Reproducible shared history-sensitive edge output warrants an upstream investigation; no Mosaic-specific correction or required invariant violation is established. No algorithm correction authorized. |
|
||||||
|
| Q15 smallest next readback? | Selected seam texels and four destination pixels per B condition at D1/D2/U2, bounded protocol below; not executed. |
|
||||||
|
| Q16 blocker or separate limitation? | Shared SceneFX edge limitation, not a demonstrated Mosaic blocker. Whole-cache/native-cause gate remains open and prevents a global FEASIBLE claim; it need not block an independent ABI audit. |
|
||||||
|
| Q17 proceed ABI/package? | Yes, an isolated read-only ABI/package feasibility audit is now justified as the next separate gate. No packaging implementation or production readiness follows. Native causal study stays a separately authorized option. |
|
||||||
|
|
||||||
|
### Proposed later minimal GPU observation — NOT EXECUTED
|
||||||
|
|
||||||
|
Only a new ticket may authorize this. Prefer one pristine fixed-geometry run
|
||||||
|
with a paired observer-off control, strict reservations, no renderer/shader
|
||||||
|
correction and no forced clearing. At H1 B natural and the last explicit B
|
||||||
|
rebuild, record source FBO identity/dimensions and actual pass ordinal.
|
||||||
|
After D1 and before D2, read only source rectangles (193,69,12,12) and
|
||||||
|
(93,143,12,12), crossing valid 200×150 right/bottom seams. After D2 and
|
||||||
|
before U2, read (96,34,7,7) and (46,71,7,7), crossing valid 100×75 seams.
|
||||||
|
These cover the ideal bilinear neighborhoods for two selected edge samples.
|
||||||
|
Read corresponding destination pixels D2 (99,37)/(49,74) and U2
|
||||||
|
(199,75)/(99,149) after their draw. Four rectangles plus four destination
|
||||||
|
pixels are 390 RGBA pixels per condition: 780 pixels / 3,120 bytes total
|
||||||
|
for the two B conditions if RGBA8 is valid. No whole-FBO read or image dump.
|
||||||
|
|
||||||
|
Observe native read format, pack state, read-FBO binding, origin and texture
|
||||||
|
transform; preserve and restore observer state. Label synchronization/timing
|
||||||
|
perturbation. Compare inside-domain versus tail texels and their change between
|
||||||
|
B rebuilds with selected destination contributions under pinned taps. This
|
||||||
|
could discriminate historical values and conversion/precision hypotheses;
|
||||||
|
readback itself still needs observer comparability and does not automatically
|
||||||
|
prove every final-pixel cause. Do not execute, create its GPU code or reserve
|
||||||
|
another run in this exhausted campaign.
|
||||||
|
|
||||||
|
### Decision and remaining scope
|
||||||
|
|
||||||
|
The missing pristine and trace controls are now qualified. The phenomenon is
|
||||||
|
shared across pristine/private rendering and layouts; no measured OPT activation
|
||||||
|
effect or forbidden Mosaic H2 contribution appears. Native edge causality is
|
||||||
|
still unresolved, so the scientific verdict is PARTIALLY_FEASIBLE and
|
||||||
|
architectural conclusion UNDECIDED. FEASIBLE would overstate the unexplained
|
||||||
|
edge property; BLOCKED would invent a required-invariant violation.
|
||||||
|
Recommend the separate SceneFX/wlroots ABI/package audit next, carrying this
|
||||||
|
explicit shared edge limitation. If selecting an upstream graphics correction
|
||||||
|
requires causal evidence, authorize the minimal observation above separately.
|
||||||
|
Neither follow-up is implemented here. No production source or policy changes.
|
||||||
|
|
||||||
|
Rotation/scaling/output changes, saved-buffer/popup/input paths, animations,
|
||||||
|
other drivers/renderers, all-frame damage and native FBO readback remain
|
||||||
|
NOT TESTED in this campaign. No saved-buffer experiment was relaunched.
|
||||||
|
STEP20C stays NEXT and production multi-output NOT YET SUPPORTED.
|
||||||
|
|
||||||
|
## Final validation and sealed inventories
|
||||||
|
|
||||||
|
PASS: shell syntax of the existing exporter (no new B shell script), AST of
|
||||||
|
all nine Python files, C17 -Wall -Wextra -Werror (unused callback parameters
|
||||||
|
explicitly exempted), duplicate-configure callback harness, final client
|
||||||
|
binary equivalence, both pristine/private SceneFX and compositor builds,
|
||||||
|
Meson mosaic-model 1/1, historical patch applicability/source equivalence,
|
||||||
|
unchanged cumulative patch forward applicability/source equivalence against
|
||||||
|
pinned pristine, loaded renderer/library identities, exact stripe calibration,
|
||||||
|
all source reservations, stable applied focus/camera/geometry, complete RGB
|
||||||
|
and edge distributions, source sampling audit, recorded R3 damage coverage,
|
||||||
|
offline/actual budgets, links/whitespace including untracked files, protected
|
||||||
|
production/V1 paths and installed /usr/bin/sway/SceneFX/wlroots hashes.
|
||||||
|
All recorded client/compositor PIDs are gone and private sockets removed.
|
||||||
|
The standalone edge-distributions.svg is an offline figure, not a 49th capture.
|
||||||
|
|
||||||
|
NOT RUN: native FBO readback/intervention, saved-buffer/popup tests, additional
|
||||||
|
geometry/driver/timing variants, ordinary headless IPC suite (no production
|
||||||
|
change; would introduce extra compositor launches), ABI/package qualification,
|
||||||
|
installation, daily-session IPC, B commit/push. The original fixture incident
|
||||||
|
is preserved only in V1; no new run or preflight build failed in this campaign.
|
||||||
|
No production behavior is claimed by compilation, screenshots or model alone.
|
||||||
|
|
||||||
|
Final source manifest: **1,020 entries**, SHA-256
|
||||||
|
`044f6ab4e0d9ced000b12daa75c7cf30f234aa32fed14dc248baa9e3e11dcdff`.
|
||||||
|
Final scientific evidence manifest: **189 entries**, SHA-256
|
||||||
|
`7554388b89fab03b5f3ad0d15c792680fcb403ee04bce8a347c55257440c73d8`.
|
||||||
|
Every entry was verified individually; sealing refuses an existing inventory.
|
||||||
|
The historical 1006/106-entry manifests remain unchanged and reverified with
|
||||||
|
the explicit pre-freeze README snapshot mapping documented by the A report.
|
||||||
|
The final result report and Git diff are captured separately from the sealed
|
||||||
|
scientific inventory to avoid self-referential digest dependencies.
|
||||||
|
|
||||||
|
Final main, origin/main and github/main remain
|
||||||
|
`e749653ccda42abad9a66a11009be6043b5b6f62`; both remotes were directly queried
|
||||||
|
again. The real index is empty; only the five synchronized tracked documents,
|
||||||
|
this new report and the source-only edge fixture are locally modified/new.
|
||||||
|
No B commit or push. The final complete Git diff, including new files, is
|
||||||
|
retained under the freeze audit directory as complete-phase-b.diff.
|
||||||
|
Production source, cumulative patch, PKGBUILD, UX, AGENTS and historical fixture
|
||||||
|
match A's published commit. Installed libraries/compositor are hash-identical.
|
||||||
|
No command targeted daily IPC/session, QuickShell, dotfiles or Codex settings.
|
||||||
|
STEP20A DONE, STEP20B EXPERIMENTAL, STEP20C NEXT, STEP20D–G PLANNED;
|
||||||
|
production multi-output NOT YET SUPPORTED.
|
||||||
|
|
||||||
|
## Independent publication freeze (2026-10-13)
|
||||||
|
|
||||||
|
The new freeze ticket reverified all 1,020 source entries and 189 evidence
|
||||||
|
entries file by file before any documentation edit; both manifest SHA-256
|
||||||
|
values above matched. Their bytes and historical evidence are preserved.
|
||||||
|
The only subsequently edited manifested source is the fixture README; its
|
||||||
|
exact historical bytes are preserved as `README.pre-freeze.md` beside it.
|
||||||
|
Use that explicit mapping when verifying the original manifest after publication.
|
||||||
|
The preceding local/uncommitted final audit describes the historical campaign,
|
||||||
|
not the publication status of this freeze. No graphical campaign, analysis
|
||||||
|
writer, model writer, seal writer or proposed GPU readback was rerun.
|
||||||
|
The verdict remains PARTIALLY_FEASIBLE and architecture UNDECIDED.
|
||||||
77
tooling/probes/step20c-optimized-blur-edge/README.md
Normal file
77
tooling/probes/step20c-optimized-blur-edge/README.md
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
# Optimized blur edge causality fixture
|
||||||
|
|
||||||
|
**EXPERIMENTAL / PRESERVED EVIDENCE; historical campaign closed.** Read the
|
||||||
|
[pre-registered protocol](../../../docs/design/STEP20C_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE.md).
|
||||||
|
The historical V1 cache campaign is closed; never launch or analyze into it.
|
||||||
|
This fixture is a new four-slot comparative campaign, not a renderer fix.
|
||||||
|
|
||||||
|
From a full project clone containing the pinned project commits, with Meson,
|
||||||
|
Ninja, C17, Wayland scanner, compatible wlroots 0.20 build dependencies,
|
||||||
|
Python numpy/Pillow, grim and swaymsg, use:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-optimized-blur-edge/test-budget.py
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-optimized-blur-edge/prepare.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Preparation builds only, creates a new LAB outside Git and retrieves pinned
|
||||||
|
SceneFX. It reads the published V1 XML/patches and older preserved patch chain
|
||||||
|
without modifying them. Compiler logs and all generated files stay in LAB.
|
||||||
|
Offline callback, source, AST, ledger, patch, build and linker preflight must
|
||||||
|
pass before any run. The client ACKs background configures without drawing;
|
||||||
|
only explicit A/B/A commands can submit its three 800×600 images.
|
||||||
|
|
||||||
|
Execute `run.py LAB R0`, then R1, R2 and R3 exactly once each, with
|
||||||
|
PYTHONDONTWRITEBYTECODE=1. The persistent locked
|
||||||
|
`~/swayfx-mosaic-optimized-edge-v1-budget.json` binds all four slots to one LAB.
|
||||||
|
Failed launch/action reservations count; no refund, reset or alternate LAB.
|
||||||
|
Each run has 3 images, 1 scoped blur cycle, 12 PNG maximum and a 150 s watchdog.
|
||||||
|
All sockets/IPC are explicitly private; cleanup targets recorded children only.
|
||||||
|
R2/R3 share binary/client/library/config; OPT_TRACE absent versus 1 toggles new
|
||||||
|
cache traces. Old private traces remain enabled in both. No GPU readback,
|
||||||
|
forced clearing, shader, algorithm, production, package or desktop changes.
|
||||||
|
|
||||||
|
Keep exact executed sources, configurations, binary/library identities,
|
||||||
|
client events, logs, PNGs, exit codes and manifests outside Git. Analyze all
|
||||||
|
RGB pixels without excluding edge bands. Model/source sampling possibilities
|
||||||
|
are not native causality. Results and final offline validation are recorded
|
||||||
|
in the protocol after the four attempts. Fixture preservation is authorized; no new graphical run is authorized.
|
||||||
|
|
||||||
|
## Closed V1 campaign
|
||||||
|
|
||||||
|
LAB `/home/fy59/swayfx-mosaic-optimized-edge-a55yjb8n` consumed all four runs,
|
||||||
|
12 images,48 captures,4 cycles and two initial Mosaic corrections; no rerun
|
||||||
|
is allowed. All controls completed. R0/R1 full RGB and R2/R3 full RGB match
|
||||||
|
in six states, while the edge anomaly persists in pristine and without OPT.
|
||||||
|
Result PARTIALLY_FEASIBLE, architecture UNDECIDED; native FBO cause unresolved.
|
||||||
|
The next justified distinct gate is ABI/package audit with this limitation.
|
||||||
|
A proposed selective GPU observation is documented but not executed.
|
||||||
|
|
||||||
|
Offline analysis in this new LAB is `analyze.py LAB` then `model.py LAB`.
|
||||||
|
`model.py` reuses exact V1 functions through AST selection without running the
|
||||||
|
historical writer. Native rebuild schedule exists only for R3. `preflight.py`
|
||||||
|
affects offline files only and must precede all graphical runs; no re-execution
|
||||||
|
of the exhausted run slots is authorized. Source/evidence manifest creation
|
||||||
|
is separate from analysis to preserve final inventories. Generated outputs
|
||||||
|
remain outside Git. All runtime/socket directories were removed and owned
|
||||||
|
children reaped; compositor exit=0, clients retain controlled-shutdown EPIPE.
|
||||||
|
|
||||||
|
`seal.py LAB` creates each final manifest once and refuses replacement; verify
|
||||||
|
its entries rather than regenerating after sealing. Optional `plot.py LAB`
|
||||||
|
requires matplotlib and produces a standalone SVG from complete column/row
|
||||||
|
arrays; it is an offline figure, not another captured PNG. Its cache stays
|
||||||
|
in LAB. Run all derived analysis before sealing.
|
||||||
|
|
||||||
|
## Freeze verification (2026-10-13)
|
||||||
|
|
||||||
|
All 1,020 source and 189 evidence entries were independently reverified before
|
||||||
|
publication. Their original manifest bytes remain unchanged. The historical
|
||||||
|
manifest entry for this README (SHA-256
|
||||||
|
`e9b4ea06512f1cbcef6107eecaa356d02767f01bb66b0a6cb3b797d8094b7d4c`)
|
||||||
|
must now be checked against [README.pre-freeze.md](README.pre-freeze.md),
|
||||||
|
the exact pre-publication snapshot; every other entry uses its recorded path.
|
||||||
|
Source manifest SHA-256:
|
||||||
|
`044f6ab4e0d9ced000b12daa75c7cf30f234aa32fed14dc248baa9e3e11dcdff`.
|
||||||
|
Evidence manifest SHA-256:
|
||||||
|
`7554388b89fab03b5f3ad0d15c792680fcb403ee04bce8a347c55257440c73d8`.
|
||||||
|
Verification must never reseal, rewrite results or rerun the exhausted campaign.
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Optimized blur edge causality fixture
|
||||||
|
|
||||||
|
**EXPERIMENTAL / LOCAL / UNCOMMITTED.** Read the
|
||||||
|
[pre-registered protocol](../../../docs/design/STEP20C_OPTIMIZED_BLUR_EDGE_CAUSALITY_PROBE.md).
|
||||||
|
The historical V1 cache campaign is closed; never launch or analyze into it.
|
||||||
|
This fixture is a new four-slot comparative campaign, not a renderer fix.
|
||||||
|
|
||||||
|
From a full project clone containing the pinned project commits, with Meson,
|
||||||
|
Ninja, C17, Wayland scanner, compatible wlroots 0.20 build dependencies,
|
||||||
|
Python numpy/Pillow, grim and swaymsg, use:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-optimized-blur-edge/test-budget.py
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 python tooling/probes/step20c-optimized-blur-edge/prepare.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Preparation builds only, creates a new LAB outside Git and retrieves pinned
|
||||||
|
SceneFX. It reads the published V1 XML/patches and older preserved patch chain
|
||||||
|
without modifying them. Compiler logs and all generated files stay in LAB.
|
||||||
|
Offline callback, source, AST, ledger, patch, build and linker preflight must
|
||||||
|
pass before any run. The client ACKs background configures without drawing;
|
||||||
|
only explicit A/B/A commands can submit its three 800×600 images.
|
||||||
|
|
||||||
|
Execute `run.py LAB R0`, then R1, R2 and R3 exactly once each, with
|
||||||
|
PYTHONDONTWRITEBYTECODE=1. The persistent locked
|
||||||
|
`~/swayfx-mosaic-optimized-edge-v1-budget.json` binds all four slots to one LAB.
|
||||||
|
Failed launch/action reservations count; no refund, reset or alternate LAB.
|
||||||
|
Each run has 3 images, 1 scoped blur cycle, 12 PNG maximum and a 150 s watchdog.
|
||||||
|
All sockets/IPC are explicitly private; cleanup targets recorded children only.
|
||||||
|
R2/R3 share binary/client/library/config; OPT_TRACE absent versus 1 toggles new
|
||||||
|
cache traces. Old private traces remain enabled in both. No GPU readback,
|
||||||
|
forced clearing, shader, algorithm, production, package or desktop changes.
|
||||||
|
|
||||||
|
Keep exact executed sources, configurations, binary/library identities,
|
||||||
|
client events, logs, PNGs, exit codes and manifests outside Git. Analyze all
|
||||||
|
RGB pixels without excluding edge bands. Model/source sampling possibilities
|
||||||
|
are not native causality. Results and final offline validation are recorded
|
||||||
|
in the protocol after the four attempts. No commit or push for this fixture.
|
||||||
|
|
||||||
|
## Closed V1 campaign
|
||||||
|
|
||||||
|
LAB `/home/fy59/swayfx-mosaic-optimized-edge-a55yjb8n` consumed all four runs,
|
||||||
|
12 images,48 captures,4 cycles and two initial Mosaic corrections; no rerun
|
||||||
|
is allowed. All controls completed. R0/R1 full RGB and R2/R3 full RGB match
|
||||||
|
in six states, while the edge anomaly persists in pristine and without OPT.
|
||||||
|
Result PARTIALLY_FEASIBLE, architecture UNDECIDED; native FBO cause unresolved.
|
||||||
|
The next justified distinct gate is ABI/package audit with this limitation.
|
||||||
|
A proposed selective GPU observation is documented but not executed.
|
||||||
|
|
||||||
|
Offline analysis in this new LAB is `analyze.py LAB` then `model.py LAB`.
|
||||||
|
`model.py` reuses exact V1 functions through AST selection without running the
|
||||||
|
historical writer. Native rebuild schedule exists only for R3. `preflight.py`
|
||||||
|
affects offline files only and must precede all graphical runs; no re-execution
|
||||||
|
of the exhausted run slots is authorized. Source/evidence manifest creation
|
||||||
|
is separate from analysis to preserve final inventories. Generated outputs
|
||||||
|
remain outside Git. All runtime/socket directories were removed and owned
|
||||||
|
children reaped; compositor exit=0, clients retain controlled-shutdown EPIPE.
|
||||||
|
|
||||||
|
`seal.py LAB` creates each final manifest once and refuses replacement; verify
|
||||||
|
its entries rather than regenerating after sealing. Optional `plot.py LAB`
|
||||||
|
requires matplotlib and produces a standalone SVG from complete column/row
|
||||||
|
arrays; it is an offline figure, not another captured PNG. Its cache stays
|
||||||
|
in LAB. Run all derived analysis before sealing.
|
||||||
203
tooling/probes/step20c-optimized-blur-edge/analyze.py
Normal file
203
tooling/probes/step20c-optimized-blur-edge/analyze.py
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Offline comparisons from retained pixels/events; no native causality invented.
|
||||||
|
|
||||||
|
CONTRACT: full RGB and pre-registered regions; traces absent remain absent.
|
||||||
|
INVARIANT: raw runs and original source manifests are not rewritten here.
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
import numpy as np
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
lab = Path(sys.argv[1]).resolve()
|
||||||
|
out = lab / 'results'
|
||||||
|
fixture = Path(__file__).resolve().parent
|
||||||
|
ROIS = {'center': (520,100,720,500), 'source': (20,100,160,500),
|
||||||
|
'boundary': (720,50,800,550), 'physical_right': (750,0,800,600),
|
||||||
|
'physical_bottom': (0,550,800,600)}
|
||||||
|
PAIRS = [('P0-FX0','P0-FX2'), ('P0-FX2','P1-B-natural'),
|
||||||
|
('P1-B-natural','P2-B-explicit'), ('P0-FX2','P3-A-natural'),
|
||||||
|
('P3-A-natural','P3-confirm')]
|
||||||
|
NAMES = ['OPT_NODE_CREATE','OPT_NODE_RENDER','OPT_BACKGROUND_COMMIT','OPT_DIRTY_SET',
|
||||||
|
'OPT_DIRTY_CLEAR','OPT_REGEN_ATTEMPT','OPT_REGEN_RESULT','OPT_GPU_REBUILD',
|
||||||
|
'OPT_GPU_RESULT','OPT_GPU_COPY','OPT_GPU_COPY_DRAWN','OPT_BLUR_USE',
|
||||||
|
'OPT_CACHE_STATE','OPT_REGULAR_NODE','OPT_OUTPUT_BUFFER','PI_SCENE',
|
||||||
|
'PI_OWNER','PI_OUTPUT_COMMIT','PI_OUTPUT_PRESENT','TEMPORAL_DAMAGE']
|
||||||
|
|
||||||
|
def write(name, value):
|
||||||
|
(out / (name + '.json')).write_text(json.dumps(value, indent=2, sort_keys=True) + '\n')
|
||||||
|
|
||||||
|
def sha(path):
|
||||||
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||||
|
|
||||||
|
def crop(image, box):
|
||||||
|
left, top, right, bottom = box
|
||||||
|
return image[top:bottom,left:right]
|
||||||
|
|
||||||
|
def metric(first, second):
|
||||||
|
delta = np.abs(first.astype(np.int16) - second.astype(np.int16))
|
||||||
|
mask = np.any(delta, axis=2)
|
||||||
|
ys, xs = np.where(mask)
|
||||||
|
return {'pixels': int(mask.sum()), 'total_pixels': int(mask.size),
|
||||||
|
'max_channel': int(delta.max()), 'mean_abs_channel': float(delta.mean()),
|
||||||
|
'bbox': [int(xs.min()),int(ys.min()),int(xs.max()+1),int(ys.max()+1)] if mask.any() else None,
|
||||||
|
'channel_amplitude_histogram': {str(i):int(n) for i,n in enumerate(np.bincount(delta.ravel(),minlength=256)) if n},
|
||||||
|
'changed_pixel_max_amplitude_histogram': {str(i):int(n) for i,n in enumerate(np.bincount(delta.max(axis=2).ravel(),minlength=256)) if n}}
|
||||||
|
|
||||||
|
def compare(first, second):
|
||||||
|
return {'whole': metric(first,second),
|
||||||
|
'ROIs': {name: metric(crop(first,box),crop(second,box)) for name,box in ROIS.items()}}
|
||||||
|
|
||||||
|
def parsed(lines, name):
|
||||||
|
return [{'raw': line, **dict(re.findall(r'([A-Za-z_]+)=([^ ]+)',line))}
|
||||||
|
for line in lines if re.search(r'\b' + name + r'\b',line)]
|
||||||
|
|
||||||
|
runs = {}
|
||||||
|
pixels = {}
|
||||||
|
columns = {}
|
||||||
|
rows = {}
|
||||||
|
renderers = {}
|
||||||
|
commits = {}
|
||||||
|
states = {}
|
||||||
|
geometries = {}
|
||||||
|
settings = {}
|
||||||
|
windows = {}
|
||||||
|
phase_traces = {}
|
||||||
|
damage = {}
|
||||||
|
contrast = {}
|
||||||
|
ledger = json.loads((out/'campaign-budget.json').read_text())
|
||||||
|
for mode in ('R0','R1','R2','R3'):
|
||||||
|
run = lab/'runs'/mode
|
||||||
|
status = json.loads((run/'exit-status.json').read_text())
|
||||||
|
events = [json.loads(line) for line in (run/'events.jsonl').read_text().splitlines()]
|
||||||
|
lines = (run/'compositor.log').read_text().splitlines()
|
||||||
|
traces = {name: parsed(lines,name) for name in NAMES}
|
||||||
|
images = {event['tag']+'-'+event['output']: np.array(Image.open(run/event['path']).convert('RGB'))
|
||||||
|
for event in events if event['kind']=='capture'}
|
||||||
|
runs[mode] = {'status':status,'events':events,'traces':traces,'images':images}
|
||||||
|
renderer_event = next(e for e in events if e['kind']=='renderer_start')
|
||||||
|
loaded = sorted(set(line.split()[-1] for line in (run/'library-maps.txt').read_text().splitlines()
|
||||||
|
if 'libscenefx' in line or 'libwlroots' in line))
|
||||||
|
renderers[mode] = {'lines':[line for line in lines if any(text in line for text in
|
||||||
|
('Using OpenGL ES','GL renderer:','GL vendor:','EGL vendor:','FX RENDERER:'))],
|
||||||
|
'loaded_libraries':{path:sha(Path(path)) for path in loaded},
|
||||||
|
'binary':renderer_event['binary'],'binary_sha256':sha(Path(renderer_event['binary'])),
|
||||||
|
'OPT_TRACE':renderer_event['OPT_TRACE'],'native_OPT_evidence':mode=='R3'}
|
||||||
|
client = parsed((run/'background.log').read_text().splitlines(),'CLIENT_COMMIT')
|
||||||
|
reserves = [e for e in events if e['kind']=='mutation_reserved']
|
||||||
|
configures = parsed((run/'background.log').read_text().splitlines(),'BACKGROUND_CONFIGURED')
|
||||||
|
assert len(client)==ledger['modes'][mode]['mutation']==len(reserves)
|
||||||
|
assert [c['pattern'] for c in client]==[r['pattern'] for r in reserves]
|
||||||
|
assert all(int(c['ns'])>r['ns'] and c['size']=='800x600' for c,r in zip(client,reserves))
|
||||||
|
assert len(status['captures'])==ledger['modes'][mode]['capture']
|
||||||
|
assert status['duration']<150 and status['runtime_removed'] and not (run/'runtime').exists()
|
||||||
|
commits[mode] = {'client':client,'configures':configures,'reservations':reserves,
|
||||||
|
'server':traces['OPT_BACKGROUND_COMMIT'],
|
||||||
|
'reservation_protocol':'PASS before every observed A/B image',
|
||||||
|
'no_configure_draw':'PASS duplicate configure ACK without autonomous image',
|
||||||
|
'identity_limit':'surface/buffer IDs may be reused; sequence/lifetime required'}
|
||||||
|
states[mode] = [e for e in events if e['kind']=='graphic_state']
|
||||||
|
geometries[mode] = {p.stem:json.loads(p.read_text()) for p in run.glob('*-outputs.json')}
|
||||||
|
settings[mode] = {'config':(run/'config').read_text(),
|
||||||
|
'commands':[e for e in events if e['kind']=='ipc' and e['args'] and e['args'][0].startswith('[app_id=')],
|
||||||
|
'pixel_effect_gate':[e for e in events if e['kind']=='P0_gate'],
|
||||||
|
'setting_limit':'accepted config + source audit; filtering proves effect; no OPT parameters fabricated for untraced controls'}
|
||||||
|
windows[mode] = status['captures']
|
||||||
|
if status['failure']:
|
||||||
|
pixels[mode] = {'failure':status['failure']}
|
||||||
|
continue
|
||||||
|
assert [c['pattern'] for c in client]==['A','B','A']
|
||||||
|
baseline = images['P0-FX0-HEADLESS-2']
|
||||||
|
p = {'comparisons':{},'H2_full':{},'capture_sha256':{q.name:sha(q) for q in run.glob('*.png')}}
|
||||||
|
columns[mode] = {}; rows[mode] = {}; contrast[mode] = {}
|
||||||
|
for first,second in PAIRS:
|
||||||
|
key=first+' -> '+second
|
||||||
|
a=images[first+'-HEADLESS-1']; b=images[second+'-HEADLESS-1']
|
||||||
|
p['comparisons'][key]=compare(a,b)
|
||||||
|
mask=np.any(a!=b,axis=2)
|
||||||
|
columns[mode][key]=mask.sum(axis=0).astype(int).tolist()
|
||||||
|
rows[mode][key]=mask.sum(axis=1).astype(int).tolist()
|
||||||
|
for name,image in images.items():
|
||||||
|
if name.endswith('HEADLESS-2'):
|
||||||
|
p['H2_full'][name]=metric(baseline,image)
|
||||||
|
else:
|
||||||
|
center=crop(image,ROIS['center']).astype(float)
|
||||||
|
luminance=center@[.2126,.7152,.0722]
|
||||||
|
contrast[mode][name]={'luminance_std':float(luminance.std()),
|
||||||
|
'adjacent_luminance':float(np.abs(np.diff(luminance,axis=1)).mean()),
|
||||||
|
'mean_RGB':center.mean(axis=(0,1)).tolist()}
|
||||||
|
# Full exposed-source calibration in every measured state, not just membership.
|
||||||
|
x=np.arange(20,160)
|
||||||
|
for tag,pattern in [('P0-FX0','A'),('P0-FX2','A'),('P1-B-natural','B'),('P2-B-explicit','B'),('P3-A-natural','A')]:
|
||||||
|
colors=np.array([[245,245,245],[15,25,45]] if pattern=='A' else [[32,192,224],[176,32,64]],dtype=np.uint8)
|
||||||
|
expected=np.broadcast_to(colors[(x//8)%2],(400,140,3))
|
||||||
|
assert np.array_equal(expected,crop(images[tag+'-HEADLESS-1'],ROIS['source']))
|
||||||
|
p['source_calibration']='PASS exact stripes A/B/B/A in exposed ROI'
|
||||||
|
pixels[mode]=p
|
||||||
|
phase_traces[mode]={}
|
||||||
|
for tag in ('P0-FX2','P1-B-natural','P2-B-explicit','P3-A-natural'):
|
||||||
|
capture=next(e for e in status['captures'] if e['tag']==tag and e['output']=='HEADLESS-1')
|
||||||
|
if tag=='P0-FX2':
|
||||||
|
start=next(e['after_ns'] for e in status['captures'] if e['tag']=='P0-reference')
|
||||||
|
elif tag=='P2-B-explicit':
|
||||||
|
start=next(e['ns'] for e in events if e['kind']=='explicit_cycle_start')
|
||||||
|
else:
|
||||||
|
start=reserves[1 if tag=='P1-B-natural' else 2]['ns']
|
||||||
|
phase_traces[mode][tag]={'start_ns':start,'capture_before_ns':capture['before_ns'],
|
||||||
|
'end_ns':capture['after_ns'],
|
||||||
|
'trace':{name:[t for t in values if 'ns' in t and start<=int(t['ns'])<=capture['after_ns']]
|
||||||
|
for name,values in traces.items()}}
|
||||||
|
if mode!='R3':
|
||||||
|
damage[mode]={'output_state_OPT_damage':'NOT AVAILABLE',
|
||||||
|
'old_scene_damage':traces['TEMPORAL_DAMAGE'],
|
||||||
|
'limit':'older private scene damage (if present) is not OPT output-state buffer damage; no equivalent coverage claim'}
|
||||||
|
else:
|
||||||
|
damage[mode]={}
|
||||||
|
for first,second in [('P0-FX0','P0-FX2'),('P0-FX2','P1-B-natural'),('P1-B-natural','P2-B-explicit'),('P2-B-explicit','P3-A-natural')]:
|
||||||
|
ca=next(e for e in status['captures'] if e['tag']==first and e['output']=='HEADLESS-1')
|
||||||
|
cb=next(e for e in status['captures'] if e['tag']==second and e['output']=='HEADLESS-1')
|
||||||
|
mask=np.any(images[first+'-HEADLESS-1']!=images[second+'-HEADLESS-1'],axis=2)
|
||||||
|
cover=np.zeros((600,800),bool); records=[]
|
||||||
|
for t in traces['OPT_OUTPUT_BUFFER']:
|
||||||
|
if t['output']!='HEADLESS-1' or not ca['before_ns']<=int(t['ns'])<=cb['after_ns']:continue
|
||||||
|
left,top,right,bottom=map(int,t['damage'].split(','));cover[max(0,top):min(600,bottom),max(0,left):min(800,right)]=True;records.append(t)
|
||||||
|
damage[mode][first+' -> '+second]={'changed_pixels':int(mask.sum()),
|
||||||
|
'uncovered_by_output_damage_extents':int((mask&~cover).sum()),'records':records,
|
||||||
|
'limit':'extent union, stabilized captures only; no all-frame coverage/minimal damage/native PNG identity'}
|
||||||
|
|
||||||
|
cross={}
|
||||||
|
for first,second in [('R0','R1'),('R2','R3')]:
|
||||||
|
key=first+' -> '+second
|
||||||
|
a=runs[first];b=runs[second]
|
||||||
|
comparable=not a['status']['failure'] and not b['status']['failure']
|
||||||
|
cross[key]={'geometry_equal':states[first]==states[second], 'comparable':comparable}
|
||||||
|
# State records contain timestamps; compare applied geometry and tags only.
|
||||||
|
cross[key]['geometry_equal']=[(e['tag'],e['geometry']) for e in states[first]]==[(e['tag'],e['geometry']) for e in states[second]]
|
||||||
|
if comparable and cross[key]['geometry_equal']:
|
||||||
|
cross[key]['states']={tag:compare(a['images'][tag+'-HEADLESS-1'],b['images'][tag+'-HEADLESS-1'])
|
||||||
|
for tag in ('P0-FX0','P0-FX2','P1-B-natural','P2-B-explicit','P3-A-natural','P3-confirm')}
|
||||||
|
cross[key]['H2']=metric(a['images']['P0-FX0-HEADLESS-2'],b['images']['P0-FX0-HEADLESS-2'])
|
||||||
|
else:cross[key]['limit']='control geometry/fixture not comparable'
|
||||||
|
write('renderer-identities',renderers);write('source-commits',commits)
|
||||||
|
write('graphic-states',states);write('output-geometries',geometries);write('blur-settings',settings)
|
||||||
|
write('edge-pixel-analysis',pixels);write('column-distribution',columns);write('row-distribution',rows)
|
||||||
|
write('capture-windows',windows);write('damage-analysis',damage);write('phase-events',phase_traces)
|
||||||
|
write('filtering-analysis',contrast);write('private-trace-comparison',cross['R2 -> R3']);write('pristine-control',cross['R0 -> R1'])
|
||||||
|
for category,names in [('cache-use',['OPT_BLUR_USE','OPT_CACHE_STATE','OPT_REGULAR_NODE']),
|
||||||
|
('dirty-events',['OPT_DIRTY_SET','OPT_DIRTY_CLEAR']),
|
||||||
|
('regeneration-events',['OPT_REGEN_ATTEMPT','OPT_REGEN_RESULT','OPT_GPU_REBUILD','OPT_GPU_RESULT','OPT_GPU_COPY','OPT_GPU_COPY_DRAWN'])]:
|
||||||
|
write(category,{mode:{name:data['traces'][name] for name in names} for mode,data in runs.items()})
|
||||||
|
write('matrix',{mode:{'failure':data['status']['failure'],'duration':data['status']['duration'],
|
||||||
|
'compositor_exit':data['status']['compositor'],'captures':len(data['status']['captures']),
|
||||||
|
'images':len(commits[mode]['client']),'runtime_removed':data['status']['runtime_removed']}
|
||||||
|
for mode,data in runs.items()})
|
||||||
|
# Never infer the final scientific verdict merely from process success.
|
||||||
|
print(json.dumps({'edge_counts':{mode:{pair:value['whole'] for pair,value in data.get('comparisons',{}).items()
|
||||||
|
if pair in ('P1-B-natural -> P2-B-explicit','P0-FX2 -> P3-A-natural')}
|
||||||
|
for mode,data in pixels.items()},
|
||||||
|
'cross':{key:{'geometry_equal':data['geometry_equal'],
|
||||||
|
'state_changed_pixels':{tag:value['whole']['pixels'] for tag,value in data.get('states',{}).items()}}
|
||||||
|
for key,data in cross.items()}},indent=2))
|
||||||
69
tooling/probes/step20c-optimized-blur-edge/budget.py
Normal file
69
tooling/probes/step20c-optimized-blur-edge/budget.py
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
"""Durable fail-closed reservations, bound to one LAB for this ticket.
|
||||||
|
|
||||||
|
WHY: a failed graphical attempt must never create capacity for a rerun.
|
||||||
|
CONTRACT: exclusive flock; fsync file then atomic replace and directory fsync.
|
||||||
|
INVARIANT: exact schema, bounded counters, no reset/refund or alternate LAB.
|
||||||
|
"""
|
||||||
|
import fcntl
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
MODES = ('R0', 'R1', 'R2', 'R3')
|
||||||
|
KEYS = ('run', 'mutation', 'capture', 'cycle', 'calibration')
|
||||||
|
CAMPAIGN = 'SWAYFX_MOSAIC_STEP20C_OPTIMIZED_CACHE_FREEZE_AND_EDGE_CAUSALITY_GATE_V1'
|
||||||
|
DEFAULT = Path.home() / 'swayfx-mosaic-optimized-edge-v1-budget.json'
|
||||||
|
|
||||||
|
def limits(mode):
|
||||||
|
return dict(run=1, mutation=3, capture=12, cycle=1,
|
||||||
|
calibration=1 if mode in ('R2', 'R3') else 0)
|
||||||
|
|
||||||
|
def validate(state, lab):
|
||||||
|
if set(state) != {'campaign', 'lab', 'modes'} or state['campaign'] != CAMPAIGN or state['lab'] != lab:
|
||||||
|
raise RuntimeError('wrong campaign/LAB or corrupt schema')
|
||||||
|
if set(state['modes']) != set(MODES):
|
||||||
|
raise RuntimeError('corrupt modes')
|
||||||
|
for mode, counts in state['modes'].items():
|
||||||
|
if set(counts) != set(KEYS):
|
||||||
|
raise RuntimeError('corrupt resource schema')
|
||||||
|
for key, value in counts.items():
|
||||||
|
if type(value) is not int or not 0 <= value <= limits(mode)[key]:
|
||||||
|
raise RuntimeError('corrupt/out-of-bounds counter')
|
||||||
|
if any(counts[k] for k in KEYS if k != 'run') and counts['run'] != 1:
|
||||||
|
raise RuntimeError('action before run')
|
||||||
|
|
||||||
|
def reserve(lab, mode, resource, path=DEFAULT):
|
||||||
|
if mode not in MODES or resource not in KEYS:
|
||||||
|
raise ValueError('unknown reservation')
|
||||||
|
lab = str(Path(lab).resolve())
|
||||||
|
path = Path(path)
|
||||||
|
with path.with_suffix('.lock').open('a+') as lock:
|
||||||
|
fcntl.flock(lock, fcntl.LOCK_EX)
|
||||||
|
state = json.loads(path.read_text()) if path.exists() else {
|
||||||
|
'campaign': CAMPAIGN, 'lab': lab,
|
||||||
|
'modes': {m: {k: 0 for k in KEYS} for m in MODES}}
|
||||||
|
validate(state, lab)
|
||||||
|
counts = state['modes'][mode]
|
||||||
|
if resource != 'run' and counts['run'] != 1:
|
||||||
|
raise RuntimeError('reserve run first')
|
||||||
|
if counts[resource] >= limits(mode)[resource]:
|
||||||
|
raise RuntimeError('budget exhausted: ' + resource)
|
||||||
|
counts[resource] += 1
|
||||||
|
fd, tmp = tempfile.mkstemp(prefix=path.name + '.', dir=path.parent)
|
||||||
|
try:
|
||||||
|
with os.fdopen(fd, 'w') as out:
|
||||||
|
json.dump(state, out, sort_keys=True)
|
||||||
|
out.write('\n')
|
||||||
|
out.flush()
|
||||||
|
os.fsync(out.fileno())
|
||||||
|
os.replace(tmp, path)
|
||||||
|
directory = os.open(path.parent, os.O_DIRECTORY)
|
||||||
|
try:
|
||||||
|
os.fsync(directory)
|
||||||
|
finally:
|
||||||
|
os.close(directory)
|
||||||
|
finally:
|
||||||
|
if os.path.exists(tmp):
|
||||||
|
os.unlink(tmp)
|
||||||
|
return state
|
||||||
303
tooling/probes/step20c-optimized-blur-edge/clients.c
Normal file
303
tooling/probes/step20c-optimized-blur-edge/clients.c
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "layer-shell-client.h"
|
||||||
|
#include "xdg-shell-client.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
|
||||||
|
/* WHY: one persistent background supplies real A/B commits below blur_tree.
|
||||||
|
* CONTRACT: fixed opaque background, premultiplied ARGB glass and static H2.
|
||||||
|
* INVARIANT: no animation, synthetic configure, popup or held transaction. */
|
||||||
|
static struct wl_display *display;
|
||||||
|
static struct wl_compositor *compositor;
|
||||||
|
static struct wl_shm *shm;
|
||||||
|
static struct xdg_wm_base *wm;
|
||||||
|
static struct zwlr_layer_shell_v1 *shell;
|
||||||
|
static struct wl_output *h1;
|
||||||
|
static struct wl_surface *surface;
|
||||||
|
static struct xdg_surface *xdg;
|
||||||
|
static struct xdg_toplevel *top;
|
||||||
|
static struct zwlr_layer_surface_v1 *layer;
|
||||||
|
static const char *mode;
|
||||||
|
static int width = 420, height = 320;
|
||||||
|
static unsigned commits, live_buffers;
|
||||||
|
static char pattern = 'A';
|
||||||
|
static volatile sig_atomic_t running = 1;
|
||||||
|
struct pixels {
|
||||||
|
struct wl_buffer *buffer;
|
||||||
|
void *map;
|
||||||
|
size_t size;
|
||||||
|
struct pixels *next;
|
||||||
|
};
|
||||||
|
static struct pixels *buffers;
|
||||||
|
static long long stamp(void) {
|
||||||
|
struct timespec t;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||||
|
return (long long)t.tv_sec * 1000000000LL + t.tv_nsec;
|
||||||
|
}
|
||||||
|
static void free_pixels(struct pixels *p) {
|
||||||
|
struct pixels **it = &buffers;
|
||||||
|
while (*it && *it != p)
|
||||||
|
it = &(*it)->next;
|
||||||
|
if (*it)
|
||||||
|
*it = p->next;
|
||||||
|
wl_buffer_destroy(p->buffer);
|
||||||
|
munmap(p->map, p->size);
|
||||||
|
free(p);
|
||||||
|
--live_buffers;
|
||||||
|
}
|
||||||
|
static void release(void *data, struct wl_buffer *b) {
|
||||||
|
fprintf(stderr, "RELEASE ns=%lld buffer=%u\n", stamp(),
|
||||||
|
wl_proxy_get_id((struct wl_proxy *)b));
|
||||||
|
free_pixels(data);
|
||||||
|
}
|
||||||
|
static const struct wl_buffer_listener buffer_listener = {.release = release};
|
||||||
|
static void draw(void) {
|
||||||
|
/* CONTRACT: exactly one runner command per reserved A/B image.
|
||||||
|
* INVARIANT: configures cannot draw, and the sequence is A/B/A only. */
|
||||||
|
if (!strcmp(mode, "background") &&
|
||||||
|
(width != 800 || height != 600 || commits >= 3 ||
|
||||||
|
pattern != (commits == 1 ? 'B' : 'A')))
|
||||||
|
exit(2);
|
||||||
|
if (width <= 0 || height <= 0 || width > 4096 || height > 4096 ||
|
||||||
|
live_buffers >= 8)
|
||||||
|
exit(2);
|
||||||
|
size_t size = (size_t)width * (size_t)height * 4;
|
||||||
|
/* CONTRACT: each mapping stays immutable until native wl_buffer.release.
|
||||||
|
* Bounds keep pool/stride integers valid, with at most eight outstanding. */
|
||||||
|
char name[512];
|
||||||
|
const char *runtime = getenv("XDG_RUNTIME_DIR");
|
||||||
|
if (!runtime || snprintf(name, sizeof(name), "%s/blur-shm-XXXXXX", runtime) >=
|
||||||
|
(int)sizeof(name))
|
||||||
|
exit(2);
|
||||||
|
int fd = mkstemp(name);
|
||||||
|
if (fd < 0)
|
||||||
|
exit(2);
|
||||||
|
unlink(name);
|
||||||
|
if (ftruncate(fd, (off_t)size) < 0)
|
||||||
|
exit(2);
|
||||||
|
struct pixels *p = calloc(1, sizeof(*p));
|
||||||
|
if (!p)
|
||||||
|
exit(2);
|
||||||
|
p->map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
p->size = size;
|
||||||
|
if (p->map == MAP_FAILED)
|
||||||
|
exit(2);
|
||||||
|
uint32_t *pixels = p->map;
|
||||||
|
for (int y = 0; y < height; ++y)
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
uint32_t color = 0x00303038;
|
||||||
|
if (!strcmp(mode, "background"))
|
||||||
|
color = pattern == 'A' ? (x / 8 % 2 ? 0x000f192d : 0x00f5f5f5)
|
||||||
|
: (x / 8 % 2 ? 0x00b02040 : 0x0020c0e0);
|
||||||
|
else if (!strcmp(mode, "glass"))
|
||||||
|
color = 0x88442010;
|
||||||
|
else if (!strcmp(mode, "filler"))
|
||||||
|
color = 0x00000000;
|
||||||
|
pixels[(size_t)y * (size_t)width + (size_t)x] = color;
|
||||||
|
}
|
||||||
|
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, (int)size);
|
||||||
|
p->buffer = wl_shm_pool_create_buffer(
|
||||||
|
pool, 0, width, height, width * 4,
|
||||||
|
(!strcmp(mode, "glass") || !strcmp(mode, "filler"))
|
||||||
|
? WL_SHM_FORMAT_ARGB8888
|
||||||
|
: WL_SHM_FORMAT_XRGB8888);
|
||||||
|
p->next = buffers;
|
||||||
|
buffers = p;
|
||||||
|
++live_buffers;
|
||||||
|
wl_buffer_add_listener(p->buffer, &buffer_listener, p);
|
||||||
|
wl_surface_attach(surface, p->buffer, 0, 0);
|
||||||
|
wl_surface_damage_buffer(surface, 0, 0, width, height);
|
||||||
|
wl_surface_commit(surface);
|
||||||
|
fprintf(stderr,
|
||||||
|
"CLIENT_COMMIT ns=%lld mode=%s surface=%u buffer=%u index=%u "
|
||||||
|
"pattern=%c size=%dx%d damage=0,0,%d,%d\n",
|
||||||
|
stamp(), mode, wl_proxy_get_id((struct wl_proxy *)surface),
|
||||||
|
wl_proxy_get_id((struct wl_proxy *)p->buffer), ++commits, pattern,
|
||||||
|
width, height, width, height);
|
||||||
|
wl_shm_pool_destroy(pool);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
static void ping(void *d, struct xdg_wm_base *b, uint32_t s) {
|
||||||
|
xdg_wm_base_pong(b, s);
|
||||||
|
}
|
||||||
|
static const struct xdg_wm_base_listener wm_listener = {.ping = ping};
|
||||||
|
static void top_configure(void *d, struct xdg_toplevel *t, int32_t w, int32_t h,
|
||||||
|
struct wl_array *a) {
|
||||||
|
if (w > 0)
|
||||||
|
width = w;
|
||||||
|
if (h > 0)
|
||||||
|
height = h;
|
||||||
|
}
|
||||||
|
static void top_close(void *d, struct xdg_toplevel *t) { running = 0; }
|
||||||
|
static const struct xdg_toplevel_listener top_listener = {
|
||||||
|
.configure = top_configure, .close = top_close};
|
||||||
|
static void configure(void *d, struct xdg_surface *s, uint32_t serial) {
|
||||||
|
xdg_surface_ack_configure(s, serial);
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
static const struct xdg_surface_listener xdg_listener = {.configure =
|
||||||
|
configure};
|
||||||
|
/* CONTRACT: configures ACK geometry, never submit an unreserved image.
|
||||||
|
* WHY: duplicate layer configures must not spend autonomous mutations.
|
||||||
|
* INVARIANT: the runner reserves then sends every A/B draw command. */
|
||||||
|
static void layer_configure(void *d, struct zwlr_layer_surface_v1 *s,
|
||||||
|
uint32_t serial, uint32_t w, uint32_t h) {
|
||||||
|
if (w == 0 || h == 0 || w > 4096 || h > 4096)
|
||||||
|
exit(2);
|
||||||
|
if (commits && ((int)w != width || (int)h != height))
|
||||||
|
exit(2);
|
||||||
|
width = (int)w;
|
||||||
|
height = (int)h;
|
||||||
|
zwlr_layer_surface_v1_ack_configure(s, serial);
|
||||||
|
fprintf(stderr, "BACKGROUND_CONFIGURED ns=%lld serial=%u size=%dx%d\n",
|
||||||
|
stamp(), serial, width, height);
|
||||||
|
}
|
||||||
|
static void layer_close(void *d, struct zwlr_layer_surface_v1 *s) {
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
static const struct zwlr_layer_surface_v1_listener layer_listener = {
|
||||||
|
.configure = layer_configure, .closed = layer_close};
|
||||||
|
static void output_name(void *d, struct wl_output *o, const char *name) {
|
||||||
|
if (!strcmp(name, "HEADLESS-1"))
|
||||||
|
h1 = o;
|
||||||
|
}
|
||||||
|
static void output_geometry(void *d, struct wl_output *o, int32_t x, int32_t y,
|
||||||
|
int32_t w, int32_t h, int32_t sp, const char *m,
|
||||||
|
const char *n, int32_t tr) {}
|
||||||
|
static void output_mode(void *d, struct wl_output *o, uint32_t flags, int32_t w,
|
||||||
|
int32_t h, int32_t refresh) {}
|
||||||
|
static void output_done(void *d, struct wl_output *o) {}
|
||||||
|
static void output_scale(void *d, struct wl_output *o, int32_t scale) {}
|
||||||
|
static void output_description(void *d, struct wl_output *o, const char *desc) {
|
||||||
|
}
|
||||||
|
static const struct wl_output_listener output_listener = {
|
||||||
|
.geometry = output_geometry,
|
||||||
|
.mode = output_mode,
|
||||||
|
.done = output_done,
|
||||||
|
.scale = output_scale,
|
||||||
|
.name = output_name,
|
||||||
|
.description = output_description};
|
||||||
|
static void global(void *d, struct wl_registry *r, uint32_t id,
|
||||||
|
const char *name, uint32_t v) {
|
||||||
|
if (!strcmp(name, "wl_compositor"))
|
||||||
|
compositor =
|
||||||
|
wl_registry_bind(r, id, &wl_compositor_interface, v < 4 ? v : 4);
|
||||||
|
else if (!strcmp(name, "wl_shm"))
|
||||||
|
shm = wl_registry_bind(r, id, &wl_shm_interface, 1);
|
||||||
|
else if (!strcmp(name, "xdg_wm_base"))
|
||||||
|
wm = wl_registry_bind(r, id, &xdg_wm_base_interface, v < 3 ? v : 3);
|
||||||
|
else if (!strcmp(name, "zwlr_layer_shell_v1"))
|
||||||
|
shell =
|
||||||
|
wl_registry_bind(r, id, &zwlr_layer_shell_v1_interface, v < 2 ? v : 2);
|
||||||
|
else if (!strcmp(name, "wl_output") && v >= 4) {
|
||||||
|
struct wl_output *o = wl_registry_bind(r, id, &wl_output_interface, 4);
|
||||||
|
wl_output_add_listener(o, &output_listener, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void removed(void *d, struct wl_registry *r, uint32_t id) {}
|
||||||
|
static const struct wl_registry_listener registry_listener = {
|
||||||
|
.global = global, .global_remove = removed};
|
||||||
|
static void stop(int s) { running = 0; }
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc != 2)
|
||||||
|
return 2;
|
||||||
|
mode = argv[1];
|
||||||
|
if (strcmp(mode, "background") && strcmp(mode, "glass") &&
|
||||||
|
strcmp(mode, "filler") && strcmp(mode, "reference"))
|
||||||
|
return 2;
|
||||||
|
signal(SIGTERM, stop);
|
||||||
|
display = wl_display_connect(NULL);
|
||||||
|
if (!display)
|
||||||
|
return 1;
|
||||||
|
struct wl_registry *r = wl_display_get_registry(display);
|
||||||
|
wl_registry_add_listener(r, ®istry_listener, NULL);
|
||||||
|
if (wl_display_roundtrip(display) < 0 || wl_display_roundtrip(display) < 0)
|
||||||
|
return 1;
|
||||||
|
if (!compositor || !shm || !wm)
|
||||||
|
return 2;
|
||||||
|
xdg_wm_base_add_listener(wm, &wm_listener, NULL);
|
||||||
|
surface = wl_compositor_create_surface(compositor);
|
||||||
|
if (!strcmp(mode, "background")) {
|
||||||
|
if (!shell || !h1)
|
||||||
|
return 2;
|
||||||
|
layer = zwlr_layer_shell_v1_get_layer_surface(
|
||||||
|
shell, surface, h1, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND,
|
||||||
|
"mosaic-dynamic-background");
|
||||||
|
zwlr_layer_surface_v1_add_listener(layer, &layer_listener, NULL);
|
||||||
|
zwlr_layer_surface_v1_set_size(layer, 0, 0);
|
||||||
|
zwlr_layer_surface_v1_set_anchor(layer,
|
||||||
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
|
||||||
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
|
||||||
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
||||||
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
|
||||||
|
zwlr_layer_surface_v1_set_exclusive_zone(layer, -1);
|
||||||
|
zwlr_layer_surface_v1_set_keyboard_interactivity(layer, 0);
|
||||||
|
} else {
|
||||||
|
xdg = xdg_wm_base_get_xdg_surface(wm, surface);
|
||||||
|
xdg_surface_add_listener(xdg, &xdg_listener, NULL);
|
||||||
|
top = xdg_surface_get_toplevel(xdg);
|
||||||
|
xdg_toplevel_add_listener(top, &top_listener, NULL);
|
||||||
|
const char *app = !strcmp(mode, "reference") ? "org.mosaic.StaticReference"
|
||||||
|
: !strcmp(mode, "glass") ? "org.mosaic.BlurGlass"
|
||||||
|
: "org.mosaic.BlurFiller";
|
||||||
|
xdg_toplevel_set_app_id(top, app);
|
||||||
|
xdg_toplevel_set_title(top, app);
|
||||||
|
}
|
||||||
|
wl_surface_commit(surface);
|
||||||
|
while (running) {
|
||||||
|
if (wl_display_dispatch_pending(display) < 0)
|
||||||
|
break;
|
||||||
|
if (wl_display_flush(display) < 0 && errno != EAGAIN)
|
||||||
|
break;
|
||||||
|
struct pollfd fds[2] = {
|
||||||
|
{.fd = wl_display_get_fd(display), .events = POLLIN},
|
||||||
|
{.fd = STDIN_FILENO, .events = POLLIN}};
|
||||||
|
int n = poll(fds, 2, 100);
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fds[0].revents & (POLLIN | POLLERR | POLLHUP))
|
||||||
|
if (wl_display_dispatch(display) < 0)
|
||||||
|
break;
|
||||||
|
if (fds[1].revents & POLLIN) {
|
||||||
|
char cmd[64];
|
||||||
|
if (!fgets(cmd, sizeof(cmd), stdin))
|
||||||
|
break;
|
||||||
|
if (!strcmp(mode, "background") && (cmd[0] == 'A' || cmd[0] == 'B') &&
|
||||||
|
cmd[1] == '\n') {
|
||||||
|
pattern = cmd[0];
|
||||||
|
draw();
|
||||||
|
fprintf(stderr, "COMMAND %c DONE ns=%lld\n", pattern, stamp());
|
||||||
|
} else if (!strncmp(cmd, "close", 5))
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int error = wl_display_get_error(display);
|
||||||
|
fprintf(stderr, "EXIT ns=%lld mode=%s error=%d commits=%u\n", stamp(), mode,
|
||||||
|
error, commits);
|
||||||
|
if (layer)
|
||||||
|
zwlr_layer_surface_v1_destroy(layer);
|
||||||
|
if (top)
|
||||||
|
xdg_toplevel_destroy(top);
|
||||||
|
if (xdg)
|
||||||
|
xdg_surface_destroy(xdg);
|
||||||
|
wl_surface_destroy(surface);
|
||||||
|
wl_display_flush(display);
|
||||||
|
while (buffers)
|
||||||
|
free_pixels(buffers);
|
||||||
|
wl_registry_destroy(r);
|
||||||
|
wl_display_disconnect(display);
|
||||||
|
return error ? 1 : 0;
|
||||||
|
}
|
||||||
82
tooling/probes/step20c-optimized-blur-edge/model.py
Normal file
82
tooling/probes/step20c-optimized-blur-edge/model.py
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Reuse V1 ideal kernels; compare hypothesis with R3 native reconstruction order.
|
||||||
|
|
||||||
|
CONTRACT: no GLSL/native precision equivalence, FBO contents or causal proof.
|
||||||
|
INVARIANT: model prediction is fixed before fitting; no kernel/offset fitting.
|
||||||
|
"""
|
||||||
|
import ast
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
import numpy as np
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
lab=Path(sys.argv[1]).resolve()
|
||||||
|
fixture=Path(__file__).resolve().parent
|
||||||
|
historical=fixture.parent/'step20c-optimized-blur-cache/edge-model.py'
|
||||||
|
source=historical.read_text()
|
||||||
|
# WHY: reuse the exact reviewed functions without executing the historical writer.
|
||||||
|
# CONTRACT: retain only function definitions/imports and W,H constants from its AST.
|
||||||
|
module=ast.parse(source)
|
||||||
|
selected=[node for node in module.body if isinstance(node,(ast.Import,ast.ImportFrom,ast.FunctionDef))
|
||||||
|
or (isinstance(node,ast.Assign) and any(isinstance(t,ast.Tuple) for t in node.targets))]
|
||||||
|
context={}
|
||||||
|
exec(compile(ast.Module(body=selected,type_ignores=[]),str(historical),'exec'),context)
|
||||||
|
rebuild=context['rebuild'];pattern=context['pattern']
|
||||||
|
run=lab/'runs/R3'
|
||||||
|
lines=(run/'compositor.log').read_text().splitlines()
|
||||||
|
commits=[]
|
||||||
|
for line in (run/'background.log').read_text().splitlines():
|
||||||
|
if line.startswith('CLIENT_COMMIT '):
|
||||||
|
commits.append((int(re.search(r'ns=(\d+)',line)[1]),re.search(r'pattern=([AB])',line)[1]))
|
||||||
|
rebuilds=[int(re.search(r'ns=(\d+)',line)[1]) for line in lines
|
||||||
|
if line.startswith('OPT_GPU_REBUILD ') and 'output=HEADLESS-1' in line]
|
||||||
|
ping=np.zeros((600,800,3));pong=ping.copy();states=[]
|
||||||
|
for ns in rebuilds:
|
||||||
|
current=next((c for t,c in reversed(commits) if t<ns),None)
|
||||||
|
image=pattern(current) if current else np.zeros((600,800,3))
|
||||||
|
cache=rebuild(image,ping,pong)
|
||||||
|
states.append((ns,current,cache))
|
||||||
|
events=[json.loads(line) for line in (run/'events.jsonl').read_text().splitlines()]
|
||||||
|
metrics={};predictions={};actuals={}
|
||||||
|
for event in events:
|
||||||
|
if event['kind']!='capture' or event['output']!='HEADLESS-1' or event['tag']=='P0-FX0':continue
|
||||||
|
ns,current,cache=next(s for s in reversed(states) if s[0]<event['before_ns'])
|
||||||
|
predicted=np.round(cache*(119/255)+[68,32,16])
|
||||||
|
actual=np.array(Image.open(run/event['path']).convert('RGB')).astype(float)
|
||||||
|
predictions[event['tag']]=predicted;actuals[event['tag']]=actual
|
||||||
|
rois={'center':(520,100,720,500),'boundary':(720,50,800,550),
|
||||||
|
'physical_right':(750,0,800,600),'glass_bottom':(480,550,800,600)}
|
||||||
|
measurements={}
|
||||||
|
for name,(l,t,r,b) in rois.items():
|
||||||
|
d=np.abs(predicted[t:b,l:r]-actual[t:b,l:r])
|
||||||
|
measurements[name]={'mean_abs_channel_error':float(d.mean()),
|
||||||
|
'max_channel_error':float(d.max()),'within_one_channel':float((d<=1).mean())}
|
||||||
|
metrics[event['tag']]={'source':current,'model_rebuild_ns':ns,'ROIs':measurements}
|
||||||
|
distribution={}
|
||||||
|
for first,second in [('P1-B-natural','P2-B-explicit'),('P0-FX2','P3-A-natural')]:
|
||||||
|
pd=predictions[second]-predictions[first];nd=actuals[second]-actuals[first]
|
||||||
|
# Model applies only to the measured glass, not the entire composited source.
|
||||||
|
pd[:,:480]=0;pm=np.any(pd!=0,axis=2);nm=np.any(nd!=0,axis=2)
|
||||||
|
union=(pm|nm).sum();intersection=(pm&nm).sum()
|
||||||
|
disagreement=np.abs(pd-nd)
|
||||||
|
distribution[first+' -> '+second]={
|
||||||
|
'predicted_changed_pixels_in_visible_glass':int(pm.sum()),'native_changed_pixels':int(nm.sum()),
|
||||||
|
'mask_intersection':int(intersection),'mask_union':int(union),
|
||||||
|
'mask_jaccard':float(intersection/union) if union else 1,
|
||||||
|
'predicted_max_channel':float(np.abs(pd).max()),'native_max_channel':float(np.abs(nd).max()),
|
||||||
|
'delta_residual_mean_abs_channel':float(disagreement[:,480:].mean()),
|
||||||
|
'predicted_columns':pm.sum(axis=0).astype(int).tolist(),
|
||||||
|
'predicted_rows':pm.sum(axis=1).astype(int).tolist(),
|
||||||
|
'native_columns':nm.sum(axis=0).astype(int).tolist(),'native_rows':nm.sum(axis=1).astype(int).tolist(),
|
||||||
|
'interpretation':'fixed-kernel history compatibility only; native FBO tail and mediump behavior unobserved'}
|
||||||
|
(lab/'results/edge-model-comparison.json').write_text(json.dumps({
|
||||||
|
'model_source':str(historical),'model_sha256':hashlib.sha256(historical.read_bytes()).hexdigest(),
|
||||||
|
'native_schedule':'R3 OPT_GPU_REBUILD timestamps only; no invented timestamps for untraced runs',
|
||||||
|
'rebuild_count':len(rebuilds),'metrics':metrics,'distributions':distribution,
|
||||||
|
'causality':'NOT DEMONSTRATED; no GPU readback or intervention'},indent=2)+'\n')
|
||||||
|
print(json.dumps({'rebuild_count':len(rebuilds),'metrics':metrics,
|
||||||
|
'distributions':{k:{n:v for n,v in d.items() if not n.endswith(('columns','rows'))}
|
||||||
|
for k,d in distribution.items()}},indent=2))
|
||||||
34
tooling/probes/step20c-optimized-blur-edge/plot.py
Normal file
34
tooling/probes/step20c-optimized-blur-edge/plot.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Optional standalone scientific SVG from complete offline distributions."""
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
lab=Path(sys.argv[1]).resolve()
|
||||||
|
os.environ['MPLCONFIGDIR']=str(lab/'plot-cache')
|
||||||
|
import matplotlib
|
||||||
|
matplotlib.use('Agg')
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
out=lab/'results'
|
||||||
|
columns=json.loads((out/'column-distribution.json').read_text())
|
||||||
|
rows=json.loads((out/'row-distribution.json').read_text())
|
||||||
|
model=json.loads((out/'edge-model-comparison.json').read_text())['distributions']
|
||||||
|
pairs=['P1-B-natural -> P2-B-explicit','P0-FX2 -> P3-A-natural']
|
||||||
|
fig,axes=plt.subplots(2,2,figsize=(12,7),constrained_layout=True)
|
||||||
|
for index,key in enumerate(pairs):
|
||||||
|
for dim,data,name in [(0,columns,'columns'),(1,rows,'rows')]:
|
||||||
|
ax=axes[dim,index]
|
||||||
|
ax.plot(data['R0'][key],label='R0/R1 standard native',color='#376ca0',linewidth=1.1)
|
||||||
|
ax.plot(data['R2'][key],label='R2/R3 Mosaic native',color='#19816b',linewidth=1.1)
|
||||||
|
ax.plot(model[key]['predicted_'+name],label='Fixed offline model, Mosaic domain',
|
||||||
|
color='#ba6d20',linewidth=1,linestyle='--',alpha=.8)
|
||||||
|
ax.axvspan(750 if dim==0 else 550,800 if dim==0 else 600,color='#888888',alpha=.12)
|
||||||
|
ax.set_title(('B natural / explicit' if index==0 else 'A initial / return')+' — '+name)
|
||||||
|
ax.set_xlabel('Output-local '+('x' if dim==0 else 'y')+' (px)')
|
||||||
|
ax.set_ylabel('Changed pixels per '+('column' if dim==0 else 'row'))
|
||||||
|
ax.set_xlim(0,800 if dim==0 else 600);ax.grid(alpha=.2)
|
||||||
|
axes[0,0].legend(fontsize=8)
|
||||||
|
fig.suptitle('Complete edge distributions — shared native behavior; offline model is not causal proof',fontsize=12)
|
||||||
|
fig.savefig(out/'edge-distributions.svg',metadata={'Date':None})
|
||||||
|
print('PASS standalone SVG; not an additional compositor capture')
|
||||||
92
tooling/probes/step20c-optimized-blur-edge/preflight.py
Normal file
92
tooling/probes/step20c-optimized-blur-edge/preflight.py
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Offline source, callback, protocol and pinned sampling audit; no graphics."""
|
||||||
|
import ast
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
lab = Path(sys.argv[1]).resolve()
|
||||||
|
fixture = Path(__file__).resolve().parent
|
||||||
|
repo = fixture.parents[2]
|
||||||
|
results = lab / 'results'
|
||||||
|
for path in fixture.glob('*.py'):
|
||||||
|
ast.parse(path.read_text(), filename=str(path))
|
||||||
|
for path in lab.glob('*.xml'):
|
||||||
|
ET.parse(path)
|
||||||
|
client = (fixture / 'clients.c').read_text()
|
||||||
|
assert client == (lab / 'client-source.c').read_text()
|
||||||
|
callback = client[client.index('static void layer_configure('):client.index('static void layer_close(')]
|
||||||
|
assert 'draw(' not in callback and 'ack_configure(s, serial)' in callback
|
||||||
|
# WHY: exercise the real callback text under duplicate configures without Wayland.
|
||||||
|
# CONTRACT: stub only ACK and clock; no native graphics or mutation reservation.
|
||||||
|
harness = '''#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
struct zwlr_layer_surface_v1 {int unused;};
|
||||||
|
static int width=420,height=320;
|
||||||
|
static unsigned commits=0,acks=0;
|
||||||
|
static long long stamp(void){return 0;}
|
||||||
|
static void zwlr_layer_surface_v1_ack_configure(struct zwlr_layer_surface_v1 *s,uint32_t serial){(void)s;(void)serial;++acks;}
|
||||||
|
''' + callback + '''
|
||||||
|
int main(void){struct zwlr_layer_surface_v1 s={0};layer_configure(NULL,&s,1,800,600);layer_configure(NULL,&s,2,800,600);assert(acks==2 && commits==0 && width==800 && height==600);commits=1;layer_configure(NULL,&s,3,800,600);assert(acks==3 && commits==1);return 0;}
|
||||||
|
'''
|
||||||
|
(lab / 'callback-test.c').write_text(harness)
|
||||||
|
subprocess.run(['cc', '-std=c17', '-Wall', '-Wextra', '-Werror', '-Wno-unused-parameter',
|
||||||
|
str(lab / 'callback-test.c'), '-o', str(lab / 'callback-test')], check=True)
|
||||||
|
subprocess.run([str(lab / 'callback-test')], check=True)
|
||||||
|
assert 'commits >= 3' in client and "pattern != (commits == 1 ? 'B' : 'A')" in client
|
||||||
|
assert 'WL_SHM_FORMAT_ARGB8888' in client and 'WL_SHM_FORMAT_XRGB8888' in client
|
||||||
|
assert 'live_buffers >= 8' in client and 'wl_buffer_listener' in client
|
||||||
|
assert 'wl_display_roundtrip(display)' in client and 'wl_output_interface, 4' in client
|
||||||
|
run = (fixture / 'run.py').read_text()
|
||||||
|
assert "reserve(lab,mode,'mutation')" in run and "reserve(lab,mode,'capture')" in run
|
||||||
|
assert "['swaymsg','-s',str(sock)" in run and "signal.setitimer(signal.ITIMER_REAL,150)" in run
|
||||||
|
assert "if instrumented:env['OPT_TRACE']='1'" in run
|
||||||
|
# Both private controls have every same unconditional borrowed read and old trace.
|
||||||
|
trace_header = (lab / 'scenefx/include/render/opt_probe.h').read_text()
|
||||||
|
assert 'if (getenv("OPT_TRACE"))' in trace_header
|
||||||
|
for shader in ('blur1.frag', 'blur2.frag'):
|
||||||
|
rel = Path('render/fx_renderer/shaders') / shader
|
||||||
|
assert (lab / 'scene0' / rel).read_bytes() == (lab / 'scenefx' / rel).read_bytes()
|
||||||
|
command = (lab / 'pristine/sway/commands/blur.c').read_text()
|
||||||
|
assert 'arrange_container(con)' in command and 'root->all_outputs' in command
|
||||||
|
passes = []
|
||||||
|
# Source-derived coordinate support, ideal bilinear positions, no driver claims.
|
||||||
|
for direction, level, valid in [('down', 0, (800,600)), ('down', 1, (400,300)),
|
||||||
|
('down', 2, (200,150)), ('up', 2, (100,75)),
|
||||||
|
('up', 1, (200,150)), ('up', 0, (400,300))]:
|
||||||
|
written = (800 // (2 ** (level + 1 if direction == 'down' else level)),
|
||||||
|
600 // (2 ** (level + 1 if direction == 'down' else level)))
|
||||||
|
mapping = '2*(p+0.5)-0.5 plus offsets +/-5' if direction == 'down' else '(p+0.5)/2-0.5 plus axial +/-2.5 and diagonal +/-1.25'
|
||||||
|
maximum = [(2 * (v - .5) - .5 + 5) if direction == 'down'
|
||||||
|
else ((v - .5) / 2 - .5 + 2.5) for v in written]
|
||||||
|
passes.append({'direction': direction, 'level': level, 'framebuffer': [800,600],
|
||||||
|
'fresh_input_domain': list(valid), 'written_domain': list(written),
|
||||||
|
'sampler_mapping': mapping, 'max_unclamped_sample_xy': maximum,
|
||||||
|
'can_read_beyond_fresh_domain': (direction == 'up') or (direction == 'down' and level > 0),
|
||||||
|
'possible_value': 'earlier write/allocation content, native content NOT OBSERVED',
|
||||||
|
'final_influence': 'propagated right/bottom boundary bands; strength predicted by model only'})
|
||||||
|
source_files = [lab / 'scene0/render/fx_renderer' / p for p in
|
||||||
|
('fx_pass.c','fx_texture.c','fx_framebuffer.c','fx_offscreen_buffers.c','shaders/blur1.frag','shaders/blur2.frag')]
|
||||||
|
(results / 'sampling-domain-audit.json').write_text(json.dumps({
|
||||||
|
'status': 'SOURCE POSSIBILITY; native intermediate content NOT OBSERVED',
|
||||||
|
'source_sha256': {str(p.relative_to(lab)): hashlib.sha256(p.read_bytes()).hexdigest() for p in source_files},
|
||||||
|
'passes': passes, 'filter': 'GL_LINEAR', 'wrap': 'GL_CLAMP_TO_EDGE full texture, not reduced domain',
|
||||||
|
'precision': 'native mediump GLES versus ideal offline bilinear/8-bit rounding',
|
||||||
|
'clear': 'no full color clear between blur passes in audited render_blur_segments',
|
||||||
|
'blur_cycle': 'scoped blur flag + arrange_container; dirty every output; natural background commit dirties its output',
|
||||||
|
'causality': 'not established by source audit'}, indent=2) + '\n')
|
||||||
|
(results / 'preflight.json').write_text(json.dumps({
|
||||||
|
'AST': 'PASS', 'XML': 'PASS', 'C17_callback_duplicate_ACK_no_draw': 'PASS',
|
||||||
|
'SHM_bounds_formats_lifetimes': 'PASS source audit, live proof pending',
|
||||||
|
'Wayland_connections_protocols': 'PASS source audit and C17 build, live proof pending',
|
||||||
|
'explicit_command_reservations': 'PASS source audit',
|
||||||
|
'timeouts_owned_cleanup': 'PASS source audit',
|
||||||
|
'shader_bytes_pristine_private': 'IDENTICAL',
|
||||||
|
'trace_toggle': 'presence only; same private code, old traces remain',
|
||||||
|
'graphical_runs': 0}, indent=2) + '\n')
|
||||||
|
print('PASS AST/XML/C17 callback, SHM/Wayland/reservation/cleanup audit, immutable shaders, sampling audit')
|
||||||
109
tooling/probes/step20c-optimized-blur-edge/prepare.py
Normal file
109
tooling/probes/step20c-optimized-blur-edge/prepare.py
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build-only reconstruction from fixed archives and immutable source patches.
|
||||||
|
|
||||||
|
CONTRACT: no compositor launch, system install or write to older fixtures.
|
||||||
|
INVARIANT: consumed LABs cannot be rebuilt, and prepared identities are hashed.
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tarfile
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
fixture = Path(__file__).resolve().parent
|
||||||
|
repo = fixture.parents[2]
|
||||||
|
lab = Path(sys.argv[1]).resolve() if len(sys.argv) == 2 else Path(
|
||||||
|
tempfile.mkdtemp(prefix='swayfx-mosaic-optimized-edge-', dir=Path.home()))
|
||||||
|
if (lab / 'runs').exists() and any((lab / 'runs').iterdir()):
|
||||||
|
raise RuntimeError('never rebuild a consumed LAB')
|
||||||
|
(lab / 'results').mkdir(parents=True, exist_ok=True)
|
||||||
|
(lab / 'runs').mkdir(exist_ok=True)
|
||||||
|
print('LAB=' + str(lab), flush=True)
|
||||||
|
|
||||||
|
def run(args, **kwargs):
|
||||||
|
with (lab / 'build.log').open('ab') as out:
|
||||||
|
subprocess.run(args, check=True, stdout=out, stderr=subprocess.STDOUT, **kwargs)
|
||||||
|
|
||||||
|
def sha(path):
|
||||||
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||||
|
|
||||||
|
def archive(git, revision, name):
|
||||||
|
target = lab / name
|
||||||
|
if target.exists():
|
||||||
|
raise RuntimeError('existing source tree; continue Meson explicitly, never overwrite')
|
||||||
|
target.mkdir()
|
||||||
|
data = subprocess.check_output(['git', '-C', str(git), 'archive', revision])
|
||||||
|
tarfile.open(fileobj=io.BytesIO(data)).extractall(target, filter='data')
|
||||||
|
|
||||||
|
scene_revision = '37ccd723bef49e6891156ffafce8f549f01446cc'
|
||||||
|
mosaic_revision = 'cd550382b311efdbfe3ed892f4e1d281d852e754'
|
||||||
|
pristine_revision = 'fd71a6bdc061bd633b488ae7b83e8a6981d22f86'
|
||||||
|
run(['git', 'clone', '--quiet', '--no-checkout', 'https://github.com/wlrfx/scenefx.git', str(lab / 'scenefx-git')])
|
||||||
|
for name in ('scene0', 'scenefx'):
|
||||||
|
archive(lab / 'scenefx-git', scene_revision, name)
|
||||||
|
archive(repo, pristine_revision, 'pristine')
|
||||||
|
archive(repo, mosaic_revision, 'mosaic')
|
||||||
|
chains = {
|
||||||
|
'scenefx': ['step20c-valid-grab/scenefx-popup-plus-base.patch',
|
||||||
|
'step20c-temporal-damage/scenefx-timing.patch',
|
||||||
|
'step20c-optimized-blur-cache/scenefx-cache-trace.patch'],
|
||||||
|
'mosaic': ['step20c-valid-grab/mosaic-popup-plus-base.patch',
|
||||||
|
'step20c-valid-grab/hidden-guard.patch',
|
||||||
|
'step20c-temporal-damage/mosaic-output-timing.patch',
|
||||||
|
'step20c-presentation-identity/presentation-events.patch',
|
||||||
|
'step20c-optimized-blur-cache/sway-source-trace.patch']}
|
||||||
|
patches = []
|
||||||
|
(lab / 'patches').mkdir()
|
||||||
|
for tree, chain in chains.items():
|
||||||
|
for name in chain:
|
||||||
|
source = repo / 'tooling/probes' / name
|
||||||
|
target = lab / 'patches' / source.name
|
||||||
|
target.write_bytes(source.read_bytes())
|
||||||
|
patches.append({'path': name, 'sha256': sha(target), 'target': tree})
|
||||||
|
run(['git', 'apply', '--check', str(target)], cwd=lab / tree)
|
||||||
|
run(['git', 'apply', str(target)], cwd=lab / tree)
|
||||||
|
for source, build in [('scene0', 'scene0-build'), ('scenefx', 'scenefx-build')]:
|
||||||
|
run(['meson', 'setup', str(lab / build), str(lab / source), '-Dexamples=false', '-Dwerror=false'])
|
||||||
|
run(['meson', 'compile', '-C', str(lab / build), '-j', '8'])
|
||||||
|
for source, build, scene in [('pristine', 'pristine-build', 'scene0-build'),
|
||||||
|
('mosaic', 'mosaic-build', 'scenefx-build')]:
|
||||||
|
env = {**os.environ, 'PKG_CONFIG_PATH': str(lab / scene / 'meson-uninstalled')}
|
||||||
|
args = ['meson', 'setup', str(lab / build), str(lab / source),
|
||||||
|
'-Ddefault-wallpaper=false', '-Dswaybar=false', '-Dswaynag=false',
|
||||||
|
'-Dman-pages=disabled', '-Dsd-bus-provider=libsystemd', '-Dwerror=false']
|
||||||
|
if source == 'mosaic':
|
||||||
|
args.append('-Dmosaic-package=true')
|
||||||
|
run(args, env=env)
|
||||||
|
run(['meson', 'compile', '-C', str(lab / build), '-j', '8'], env=env)
|
||||||
|
protocols = repo / 'tooling/probes/step20c-optimized-blur-cache'
|
||||||
|
for stem, name, digest in [
|
||||||
|
('layer-shell', 'wlr-layer-shell-unstable-v1.xml', '996b8c66e1c2276c443336d4cb174634e8e5948823779042f244930525b79cc2'),
|
||||||
|
('xdg-shell', 'xdg-shell.xml', '7ba7f9c8473deee674cb1f154a18abd0bb0cc072604fc055b0c15e459fc4c7df')]:
|
||||||
|
xml = protocols / name
|
||||||
|
assert sha(xml) == digest
|
||||||
|
target = lab / name
|
||||||
|
target.write_bytes(xml.read_bytes())
|
||||||
|
run(['wayland-scanner', 'client-header', str(target), str(lab / (stem + '-client.h'))])
|
||||||
|
run(['wayland-scanner', 'private-code', str(target), str(lab / (stem + '-protocol.c'))])
|
||||||
|
(lab / 'client-source.c').write_bytes((fixture / 'clients.c').read_bytes())
|
||||||
|
flags = subprocess.check_output(['pkg-config', '--cflags', '--libs', 'wayland-client'], text=True).split()
|
||||||
|
run(['cc', '-std=c17', '-Wall', '-Wextra', '-Werror', '-Wno-unused-parameter',
|
||||||
|
'-I' + str(lab), str(lab / 'client-source.c'), str(lab / 'xdg-shell-protocol.c'),
|
||||||
|
str(lab / 'layer-shell-protocol.c'), '-o', str(lab / 'clients'), *flags])
|
||||||
|
run(['meson', 'test', '-C', str(lab / 'mosaic-build'), 'mosaic-model', '--print-errorlogs'])
|
||||||
|
versions = {package: subprocess.check_output(['pkg-config', '--modversion', package], text=True).strip()
|
||||||
|
for package in ('wlroots-0.20', 'scenefx-0.5', 'wayland-client', 'wayland-protocols')}
|
||||||
|
binaries = {str(p.relative_to(lab)): sha(p) for p in [
|
||||||
|
lab / 'clients', lab / 'mosaic-build/sway/swayfx-mosaic', lab / 'pristine-build/sway/sway',
|
||||||
|
lab / 'scenefx-build/libscenefx-0.5.so', lab / 'scene0-build/libscenefx-0.5.so']}
|
||||||
|
for rel in ('mosaic-build/sway/swayfx-mosaic', 'pristine-build/sway/sway'):
|
||||||
|
run(['ldd', str(lab / rel)])
|
||||||
|
(lab / 'results/build-identities.json').write_text(json.dumps({
|
||||||
|
'revisions': {'SceneFX': scene_revision, 'Mosaic': mosaic_revision, 'pristine': pristine_revision},
|
||||||
|
'packages': versions, 'patches': patches, 'binaries': binaries,
|
||||||
|
'R2_R3': 'identical binary/library/client/config; only OPT_TRACE presence differs'}, indent=2) + '\n')
|
||||||
|
print('BUILD_PASS LAB=' + str(lab), flush=True)
|
||||||
180
tooling/probes/step20c-optimized-blur-edge/run.py
Normal file
180
tooling/probes/step20c-optimized-blur-edge/run.py
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""One reserved, deadline-limited run per mode; only owned headless processes."""
|
||||||
|
import argparse,json,os,re,shutil,signal,subprocess,time
|
||||||
|
from pathlib import Path
|
||||||
|
import numpy as np
|
||||||
|
from PIL import Image
|
||||||
|
from budget import reserve,DEFAULT
|
||||||
|
p=argparse.ArgumentParser();p.add_argument('lab',type=Path);p.add_argument('mode',choices=['R0','R1','R2','R3']);a=p.parse_args()
|
||||||
|
lab=a.lab.resolve();mode=a.mode
|
||||||
|
if not (lab/'clients').is_file():p.error('prepared LAB required')
|
||||||
|
if not (lab/'results/preflight.json').is_file():p.error('offline preflight required')
|
||||||
|
import hashlib
|
||||||
|
identities=json.loads((lab/'results/build-identities.json').read_text())
|
||||||
|
for rel,digest in identities['binaries'].items():
|
||||||
|
if hashlib.sha256((lab/rel).read_bytes()).hexdigest()!=digest:p.error('changed prepared binary/library')
|
||||||
|
if (lab/'client-source.c').read_bytes()!=Path(__file__).with_name('clients.c').read_bytes():p.error('changed compiled client source')
|
||||||
|
reserve(lab,mode,'run')
|
||||||
|
run=lab/'runs'/mode;run.mkdir(mode=0o700)
|
||||||
|
runtime=run/'runtime';runtime.mkdir(mode=0o700)
|
||||||
|
(run/'fixture-source.py').write_text(Path(__file__).read_text())
|
||||||
|
shutil.copy2(Path(__file__).with_name('clients.c'),run/'client-source.c')
|
||||||
|
(run/'config').write_text('''output HEADLESS-1 resolution 800x600 scale 1 transform normal position -800 0
|
||||||
|
output HEADLESS-2 resolution 800x600 scale 1 transform normal position 0 0
|
||||||
|
workspace 1 output HEADLESS-1
|
||||||
|
workspace 2 output HEADLESS-2
|
||||||
|
focus_follows_mouse no
|
||||||
|
mouse_warping none
|
||||||
|
default_border none
|
||||||
|
font monospace 8
|
||||||
|
shadows disable
|
||||||
|
blur disable
|
||||||
|
blur_xray disable
|
||||||
|
blur_radius 5
|
||||||
|
blur_passes 3
|
||||||
|
blur_noise 0
|
||||||
|
blur_brightness 1
|
||||||
|
blur_contrast 1
|
||||||
|
blur_saturation 1
|
||||||
|
corner_radius 0
|
||||||
|
animation_duration_ms 0
|
||||||
|
''')
|
||||||
|
env={k:v for k,v in os.environ.items() if k not in ['SWAYSOCK','I3SOCK','WAYLAND_DISPLAY','LD_LIBRARY_PATH','OPT_TRACE','SAVED_TRACE','SAVED_HIT_TRACE','FX_TRACE']}
|
||||||
|
env.update(XDG_RUNTIME_DIR=str(runtime),WLR_BACKENDS='headless',WLR_HEADLESS_OUTPUTS='2',WLR_RENDERER='gles2')
|
||||||
|
private=mode!='R0'
|
||||||
|
mosaic=mode in ('R2','R3')
|
||||||
|
instrumented=mode=='R3'
|
||||||
|
binary=lab/('mosaic-build/sway/swayfx-mosaic' if private else 'pristine-build/sway/sway')
|
||||||
|
env['LD_LIBRARY_PATH']=str(lab/('scenefx-build' if private else 'scene0-build'))
|
||||||
|
if instrumented:env['OPT_TRACE']='1'
|
||||||
|
geometry_baseline={}
|
||||||
|
children=[];files=[];comp=None;sock=None;failure=None;started=time.monotonic();captures=[]
|
||||||
|
|
||||||
|
def event(kind,**data):
|
||||||
|
with (run/'events.jsonl').open('a') as out:out.write(json.dumps({'kind':kind,'ns':time.monotonic_ns(),**data})+'\n')
|
||||||
|
def guard():
|
||||||
|
if time.monotonic()-started>150:raise TimeoutError('run deadline')
|
||||||
|
for q in run.glob('*.log'):
|
||||||
|
if q.stat().st_size>25_000_000:raise RuntimeError('bounded log exceeded')
|
||||||
|
def spawn(argv,name,stdin=False):
|
||||||
|
guard();f=(run/name).open('w');files.append(f)
|
||||||
|
child=subprocess.Popen(argv,env=env,stdin=subprocess.PIPE if stdin else subprocess.DEVNULL,stdout=f,stderr=subprocess.STDOUT,text=stdin,start_new_session=True);children.append(child)
|
||||||
|
event('spawn',argv=argv,pid=child.pid);return child
|
||||||
|
def wait(fn,seconds=8):
|
||||||
|
end=time.monotonic()+seconds
|
||||||
|
while time.monotonic()<end:
|
||||||
|
guard();result=fn()
|
||||||
|
if result:return result
|
||||||
|
if comp and comp.poll() is not None:raise RuntimeError('compositor exited')
|
||||||
|
time.sleep(.025)
|
||||||
|
raise TimeoutError('fixture wait')
|
||||||
|
def ipc(*args):
|
||||||
|
guard();r=subprocess.run(['swaymsg','-s',str(sock),*args],env=env,capture_output=True,text=True,timeout=5,check=True)
|
||||||
|
data=json.loads(r.stdout);event('ipc',args=args,data=data);return data
|
||||||
|
def command(s):
|
||||||
|
r=ipc(s)
|
||||||
|
if not r or not all(v.get('success') for v in r):raise RuntimeError('IPC rejected '+s)
|
||||||
|
def nodes(n):
|
||||||
|
yield n
|
||||||
|
for c in n.get('nodes',[])+n.get('floating_nodes',[]):yield from nodes(c)
|
||||||
|
def find(app):return next((n for n in nodes(ipc('-t','get_tree')) if n.get('app_id')==app),None)
|
||||||
|
def log(name):return (run/name).read_text()
|
||||||
|
def snapshot(tag,only_h2=False,only_h1=False):
|
||||||
|
outs=ipc('-t','get_outputs');expected={'HEADLESS-1':(-800,0,800,600),'HEADLESS-2':(0,0,800,600)}
|
||||||
|
if log('background.log').count('CLIENT_COMMIT ')!=json.loads(DEFAULT.read_text())['modes'][mode]['mutation']:raise RuntimeError('unreserved background image')
|
||||||
|
actual={o['name']:tuple(o['rect'][k] for k in ['x','y','width','height']) for o in outs if o['active']}
|
||||||
|
if actual!=expected or any(o['scale']!=1 or o['transform']!='normal' for o in outs if o['active']):raise RuntimeError('output geometry gate')
|
||||||
|
(run/(tag+'-outputs.json')).write_text(json.dumps(outs,indent=2)+'\n')
|
||||||
|
tree=ipc('-t','get_tree')
|
||||||
|
(run/(tag+'-tree.json')).write_text(json.dumps(tree,indent=2)+'\n')
|
||||||
|
geometry={n['app_id']:{k:n.get(k) for k in ('rect','window_rect','deco_rect','geometry','opacity')} for n in nodes(tree) if n.get('app_id')}
|
||||||
|
if tag=='P0-FX0':geometry_baseline.update(geometry)
|
||||||
|
if geometry!=geometry_baseline:raise RuntimeError('applied client geometry/opacity changed')
|
||||||
|
event('graphic_state',tag=tag,geometry=geometry)
|
||||||
|
for name in (['HEADLESS-2'] if only_h2 else ['HEADLESS-1'] if only_h1 else ['HEADLESS-1','HEADLESS-2']):
|
||||||
|
reserve(lab,mode,'capture');q=run/(tag+'-'+name+'.png');before=time.monotonic_ns()
|
||||||
|
subprocess.run(['grim','-s','1','-o',name,str(q)],env=env,timeout=5,check=True,stdout=subprocess.DEVNULL)
|
||||||
|
if Image.open(q).size!=(800,600):raise RuntimeError('capture size gate')
|
||||||
|
record={'tag':tag,'output':name,'path':q.name,'before_ns':before,'after_ns':time.monotonic_ns()};captures.append(record);event('capture',**record)
|
||||||
|
def image(tag,out='HEADLESS-1'):return np.array(Image.open(run/(tag+'-'+out+'.png')).convert('RGB'))
|
||||||
|
def native_gate():
|
||||||
|
text=log('compositor.log')
|
||||||
|
return 'OPT_BLUR_USE' in text and 'OPT_REGEN_RESULT' in text and any('OPT_REGEN_RESULT' in x and 'output=HEADLESS-1' in x and 'result=1' in x for x in text.splitlines()) and any('OPT_BLUR_USE' in x and 'output=HEADLESS-1' in x and 'optimized=1' in x and 'chosen=(nil)' not in x for x in text.splitlines())
|
||||||
|
def mutate(pattern):
|
||||||
|
reserve(lab,mode,'mutation');before=log('background.log').count('CLIENT_COMMIT ');event('mutation_reserved',pattern=pattern)
|
||||||
|
background.stdin.write(pattern+'\n');background.stdin.flush()
|
||||||
|
wait(lambda:log('background.log').count('CLIENT_COMMIT ')>before)
|
||||||
|
count=log('background.log').count('CLIENT_COMMIT ')
|
||||||
|
if count!=before+1:raise RuntimeError('unexpected background commits')
|
||||||
|
event('mutation_received_client',pattern=pattern,count=count);time.sleep(.35)
|
||||||
|
def alarm(s,f):raise TimeoutError('150 second watchdog')
|
||||||
|
signal.signal(signal.SIGALRM,alarm);signal.setitimer(signal.ITIMER_REAL,150)
|
||||||
|
try:
|
||||||
|
f=(run/'compositor.log').open('w');files.append(f)
|
||||||
|
comp=subprocess.Popen([str(binary),'-d','-c',str(run/'config')],env=env,stdout=f,stderr=subprocess.STDOUT,start_new_session=True)
|
||||||
|
def sockets():
|
||||||
|
s=next(iter(runtime.glob('sway-ipc.*.sock')),None);w=next((q for q in runtime.glob('wayland-*') if q.is_socket()),None)
|
||||||
|
return (s,w) if s and w else None
|
||||||
|
sock,way=wait(sockets);env.update(SWAYSOCK=str(sock),WAYLAND_DISPLAY=way.name)
|
||||||
|
(run/'library-maps.txt').write_text(Path(f'/proc/{comp.pid}/maps').read_text())
|
||||||
|
event('renderer_start',pid=comp.pid,binary=str(binary),library=env['LD_LIBRARY_PATH'],OPT_TRACE=env.get('OPT_TRACE'),layout='mosaic' if mosaic else 'splith')
|
||||||
|
background=spawn([str(lab/'clients'),'background'],'background.log',True)
|
||||||
|
wait(lambda:'BACKGROUND_CONFIGURED ' in log('background.log'))
|
||||||
|
if log('background.log').count('CLIENT_COMMIT ')!=0:raise RuntimeError('unreserved configure image')
|
||||||
|
mutate('A')
|
||||||
|
command('workspace 1');command('layout mosaic' if mosaic else 'layout splith')
|
||||||
|
filler=spawn([str(lab/'clients'),'filler'],'filler.log',True);wait(lambda:find('org.mosaic.BlurFiller'))
|
||||||
|
glass=spawn([str(lab/'clients'),'glass'],'glass.log',True);wait(lambda:find('org.mosaic.BlurGlass'))
|
||||||
|
command('workspace 2');reference=spawn([str(lab/'clients'),'reference'],'reference.log',True);wait(lambda:find('org.mosaic.StaticReference'))
|
||||||
|
command('[app_id="org.mosaic.BlurGlass"] focus');time.sleep(.5)
|
||||||
|
if mosaic:
|
||||||
|
tree=ipc('-t','get_tree');ws=next(n for n in nodes(tree) if n.get('type')=='workspace' and n.get('name')=='1');owner=next(n for n in nodes(ws) if n.get('app_id')=='org.mosaic.BlurGlass')
|
||||||
|
current=ws['mosaic']['rows'][0]['scroll_x'];left=owner['rect']['x']+owner['window_rect']['x']-current
|
||||||
|
delta=int(left+owner['window_rect']['width']//2)
|
||||||
|
reserve(lab,mode,'calibration');event('camera_calibration',current=current,logical=owner['rect'],window=owner['window_rect'],delta=delta)
|
||||||
|
command('layout mosaic scroll '+str(delta));time.sleep(.35)
|
||||||
|
if log('background.log').count('CLIENT_COMMIT ')!=1:raise RuntimeError('unexpected initial background image count')
|
||||||
|
snapshot('P0-FX0');time.sleep(.75);snapshot('P0-reference',True)
|
||||||
|
if not np.array_equal(image('P0-FX0','HEADLESS-2'),image('P0-reference','HEADLESS-2')):raise RuntimeError('H2 preflight instability')
|
||||||
|
# Source A must be visible outside glass before interpretation of any cache.
|
||||||
|
source=image('P0-FX0')[100:500,20:160]
|
||||||
|
colors={tuple(x) for x in source.reshape(-1,3)}
|
||||||
|
if not {(245,245,245),(15,25,45)}<=colors:raise RuntimeError('unblurred source gate')
|
||||||
|
command('[app_id="org.mosaic.BlurGlass"] blur enable');time.sleep(.35);snapshot('P0-FX2')
|
||||||
|
roi0=image('P0-FX0')[100:500,520:720].astype(float);roi2=image('P0-FX2')[100:500,520:720].astype(float)
|
||||||
|
adjacent0=np.abs(np.diff(roi0,axis=1)).mean();adjacent2=np.abs(np.diff(roi2,axis=1)).mean()
|
||||||
|
if adjacent0<=5 or adjacent2>=adjacent0*.8 or not np.any(roi0!=roi2):raise RuntimeError('visible filtering gate')
|
||||||
|
if instrumented and not native_gate():raise RuntimeError('optimized native use gate')
|
||||||
|
event('P0_gate',source=True,filtering=True,native_optimized=bool(instrumented),adjacent_fx0=adjacent0,adjacent_fx2=adjacent2)
|
||||||
|
mutate('B');snapshot('P1-B-natural')
|
||||||
|
reserve(lab,mode,'cycle');event('explicit_cycle_start')
|
||||||
|
command('[app_id="org.mosaic.BlurGlass"] blur disable');time.sleep(.15)
|
||||||
|
command('[app_id="org.mosaic.BlurGlass"] blur enable');time.sleep(.35);snapshot('P2-B-explicit')
|
||||||
|
mutate('A');snapshot('P3-A-natural')
|
||||||
|
time.sleep(.35);snapshot('P3-confirm',only_h1=True)
|
||||||
|
if not np.array_equal(image('P3-A-natural'),image('P3-confirm')):raise RuntimeError('final whole-H1 stabilization gate')
|
||||||
|
event('complete',camera_pair='NOT EXERCISED: forbidden by this campaign')
|
||||||
|
except Exception as exc:
|
||||||
|
failure=repr(exc);event('failure',error=failure)
|
||||||
|
finally:
|
||||||
|
signal.setitimer(signal.ITIMER_REAL,0)
|
||||||
|
# WHY: request normal compositor teardown first so cache destructors can log.
|
||||||
|
# CONTRACT: explicit private socket, then only recorded owned process groups.
|
||||||
|
if comp and comp.poll() is None and sock:
|
||||||
|
try:command('exit');comp.wait(timeout=5)
|
||||||
|
except (subprocess.SubprocessError,RuntimeError,OSError):pass
|
||||||
|
for c in children+([comp] if comp else []):
|
||||||
|
if c.poll() is None:
|
||||||
|
try:os.killpg(c.pid,signal.SIGTERM)
|
||||||
|
except ProcessLookupError:pass
|
||||||
|
for c in children+([comp] if comp else []):
|
||||||
|
try:c.wait(timeout=3)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
os.killpg(c.pid,signal.SIGKILL);c.wait(timeout=3)
|
||||||
|
for f in files:f.close()
|
||||||
|
shutil.rmtree(runtime)
|
||||||
|
(run/'exit-status.json').write_text(json.dumps({'failure':failure,'duration':time.monotonic()-started,'compositor':comp.returncode if comp else None,'children':[{'args':c.args,'pid':c.pid,'code':c.returncode} for c in children],'runtime_removed':not runtime.exists(),'captures':captures},indent=2)+'\n')
|
||||||
|
shutil.copy2(DEFAULT,lab/'results/campaign-budget.json')
|
||||||
|
event('cleanup',runtime_removed=not runtime.exists())
|
||||||
|
print(mode,'FAILURE='+str(failure),'RUN='+str(run),flush=True)
|
||||||
|
if failure:raise SystemExit(1)
|
||||||
43
tooling/probes/step20c-optimized-blur-edge/seal.py
Normal file
43
tooling/probes/step20c-optimized-blur-edge/seal.py
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Seal retained source and evidence inventories once, without overwriting.
|
||||||
|
|
||||||
|
CONTRACT: raw observations and completed source fixtures precede this seal.
|
||||||
|
INVARIANT: existing manifests are refused; verification never regenerates them.
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
lab=Path(sys.argv[1]).resolve()
|
||||||
|
fixture=Path(__file__).resolve().parent
|
||||||
|
out=lab/'results'
|
||||||
|
if any((out/name).exists() for name in ('source-sha256.txt','evidence-sha256.txt')):
|
||||||
|
raise RuntimeError('sealed inventories already exist; verify, never overwrite')
|
||||||
|
|
||||||
|
def sha(path):
|
||||||
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||||
|
|
||||||
|
sources=set(p for p in fixture.iterdir() if p.is_file())
|
||||||
|
sources.add(fixture.parent/'step20c-optimized-blur-cache/edge-model.py')
|
||||||
|
for name in ('scene0','scenefx','mosaic','pristine'):
|
||||||
|
sources.update(p for p in (lab/name).rglob('*')
|
||||||
|
if p.is_file() and 'subprojects' not in p.relative_to(lab/name).parts)
|
||||||
|
sources.update(p for p in (lab/'patches').iterdir() if p.is_file())
|
||||||
|
sources.update(p for p in lab.iterdir() if p.is_file() and p.suffix in ('.c','.h','.xml'))
|
||||||
|
sources.add(lab/'protocol-before-results.md')
|
||||||
|
for run in (lab/'runs').iterdir():
|
||||||
|
sources.update(run/name for name in ('fixture-source.py','client-source.c','config'))
|
||||||
|
source_manifest=out/'source-sha256.txt'
|
||||||
|
source_manifest.write_text(''.join(f'{sha(p)} {p}\n' for p in sorted(sources)))
|
||||||
|
# Evidence includes all run files, result categories and build/analysis/model/final
|
||||||
|
# validation logs. Build binaries are identified by digests in build-identities.
|
||||||
|
evidence=set(p for p in (lab/'runs').rglob('*') if p.is_file())
|
||||||
|
evidence.update(p for p in out.iterdir() if p.is_file() and not p.name.endswith('-sha256.txt'))
|
||||||
|
evidence.update(p for p in lab.glob('*.log') if p.is_file())
|
||||||
|
evidence_manifest=out/'evidence-sha256.txt'
|
||||||
|
evidence_manifest.write_text(''.join(f'{sha(p)} {p}\n' for p in sorted(evidence)))
|
||||||
|
for manifest in (source_manifest,evidence_manifest):
|
||||||
|
for line in manifest.read_text().splitlines():
|
||||||
|
digest,path=line.split(' ',1)
|
||||||
|
assert sha(Path(path))==digest,path
|
||||||
|
print(manifest.name,len(manifest.read_text().splitlines()),sha(manifest))
|
||||||
55
tooling/probes/step20c-optimized-blur-edge/test-budget.py
Normal file
55
tooling/probes/step20c-optimized-blur-edge/test-budget.py
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
"""Offline tests use disposable ledgers; never touch campaign reservations."""
|
||||||
|
import json
|
||||||
|
import multiprocessing
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
from budget import reserve, MODES
|
||||||
|
|
||||||
|
def denied(call):
|
||||||
|
try:
|
||||||
|
call()
|
||||||
|
except (ValueError, RuntimeError, KeyError, TypeError):
|
||||||
|
return
|
||||||
|
raise AssertionError('accepted forbidden reservation')
|
||||||
|
|
||||||
|
def contender(root, queue):
|
||||||
|
try:
|
||||||
|
reserve(root, 'R0', 'run', Path(root) / 'contention.json')
|
||||||
|
queue.put('accepted')
|
||||||
|
except RuntimeError:
|
||||||
|
queue.put('denied')
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
path = Path(tmp) / 'budget.json'
|
||||||
|
denied(lambda: reserve(tmp, 'R0', 'capture', path))
|
||||||
|
for mode in MODES:
|
||||||
|
reserve(tmp, mode, 'run', path)
|
||||||
|
denied(lambda: reserve(tmp, mode, 'run', path))
|
||||||
|
for key, count in [('mutation', 3), ('capture', 12), ('cycle', 1),
|
||||||
|
('calibration', 1 if mode in ('R2', 'R3') else 0)]:
|
||||||
|
for _ in range(count):
|
||||||
|
reserve(tmp, mode, key, path)
|
||||||
|
denied(lambda: reserve(tmp, mode, key, path))
|
||||||
|
denied(lambda: reserve(tmp + '-another', 'R0', 'run', path))
|
||||||
|
denied(lambda: reserve(tmp, 'R4', 'run', path))
|
||||||
|
state = json.loads(path.read_text())
|
||||||
|
assert sum(c['capture'] for c in state['modes'].values()) == 48
|
||||||
|
assert sum(c['mutation'] for c in state['modes'].values()) == 12
|
||||||
|
for bad in ['', '{}', '{"campaign":"wrong"}']:
|
||||||
|
path.write_text(bad)
|
||||||
|
denied(lambda: reserve(tmp, 'R0', 'run', path))
|
||||||
|
for corrupt in [True, -1, 2, 1.0]:
|
||||||
|
state['modes']['R0']['run'] = corrupt
|
||||||
|
path.write_text(json.dumps(state))
|
||||||
|
denied(lambda: reserve(tmp, 'R1', 'capture', path))
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
ctx = multiprocessing.get_context('fork')
|
||||||
|
queue = ctx.Queue()
|
||||||
|
children = [ctx.Process(target=contender, args=(tmp, queue)) for _ in range(2)]
|
||||||
|
for child in children:
|
||||||
|
child.start()
|
||||||
|
for child in children:
|
||||||
|
child.join(5)
|
||||||
|
assert child.exitcode == 0
|
||||||
|
assert sorted(queue.get(timeout=1) for _ in children) == ['accepted', 'denied']
|
||||||
|
print('PASS exact exhaustion, no fifth run, cross-LAB, corrupt schema/counters, exclusive lock')
|
||||||
Loading…
Reference in a new issue