uzor-proof-harness 1.5.1

Dev-only multi-backend (tiny-skia / vello-cpu / vello-gpu / urx-cpu / urx-gpu) headless proof-render harness: drives one RenderContext-driven draw closure through every available rasterizer backend (three CPU legs always, two GPU legs gracefully skipped when no adapter is available), reports pairwise pixel-diff fractions, and writes a labelled side-by-side composite PNG. Promoted out of uzor-examples/src/parity_harness.rs (URX Wave 6) so any publish = false engine crate (uzor-figures first) can reach it as a dev-dependency without adding a runtime dependency to its own [dependencies].
docs.rs failed to build uzor-proof-harness-1.5.1
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

uzor-proof-harness — dev-only multi-backend proof-render harness.

Why this exists: every visual proof render across the figures/ text/typeset stack rasterizes through uzor-export::render_to_png, which is HARDCODED to tiny-skia (uzor-export/src/lib.rs:46,162) — the workspace's last-resort fallback rasterizer family, not one of the two production families (vello, URX). Two real backend-specific defects (tiny-skia's fill_text ignoring a rotation transform; a shaper outline-rounding bug) were invisible to single-backend proofs before this crate existed. Owner directive: "если может быть какой-то диф в работе бекендов — тестируй на всех семьях; везде есть цпу варианты" — render every proof through all three CPU family legs and let divergence surface loudly, not silently.

GPU legs added (owner follow-up: "могут ли быть расхождения на гпу? надо бы тоже включить их" — the CPU legs already caught a world-frame CTM composition bug and a missing-vertical-AA defect; the GPU legs test a DIFFERENT axis — the actual rasterisers (compute pipeline vs scanline, SDF/MSAA vs analytic, glyph atlas vs CPU glyph rasterisation) and the URX GPU degrade counters). [render_vello_gpu] and [render_urx_wgpu] each return an Option/a struct wrapping one, and [MultiLegRender::capture] SKIPS a leg gracefully (printing why) when no GPU/software adapter is available — the whole suite still runs, minus those two legs, on a GPU-less machine. The composite PNG and every pairwise diff table then only cover legs that actually rendered.

use std::path::Path;
use uzor_proof_harness::{ChannelTolerance, MultiLegDiff, MultiLegRender, write_composite_png};

let render = MultiLegRender::capture(200, 100, |ctx| {
    ctx.set_fill_color("#ff0000");
    ctx.fill_rect(10.0, 10.0, 50.0, 50.0);
});
let diff = MultiLegDiff::compute(&render, ChannelTolerance::default());
for line in diff.report_lines() {
    println!("{line}");
}
write_composite_png(&render, Path::new("out/example_backends.png")).expect("write composite");
assert!(diff.all_within_budget(), "structural backend divergence detected");