Structural-corruption distortion corpus for zensim negative-tail validation
- Dominant language
- Rust
- Stars
- 13
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
## Purpose
Build a held-out **structural-corruption distortion corpus** to validate and calibrate zensim's intentional *negative tail*. A faithful similarity metric must rank a localized, catastrophic decode/render defect (channel swap, off-by-one edge, dropped MCU) **below** an honest uniform low-quality encode of the same reference. This corpus is the ground truth for the regression-test use case: a broken decode must score worse than a legitimately-lossy one, so a test catches the bug instead of passing it.
**Spec:** `zensim/docs/structural_corruption_corpus_spec_2026-05-27.md` (in the zensim repo). The gate every entry asserts:
```
score(ref, corruption) < score(ref, honest_lq_anchor)
```
where `honest_lq_anchor` = a uniform JPEG q20 (and q10) encode of the reference. For egregious corruptions (large region, opaque channel swap), the calibrated score should be `< 0`. Subtle ones (8x8 block, 1px 20%-opacity border) need only rank below the lq anchor — they are the hard cases and the research signal for the negative-tail calibration.
## Synthetic distortion families (10, from the spec)
Each family is parameterized by **region size** (sweep: whole-image -> 1/4 -> 1/16 -> 64x64 -> 16x16 -> 8x8 -> single-pixel where meaningful) and **severity** (opacity/magnitude). Generate deterministically (seeded) on a content-varied reference set.
1. **Channel corruption** — within a rectangle: invert (255-v), channel swap (RGB->BGR, R<->G, R<->B, G<->B), single-channel zero/max.
2. **Block corruption** — N×N block: zero-fill, mid-gray fill, garbage, copy-from-wrong-location (MCU mispredict), repeat-neighbor.
3. **Edge / border artifacts** — k-px border (k in {1,2,4}) at p% opacity (p in {20,50,100}); 1px interior shift (off-by-one crop/pad); duplicated/dropped edge row.
4. **Salt-and-pepper / bit errors** — k random pixels (1 .. 0.1%) to black/white/random; single-bit channel flips.
5. **Local tone / gamma** — within a block: wrong transfer function (apply/undo sRGB), local contrast boost ×1.5, brightness offset.
6. **Low-opacity overlay** — shape (rect/line/glyph) at 5-30% opacity (render leak / watermark bleed).
7. **Chroma-boundary mismatch** — upsample chroma with wrong phase / different kernel than luma at block boundaries.
8. **Aliasing / moiré** — NN downscale->upscale, or HF pattern downsampled without prefilter.
9. **Geometric** — 1px translation / sub-pixel shift / small rotation / flip / 1px skew of a region.
10. **Wrong-background compositing** — premultiplied-as-straight (and vice-versa); composite onto wrong bg (black/white/gray).
## Gold-standard members: MINED real historical decoder/renderer bugs (MANDATORY)
These are reproductions of real shipped wrong-pixel bugs from imageflow + the zensim-regress codec users. Each must appear as a corpus entry: the reference + the buggy output (recovered from the fixed test/fixture) OR a synthetic repro of the bug's exact pixel pattern. `source: "real-bug:#"` in the manifest.
| repo | bug (1 line) | pixel-defect pattern | commit / issue ref | repro available? |
|---|---|---|---|---|
| zenjpeg | Progressive decoder truncated AC coeffs near restart markers | Trailing blocks zeroed -> blocky/desaturated trailing MCUs | commit `08ef601` (Q91-93, DRI=216, 576x576) | fixed-test repro: `quality_regression diagnostic_coefficient_comparison` |
| zenjpeg | Progressive MCU-padded storage stride mismatch (4:2:0 non-MCU-aligned width) | 1-block-per-row horizontal shift accumulating to max_diff=255 | commit `29d6d81` (~20/543 corpus files) | yes (fixed regression) |
| zenjpeg | Progressive interleaved DC scan padding desynced Huffman decoder | "invalid Huffman code" / wrong block decode on 80/543 4:2:0 files | commit `759a4a7` | yes |
| zenjpeg | 4:2:0 scanline chroma upsampling used edge-replication at MCU **bottom** boundary | Horizontal chroma band at MCU row edges (max ~43-57 px err) | commit `bd0f8d7` | yes — this IS family #7 (chroma-boundary mismatch) |
| zenjpeg | XYB Full mode emitted BQuarter MCU block ordering | Every component read as wrong plane -> catastrophic color (red->green) | commit `daf52508` | yes (4-quadrant test image) |
| zenjpeg | XYB linear-input path double-scaled -> Y~1600 saturates every MCU | Decodes to **solid white** | commits `28658af6`+`9e2348fe` (Known Bug #7) | yes (`xyb_roundtrip.rs`) |
| zenjpeg | XYB 4:2:0 DC category clamped to 11 but encoder wrote unclamped | Huffman code=0,len=0 -> **corrupted bitstream**, undecodable | commit `b0cafce` | partial (files in `testdata/decode_failures/`) |
| zenjpeg | False XYB-ICC detection on cjpegli JPEGs ("jxl " CMM) | Wrong XYB->RGB path -> completely wrong colors (max_diff=252) | commit `744d38a` | yes |
| zenjpeg | grayscale Hi/Vi>1 + Bgr -> wrong bytes (IDCT strip overflow) | Garbled grayscale output | commit `4af35564` | yes (`grayscale_*_sampling2x2.jpg`) |
| zenjpeg | h2v2 boundary fixup overflow / sharp-YUV y_offset sign error | green color shift (Cb/Cr pushed low) | `1c9631a8` (closes zenwebp#17) | yes |
| zenwebp | Multi-pass probability signaling bug | encoder signals 0 prob updates, decoder expects ~125 -> 99.9% pixels garbage | commit `d58fc25` | yes |
| zenwebp | Chroma error-diffusion applied in encode but not in reconstruction | encoder recon != bitstream -> decoder produces different pixels | commit `eaa7afe` | yes |
| zenwebp | Missing U/V chroma-conversion rounding | 99% of U/V off-by-1 vs reference | commit `11465dd` | yes |
| zenwebp | sharp_yuv used non-gamma-corrected BT.601 forward matrix | systematic **green shift** (Cb/Cr ~12 low) | commit `7a23ffa` | yes |
| zenwebp | fused-scalar fancy-upsampling collapsed to single chroma sample | chroma blockiness (no neighbor blend) | commit `c63d898` | yes |
| zenwebp | NEON `sse_8x8_chroma` chroma-width stride bug | wrong chroma SSE -> mode mis-selection | commit `167ad48` | yes (parity tests) |
| zenwebp | animation dispose-to-background used 3-byte stride on RGBA canvas | misaligned writes -> **canvas corruption** of cleared rect | commit `a8df324` | yes |
| zenwebp | lossless + alpha + padded-stride corruption | alpha plane corruption | PR #18 / issue #10 (`8c29215`) | yes (regression tests) |
| zenwebp | color-indexing transform decode bug | wrong indexed colors | commit `cfd582c` (#28) | upstream-fixed |
| zenwebp | lossless color-cache update missing in fast path | wrong pixels in lossless decode | commit `7b2bbbc` (#114) | upstream-fixed |
| zenwebp | systematic quality drops at q75->80 and q87->90 (mode switches) | non-monotonic quality cliff at codec mode boundaries | zensim MEMORY.md (Known Issues) | needs synthetic repro |
| zengif | transparent pixels mapped to nearest palette color (shared-palette mode) | transparent regions render as dark gray (SSIM2 down to 41) | commit `93b6da2` | yes |
| zengif | quantize_frame returned raw indices w/o alpha->transparent-index post-process | transparent pixels render opaque | commit `0d9f031` | yes |
| zenpng | U16->U8 depth reduction used `>>8` truncation not rounding | per-channel off-by-up-to-1 banding on 16-bit PNG | commit `d88325c` | yes |
| zenpng | 16-bit PNG decode truncated to u8 before f32 (precision loss) | lost 16-bit precision -> banding | commit `838cad7` | yes |
| zenpng | Adam7 interlaced decode buffer too small for wide images | infinite loop / failed decode on wide interlaced PNG | commit `3cbed35` | yes (`8625x8625`) |
| zenavif | `unpremultiply8` truncated `(c*255/a)` instead of rounding | off-by-1 on un-premultiplied (alpha) pixels | commit `4509713` | yes |
| zenavif | `scale_from_u16` half-up rounding fought LSB replication | 50% (511/1024) of 10-bit values shifted +1 on roundtrip | commit `42d06a7` | yes |
| zenavif | bilinear chroma interp negative weights at image edges | broken edge chroma interpolation | commit `cb366c5` | yes |
| zenavif | f32 PQ/HLG routed through `linear_to_srgb_u8` | HDR signal destroyed (tone-clipped) | commit `37d2073` | yes |
| heic | chroma MC shift 4 instead of 6 (uni-pred) | **chroma scaled 4x** -> wildly wrong color | commit `c20861e` | yes (conformance) |
| heic | chroma MC wrong intermediate precision (bi-pred) | wrong chroma in B-slices | commit `b24c111` | yes |
| heic | spurious rounding offset in bi-pred MC vertical pass | luma off-by small amount in bi-pred | commit `9e9b1c5` | yes |
| heic | deblocking boundary strength wrong (inter) / SAO corruption | edge artifacts / SAO corruption | commits `251968b`, `754a029` | yes (conformance) |
| heic | tile-boundary CABAC/QP/MPM errors | wrong pixels across tile boundaries (grid HEIC) | commits `dafa255`, `5d035ec` | yes |
| imageflow | transparent PNG->JPEG loses color (bgcolor=transparent matte) | desaturated / wrong matte on flatten | issue #669 | repro inputs in issue |
| imageflow | "within" constraint rounding -> 1px transparent border | 99x33 content in a 100x33 canvas (off-by-one edge) | issue #656 | yes — this IS family #3 (edge off-by-one) |
| imageflow | transparent PNG shows black background on JPEG convert | wrong-bg composite (black not white) | issues #158, #190, #175 | yes — family #10 (wrong-bg) |
| imageflow | swapped width/height in `enable_transparency` canvas creation | misaligned transparent canvas | CHANGELOG security-audit (`0e7c0385`) | needs synthetic repro |
| imageflow | EXIF-orientated image cropped in wrong region | crop applied pre-orientation -> wrong content | issue #553 | yes (orientation samples) |
| imageflow | WebPLossy desaturated color | systematic desaturation vs mozjpeg | issue #588 | repro inputs in issue |
**Family coverage check:** families #3 (edge off-by-one), #7 (chroma-boundary), #10 (wrong-bg composite) have **direct real-bug analogues** above (imageflow #656; zenjpeg `bd0f8d7`; imageflow #158/#190). Family #1 (channel corruption) maps to zenjpeg `daf52508` (wrong-plane). Family #2 (block corruption) maps to zenjpeg progressive-truncation/stride bugs. Family #5 (local gamma) maps to zenjpeg cjpegli-ICC + zenavif PQ/HLG. Families with **no exact real-bug analogue found** (synthetic-only): **#4 salt-and-pepper / single-bit errors**, **#6 low-opacity overlay / watermark bleed**, **#8 aliasing / moiré (resampler)**, **#9 geometric (rotation/flip/skew)**. These remain synthetic; flag in the manifest as `source: "synthetic"`.
**Bug class the spec under-weights:** *off-by-one rounding in bit-depth/range conversion* (zenpng `d88325c` U16->U8, zenavif `42d06a7` 10-bit roundtrip, zenwebp `11465dd` U/V rounding, zenavif `4509713` unpremul). These are extremely subtle (max_diff=1) but systematic across the whole image — a worst case for a saturating metric. Worth a dedicated "global off-by-one rounding" sub-family beyond the localized families.
## Corpus deliverables checklist
- [ ] `corruptions/` module with deterministic seeded Rust generators, one fn per family, parameterized by region + severity.
- [ ] `_MANIFEST.json` per entry: `{ ref_id, family, params, expected_below_lq: true, expected_negative: bool, source: "synthetic" | "real-bug:#" }`.
- [ ] Reuse codec-corpus curated references; do NOT commit large generated images — prefer on-demand generation from seed + ref_id (reproducible without committing bytes).
- [ ] Region-size sweep dense from whole-image down to 8x8 (and 1px for edge/geometric); severity from subtle (20% opacity, 8x8) to obvious (opaque, whole-image).
- [ ] >= 5 content classes (photo, screen/UI, line-art, text, gradient) x >= 10 references each.
- [ ] Real-bug gold-standard members (every row in the table above), with recovered buggy output where the fixed test/fixture provides it, else a synthetic pixel-pattern repro.
- [ ] zensim-gate driver: given a reference, emits `(ref, corruption, q20-anchor, q10-anchor)` so the gate runs directly.
- [ ] zensim eval reporting per family x region x severity: `score(corruption)`, `score(q20)`, `score(q10)`, gate pass/fail `score(corruption) < score(q20)` (measured, not asserted, on the subtle end).
## Note
The corpus **build is being done in parallel** (another agent). This issue is the tracking + the real-bug requirements: the mined gold-standard members above are mandatory members, not optional.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.