swayfx-mosaic/docs/design/STEP20C_OPTIMIZED_BLUR_CACHE_PROBE.md

30 KiB
Raw Permalink Blame History

STEP20C optimized blur cache invalidation probe

EXPERIMENTAL / PARTIALLY_FEASIBLE; architecture UNDECIDED. The protocol below preceded the graphical runs; actual evidence follows. The previous ticket published its saved-timeout phase at 6fd8945d10d1072871bf66f639153a717d7ca758. Its optimized-cache phase was local until this separate evidence-freeze ticket. No graphical run is authorized in the closed historical laboratory. STEP20A DONE, STEP20B EXPERIMENTAL, STEP20C NEXT, STEP20D–G PLANNED; production multi-output Mosaic NOT YET SUPPORTED. No UX change.

Question, historical evidence and source contract

Does a normal same-size commit from the actual background source update the optimized cache and the final visibly filtered translucent pixels? Separate logical dirty state, reconstruction attempt/result, GPU cache copies, regular blur selection, final drawing clip and output damage. The effects/damage probe established visible blur and sampled clipping, but did not qualify cache invalidation. Its FX2 tiled path could already select optimized blur, so FX3 is not an independent non-optimized control. Its reference/trace difference had unproven causality. This campaign uses no animated reference.

Pinned inputs: SwayFX 0.6 fd71a6bdc061bd633b488ae7b83e8a6981d22f86, private Mosaic cd550382b311efdbfe3ed892f4e1d281d852e754, SceneFX 0.5 37ccd723bef49e6891156ffafce8f549f01446cc, installed wlroots 0.20.2 (previous audited source d783533489e1f75d6886c2ab5c5960090ef268f8). Reconstruct archives from these commits and the unchanged preserved clip, owner guard and passive timing/native-presentation patches. New passive patches record borrowed identities only. No algorithm, shader, public ABI, installed library, package or production source changes.

