# Iteration 8 — Phase 8 (close) Closes 2026-05-13. iter8 = Bug 4 (H.264 partial-fill, originally "inter race-loss") PARTIAL close — narrowed via three eliminations, not fixed. ## Summary | Metric | Value | |---|---| | Iteration target | Bug 4 — H.264 libva produces 16×32 partial-fill instead of full frame | | Hardware | RK3399 rkvdec | | Fork tip start (iter7 close) | `6df2159` | | Fork tip end (iter8 close) | `0226684` (4 commits: γ dump, IMP-1 pre-zero, stdlib include fix-fwd, α-2 POC strip removal) | | LOC delta | +103 / -3 across `src/surface.c`, `src/picture.c`, `src/h264.c` | | Phase 1 criteria | 5/6 PASS (C1 PARTIAL — Bug 4 narrowed not fixed) | | Reviews | 2 (Phase 5 γ-plan review + Phase 5b/5c α candidate reviews); 1 plan killed (α-1) | | Hypotheses eliminated | 5 (libva-readback, slot-binding, stale-residue, constraint_set_flags, POC sentinel) | | Campaign scoreboard | Unchanged on pixel-correctness axis; +0 net codec fixes. +diagnostic instrumentation (γ dump, pre-zero gate). | ## Phase-by-phase narrative ### Phase 0 — Bug 4 locked User pick: H.264 inter race-loss (carryover label from iter4 Phase 7). Lock criterion: `libva_h264 == kdirect_h264` byte-identical. ### Phase 2 — H.264 source-read Walked h264.c pipeline end-to-end (994 LOC). Mapped per-frame decode flow (BeginPicture → RenderPicture → EndPicture → SyncSurface). Eliminated 6 of 13 surface-level hypotheses by source-read alone. ### Phase 3 — empirical strace + byte-level YUV examination **Bug redefinition**: NOT inter-race-loss — even keyframe (IDR) fails. Pattern: structured 16×32 byte patch of luma-neutral data at Y top-left, rest zero. Per-codec diff: VP9 works via libva, HEVC/H.264 don't. SPS bytes: only diff is `constraint_set_flags` (libva=0 vs kdirect=2). DECODE_PARAMS shows POC sentinel diff (libva strips, kdirect doesn't). ### Phase 4 — γ-then-α plan Decided: diagnostic dump γ FIRST to distinguish "kernel didn't write" from "libva mis-reads." ### Phase 5 — γ plan reviewed Sonnet-architect: 2 CRIT (logging API misuse, missing null guard) + 4 IMP + 3 MIN. All mechanical; strategy stood. ### Phase 6 — γ implemented Added env-gated diagnostic dump to surface.c::RequestSyncSurface. Built, installed. ### Phase 7 — γ + IMP-1 verification γ dump showed libva-readback path returns exactly what's in the buffer (no readback bug). IMP-1 memset experiment confirmed the 16×32 patch is deterministic (NOT stale residue). **Bug pinned to kernel-side**: rkvdec accepts request, writes only 512 bytes, stops without error flag. ### Phase 4b/5b — α-1 SPS constraint_set_flags fix (KILLED) Plan: derive constraint_set_flags per-profile. Phase 5b reviewer empirically read rkvdec-h264.c end-to-end and found `constraint_set_flags` is NEVER accessed by the driver. **CRIT-1 killed α-1 before any build.** Saved ~15 LOC + a build/install/test cycle. Reviewer redirected to DPB / POC diff. ### Phase 4c/5c/6c — α-2 POC sentinel strip removal Plan: remove `h264_strip_ffmpeg_poc_sentinel` (hantro-specific kludge that's not needed for rkvdec). Phase 5c greenlit with one amendment (preserve VA_PICTURE_H264_INVALID → 0 guard). Phase 6c implemented: ~12 LOC change in h264.c. ### Phase 7c — α-2 verification α-2 changed wire bytes (POC now matches kdirect's 0x00010000) but output unchanged. **POC isn't load-bearing for Bug 4.** Three more hypotheses eliminated (libva-readback, slot-binding, stale-residue, constraint_set_flags, POC sentinel — 5 total). 5-codec regression sweep: all 4 non-H.264 hashes unchanged. Zero regression. ## Commits shipped ### Fork (libva-v4l2-request-fourier) | SHA | Files | LOC | Description | |---|---|---|---| | `7eae6ea` | src/surface.c | +78 / -1 | γ env-gated CAPTURE buffer diagnostic dump | | `66ecbef` | src/picture.c | +23 | IMP-1 env-gated CAPTURE pre-zero diagnostic | | `6f4e583` | src/picture.c | +1 | stdlib.h include fix-forward (getenv) | | `0226684` | src/h264.c | +12 / -2 | α-2: pass H.264 POC values through unchanged | ### Campaign repo (fresnel-fourier) | Commit | Phase | Description | |---|---|---| | `e47a7ba` | P0 | Lock Bug 4 | | `abd97e3` | P2 | H.264 source-read | | `4320d78` | P3 | Strace findings + bug redefinition | | `3a63076` | P4 | γ-then-α plan | | `d4c04b4` | P5 | Architect review | | (this) | P7 + P8 | Verification + close | ## What worked - **Phase 5b's empirical source-read killed α-1 BEFORE the build cycle**. Saved a build/install/test pass. Pure win for the review discipline. - **γ dump immediately ruled out libva-readback hypothesis**. Without γ, iter9 would still be considering libva-side fixes. - **IMP-1 memset experiment** was a one-line discriminator (env-gated) that definitively ruled out stale-residue. - **5-codec regression sweep at every step**: no anchors moved across γ, IMP-1, α-2 changes. Zero regression risk to date. ## What didn't work - **α-1 (constraint_set_flags)**: hypothesis dead per source read. - **α-2 (POC strip)**: wire bytes changed; output unchanged. Net: 5 hypotheses eliminated, Bug 4 still present. ## Lessons distilled ### Lesson 1: Wire-byte equivalence ≠ behavior equivalence α-2 made libva's wire-byte output match kdirect's for POC fields. Output unchanged. **A single-field wire diff is a necessary signal but not sufficient — without knowing whether the kernel actually consumes that field, matching it is theater.** Phase 5b CRIT-1's source-read methodology is the right discipline. ### Lesson 2: Per-driver kludges should be flagged as such `h264_strip_ffmpeg_poc_sentinel` was a hantro-specific workaround embedded in shared H.264 code without per-driver gating. iter5b-β's `feedback_unconditional_codec_state.md` rule covers per-codec; this case suggests an analogous **per-V4L2-driver** rule for any kludge with implementation-specific motivation. Memory candidate. ### Lesson 3: Bug carryover labels can mislead "H.264 inter race-loss" was the label since iter4 P7. Phase 3 empirically showed the keyframe also fails — the bug isn't race-related at all. **Re-validate the bug shape with empirical evidence before assuming the prior label is correct.** Memory candidate. ## Cross-cutting backlog status (iter8 increment) Closed: - (none — Bug 4 is PARTIAL, not closed) Narrowed: - **Bug 4**: 5 hypotheses eliminated. Remaining candidates: PPS field diff, DPB ordering, DECODE_PARAMS post-DPB fields, slice data encoding. Still open (unchanged): - iter4-B1b (multi-decoder routing) - iter4-B2, B3, Q6, COLOR_RANGE, L3 - Bug 5 (HEVC kernel rejection) - Bug 6 (VP8 partial output, kernel-side per iter6 narrowing) ## Iter8 → iter9 handoff Substrate at close: - Fork tip `0226684` on noether + fresnel + gitea. - Backend SHA `b6a3958a…` on fresnel. - Kernel `linux-fresnel-fourier 7.0-1` unchanged. - Test fixtures unchanged. - γ + IMP-1 diagnostic infrastructure in place (env-gated off by default). Campaign scoreboard (unchanged from iter7): ``` Codec | Site | Status | Notes ========|===========|===============|==================================== H.264 | rkvdec | PARTIAL | Bug 4 narrowed; PPS diff next (iter9) HEVC | rkvdec | TRANSITIVE * | Bug 5 deferred VP9 | rkvdec | PASS direct | iter5b-β fix MPEG-2 | hantro | PASS (env) | iter1 PASS VP8 | hantro | PARTIAL (env) | Bug 6 deferred ``` iter9 candidate ranking (per Phase 7c): 1. **α-3 PPS full-byte diff** (lowest LOC, mechanical strace re-run + diff) 2. **α-6 DECODE_PARAMS post-DPB fields** (strace re-run with longer -s, diff bytes 512-559) 3. **α-4 DPB entry ordering** (~10 LOC change to h264_fill_dpb) 4. **α-5 Slice data encoding** (deepest investigation, ~60 min) ## Memory rule candidates (deferred to next memory-curation pass) - **Per-V4L2-driver kludge gating**: any hantro / rkvdec / cedrus-specific workaround in shared codec code must be gated, similar to per-codec gating per `feedback_unconditional_codec_state.md`. - **Bug label revalidation**: when picking up a carryover bug, run Phase 3-equivalent empirical reproduction first; the label may be wrong. - **Wire-byte equivalence ≠ behavior equivalence**: a successful "match kdirect's bytes" change isn't proof of fix. Always run the success criterion verifier post-change. ## Phase 8 commit This document records iter8 close. Fork at `0226684`. Backend SHA `b6a3958a…`. Bug 4 narrowed via 5 eliminations; 4 of 5 codec criteria unchanged (PASS); criterion-1 H.264 still PARTIAL. iter8 = 5/6 PASS. iter9 has a clearer search space than iter8 opened with.