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
|
||||
|
||||
- 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 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
|
||||
qualification. This evidence freeze changes no production or UX contract.
|
||||
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
|
||||
qualification. This evidence freeze changes no production or UX contract.
|
||||
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
|
||||
qualification. This evidence freeze changes no production or UX contract.
|
||||
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
|
||||
qualification. This evidence freeze changes no production or UX contract.
|
||||
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