Source audit before instrumentation (pinned SceneFX and SwayFX):

  1. sway/tree/output.c:output_create creates one optimized node under staging, initially sized zero. arrange_root reparents it to global root->layers.blur_tree, at its own output origin. arrange_output controls its size and enabled state; fullscreen disables it.
  2. root_create orders shell background, shell bottom, optimized blur, tiling, floating, shell top, fullscreen, overlay, popup, seat and lock. Render-list traversal reverses its top-to-bottom list for drawing. The optimized source is the main output framebuffer at this stage, containing lower background/bottom composition, not arbitrary tiled content above the cache node.
  3. handle_surface_commit in sway/desktop/layer_shell.c explicitly marks the output cache dirty on EVERY background/bottom surface commit, including ordinary pixel commits without layer-state changes. The existing comment says “Rerender the optimized blur on change”. Destroy of those layers also invalidates. This is the tested correctness intent.
  4. cmd_blur and cmd_blur_xray mark all output optimized nodes dirty. Blur radius/passes/noise/brightness/contrast/saturation setters traverse and invalidate optimized nodes when their parameter actually changes. Output reconfiguration directly sets dirty for FBO-dependent changes.
  5. wlr_scene_optimized_blur_mark_dirty skips disabled nodes, otherwise sets dirty and calls scene_node_update. set_size invalidates on a size change. Generic scene_node_update recomputes visibility and damages old/new regions; it does not universally invalidate optimized caches. Generic geometry/visibility/buffer mutations are not interchangeable with the Sway layer-shell commit hook. Other source owners need separate audit; absent mark calls alone are not proof of stale rendering.
  6. scene_node_visibility ignores disabled nodes. The inherited private scene_node_intersect_clip restricts tiled leaves. Optimized nodes have a different global parent and do not inherit the tiled clip.
  7. wlr_scene_output_build_state initializes FX offscreen buffers before blur damage expansion. should_blur_node_extend_damage sets has_blur for optimized regular blur at full strength; dirty optimized nodes, full damage and apply_blur_region intersections provide other routes.
  8. scene_entry_render first requires a nonempty visible/damage intersection. An optimized regeneration then requires has_blur, enabled blur data and dirty. fx_render_pass_add_optimized_blur calls get_main_buffer_blur with the current main framebuffer, and copies blurred and unblurred results into the two output caches. It returns false with no offscreen buffers or no blur result; dirty is cleared only on true and otherwise retained for a later visible blur. A true return is not itself pixel proof.
  9. fx_render_pass_read_to_buffer performs a GPU texture draw/copy, not CPU readback. It returns void and can skip a copy if texture import fails; trace attempted and completed draw calls separately from regeneration. No mass GPU readback is planned.
  10. fx_render_pass_add_blur selects optimized_blur_buffer when optimized and strength 1; a lower strength reblurs optimized_no_blur_buffer. Ordinary nonoptimized blur instead uses the current main framebuffer. Sway's config->blur_xray || !could_container_overlap(con) explains optimized selection with xray disabled. Keep opacity 1 and SHM alpha partial, so buffer alpha and compositor blur strength remain distinct.
  11. fx_offscreen_buffers_try_get finds/creates an output-owned addon. fx_render_pass_init_offscreen_buffers obtains output-size framebuffers. fx_framebuffer_get_or_create_custom reuses equal sizes, drops/resizes different sizes and reports allocation failures; failure destroys the offscreen set. No output resize is exercised here.
  12. Framebuffers use allocator buffers, EGL images and GLES FBOs/stencils. The output addon destructor drops all five buffers, finishes the addon and frees the set; renderer teardown also owns cleanup. Observed object destruction is not proof of every driver/GPU reference lifetime.
  13. Optimized regeneration copies the output-sized destination region. Final regular blur receives visible intersect damage and ancestor clip. Shader sampling expands/clamps to output framebuffer bounds and can read beyond a tiled draw clip. Such reads are not automatically leaks; the decisive contract is absence of forbidden final contributions.
  14. apply_blur_region expands damage for sampling/artifact prevention and includes it in output-state damage. Client buffer damage, scene damage, cache copy regions and output damage are separate. Captures and extent coverage cannot enumerate intermediate frames or native PNG identities.

Fixed geometry, clients and comparators

H1 (-800,0), H2 (0,0), both physical/logical 800×600, scale 1, normal. C0: pinned pristine SwayFX splith, pristine private SceneFX without new logs. C1: private SwayFX splith with inherited clip/guard, private SceneFX plus passive logs. C2: same private compositor/renderer with Mosaic enabled. C0/C1 provide a bounded visual instrumentation comparison; source/library clip differences prevent claiming perfect log-only causal isolation. Each configuration has exactly one reserved run, with identical client sources and blur settings. No installed /usr/bin/sway is executed.

