# Actual WGPU label-ink evaluator — 2026-09-13 Status: authored, **not compiled or executed**. Source inspected at `345f7b3`, evidence checkout `2f90cf2`; the integration owner must capture exact file hashes when running. Only this new experiment directory changes. The measured-label module, corridor candidate and production renderer remain untouched. ## Question and competing expectations Does a single-line label measured by the pinned Iced text allocator fit its proposed painted backplate and horizontal free interval after the actual canvas camera transform? Layout advances are not glyph-ink bounds. Italic bearings, combining marks, fallback fonts, antialiasing and device scaling can falsify containment despite a successful width measurement. The experiment distinguishes three claims: 1. **Advance-only hypothesis:** every painted pixel lies in the returned layout rectangle. Count strict violations and violations after a one-physical-pixel halo. Violations are evidence, not automatic evaluator failure: the module explicitly does not promise ink containment. 2. **Candidate padding hypothesis:** adding 3 horizontal / 2 vertical world units to that rectangle contains ink, with a separately reported one-physical-pixel halo. This is an unaccepted probe policy. A violation beyond the halo is a finding, not grounds to silently increase the constant. 3. **Corridor/blocker hypothesis:** ink does not extend horizontally beyond the supplied interval plus one physical pixel, and does not change the painted interiors of nearby activation-like blockers. These are fixed independent probes, not the `widest_clear` algorithm or real Scene membership. Strict counts remain visible even when the one-pixel halo passes; the halo is an explicit experimental allowance, not proof of zero overlap. Pixel difference threshold is greater than 3 in any 8-bit RGBA channel. We retain raw pixels so weaker ink and alternative tolerances can be investigated without rerendering. ## Actual path and independent controls `main.rs` imports the existing `scenario_label.rs` using `#[path]`, without copying it and without enabling its test module. It creates an actual `iced::Renderer` through `Headless::new(..., Some("wgpu"))`, creates `canvas::Frame`, applies translation then positive uniform scale, calls the label's `canvas_text` followed by `Frame::fill_text`, records `draw_geometry`, and reads actual RGBA using `Headless::screenshot`. No alternate text renderer, native window, screenshot mock, or hand-drawn glyph is involved. All 32 cases are evaluated in one dedicated executable process. Global fonts initialize before a fresh renderer and `RenderSession`; no font mutation is allowed until process exit. Each frame resets renderer geometry while retaining its genuine WGPU caches. Cases cover: - A realistic existing scenario-style call label, CJK, decomposed combining marks, and an italic label beginning with `jfj`. - Widths 160 and 760 world units. The wide case must preserve the explicit full source; the narrow case must show an ellipsis and retain a nonempty proper source prefix. - `(zoom, DPI)` of `(0.65,1)`, `(1,1)`, `(1.75,1)`, `(1,1.5)`. Fractional camera translation and text origins exercise subpixel positioning. The independently constructed `canvas::Text` control must paint the same pixels as the guarded payload. A second actual Frame shifts camera translation by exactly 16 physical pixels; its pixels must equal the original shifted by 16. These checks can reveal wrong coordinate assumptions before any ink conclusion. The viewport has generous right/bottom margin; any observed ink touching its boundary invalidates the probe because clipping may have hidden overhang. Text-only pixels against white provide the ink mask. A separate decoration render contains yellow backplate then blue blocker rectangles. A composite adds actual text. Actual opaque blue interior pixels must remain unchanged. Because the blockers are painted after the backplate, this specifically evaluates foreground text interference; it does not infer that arbitrary backplate geometry never overlaps a blocker or that every antialiased border remains untouched. The independent world rectangles provide 1 world unit of clearance between a maximally wide padded plate and its blocker. Actual shaped glyph IDs and resolved font faces are recorded as a **coverage gate only**. Glyph ID zero, no glyphs, or no resolved italic/oblique face for the italic case invalidates that case. CJK missing-font boxes cannot count as CJK acceptance. The inspected shaping buffer does not supply the ink bounds. System fonts may differ across machines; face identities/families/styles are recorded, but this is not a portable pixel-golden suite or a complete font-file provenance recorder. Pin and hash relevant system font files for a cross-machine comparison. ## Build and run: integration owner only No Cargo or new crate dependencies are required. Compile a normal executable, **not `rustc --test`**, against the exact already-built Iced 0.14.0 and unicode-segmentation artifacts, plus their matching transitive dependency directory. The active Iced artifact must have WGPU, canvas and advanced enabled; tiny-skia fallback is not accepted by this harness. This imports the real candidate but does not wire it into desktop production. Equivalent raw invocation, substituting actual absolute paths: ```powershell & $rustc --edition=2024 --crate-name scenario_label_wgpu --crate-type bin ` -C debuginfo=0 -C "linker=$clang" -L "dependency=$deps" -L "native=$nativeLibs" ` --extern "iced=$icedRlib" --extern "unicode_segmentation=$unicodeRlib" ` $mainRs -o $newExecutable & $newExecutable $newPixelDirectory ``` `build-and-run.ps1` accepts those paths explicitly and refuses an existing run directory. It hashes the resolved compiler, linker, direct libraries and source inputs, and passes the resolved linker path through `-C linker=...`. For Windows gnullvm, initialize the parent's existing `.local/toolchain/env.ps1`, resolve `$clang = (Get-Command clang.exe).Source`, and set `$nativeLibs` to the repository's `.local/toolchain/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows_x86_64_gnullvm-0.52.6/lib`. This exact native search directory and `linker=clang.exe` appear in the successful parent `.local/scenario-label-gates-attempt4-20260913/compile-receipt.json` (rustc 1.98.1, x86_64-pc-windows-gnullvm). That prior module gate is linkage evidence, not an executed result for this WGPU harness. The runner records the complete recursively enumerated Rust link/metadata artifact set (`.rlib`, `.rmeta`, `.dll`, `.lib`, `.a`, `.o`, `.obj`) in the supplied dependency directory and every file in the explicit native directory. It rehashes and compares both manifests after linking, detecting additions, removals or changed content. It separately rechecks source/direct-library/compiler/linker inputs before running. These are artifact supersets, not assertions that every file was linked. It hashes the executable before and after its fresh-process run and preserves an output manifest of generated logs, receipts, executable, metrics and images, including nonzero evaluator outcomes. The successful attempt4 used Iced `ee73abd722c72024` and unicode-segmentation `85698043f7780858`. Another Iced artifact `a4e48b220c5d9711` also exists; use the matching tested dependency set rather than treating them as interchangeable. Required runtime DLL paths and a working WGPU adapter remain prerequisites. Adapter/device creation failure is an infrastructure failure, never an ignored pass. ```powershell & ./build-and-run.ps1 -Rustc $rustc -IcedRlib $icedRlib ` -UnicodeSegmentationRlib $unicodeRlib -DependencyDirectory $deps ` -Linker $clang -NativeLibraryDirectory $nativeLibs ` -NewRunDirectory $freshRun ``` The script is also unexecuted and requires PowerShell 7 (`Path.GetRelativePath`). Compile/run only after acquiring the parent's sole compiler/GPU resource. Before/after hashes do not detect a file temporarily changed and restored during linking; exclusive input ownership remains required. This is not a hermetic toolchain capture: implicitly searched system SDK libraries, clang's auxiliary executables/DLLs, runtime dependencies, system fonts and GPU drivers outside the explicit directories are not all hashed. Preserve that environment separately. The renderer exposes the backend name `wgpu`, not complete adapter identity through `Headless`; retain driver/backend logs and hardware identity separately. `WGPU_BACKEND` is recorded if set. Do not infer native acceptance from this offscreen run. ## Artifacts and interpretation Each case writes `metrics.txt` with source/display/prefix, font faces, coordinates, ink pixel bounding box/counts, control differences and findings. It writes `text`, `decoration` and `composite` as both tightly packed, top-to-bottom RGBA8 `.rgba` and standard P6 `.ppm`. Width/height are in `metrics.txt` and the PPM header. Failed controls also preserve their rendered pixels. No image conversion participates in the oracle. These are real WGPU readbacks; inspect the PPMs or convert the preserved pixels for review after the numeric run. Exit 0 means exactly 32 valid probes without a candidate-padding/corridor finding. Exit 2 means a candidate finding. Exit 3 means a coverage or control failure makes at least one probe invalid. Panic, missing summary or fewer than 32 cases is nonacceptance. Every completed run writes `summary.txt`; preserve failures before changing source. Report exact source, executable, artifact and environment provenance alongside any finding. A positive result supports only the specified strings/fonts/scales/padding; no universal raster containment claim follows. This is intentionally smaller than Scene integration: no parsed model, occurrence/navigation hit testing, old renderer comparison, real activation/frame paint ordering, self-call or reversed-message corridor selection, clipping near viewport edges, rotation, wrapping, row-height policy, gesture performance, dynamic font replacement, or native user workflow is accepted. Those remain integration evaluators. A finding here should refine the shared measured-label/ink-clearance contract before production callers are added. ## Pinned primary API evidence Registry source root is the repository-local `.local/toolchain/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/` (outside this worktree): - `iced_core-0.14.0/src/renderer.rs`: `Headless::new`, `name`, `screenshot` explicitly return RGBA; `Renderer::reset` resets the frame. - `iced_wgpu-0.14.0/src/lib.rs:912`: headless creation uses WGPU's actual adapter/device, RGBA render target and MSAAx4; screenshot uses a physical viewport and supplied DPI. - `iced_wgpu-0.14.0/src/geometry.rs:306`: positive uniform-scale `fill_text` transforms the position, scales font size/absolute line height, and emits `Text::Cached`. Nonuniform/rotated vector fallback is outside this experiment. - `iced_widget-0.14.2/src/canvas.rs`: canvas draws generated geometry through `geometry::Renderer::draw_geometry`. - `iced_graphics-0.14.0/src/text/cache.rs`: glyph coverage introspection uses the actual allocator's buffer and resolved fonts. Its metrics are not substituted for screenshots. - Current desktop `behavior.rs:2158` translates the camera then scales its actual Frame. This evaluator preserves that order without claiming to import the whole Scene.