Wave-2 PW2 (design/linux-host-performance-wave2-pyrowave.md). Observability only — no
behaviour change to any capture decision — and it lands first because every later package
in the program is measured by an A/B whose "before" is currently unreadable.
The defect: the capture path's CPU-fallback warning was gated on `backend_is_vaapi`, which
reads the HOST-GLOBAL encoder pref. A PyroWave session is negotiated PER SESSION, so on an
NVIDIA/auto host that gate is false — and the session then fell out of every arm of the
negotiation log chain, emitting nothing whatsoever while paying a full-resolution CPU pixel
touch on every frame. A degraded host and a healthy one produced identical logs.
Four sites, matching PW2.1-2.4:
1. The CPU-path warning now asks the per-session question (`consumer_kind`) instead of the
pref, and names the consumer. Its gate widened to every GPU consumer and excludes only
the software encoder, whose native input IS CPU frames — an NVENC session silently on
the CPU path is the same defect, not a different one. `pyrowave_session` deliberately
outranks `backend_is_vaapi`, because a PyroWave pref flips `backend_is_vaapi` on too
(`linux_zero_copy_is_vaapi_for`'s `Pyrowave` arm), so testing vaapi first would swallow
every PyroWave session.
2. The raw-passthrough block in `consume_frame` had four silent exits — no format, an
SHM/MemFd buffer, no DRM fourcc, a failed `F_DUPFD_CLOEXEC` — each falling out of three
nested `if`s into the CPU de-pad path. It is now a labeled block that breaks with a named
`PassthroughFallback`, logged once per distinct reason per session with a running count,
so a persistent downgrade is distinguishable from a hiccup at renegotiation. `.process`
runs per frame, so the rate limit is the shippable part and is what the tests pin.
Note `NoFormat` does NOT fall back — the CPU path needs `ud.format` too and returns — so
the line says DROPPED for that one. Three of four downgrade; one loses the frame.
3. `force_cpu_for_nvenc_444` told a 4:4:4 PyroWave session it was "on the NVENC path", which
is false in every particular: the wavelet encoder never touches NVENC, never swscales to
YUV444P, and what it actually loses is the raw-dmabuf passthrough its design assumes.
4. One INFO line at pipeline build states the resolved arm and consumer
(`capture pipeline resolved: dmabuf-passthrough → pyrowave`). Nothing stated it before;
the 2026-08-08 triage reconstructed it from four files, and for the arm that matters most
there was no detail line to reconstruct it from.
Also: `spike --codec pyrowave`, so a PyroWave capture→encode pass can be driven without a
client. That is the harness the rest of this program measures on, and it did not exist.
Gates on .21 at CI parity: fmt, workspace clippy -D warnings, pf-encode clippy with
nvenc,vulkan-encode,pyrowave and without, workspace tests.