A background layer-shell SHM client explicitly binds HEADLESS-1, uses layer BACKGROUND, all four anchors, exclusive zone -1 and no keyboard input. It remains mapped and submits opaque 8-pixel vertical stripes A (#f5f5f5 / #0f192d) and B (#20c0e0 / #b02040), same dimensions, by normal attach, damage_buffer and commit. Generated layer-shell protocol comes from pinned wlr-protocols b010a03648b88d143236de193bddbfea0c08bc84, with its XML hash and URL retained before code generation. XDG XML is recorded and hashed. The glass client uses premultiplied ARGB 0x88442010, no opaque region, normal XDG configure/ACK and no animation; the H2 XDG static reference org.mosaic.StaticReference uses fixed XRGB #303038. A separate transparent ARGB filler with blur disabled provides a second tiled cell without occluding the exposed source ROI. Only the glass receives scoped blur commands. All identities are discovered by app ID.

Before scoring, verify background surface/buffer, output, layer, scene parent under shell_background below blur_tree, real client and compositor commits, source pattern visible outside glass and within FX0 alpha blending. Correlate renderer/FBO/cache identities, actual optimized regular use and reconstruction. A node alone cannot pass the gate. FX0 blur disabled; FX2 blur enabled, radius 5, passes 3, noise 0, brightness/contrast/saturation 1, shadows off, corner radius 0, xray off, opacity 1. Log real renderer (not environment hint).

ROIs predefined in output-local pixels: glass interior (520,100,720,500), exposed source (20,100,160,500), H1 boundary (720,50,800,550) and H2 whole image (0,0,800,600). Record full RGB diffs/bboxes/counts, ROI luminance standard deviation and mean absolute horizontal adjacent-pixel contrast. FX0/FX2 must show filtering beyond simple alpha. Geometry is recorded from IPC and actual scene buffer draw positions; Mosaic camera is calibrated once from current IPC camera and logical cell geometry to put glass across x=0. Calibration is not P5 and occurs before P1. No focus or camera change during P1–P3. Standard cells use the same splith/tiled identities without camera.

Ordered protocol and gates

P0 map A, filler, glass, H2 reference; settle outputs/geometries. Capture both outputs FX0, capture H2 a second time >=0.7s later and require complete RGB equality. Enable FX2, capture both. Stop dependent cases if renderer, source or visibly optimized filtering gate fails. Reserve capture before grim.

P1 submit B once with a normal same-size background pixel commit. Keep position, geometry, alpha, focus, camera, output, clip and parameters fixed. Capture both after stabilization. Observe dirty, attempt, return, copies, regular use, damage and final pixels separately. No forced dirty in P1.

P2 (private C1/C2 only) perform one normal blur disable / blur enable cycle, with no parameter or source change, then capture both. Audit/observe cmd_blur's dirty route. This is a positive reconstruction control; never substitute this image for P1. C0 keeps visual natural-mutation control only.

P3 submit A once, same geometry, capture both; compare with P0 FX2 and count any residual B pixels. P4 uses the C2 boundary and tiled clip observations from all these stages, verifies final draw bounds and whole H2 stability. The global output cache is not claimed to be a tiled-owned clipped cache. P5 optional one hide/return camera pair only if earlier gates pass and it adds a distinct assertion. Omit if main mutation/cache evidence suffices.

Retain scene damage, physical extents, native output commits/presents where instrumented, output-buffer identities and capture windows. Compare damage union on the correct output against stabilized RGB changes, with no claim of minimal damage, every frame or DRM presentation. Exit compositor through its explicit private socket and retain teardown events before owned-process fallback cleanup. Destroy/remove only fixture-owned sockets/process groups.

Budgets, isolation and stop rules

One independent persistent campaign ledger under LAB, exclusive flock, fsync and reservation BEFORE launch/action. Failed reservations consume; no refunds, reset or repeat mode. Max 3 total runs, 1 per configuration, 4 background mutations/run (initial A counts), 1 explicit cycle/private run, 1 optional camera pair globally, 20 PNG/run and 60 globally, 150s/run. Run deadline enforced by parent watchdog; all subprocess operations bounded. No migration, resize, transform, hotplug, saved episode, popup, close animation or scheduling test. Offline ledger tests precede any compositor. Logs/files are bounded and monitored; only a finite client/renderer matrix. Private 0700 runtime, explicit WAYLAND_DISPLAY, SWAYSOCK and swaymsg -s, headless backend, no inherited daily sockets/library overrides. Generated files/builds/captures/logs outside Git; home filesystem LAB avoids the observed /tmp quota. Cleanup retains evidence, removes private socket tree.

FEASIBLE: all real renderer/source/optimized/filtering gates, natural required reconstruction, correct stabilized A/B/A pixels, P2 positive reconstruction, Mosaic boundary exclusion, stable H2 and supportive damage in measured matrix. PARTIALLY_FEASIBLE: working subset with unqualified mutation/rebuild/damage. INCONCLUSIVE: optimized source/use or filtering is not exercised/distinguishable. BLOCKED: a measured stale image violates the identified source correction intent, forbidden pixels, lifetime defect/crash or blocking standard regression. Absent dirty alone cannot classify BLOCKED. Preserve failed fixture facts; never spend an extra run to repair a calibration. No algorithmic correction. Broader sources, partial damage, failure paths, GPU references, every frame, other outputs/renderers and ABI/package remain NOT TESTED unless measured.

C0 fixture failure and pre-run amendment

The sole C0 reservation stopped before captures (0.97s): two same-size layer configures caused the original client to submit A twice. Actual mutations are 2, with the second charged after observation, not reserved before submission. This protocol deviation is retained; no budget is refunded and C0 is never relaunched. Pristine graphical cache/filtering control is NOT EXERCISED. The exact C0 runner/client and binary hash are retained in its run directory. The remaining C1/C2 clients ACK configures without drawing and submit every image only on an explicitly reserved runner command. This is fixture correction, not a renderer/SceneFX change. The standard library/renderer identity from C0 remains usable; its missing visual comparison cannot be replaced by private source claims.

Retained campaign and actual observations

LAB: /home/fy59/swayfx-mosaic-optimized-blur-_ppdud_y/. No prior /tmp laboratory is a reconstruction dependency. prepare.py archives the pinned project commits, clones SceneFX at its pin, applies unchanged historical patches, adds separate passive traces and builds privately. New XML inputs, protocol hashes, current and failed-C0 client/runner sources are preserved in the source fixture. Generated protocols, binaries, logs, PNGs and builds remain outside Git.

Configuration Duration Actual background images PNGs Explicit cycles Result
C0 pristine splith, pristine SceneFX 0.972 s 2 × A 0 0 Fixture failure before graphical gates; no repeat
C1 private splith 4.075 s A/B/A (3) 11 1 Real cache update, central pixel equality; boundary equivalence unresolved
C2 private Mosaic 4.434 s A/B/A (3) 11 1 Same update; measured final clip excludes H2; boundary equivalence unresolved

All three run reservations are consumed. Actual totals: 8 background images, 22 PNGs of 60, one cycle per private mode, zero camera pairs, one computed C2 calibration, no migration/resize/transform. C0's second image was charged only after observation; this is a retained reservation-protocol deviation, although no numerical limit was exceeded. Every C1/C2 image was explicitly reserved before its draw command. The shared ticket ledger refuses another LAB, another run per mode, refunds and corrupt/empty state. No extra untraced graphical run was possible after C0 failed. Instrumentation neutrality is NOT TESTED, not inferred from similar private outcomes.

Renderer, layer source and actual use

All three compositors report SceneFX FX, OpenGL ES 3.2, Mesa 26.2.4-arch1.1, AMD Radeon 780M. /proc/PID/maps records the correct private SceneFX library and installed wlroots 0.20 library. C0 uses a fresh pristine SceneFX build; C1/C2 use the same private clip/timing/cache-trace library. Environment WLR_RENDERER=gles2 is not the renderer evidence. The FX pass is additionally proven in C1/C2 by successful offscreen setup, GPU blur/copy and regular optimized-use traces. C0 has renderer identity but no qualifying graphical/native-cache control.

C1/C2 background server commits show surface resource 3, layer 0 BACKGROUND, mapped=true, global (-800,0), full buffer damage 800×600, and the namespace mosaic-dynamic-background. Their actual scene parent is the output shell-background tree, whose parent is the global shell-background tree. The optimized node's actual parent is blur_tree. The pinned root's applied layer order draws background/bottom before blur and tiling afterwards. OPT_BUFFER_DRAW correlates the surface and its buffer to a full-output draw before OPT_GPU_REBUILD. Client logs record A/B/A, normal SHM buffers, attach/damage/commit and release. Server sequences 2/3/4 correlate to those three content commits; resource/buffer pointers can be reused after release and are never treated as permanent image IDs. The exposed source ROI contains the exact A or B stripe colors. Thus the mutated surface is a real lower cache source, not a tiled proxy above it.

The glass buffer is fixed premultiplied ARGB 0x88442010. Its compositor opacity/blur strength stays 1; alpha blending and blur strength are distinct. Only the glass receives scoped blur enable/disable. Shadow and corners are zero; radius 5, passes 3, noise 0, brightness/contrast/saturation 1 and xray false remain fixed. Both private runs record optimized=1, strength 1, non-null selected cached framebuffer FBO 11 in OPT_BLUR_USE. This proves actual optimized selection independently of xray and node presence.

Natural invalidation, explicit control and cache ownership

For each private mode, P1 B and P3 A each show one real source commit, one dirty set for H1, one H1 regeneration attempt/result=1, GPU source blur, two cache copy draw completions, dirty clear to false and regular optimized use. H2 has zero regeneration in these natural-mutation windows. The source-only Sway layer-shell hook provides the natural dirty; no blur command, camera, focus, geometry or parameter mutation is inserted in P1. P2's one normal disable/enable cycle records six dirty-set observations, two successful H1 and two successful H2 regenerations, then optimized glass use on H1. A global dirty consequence of scoped cmd_blur is source-defined; H2 rebuilds in P2 do not demonstrate contamination. H2 pixels remain stable.

Successful regeneration, completed GPU texture-draw calls and final pixels remain separate evidence. fx_render_pass_read_to_buffer has no success return or driver fence proof. No GPU readback was added. Initial optimized nodes start dirty=false, are invalidated by normal setup and source changes, and clear to false on observed successful regenerations. P3's last stable H1 render observes dirty=true before regeneration and dirty=false after it; teardown invalidation is a separate lifetime phase.

Mode Output Offscreen set Optimized framebuffer Size Reuses
C1 H1 0x563e16fee600 0x563e16fe4750, FBO 11 800×600 18
C1 H2 0x563e16f3d430 0x563e16f43950, FBO 5 800×600 10
C2 H1 0x55e94e85cee0 0x55e94e852310, FBO 11 800×600 19
C2 H2 0x55e94e6a8f00 0x55e94e7b13e0, FBO 5 800×600 10

Each set retains one blur object and one distinct unblurred object during its observed lifetime. Normal explicit private compositor exit logs cache set destruction and exactly one destructor event for each optimized blur and unblurred FBO object. No resize/allocation-failure path is exercised. This demonstrates sampled object cleanup, not every GPU/driver reference. Clients exit with Wayland EPIPE (32) after controlled compositor shutdown; the compositor exit code is 0 in every run, with no observed compositor crash. Every private runtime directory/socket is removed and owned child processes are reaped. There is no daily-session IPC or global kill command.

Pixels, filtering and the retained boundary anomaly

Measurement, identical in C1/C2 central ROI Value
FX0 luminance standard deviation 51.165618
FX2 luminance standard deviation 0.132211
FX0 horizontal adjacent luminance contrast 12.351341
FX2 horizontal adjacent luminance contrast 0.015453
B natural versus B explicit, central changed pixels 0
A initial versus A returned, central changed pixels 0
H2 whole RGB differences, every comparison 0

FX0/FX2 changes 240,000 H1 pixels in C1 and 192,000 in C2. These contrast measurements establish actual filtering beyond fixed alpha compositing. A→B changes all 480,000 H1 pixels, including the exposed source and glass. The 80,000-pixel central glass ROI changes with B, equals the independent explicit reconstruction result exactly and returns exactly to measured A. This establishes freshness in that central ROI; it is not a whole-cache PASS. All six H2 PNGs per private run are whole-RGB identical, without masks.

Whole H1 comparison C1 changed pixels C2 changed pixels Maximum RGB channel delta
B natural → B explicit 36,776 33,915 6
A initial → A returned 38,308 35,340 6

The B comparison bboxes are [400,800)×[0,600) in C1 and [480,800)×[0,600) in C2; A return has the same respective bboxes. Differences concentrate near output/filter boundaries; central/source ROIs are exactly unchanged in these equivalence comparisons. The predefined right boundary ROI changes 19,007 pixels for B natural/explicit and 20,486 for A return in BOTH private modes, with maximum differences 4 and 5 respectively. These nonzero differences are preserved, never masked, and cannot be promoted to exact full-image restoration. This is a shared private standard/Mosaic anomaly, not a demonstrated Mosaic-only defect. Pristine comparison is missing, so an unmodified SceneFX runtime attribution remains unproven.

A bounded offline audit of render_blur_segments, get_main_buffer_blur, blur1.frag, blur2.frag and FX texture creation found a plausible history mechanism: downsample writes only a reduced top-left domain in full-size ping-pong FBOs, while upsample taps can reach beyond that freshly written domain; GL_CLAMP_TO_EDGE bounds the whole texture rather than the reduced valid domain. edge-model.py applies the pinned kernels with ideal bilinear sampling and 8-bit rounding to the retained regeneration/source sequence. It exhibits history dependence without any renderer edit. In the predefined boundary ROI, absolute model/native mean channel error is 0.199–0.518, with 96.67–97.91% of channels within one level; maximum residual is 4. This supports the hypothesis but does not establish native intermediate FBO tail contents, GLES precision or causality. No model threshold turns the anomaly into a PASS, and no shader/algorithm correction is authorized. A proven stale-image invariant violation is not claimed on that model alone.

Mosaic clipping and damage

C2 calibration derives delta -320 from its current camera 480 and actual glass geometry; applied camera becomes 160. These coincident values are measured here, not historical IDs/constants in the fixture. The regular glass blur is actually at global (-320,0), size 640×600, so its geometric right edge is +320 on H2. Its final H1 draw is [480,800)×[0,600) output-local, equivalent to global [-320,0). PI_SCENE records applied tiling scene (-160,0), local clip (160,0,800,600) under the H1 output parent. The global tiled viewport is [-800,0)×[0,600). No target regular-blur draw on H2 is observed; complete H2 RGB stays unchanged throughout. The cache still covers its full 800×600 output, with a different owner than the tiled final clip. No input event or universal shader-sampling confinement is asserted.

OPT_OUTPUT_BUFFER identifies successful rendered output-state buffers and physical output damage extents. Native commit/present traces retain their own identities; no PNG is assigned to a particular native presented buffer. For all four stabilized H1 transitions in each private mode, the union of available output-damage extents leaves zero changed pixels uncovered. Client damage, scene TEMPORAL_DAMAGE, cache full-output GPU copies and output-state damage are recorded separately. Extent coverage proves neither minimum damage nor every intervening frame. P5 hide/return is NOT EXERCISED: P1/P3 already address the distinct source mutation, and a camera pair would not resolve missing pristine control or the boundary source/sampling issue.

Decision and next gate

SWAYFX_MOSAIC_OPTIMIZED_BLUR_CACHE_PROBE=PARTIALLY_FEASIBLE. Architectural conclusion: UNDECIDED. Actual output-scoped cache source, optimized selection, natural dirty/reconstruction, visible filtering, central A/B/A freshness, sampled final Mosaic clipping, stable H2 and sampled teardown are established in C1/C2. Whole-cache correctness is not established: boundary differences remain, C0 graphical control failed, and instrumentation neutrality is NOT TESTED. There is no basis here to merge a private patch or to require a Mosaic-specific redesign.

The next separate rendering gate should complete pristine and untraced controls and discriminate reduced-domain edge sampling/history at fixed geometry before the ABI/package gate. Retain this campaign's exact pixels, source traces and offline model; do not repeat V1 runs or silently strengthen its result. A later targeted native observation may be justified only by a predefined bounded hypothesis. Other source layers, partial damage, hidden owner/camera transitions, output resize/migration, scaling/rotation, failure paths, driver references and intermediate frames remain NOT TESTED. STEP20C stays NEXT, production multi-output NOT YET SUPPORTED.

Offline validation and preservation

Python AST (all current and original fixtures, no bytecode), XML parsing, controlled protocol regeneration byte equivalence, both C clients compiled separately as C17 with -Wall -Wextra -Werror -Wno-unused-parameter, locked ledger exhaustion/concurrency/cross-LAB/corruption tests, pinned private patch applicability and full reconstructed source equivalence passed. Pristine SwayFX source was independently compared with its pinned archive. Final private SceneFX/Mosaic and pristine builds pass; Meson mosaic-model passes 1/1. Existing pinned SwayFX libinput switch warnings are retained; the new trace's pre-run radius-format warning was corrected before graphics. The two passive instrumentation insertion failures and C0 fixture failure remain in raw preparation/run evidence. No failure was hidden by retrying an already-consumed graphical configuration.

Local Markdown targets, complete tracked/new-file diff, whitespace and bytecode/generated-artifact protection were checked. Production sway/, include/, Meson files, cumulative patch, PKGBUILD, UX and AGENTS match the pre-ticket baseline. Installed compositor/libraries, daily IPC/session, QuickShell and dotfiles were not modified or targeted by any command. Cache/source/state/output JSON categories, all run logs, client sources, configs, captures, native events and exit statuses remain in LAB/results and LAB/runs. The failed C0 has zero images; no visual result is invented. All owned processes are reaped and private runtime/socket trees removed. That validation preceded publication of this historical probe. The new evidence freeze does not upgrade STEP20C.

Final source manifest: 1006 entries, SHA-256 0067ad29b7363d2850f8a7418b271c4e5e7044f6a08fd8e85f39b63413a2d152. Final evidence manifest: 106 entries, SHA-256 3a83bbf303217d020b5dadb29e357836975a08055540bae006b5c770feb1d34c. Every entry was available and matched its recorded digest. The earlier A 913/46-entry historical manifests were reverified after B and remain unchanged. The B H2 PNG digest in both private modes is 4471e93ccb6cf3ff4970f61fce405431a228af598d2f1f030a3b7586962ecd7a; all six images per mode share it and match complete RGB without a mask.

Independent evidence freeze (2026-10-13)

The new freeze audited the initial main at 6fd8945d10d1072871bf66f639153a717d7ca758 and directly queried both remotes at that same commit. All 1006 source and 106 evidence manifest entries were available and matched, before publication-only documentation edits. The two original manifests and the historical laboratory remain byte-identical; neither analyzer nor runner was executed there. A copy of every pre-freeze fixture file is retained in /home/fy59/swayfx-mosaic-cache-freeze-audit-m7o528qk/fixture-before-freeze/. The historical source manifest names the old README at its repository path; after this freeze its matching original bytes are in that snapshot. This provenance distinction is explicit, not a regenerated historical manifest.

An independent reconstruction in the same audit directory applied the full private patch chain to the pinned archives, then compared all relevant source bytes to the historical compiled trees. All patches apply without forced hunks. Both new trace patch hashes match the recorded values: a0fd5a64156a79b1605ff3b52bd9accb20390199b2b36e1970389f5086b68f39 and b83ff12bf24ee879cc713a134b0c312e9b8bd1b4034ecc2aea124d55a743ebb7. C17 builds of the corrected and failed-C0 clients with fatal warnings, both SceneFX builds, pristine SwayFX, private Mosaic and Meson mosaic-model passed. The actual corrected callback, extracted verbatim for a bounded offline harness, ACKed duplicate 800×600 configures without incrementing image submissions. Locked ledger tests passed; no historical reservation changed.

Independent whole-RGB recalculation reproduces 36,776/33,915 changed B pixels, 38,308/35,340 changed A-return pixels, maximum channel delta 6, zero central differences and stable H2. The offline model was rerun into a separate output directory and reproduces its historical JSON exactly. These checks establish evidence integrity, not native FBO causality or instrumentation neutrality.

The narrow .gitattributes patch rule preserves original unified-diff bytes: blank context lines carry a required leading space and context source tabs follow a diff marker. C, Python and Markdown retain ordinary whitespace checks. Source-context applicability and reconstructed source equivalence were checked independently of the patch-file whitespace exclusion.