imazen / imazen/squintly

Near-lossless (sub-JND) methodology: audit vs the IQA literature + a boosted-triplet study squintly can set up

Open
#8 0 comments 0 reactions 1 assignee Claimed by @lilith View on GitHub
Dominant language
Rust
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

# Near-lossless (sub-JND) methodology: audit vs the IQA literature + a boosted-triplet study squintly can set up

Audited at `ce781fa` (claims verified against code, not README). Companion to #4. Literature claims below are sourced from the zenpapers corpus (ids + file paths in §5); where the corpus explicitly lacks a source, that is stated rather than papered over.

## 0. Summary

Squintly's current instrument is genuinely strong **for the zone it was designed for** — supra-threshold quality scaling and notice/dislike/hate thresholds at web-typical qualities. The audit finding is not a rigor gap; it is a **zone gap**: the instrument structurally cannot measure the near-lossless band (q ≈ 75–100, roughly 0–2.5 JND from reference), which is simultaneously

- where compression product decisions live (the "is this visually lossless on THIS phone" question an encoder picker asks),
- zensim's measured weak zone (zensim CLAUDE.md: "HF near-lossless is the metric's WEAK ZONE"), and
- the zone the modern methodology literature — JPEG AIC-3 boosted triplets, KonJND-style flicker thresholds, the AIC-2/ISO 29170-2 lineage — built specialized protocols for, none of which squintly implements yet (README lever #14 is planned with no design attached).

This issue delivers: (a) a current-vs-proper comparison table, (b) a concrete near-lossless study design built from squintly's existing machinery plus the AIC-3/KonJND protocol family, (c) an implementation checklist mapped to files.

## 1. What squintly currently does (verified)

| Dimension | Current implementation (evidence) |
|---|---|
| Task types | Type S: 4-tier ACR (imperceptible / notice / dislike / hate) driving Levitt transformed up–down staircases — 3-down-1-up → 79.4 % (`q_notice`), 2-down-1-up → 70.7 % (`q_dislike`), 1-down-1-up → 50 % (`q_hate`) (`src/staircase.rs`). Type P: triplet (reference, A, B) forced choice with tie, reference revealable via hold (`docs/STUDY.md` §4.2). Mix `p_single = 0.65` (`src/sampling.rs:245`). |
| Scale model | Bradley–Terry–Davidson (ties first-class) per (source, condition_bucket), reference anchored at 0, Gaussian prior, CID22-style monotonicity dummies N=200; unified Pérez-Ortiz-2019 pairwise + ordinal-ACR joint fit with per-observer (δ_o, σ_o) (`src/bt.rs`, `src/unified.rs`, `docs/methodology.md` §5). |
| Active sampling | ASAP-style EIG pair selection IS wired into `next_trial` (`src/handlers.rs:606` → `enhance_pair_with_asap`, `tests/asap_wire.rs`), refit per request, fallback to random adjacent below 8 observations. |
| Screening / QC | 5 calibration trials incl. an instructed-response item; 8-trial qualifier (≥ 6 correct); honeypots at `p_honeypot = 0.083` (1/12), fail-two-ends-session; per-trial flags (dwell floor/ceiling, no-reveal, viewport-clipped); session grade A–F (geometric mean of five sub-scores) → `session_weight ∈ {0, 0.5, 1.0, 1.5}`; first-3-trials warmup discarded (`src/grading.rs`, `docs/methodology.md` §3–4). Crowd-BT η + pwcmp LOO: partial (nightly aggregation ships; η/LOO are TODO at `src/grading.rs:340`). |
| Presentation | Hard 1:1 device-pixel minimum, never downscaled; pan preserved across swaps; zoom only IN, integer factors, nearest-neighbour; per-response `zoom_factor` + pan/visible geometry (`docs/methodology.md` §2). |
| Conditions | 65-column per-response vector: DPR, calibrated CSS-px/mm (credit-card slider), pixels-per-degree, distance, ambient, gamut, dwell, reveal counts, input mode… unaggregated (`src/export.rs` `RESPONSES_TSV_HEADER`). |
| Corpus | imazen26-v4-test, 180 test-split sources / 21 strata, 4 real codecs (libjpeg-turbo, jpegli, libwebp, libavif), quality ladder **{15, 30, 45, 60, 80, 92}** (`scripts/build_demo_corpus.py:123`, DEPLOY.md §15). |
| Exports | `pareto/thresholds/responses/unified.tsv` + manifest sidecars with `build_commit`, `schema_version`, `sha256` (`src/handlers.rs:1330`). |
| Sample-size targets | CID22-derived floors (≥ 80 single-stimulus opinions per anchor, ≥ 5 pair opinions per pair); convergence target 95 % CI ≤ 0.5 JOD (`docs/methodology.md` §8, `docs/STUDY.md` §6). |

Doc drift found while auditing (small cleanup commit, separable from this study):

1. `docs/methodology.md` §11 and `docs/STUDY.md` §4.4 say ASAP is "not yet wired into the runtime sampler" — it is (`handlers.rs:606`, `tests/asap_wire.rs`). README is correct.
2. README lever #4 describes the trivial-pair filter as "the metric ensemble unanimously predicts (≥ 95 %)" — the implemented filter is the CID22 heuristic (quality-gap ≥ ⌈grid/2⌉, bytes-ratio > 4×; `docs/methodology.md` §3.4). The ensemble version is lever #13, planned.
3. README §3 says honeypots at "~1/30"; code and methodology.md say 1/12 (`p_honeypot = 0.083`).
4. README lever #14 claims "expected ~3× discrimination" from AIC-3 boosting. The paper's own statement (arXiv:2410.09501) is that boosted scales are "larger than the unboosted ones by a factor of **about 2**" with precision "about twice as good" — i.e. ~2× per-trial precision, ~4× fewer trials at equal CI, not 3×/9×.
5. `docs/STUDY.md` §5.1 attributes "Gaussian prior on θ (σ_prior = 1.0)" to pwcmp (arXiv:1712.03686). The paper actually uses a **finite distance prior** (mode ≈ 2.5 JOD, offset γ = 0.1) and explicitly warns that the Normal prior "strongly reduces confidence intervals … but also introduces a large error in the estimates (large RMSE)". Worth re-verifying the prior choice — it becomes load-bearing in the near-lossless zone, where unanimous "can't tell" pairs dominate and the prior is what keeps the MLE finite.

## 2. Current vs proper methodology — comparison table

"Proper" = what the subjective-methodology literature in zenpapers prescribes per dimension. Verdicts: OK (matches best practice), GAP (fixable within the current design), **CRITICAL** (structurally cannot answer the near-lossless question).

| # | Dimension | Squintly today | Literature-proper | Verdict |
|---|---|---|---|---|
| 1 | Test-class taxonomy | 4-tier ACR + PC-with-ties + adaptive staircases, interleaved | ITU-T P.910 classes (ACR, DCR, PC) all represented; the revealable reference makes Type P effectively DCR-shaped. (Cite P.910 10/2023 — **P.913 was deleted 2024-02 and merged into it**; the ITU texts themselves are not in the corpus, only secondhand parameters.) | OK |
| 2 | Scale reconstruction | BT-Davidson + unified pairwise/ACR (Pérez-Ortiz 2019), observer-bootstrap CIs | The pwcmp / unified-scale line of work exactly | OK-minus — the prior-attribution nit (§1 item 5); also pwcmp: CIs "can be very large if the number of observers is less than 20" — a per-cell distinct-observer floor belongs next to the existing opinion floors |
| 3 | Pair scheduling | ASAP-style EIG, wired | Active sampling reaches > 0.9 correlation with complete-design BT at ~10 % of pairs (arXiv:2311.06093) | OK (fix doc drift) |
| 4 | Observer screening | Qualifier + IMC + honeypots + A–F grading + warmup discard; η/LOO pending | Golden/trap units are universal: KADID-10k raw crowd data literally ships `_golden`/`_trust` columns; AIC-3 uses 5.6 % trap + 2.8 % bias questions with a ≥ 70 % trap gate; SDR25 adds mirrored-pair consistency scoring (1 / 0.375 / 0) with an Otsu-thresholded accuracy+consistency screen | OK-minus — finish η + LOO; add mirrored-repeat consistency (§3.5) |
| 5 | **Stimulus range** | Ladder tops out at **q92**, two rungs ≥ 80, none above 92; reference not a rung | The AIC-3 family samples 0.25–2.5 JND from reference in **0.25-JND steps**; its dataset floor (−2.5 JND) was *chosen* to be where squintly's ladder *starts* being dense | **CRITICAL** — `q_notice` staircases start at the grid top (`staircase.rs:122`), so any observer who still notices artifacts at q92 (common on phones at 1:1) exits **censored at the ceiling**, with no censoring flag; the threshold table silently reports 92 |
| 6 | **Sub-JND sensitivity** | Plain forced choice + plain ACR | Boosted triplet comparisons (AIC-3: zoom + ×2 artifact amplification + 10 Hz flicker) — measured ~2× scale magnification/precision, i.e. ~4× fewer trials at equal CI; KonJND-1k's flicker threshold protocol ("twice the sensitivity of a side-by-side comparison") | **CRITICAL** — plain 2AFC needs ≈ 435 trials/pair to merely *detect* a 0.25-JND difference (§3.1); boosted ≈ 110. Near reference p → 0.5, the EIG surface flattens, and ASAP has nothing to optimize |
| 7 | Threshold protocol | Levitt staircases on a 6-rung grid; exit only via reversal count; flicker absent | Threshold search under flicker presentation: KonJND-1k (8 Hz alternation + slider, MTurk-validated at 503 workers) — slider adjustment was "1.5 to 2× faster" than relaxed binary search at comparable accuracy. NB the corpus has **no IQA use of Levitt staircases at all** — squintly's Levitt citation stands on the psychoacoustics original, which is fine, but untested in this domain | GAP — algorithm defensible, grid + censoring + presentation are not |
| 8 | Cross-dataset anchoring | `corpus_anchors` table exists and is **empty**; README notes CID22 content overlap is "zero, probably" | UPIQ-style psychometric merging (arXiv:2012.10758): re-judge cross-dataset pairs of similar quality inside one instrument — ~6,000 comparisons / 220 participants / 6 per pair sufficed to fuse 4 datasets onto one JOD scale, references pinned at 0 | GAP — and the HF study is the natural fix: AIC-3's reference PNGs are on disk (`/mnt/v/datasets/aic3-btc-ptc/test-images/`, `*_0ref_00.png` in the archives) with ~472k raw triplet responses (420k boosted + 52k plain, row-counted) to align against |
| 9 | Display / environment | 1:1 device pixels, integer NN zoom, pan telemetry, per-trial conditions, codec probe — **exceeds typical crowd practice** (KonJND's JS gate is the only comparable corpus example); no gamma/color-vision probe | Lab specs are unattainable in crowd; corpus-documented mitigations: log-and-covariate (grey-ramp gamma check at {0,51,102,153,204,255}, 2 Ishihara plates as in SDR25), per-response display fields, strict no-resample rendering — squintly already does the last two | OK-minus — add the gamma ramp + Ishihara to onboarding; lock zoom during flicker trials (KonJND blocked browser zoom for exactly this reason) |
| 10 | Session / fatigue limits | Open-ended sessions; ~30 trials/session assumed in budget math, not enforced | ≤ 30 min sessions (P.913-era guidance, cited via arXiv:2311.03850); AIC-HDR2025 caps at 2 batches × 120 questions with a **mandatory 3-min break** (measured 10.7–20.1 min/batch) | GAP (low) — add a soft cap + break nudge |
| 11 | Output orientation contract | `pareto.tsv` `quality` is higher-better by construction; **nothing declares it**; `responses.tsv` has a column literally named `orientation` that is *screen* orientation | zensim ingestion is now orientation-gated (`scripts/canonical_corpus/check_target_orientation.py`: sign test vs raw ground truth, verdict recorded in `_MANIFEST.json`) after the 2026-08-04 KADID inversion shipped sign-flipped published numbers for six weeks — and KADID's flip happened at exactly this producer/consumer boundary | GAP (cheap, high value) — declare + self-test orientation in every export manifest; name the HF screen column `screen_orientation` |
| 12 | Sample-size math | CID22-derived floors; JOD CI ≤ 0.5 via ladder pooling | Correct supra-threshold; collapses sub-JND (row 6). The AIC-grade precision bar for this band is **95 % CI half-width ≤ 0.27 JND at 1 JND** (AIC-HDR2025 achieved it at 24 responses/triplet with 100 % mirrored pairs) | folded into 6 |

Bottom line: rows 1–4 and 9 are at or above published crowd-study practice. Rows 5–7 make the near-lossless zone invisible to the instrument, and row 8 leaves squintly's scale unanchored to the two high-fidelity human datasets already on disk (AIC-3, JPEG-AI-SDR25).

## 3. Proposed study: `hf-nearlossless`

A new compiled-in study (per the `src/studies.rs` doctrine: studies are pre-registration; an env-var typo must not be able to invent one). It reuses the existing machinery — staircases, BT-Davidson, ASAP, grading, condition capture, hold-to-reveal — and adds three things: a dense HF ladder, the AIC-3/KonJND presentation modes (boosted triplets, flicker threshold search), and a JND-unit export with a declared orientation contract.

### 3.0 Questions + pre-registered gates (STUDY.md amendment, locked before the pilot)

- **HF-RQ1.** Per (source, codec, condition-bin): at what q does the encode become flicker-detectable from the reference (`q_flicker_notice`), and how does it depend on the condition vector?
- **HF-RQ2.** Sub-JND scale: latent quality in JND-from-reference units across the HF ladder, aligned to the AIC-3/SDR25 scales via re-judged anchor stimuli — including the first measurement of the **boosting transfer function under mobile viewing** (the corpus marks this honest-stop: BTC's ×2 amplification is calibrated to lab ppd and "over-boosts" at mobile ppd; nobody has measured by how much).
- **HF-RQ3.** Does zensim retrained with these labels improve on the HF weak zone without regressing elsewhere?

Gates (Bonferroni alongside H1–H5):

- **HF-H1**: `μ_notice(c)` transfers — GAM R² ≥ 0.5 on held-out sources for `q_flicker_notice`.
- **HF-H2**: boosted-scale validity — plain-triplet (Tier P) scale points fall within the 95 % CIs of the aligned boosted scale (the AIC-3 validity check, run on our data), and SROCC ≥ 0.90 between the two on overlap cells.
- **HF-H3**: zensim-v49-hf ≥ +0.05 SROCC on hf_nearlossless val vs current ship, CID22 regression < 0.005 (mirrors the v48 decision-rule shape).

### 3.1 Why plain pairs cannot do this (the math)

Convention (pwcmp + AIC-3, corpus-reconciled): 1 JOD/JND ⇔ 75 % preference, p = Φ(0.6745·Δ); 2 units ⇔ 91 %.

- SE of a single-pair scale estimate from n plain comparisons at Δ ≈ 1: SE(Δ) ≈ 2.02/√n → 95 % CI ± 0.5 JND needs **n ≈ 63**; ± 0.25 needs **n ≈ 251**.
- To merely *detect* Δ = 0.25 JND (p = 0.567 vs 0.5) at α = 0.05, power 0.8: **n ≈ 435 trials for one pair**.
- AIC-3's measured boosting gain — zoom + amplification + flicker combined — is a **~2× scale magnification** (arXiv:2410.09501: boosted scales "larger … by a factor of about 2", precision "about twice as good"). At 2×, the same detection needs **n ≈ 110**, and equal-CI budgets drop **~4×**. KonJND-1k measured the flicker component alone at ~2× the sensitivity of side-by-side viewing.
- Observer floors, independent of trial counts: ≥ 15 subjects (P.910, via arXiv:2311.06093) and ≥ 20 for stable pwcmp CIs — so per-cell budgets below must land on ≥ 20 distinct observers per fitted cell.

Ladder pooling (the psychometric fit borrows strength across rungs) improves all of this but cannot rescue a regime where every pairwise probability sits within noise of 0.5 — boosting moves the probabilities away from 0.5 *before* statistics happen. One caution the literature adds: plain flicker is a *threshold* instrument, not a *scaling* one — the ACM MM 2023 protocol face-off found the flicker test "too sensitive [to] provide any meaningful result in the quality range of interest" when used for quality scaling, which is exactly why AIC-3 embeds flicker inside boosted *triplets* instead. The design below follows that split.

### 3.2 Stimuli

- **Sources: 48 of the existing 180 imazen26-v4-test sources** — within the 21 strata, k-medoid picks on the `feat_*` embedding (not random; random over-samples the modal class), ≥ 2 per stratum, preserving the ~50 % non-photo share. Plus **5–8 anchor sources = AIC-3's own references** (extracted from the local archives), re-encoded on our ladder. Anchors are the row-8 fix, UPIQ-style: shared content re-judged in-instrument, aligned to the published JND scales.
- **Codecs: the 4 browser-native ones already deployed** (libjpeg-turbo, jpegli, libwebp, libavif). JXL stays out (no browser decode; the codec probe would drop it); JXL HF coverage continues to come from the existing hf_nearlossless tables.
- **HF ladder: 8 rungs + reference as the top rung**: q ∈ {75, 80, 85, 88, 91, 94, 97, 99} (avif via its quality parameter; jpegli on the IJG scale). Rung spacing tightens toward the top, aiming for roughly 0.25–0.5-JND steps in the band AIC-3 showed matters (their 10 levels span 0.25–2.5 JND). Reference participates as rung 9 so "indistinguishable" is on-scale, not censored.
- **Boosted variants, precomputed offline** — never synthesized in-browser (canvas color management + resampling would fabricate evidence; methodology.md §2's own rule). Replicate AIC-3 verbatim for anchor comparability: (1) crop to half size per dimension, Lanczos-upscale back (net 2× linear zoom); (2) pixel-wise (ref − dist) difference amplified **×2 per channel**; flicker (the third boost component) happens at presentation time. Note the deliberate, pre-registered exception to squintly's nearest-neighbour rule: Lanczos here is part of the *stimulus transform applied identically to both sides offline*, not a viewer magnifier — document it in methodology.md when landing.
- **Condition bins: 2 primary** — (phone, DPR ≥ 2, calibrated distance ≤ 45 cm) vs (desktop, DPR ≈ 1, arm's length). Calibration (credit-card slider) is **required** for HF sessions; an unbinnable session gets weight 0. Fine-grained condition resolution stays with the main study.

Cells: (48 + 8) sources × 4 codecs × 2 bins = **448 threshold cells**; the scale tiers run on a subset (§3.3).

### 3.3 Trial protocol (three tiers = the AIC-3/KonJND family, cheapest-discriminating-first)

- **Tier T — flicker threshold (all 448 cells).** In-place temporal alternation reference ↔ encode at **8 Hz** (KonJND's rate; rAF-scheduled from pre-decoded ImageBitmaps — 8 Hz is unreachable cleanly at 60 Hz refresh (60/8 = 7.5 frames/phase), so pin phase length in integer frames per device class: 7 or 8 frames at 60 Hz ≈ 8.6/7.5 Hz, 15 at 120 Hz = 8 Hz exactly, and record the achieved rate), same 1:1 rule, **zoom locked at 1×**, question: "does any region flicker?" Two response instruments, A/B-tested in the pilot: (a) the existing Levitt 3-down-1-up staircase over the ladder (implemented, known convergence, ~16 trials/threshold); (b) KonJND-style **slider adjustment** — scrub the ladder with live flicker, stop at the smallest q where flicker appears (~1 response/threshold; KonJND found sliders 1.5–2× faster than relaxed binary search at comparable accuracy, and it is the only threshold instrument in the corpus validated on crowdsourcing at scale). Record `flicker_hz_target`/`flicker_hz_achieved` per response; discard < 80 % of target (VRR, throttling); route `prefers-reduced-motion` observers to Tier P instead. Output: `q_flicker_notice` — the **conservative** visually-lossless bound (flicker ≈ 2× more sensitive than natural viewing; that conservatism is a feature for a "safe q" product answer, and the Tier B scale gives the natural-viewing complement).
- **Tier B — boosted triplets (scale instrument; anchors + 16 of the 48 sources, 4 codecs, 2 bins ≈ 192 cells).** AIC-3 BTC shape: triplet with the **source as middle pivot**, boosted A/B from adjacent ladder rungs (reference rung included), responses Left / Right / **Not Sure**, ASAP-scheduled. Presentation timing per AIC-3 (8 s exposure + answer window) is worth keeping for comparability.
- **Tier P — plain triplets (transfer anchor; ~15 % of Tier-B volume, interleaved).** AIC-3 PTC shape: source pivot, unboosted sides, in-place toggle rate-limited ≤ 2 Hz with **at least one toggle required** — squintly's hold-to-reveal + `no_reveal` flag already implement exactly this interaction. SDR25 ran the same ~12 % plain-to-boosted ratio (10.3k PTC vs 85.2k BTC rows in the local raw data). Tier P identifies the boost transfer so the final scale is in *plain-viewing* JND units, and doubles as HF-H2.

The existing 4-tier ACR stays out of the fits in this band (not sensitive there); calibration/honeypot content continues to use it. If a rating instrument is wanted later, the corpus notes IDSQS (arXiv:2508.09777) — in-place toggle + 0–100 rating on the same AIC-3 stimuli, with public code — as the direct alternative.

### 3.4 Sampling

- Tier T first per cell (thresholds are cheap and gate the rest): rungs entirely above a cell's `q_flicker_notice` get scale trials only in anchor cells.
- ASAP EIG extends to the HF ladder with reference as a rung; boosted responses un-flatten the EIG surface (§3.1), which is what makes active sampling useful again in this band.
- Inverse-coverage weighting across cells as today; ≥ 20 distinct observers per fitted cell enforced at allocation time, not just post-hoc.

### 3.5 Trap + reliability design (extends the current honeypot system; rates follow AIC-3/SDR25 precedent)

| Trap | Construction | Expected response | Rate | Precedent |
|---|---|---|---|---|
| Positive catch | boosted reference vs q40 (level-0-vs-level-10 analog) | pick the distorted side / "flicker visible" | keep `p_honeypot = 0.083` (AIC-3 used 5.6 % trap; KonJND 1 gold per 10-image HIT) | AIC-3 `is_trap`; KADID `_golden` |
| Null / bias probe | A == B byte-identical | tie / "not sure" | ~1/20 of triplets | AIC-3 `is_bias` (2.8 %) — their raw data showed a strong right-side bias that vanished after reliability screening; the probe is what detects it |
| Flicker null | alternation between two copies of the reference | "no flicker" | ~1/20 of flicker trials | doubles as a display-fidelity probe: DPR resampling or dropped frames manufacture false flicker (the corpus calls DPR resampling "fatal" for flicker protocols) |
| Mirrored repeats | same triplet, sides swapped, later in session | consistent choice | ~5–10 % of triplets | SDR25 consistency score 1 / 0.375 / 0 (match / one not-sure / contradiction); AIC-HDR2025 mirrored 100 % of triplets and hit 0.27-JND CIs at 24 responses/triplet |
| Hard gates | reference rated ≥ dislike → F; q5 rated imperceptible → F | — | as today | CID22-verbatim gates in grading.rs |

Response-time gate for slider trials: KonJND dropped slider responses < 2.45 s, choosing the threshold adaptively as the minimum time at which gold accuracy stayed ≥ 70 % — adopt the *method* (fit the gate on pilot gold data), not the constant. Screening aggregate: per-batch accuracy+consistency with an Otsu threshold (SDR25) or the fixed 0.7 (AIC-HDR2025) — pre-register one; both feed the existing A–F/weight machinery rather than replacing it. Ishihara plates (SDR25 used ground-truth plates 2 and 16) + a grey-ramp render check at {0, 51, 102, 153, 204, 255} join onboarding as **log-and-covariate** fields, not rejection gates.

### 3.6 Observer model + reconstruction

- Scale fit: Thurstone/BT over Tier B + Tier P with the boosting transfer `t(d) = γ₁·d + γ₂·d²` (AIC-3's quadratic-through-origin, selected there by AIC over global/per-codec/per-source variants) linking boosted to plain discriminability; reference pinned at 0; JND units via ÷ Φ⁻¹(0.75) ≈ 0.6745. Ties: either Davidson (already in `src/bt.rs`) or AIC-3's "Not Sure = ½ left + ½ right" — decide on the replay data (below), noting pwcmp's caveat that ties tend to under-estimate scale distances while the relaxed-choice study (arXiv:2305.00220) found offering them improves performance: model them explicitly, never drop them.
- **Transfer γ is fit per condition-bin.** This is the mobile honest-stop turned into a contribution: BTC's ×2 amplification is CSF-calibrated to lab ppd; at phone ppd it over-boosts by an unknown amount. Per-bin Tier-P anchoring measures the transfer where it is actually deployed instead of assuming the lab value.
- Per-observer: finish lever #9 (Crowd-BT η, `Pr(correct) = η·BT + (1−η)·(1−BT)`; pwcmp LOO with the customary 1.5 threshold) — a dependency of this study, not new scope. Add per-observer `p_repeat` from the mirrored repeats (the `studies.rs` ρ/ceiling doctrine; self-agreement near threshold IS the noise ceiling).
- **Reconstruction-code validation gate (zero human cost, do first):** the implementation must, run against the local AIC-3 raw CSVs (472k rows) and SDR25 (95k rows), reproduce the published JND scales (target SROCC ≥ 0.98 per source vs their released reconstructions). We hold the raw data; no fresh reconstruction code touches squintly data before it reproduces theirs.

### 3.7 Budget (formulas + assumptions; the pilot recalibrates)

- Tier T: staircase arm ≈ 16 trials × 3 completions = 48/cell; slider arm ≈ 8 responses/cell. 448 cells → **3.6 k (slider) to 21.5 k (staircase) trials** — the pilot A/B decides, and the spread is exactly why it should.
- Tier B: at 2× boost, single-pair ± 0.5-JND CI needs ≈ 63/4 ≈ 16 comparisons before pooling; with ladder pooling budget ~14/adjacent pair × 8 pairs ≈ 112/cell × 192 cells ≈ **21.5 k trials**, + 15 % Tier P ≈ 3.2 k. Anchor cells get top-ups toward the AIC-grade 0.27-JND bar where alignment needs it.
- Total ≈ **28–46 k trials ≈ 700–1,150 sessions** at ~40 trials/session — same order as the pre-registered v1.0 main study (1,500), before ASAP savings (H4's ≥ 5× claim would cut the scale tier further; budget without it).
- **Pilot: 40 sessions**, pre-registered go/no-go: trusted-observer trap failure ≤ 5 %; `flicker_hz_achieved` ≥ 80 % of target on ≥ 90 % of phone trials; slider-vs-staircase agreement within 1 rung median (else keep staircase); σ_thr ≤ 2 rungs; per-bin γ identifiable (CI excludes 0). Fail → fix instrument, re-pilot; never widen gates.
- Session cap for HF: ≤ 15 min with a break nudge (AIC-HDR ran 10.7–20.1 min batches with a mandatory 3-min break).
- Stopping: 95 % CI ≤ 0.5 JND on ≥ 80 % of fitted cells, **censored fraction reported alongside** — a threshold above q99 is a finding, and must export as censored, never as "q99".

### 3.8 Output schema (orientation-gated by construction)

Two new exports + manifest fields; raw responses ride `responses.tsv` with new columns.

`hf_thresholds.tsv`: `source_hash, source_filename, codec, condition_bin, q_flicker_notice, q_lo, q_hi, censored ∈ {none, ceiling, floor}, instrument ∈ {staircase, slider}, n_estimates, n_trials, n_observers, weight, held_out`

`hf_jnd_scale.tsv`: `source_hash, codec, condition_bin, q, encoding_id, quality_jnd, jnd_lo, jnd_hi, n_boosted, n_plain, n_observers, weight, held_out` — with `quality_jnd = −(JND-from-reference)`, so **higher = better**, 0 = reference, matching the downstream `human_score` convention.

Manifest additions (both exports): `score_orientation: "higher_is_better"`, `scale_unit: "jnd (1 = 75% detection)"`, `anchor: "reference = 0"`, `boost_transfer: {gamma1, gamma2, per_bin, fit_ci}`, plus existing `build_commit`/`schema_version`/`sha256` — and a **self-run orientation sign test** recorded as `target_orientation`, mirroring zensim's `check_target_orientation.py` contract: assert `sign(SROCC(quality_jnd, q)) > 0` within every (source, codec, bin) ladder against the raw choice directions. Rationale: the 2026-08-04 KADID incident (a quality-oriented column treated as distortion-oriented; six weeks of sign-flipped published numbers) happened at exactly this producer→trainer boundary; squintly ships human labels into the same ingestion path, so the declaration + gate belong at the producer too. In HF exports, name the screen-rotation column `screen_orientation` so no grep for the orientation *contract* lands on portrait/landscape.

Reported stats follow the standing panel spec (SROCC/PLCC/KROCC/OR/PWRC/Z-RMSE + bootstrap CIs, 1000 resamples) so the tables drop into the existing eval tooling unchanged.

Ingestion: zensim's `scripts/canonical_corpus/` gains a `squintly-hf` builder emitting hf_nearlossless-shaped rows (`ref_basename, codec, q, human_score ← quality_jnd rescaled`), and `check_target_orientation.py` gains a `squintly-hf` entry whose ground truth is the raw choice table — the gate that now protects KADID/TID protects this dataset from day one.

## 4. Implementation checklist

Ordered cheapest-discriminating-first; items 1–3 cost no human trials.

- [ ] **Reconstruction validation replay** (§3.6): BTC+PTC Thurstone reconstruction with quadratic transfer (new `src/hf.rs` or extend `src/unified.rs`); reproduce AIC-3 + SDR25 published scales from the local raw CSVs; commit the parity report. *Gate: SROCC ≥ 0.98 per source.*
- [ ] **Doc drift fixes** (§1, five items) + re-verify the STUDY.md §5.1 prior attribution against arXiv:1712.03686.
- [ ] **Orientation contract on existing exports**: `score_orientation` + sign test in every manifest (`src/handlers.rs::build_export_manifest`, `src/export.rs`) — protects the main study too.
- [ ] **Corpus**: `build_demo_corpus.py --hf-ladder 75,80,85,88,91,94,97,99` + offline boosted-variant generation (AIC-3-verbatim: half-crop + Lanczos 2× + ×2 per-channel diff amplification) → publish `imazen26-v5-hf` under a fresh versioned prefix (DEPLOY.md roll-forward rule); AIC-3 anchor sources with license badges via `src/licensing.rs`; methodology.md records the pre-registered Lanczos exception to the NN rule.
- [ ] **Study registration**: `src/studies.rs` `hf-nearlossless` entry (SamplerConfig, ContentFilter, min-viable counts, per-cell observer floor) + the guard-test pattern used for the photo-control arm.
- [ ] **Staircase**: audit grid-edge behavior in `src/staircase.rs` (start index is the grid top; repeated ceiling-pinned responses must exit as `censored=ceiling`, not loop or silently report the rung) + persist the censoring flag.
- [ ] **Flicker + slider instruments**: `web/src/trial.ts` rAF alternation (integer frames/phase, measured `flicker_hz_achieved`, abort-below-80 %, zoom locked, `prefers-reduced-motion` routing) + the KonJND-style ladder slider; migration `0015_hf_study.sql` adds `boost_factor, flicker_hz_target, flicker_hz_achieved, staircase_censored, instrument` columns.
- [ ] **Sampler + traps**: honeypot-pool extensions (null pair, flicker null, mirrored repeats, boosted catch) in `src/sampling.rs`; Tier T/B/P scheduling + rung gating; RT gate fit on pilot gold data.
- [ ] **Onboarding probes**: grey-ramp gamma check + 2 Ishihara plates in `web/src/calibration-onboarding.ts`, stored as covariates (never rejection gates).
- [ ] **Exports**: `hf_thresholds.tsv` + `hf_jnd_scale.tsv` + manifest fields + header-matches-select tests (existing pattern).
- [ ] **Pre-registration amendment**: STUDY.md HF section (HF-RQ1–3, HF-H1–3, pilot gates, stopping rule, session cap) locked before the pilot's first session.
- [ ] **Pilot**: 40 sessions; evaluate the go/no-go gates (§3.7); then main run.
- [ ] **zensim ingestion**: canonical-corpus builder + orientation-gate entry (zensim repo; tracked there, referenced here).

## 5. Citations

Zenpapers corpus ids (searchable via the zenpapers CLI / `manifest/seed.jsonl`; synthesis chapters under `docs/iqa-methods/reference-book/`):

- **arXiv:2410.09501** — Testolina, Jenadeleh, Mohammadi, Su, Ascenso, Ebrahimi, Sneyers, Saupe, *Fine-grained subjective visual quality assessment for high-fidelity compressed images* (AIC-3 BTC/PTC): the boosting triple (2× crop-zoom via Lanczos, ×2 per-channel amplification, 10 Hz flicker), source-as-pivot triplets, quadratic per-(source, codec) transfer selected by AIC, JND = scale/0.6745, ~2× scale/precision gain, trap 5.6 %/bias 2.8 %, ≥ 70 % trap screen, 0.25-JND level spacing.
- **arXiv:2504.06301** — Jenadeleh et al., *Subjective Visual Quality Assessment for High-Fidelity Learning-Based Image Compression* (JPEG-AI-SDR25): BTC+PTC at ~12 % plain ratio, Otsu accuracy+consistency screening, mirrored-pair consistency 1/0.375/0, Ishihara plates.
- **arXiv:2506.12505** — AIC-HDR2025: 100 % mirrored triplets, 24 responses/triplet, 95 % CIs averaging 0.27 JND at 1 JND, mandatory 3-min break, batch timing.
- **10.1145/3581783.3613835** — Testolina et al., *On the Performance of Subjective Visual Quality Assessment Protocols for Nearly Visually Lossless Image Compression* (ACM MM 2023): DSCQS vs AIC-2 Annex A vs flicker face-off; flicker "too sensitive … in the quality range of interest"; CDR quantisation at 1/N; the AIC-2 CDR = 0.75 visually-lossless rule.
- **10.1117/12.2636687** + **10.1109/QoMEX58391.2023.10178554** — the AIC-3 framing + dataset papers (why appeal-based methods saturate; QualityCrowd 2, 31 experts, the −2.5 JND dataset floor).
- **10.1109/TCSVT.2022.3163860** — Lin, Chen, Jenadeleh, Hosu, Reips, Hamzaoui, Saupe, *KonJND-1k*: 8 Hz flicker + slider adjustment on MTurk (503 workers), slider 1.5–2× faster than relaxed binary search, flicker ≈ 2× side-by-side sensitivity, the JS device gate (ID-1 card px/mm, zoom blocked), three-level outlier removal, adaptive RT gate.
- **arXiv:1712.03686** — Pérez-Ortiz & Mantiuk, *A practical guide and software for analysing pairwise comparison experiments* (pwcmp): the 0.75/1-JOD convention (σ 1.4826), finite distance prior vs Gaussian-prior RMSE warning, observer-bootstrap CIs, LOO outlier threshold 1.5, "very large [CIs] if observers < 20", tie under-estimation caveat.
- **arXiv:2012.10758** — Mikhailiuk et al., *Consolidated Dataset and Metrics for High-Dynamic-Range Image Quality* (UPIQ): cross-dataset psychometric merging — similar-quality cross-dataset pairs, ~6,000 comparisons/220 participants, references pinned to 0, σ = 1.048.
- **arXiv:2311.06093** — Mohammadi & Ascenso, *Evaluation of Sampling Algorithms for Pairwise Subjective Assessment*: active sampling > 0.9 correlation at ~10 % of pairs; the P.910 15-subject floor.
- **arXiv:2311.03850** — Mohammadi & Ascenso, PS-PC (predict/defer pair classification; README lever #13's basis) + the ≤ 30-min session constraint.
- **arXiv:2305.00220** — Jenadeleh et al., *Relaxed forced choice improves performance of visual quality assessment methods* (keep the tie option; model it).
- **arXiv:2508.09777** — Mohammadi et al., IDSQS (in-place double-stimulus 0–100 alternative for this band, public code).
- **10.1109/VCIP59821.2023.10402707** — Zhu et al.: SUR = CCDF of the PJND distribution, 75 % convention — the product-side consumer of `q_flicker_notice`.
- **KADID-10k** (Lin, Hosu, Saupe, QoMEX 2019; raw CSV on disk): `_golden`/`_trust`/`_tainted` columns — the live golden-unit example.
- **arXiv:2509.13150** — Mohammadi et al., *Evaluation of Objective IQA Metrics for High-Fidelity Image Compression*: the 6-stat reporting panel + bootstrap-CI requirements the exports follow.
- Reference-book syntheses: `docs/iqa-methods/reference-book/ch1-2_designs_and_scaling.md` (protocol + scaling math), `ch3-5_sampling_screening_cis.md` (screening/CIs), `ch6_dataset_reproductions.md` (per-dataset recipes incl. AIC-3/SDR25/KonJND), `ch10_human_eval_collection.md` + `ch11_mobile_specific.md` (crowd/mobile mitigations, the BTC mobile over-boost honest-stop).

**Deliberately NOT cited from the corpus** (it lacks them; do not let future edits invent these citations): the ITU texts themselves (BT.500-x, P.910, deleted P.913, P.808 — parameters above are secondhand via the papers), the ISO/IEC 29170-2/-3 standard texts, Levitt 1971 for IQA use (no IQA staircase precedent exists in the corpus — squintly's Levitt citation stands on the psychoacoustics original), and the standalone ASAP/Crowd-BT papers (described only via the sampling survey).

Local datasets referenced (row counts verified on disk): KADID-10k raw crowd data (`/mnt/v/dataset/kadid10k/`, 349,800 DCR ratings); JPEG AIC-3 raw responses + test images (`/mnt/v/datasets/aic3-btc-ptc/`, 419,760 BTC + 51,870 plain-triplet rows, `is_trap`/`is_bias` columns); JPEG-AI-SDR25 (`/mnt/v/datasets/jpeg-ai-sdr25/`, 85,200 BTC + 10,290 PTC rows); hf_nearlossless train/val parquets (`/mnt/v/zen/zensim-training/canonical-2026-07-15/train/`, human_score 0.92–1.0 — the zone this study labels).

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.