feat(core): add percentile temporal pooling to the public C API - #1340
Conversation
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
b365939 to
fc96927
Compare
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
fc96927 to
f9fca45
Compare
Duplicate resolution: this PR is the keeper for percentile temporal pooling#1311 implements the same feature (its Part A, ADR-1181). Comparing the two diffs, this
Both implementations produce the same numbers (#1311's #1311 stays open — it also carries the unrelated Windows UTF-8 path contract Ledger: both PRs move Follow-up to pick up here or in a separate PR: #1311 is the only place the Go binding |
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
…t tidy-clean Three follow-ups found while rebasing this branch onto current master: - docs/state.md: the earlier "drop the duplicate rows a keep-both rebase created" commit removed the wrong copy — it deleted the branch's new Recently-closed row instead of the stale Open-bugs row, leaving the bug marked open while the moved-to comment claimed otherwise. Move the row for real (ADR-0165: exactly one row per id, citing PR #1340). - core/test/test_pool_percentile.c: the file is new, so its clang-tidy ratchet baseline is 0 and its 18 findings were a regression (ADR-0141 / ADR-1142). Drive the expectations off PoolCase tables through a shared helper so each test body stays inside readability-function-size's 15-branch budget, use nullptr, and drop the deprecated VMAF_POOL_METHOD_NB references. The one remaining finding is the deliberate out-of-range discriminant cast, which is the subject of the negative test; it carries an inline ADR-1188 citation. - docs/reference/faq.md: the list names eight pooling methods, not seven. Behaviour is unchanged: 6/6 in test_pool_percentile, 115/115 in --suite=fast.
f9fca45 to
37c3da6
Compare
|
Queue audit (read-only verification pass, 2026-09-06). Two findings on this PR, both checked locally rather than inferred. 1. ADR-1138 violation — 2. Duplicate feature with PR #1311. Otherwise clean: no merge conflict against current master, the six-deliverable gate passes locally, and the new test file measures 0 clang-tidy findings under the repo |
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
…t tidy-clean Three follow-ups found while rebasing this branch onto current master: - docs/state.md: the earlier "drop the duplicate rows a keep-both rebase created" commit removed the wrong copy — it deleted the branch's new Recently-closed row instead of the stale Open-bugs row, leaving the bug marked open while the moved-to comment claimed otherwise. Move the row for real (ADR-0165: exactly one row per id, citing PR #1340). - core/test/test_pool_percentile.c: the file is new, so its clang-tidy ratchet baseline is 0 and its 18 findings were a regression (ADR-0141 / ADR-1142). Drive the expectations off PoolCase tables through a shared helper so each test body stays inside readability-function-size's 15-branch budget, use nullptr, and drop the deprecated VMAF_POOL_METHOD_NB references. The one remaining finding is the deliberate out-of-range discriminant cast, which is the subject of the negative test; it carries an inline ADR-1188 citation. - docs/reference/faq.md: the list names eight pooling methods, not seven. Behaviour is unchanged: 6/6 in test_pool_percentile, 115/115 in --suite=fast.
37c3da6 to
44d32cb
Compare
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
…t tidy-clean Three follow-ups found while rebasing this branch onto current master: - docs/state.md: the earlier "drop the duplicate rows a keep-both rebase created" commit removed the wrong copy — it deleted the branch's new Recently-closed row instead of the stale Open-bugs row, leaving the bug marked open while the moved-to comment claimed otherwise. Move the row for real (ADR-0165: exactly one row per id, citing PR #1340). - core/test/test_pool_percentile.c: the file is new, so its clang-tidy ratchet baseline is 0 and its 18 findings were a regression (ADR-0141 / ADR-1142). Drive the expectations off PoolCase tables through a shared helper so each test body stays inside readability-function-size's 15-branch budget, use nullptr, and drop the deprecated VMAF_POOL_METHOD_NB references. The one remaining finding is the deliberate out-of-range discriminant cast, which is the subject of the negative test; it carries an inline ADR-1188 citation. - docs/reference/faq.md: the list names eight pooling methods, not seven. Behaviour is unchanged: 6/6 in test_pool_percentile, 115/115 in --suite=fast.
44d32cb to
e5174f1
Compare
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
f90bb93 to
16f2868
Compare
…t tidy-clean Three follow-ups found while rebasing this branch onto current master: - docs/state.md: the earlier "drop the duplicate rows a keep-both rebase created" commit removed the wrong copy — it deleted the branch's new Recently-closed row instead of the stale Open-bugs row, leaving the bug marked open while the moved-to comment claimed otherwise. Move the row for real (ADR-0165: exactly one row per id, citing PR #1340). - core/test/test_pool_percentile.c: the file is new, so its clang-tidy ratchet baseline is 0 and its 18 findings were a regression (ADR-0141 / ADR-1142). Drive the expectations off PoolCase tables through a shared helper so each test body stays inside readability-function-size's 15-branch budget, use nullptr, and drop the deprecated VMAF_POOL_METHOD_NB references. The one remaining finding is the deliberate out-of-range discriminant cast, which is the subject of the negative test; it carries an inline ADR-1188 citation. - docs/reference/faq.md: the list names eight pooling methods, not seven. Behaviour is unchanged: 6/6 in test_pool_percentile, 115/115 in --suite=fast.
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
…t tidy-clean Three follow-ups found while rebasing this branch onto current master: - docs/state.md: the earlier "drop the duplicate rows a keep-both rebase created" commit removed the wrong copy — it deleted the branch's new Recently-closed row instead of the stale Open-bugs row, leaving the bug marked open while the moved-to comment claimed otherwise. Move the row for real (ADR-0165: exactly one row per id, citing PR #1340). - core/test/test_pool_percentile.c: the file is new, so its clang-tidy ratchet baseline is 0 and its 18 findings were a regression (ADR-0141 / ADR-1142). Drive the expectations off PoolCase tables through a shared helper so each test body stays inside readability-function-size's 15-branch budget, use nullptr, and drop the deprecated VMAF_POOL_METHOD_NB references. The one remaining finding is the deliberate out-of-range discriminant cast, which is the subject of the negative test; it carries an inline ADR-1188 citation. - docs/reference/faq.md: the list names eight pooling methods, not seven. Behaviour is unchanged: 6/6 in test_pool_percentile, 115/115 in --suite=fast.
16f2868 to
40e28b9
Compare
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
…t tidy-clean Three follow-ups found while rebasing this branch onto current master: - docs/state.md: the earlier "drop the duplicate rows a keep-both rebase created" commit removed the wrong copy — it deleted the branch's new Recently-closed row instead of the stale Open-bugs row, leaving the bug marked open while the moved-to comment claimed otherwise. Move the row for real (ADR-0165: exactly one row per id, citing PR #1340). - core/test/test_pool_percentile.c: the file is new, so its clang-tidy ratchet baseline is 0 and its 18 findings were a regression (ADR-0141 / ADR-1142). Drive the expectations off PoolCase tables through a shared helper so each test body stays inside readability-function-size's 15-branch budget, use nullptr, and drop the deprecated VMAF_POOL_METHOD_NB references. The one remaining finding is the deliberate out-of-range discriminant cast, which is the subject of the negative test; it carries an inline ADR-1188 citation. - docs/reference/faq.md: the list names eight pooling methods, not seven. Behaviour is unchanged: 6/6 in test_pool_percentile, 115/115 in --suite=fast.
40e28b9 to
9042800
Compare
`enum VmafPoolingMethod` exposed only {UNKNOWN, MIN, MAX, MEAN,
HARMONIC_MEAN}, so a C-API, Rust-binding or FFmpeg consumer could not ask
for the median or the perc5/perc10/perc20 summaries the Python harness has
always offered through `ListStats` — any discriminant past HARMONIC_MEAN
was rejected with -EINVAL. Closes the verified ledger row
T-UPSTREAM-818-POOLING-ENUM-NO-PERCENTILES-2026-09-03 (Netflix/vmaf#818).
Append VMAF_POOL_METHOD_MEDIAN / _PERC5 / _PERC10 / _PERC20 after
HARMONIC_MEAN so every existing discriminant keeps its value, and define
VMAF_HAVE_PERCENTILE_POOLING so an integration can detect them with
`#ifdef`. Percentiles cannot come from running accumulators, so the frame
walk moved into `pool_accumulate()`, which additionally retains the
per-frame scores in a geometrically-grown buffer — but only when the
requested method is an order statistic. `pool_reduce_percentile()` sorts
that buffer and interpolates linearly between ranks, sharing
`vmaf_percentile()` with the bootstrap confidence intervals via the new
header-only `core/src/percentile.h`. That rule is
`numpy.percentile(method="linear")`, so the C API and the Python harness
report the same pooled number for the same frames.
The accumulator path is untouched: MEAN / HARMONIC_MEAN run the same float
expressions in the same order, allocate nothing, and the Netflix golden
gate is unmoved (ADR-1118 isolation, 271 passed / 12 skipped). Percentiles
are order statistics and therefore ignore ADR-1118 perceptual weighting,
exactly as MIN / MAX do. `output.cpp` now iterates an explicit
`pool_report_order[]` instead of [1, VMAF_POOL_METHOD_NB), so appending
enumerators does not silently widen the `pooled_metrics` report schema.
Also: Rust `PoolingMethod::{Median, Perc5, Perc10, Perc20}`;
ffmpeg-patches/0018 maps the `pool=median|perc5|perc10|perc20` option
strings (and `max`, which FFmpeg's mapper never accepted) — all 18 patches
replay onto pristine n9.0.1 via `git am --3way`; docs/reference/faq.md no
longer claims a `--pool` CLI flag that does not exist.
Refs: ADR-1188
…-03 (PR #1340) Move the pooling-enum row from Open bugs to Recently closed now that the four order-statistic enumerators ship (ADR-1188), and point the Confirmed not-affected entry for Netflix/vmaf#818 at the closed row. Per ADR-0165 the ledger update lands in the same PR as the fix.
Each dropped row restates one origin/master already carries; master is the authoritative record. Verified with scripts/ci/check-state-md-rows.sh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t tidy-clean Three follow-ups found while rebasing this branch onto current master: - docs/state.md: the earlier "drop the duplicate rows a keep-both rebase created" commit removed the wrong copy — it deleted the branch's new Recently-closed row instead of the stale Open-bugs row, leaving the bug marked open while the moved-to comment claimed otherwise. Move the row for real (ADR-0165: exactly one row per id, citing PR #1340). - core/test/test_pool_percentile.c: the file is new, so its clang-tidy ratchet baseline is 0 and its 18 findings were a regression (ADR-0141 / ADR-1142). Drive the expectations off PoolCase tables through a shared helper so each test body stays inside readability-function-size's 15-branch budget, use nullptr, and drop the deprecated VMAF_POOL_METHOD_NB references. The one remaining finding is the deliberate out-of-range discriminant cast, which is the subject of the negative test; it carries an inline ADR-1188 citation. - docs/reference/faq.md: the list names eight pooling methods, not seven. Behaviour is unchanged: 6/6 in test_pool_percentile, 115/115 in --suite=fast.
Each dropped row restates one origin/master already carries; master is the authoritative record. Verified with scripts/ci/check-state-md-rows.sh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
My rebase dedup kept the wrong side. Its rule -- when a bug id appears twice after a keep-both rebase, keep the row matching origin/master -- is right when the branch merely restates a row master already carries, and WRONG when the branch is the PR that closes the bug. Then the branch's past-tense Recently-closed row is the correct survivor and master's present-tense Open row is the stale one. Restored the closure row and left a tombstone where the Open row was, matching the convention used elsewhere in this file. Exactly one row per bug id; scripts/ci/check-state-md-rows.sh reports OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
9042800 to
d84d273
Compare
…ally implements The required Windows MSVC+CUDA lane rejected this file with 21 errors. Two independent C-conformance problems, both invisible to gcc and clang: 1. `nullptr` in a C translation unit (19x, C2065 'undeclared identifier'). ADR-1138 decided exactly this case: C TUs keep `NULL` because MSVC's documented /std:clatest C23 feature set does not list `nullptr` and the Windows build compiles core/ with cl.exe. The ADR called the keyword "an unverified bet against a required status check"; this file placed that bet and lost. Now `NULL`, with the file-scoped cited NOLINTBEGIN/END bracket the ADR prescribes. 2. A `static const double` used to initialise a `static const PoolCase[]` (C2099 'initializer is not a constant'). In C a `static const double` is a const-qualified *object*, not a constant expression, so it cannot appear in a static aggregate's initialiser. gcc accepts it as an extension and does not diagnose it even under `-std=c23 -pedantic-errors`, which is why the local build stayed silent. cl.exe correctly rejects it and then mis-pairs the remaining initialisers, producing the five cascading C2440 'cannot convert from char [45] to double' errors -- the string literal sliding into the `.tol` slot vacated by the dropped constant. The six golden/harness constants become object-like macros, which are constant expressions in every context. GOLDEN_CNT above them was already a macro for the same reason. Verified: `ninja -C build test/test_pool_percentile && ./test_pool_percentile` -> 6 tests run, 6 passed, and the golden percentile values are unchanged -- the macros carry the identical literals. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ped tonight PR #1340 added one new C test file that the required Windows MSVC+CUDA lane rejected with 21 errors, on a branch that was green under local gcc. Neither failure class was covered: 1. `nullptr` in a C translation unit (C2065 x19). ADR-1138 already decided that C TUs keep `NULL` — MSVC's documented /std:clatest C23 feature set does not implement the keyword — but nothing enforced it locally. A grep over changed `.c` files does, skipping comment lines because the ADR-1138 NOLINT bracket names the keyword in prose. 2. A `static const double` used to initialise a `static const` aggregate (C2099, then five cascading C2440s). In C such a declaration is a const-qualified *object*, not a constant expression, so it may not appear in a static initialiser. This one cannot be grepped line-locally and, more importantly, no locally available compiler diagnoses it *at all* — gcc and clang both accept it silently under `-std=c23 -pedantic-errors`, and clang stays silent under `-Weverything` too. `find-nonconst-static-init.py` collects the file-scope `static const <scalar>` names and reports any that appear inside a braced `static` initialiser, with string and character literals masked so a name occurring in a message does not count. Verified against the file that broke: planted as an untracked source, the stage reports both classes and fails; with the merged fix in place it passes. The scanner finds zero hits across all 438 `.c` files in the tree, and the nullptr grep finds nothing outside ADR-1138 comment text — so neither check starts life with a backlog to suppress. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…TS.md Two hunks in this branch had been committed with their conflict markers still in place — an `#include` block in `core/src/feature/sycl/integer_adm_sycl.cpp` that needed both `adm_csf_fixed_point.h` and `adm_angle_flag.h`, and an appended section in `core/src/feature/AGENTS.md` where both sides were wanted. Both are keep-both resolutions: includes sorted, sections concatenated. Rebasing onto master after #1340 landed added a third, in `core/test/meson.build`: master's new `test_pool_percentile` executable and this branch's `test_adm_angle_flag` claim the same position. Also keep-both — the two are unrelated tests, and master registers `test_pool_percentile` in the separate `test()` block further down, so only the `executable()` definitions collide. The diff against master for that file is now purely additive. Verified after the rebase: `meson test --suite=fast` is 119/119, with `test_adm_angle_flag` and `test_pool_percentile` both OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…TS.md Two hunks in this branch had been committed with their conflict markers still in place — an `#include` block in `core/src/feature/sycl/integer_adm_sycl.cpp` that needed both `adm_csf_fixed_point.h` and `adm_angle_flag.h`, and an appended section in `core/src/feature/AGENTS.md` where both sides were wanted. Both are keep-both resolutions: includes sorted, sections concatenated. Rebasing onto master after #1340 landed added a third, in `core/test/meson.build`: master's new `test_pool_percentile` executable and this branch's `test_adm_angle_flag` claim the same position. Also keep-both — the two are unrelated tests, and master registers `test_pool_percentile` in the separate `test()` block further down, so only the `executable()` definitions collide. The diff against master for that file is now purely additive. Verified after the rebase: `meson test --suite=fast` is 119/119, with `test_adm_angle_flag` and `test_pool_percentile` both OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ped tonight PR #1340 added one new C test file that the required Windows MSVC+CUDA lane rejected with 21 errors, on a branch that was green under local gcc. Neither failure class was covered: 1. `nullptr` in a C translation unit (C2065 x19). ADR-1138 already decided that C TUs keep `NULL` — MSVC's documented /std:clatest C23 feature set does not implement the keyword — but nothing enforced it locally. A grep over changed `.c` files does, skipping comment lines because the ADR-1138 NOLINT bracket names the keyword in prose. 2. A `static const double` used to initialise a `static const` aggregate (C2099, then five cascading C2440s). In C such a declaration is a const-qualified *object*, not a constant expression, so it may not appear in a static initialiser. This one cannot be grepped line-locally and, more importantly, no locally available compiler diagnoses it *at all* — gcc and clang both accept it silently under `-std=c23 -pedantic-errors`, and clang stays silent under `-Weverything` too. `find-nonconst-static-init.py` collects the file-scope `static const <scalar>` names and reports any that appear inside a braced `static` initialiser, with string and character literals masked so a name occurring in a message does not count. Verified against the file that broke: planted as an untracked source, the stage reports both classes and fails; with the merged fix in place it passes. The scanner finds zero hits across all 438 `.c` files in the tree, and the nullptr grep finds nothing outside ADR-1138 comment text — so neither check starts life with a backlog to suppress. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…GPU filters #1340 landed the percentile pooling C API (ADR-1188). This branch had implemented the same feature independently under ADR-1181 -- byte-identical enum names, order and semantics -- so its core half is now dead code that can never merge: it collides with master on libvmaf.h, libvmaf.c, output.cpp, predict.c and core/test/meson.build. Reduced to the consumer surfaces #1340 did not ship, which are genuinely additive: - pkg/libvmaf: a typed `PoolMethod` with a String() mapping to the on-the-wire names, so Go callers pick a pooling method without touching cgo enums. - ffmpeg-patches 0005 / 0006 / 0013: the libvmaf_sycl, libvmaf_vulkan and libvmaf_metal filters accept the four new `pool` values. The CPU libvmaf filter already did. - docs/usage/cli.md: documents them on the CLI. - python/test/command_line_test.py: end-to-end coverage through the CLI. Dropped: the duplicate core implementation, core/src/pooling_percentile.h, core/test/test_pooling_percentile.c, ADR-1181 and its index rows, and the docs/api, docs/state and rebase-notes edits master already carries from #1340. ADR-1181 is not superseded because it never landed -- ADR-1188 is the record. The changelog fragment now describes only the consumer wiring; master already carries `percentile-pooling-methods.md` for the API itself. Verified against master's implementation rather than its own: `go build` and `go vet ./pkg/libvmaf/` are clean and `gofmt -l` is empty, which also confirms the enum values agree. `go test ./pkg/libvmaf/` cannot link here for an unrelated reason -- the workstation has no DNN-enabled libvmaf installed, so cgo fails on vmaf_dnn_session_run; plain master fails identically, and CI's Go lane builds the library first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…one (#1342) * fix(gpu): collapse the four divergent ADM angle_flag predicates onto one `decouple()`'s 1-degree `angle_flag` test had four different spellings in the tree. The CPU, AVX2 and AVX-512 paths narrow the exact int64 operands to `float` and then compare in `double` — the form the Netflix golden gate freezes. CUDA and HIP scale 0 compared the *exact* int64 products in `double` (a strictly more accurate angle test, and therefore a different one); SYCL did the whole comparison in `float`; Metal narrowed the exact products to `float`. CUDA/HIP scales 1-3 already used the golden form, so `s0` and `s123` disagreed inside a single backend. `angle_flag` selects the enhancement-gain-limited branch of `decouple()`, so a flipped flag moves the adm scores. Instrumenting the scalar CPU decouple shows the divergence is reachable on the Netflix golden pair itself: of 1 540 608 scale-0 pixels, the legacy SYCL form flips 2 and the legacy Metal form flips 3; on a full-contrast 1080p noise clip the counts are 11 / 11 / 18 (CUDA/HIP, SYCL, Metal). The predicate now lives once, in `core/src/feature/adm_angle_flag.h`: * `adm_angle_flag_fp64()` — the golden expression, verbatim. The scalar CPU path, CUDA and HIP call it at both scales. * `adm_angle_flag_i64()` — a bit-identical evaluation in 64-bit integer arithmetic that uses no floating point of any width. SYCL calls it (Intel Arc A-series and most iGPUs expose no fp64, and one fp64 instruction anywhere in that translation unit makes the runtime reject the whole SPIR-V module); `metal/integer_adm.metal` mirrors it in MSL (MSL has no `double` type). Verified: `integer_adm.c` compiles to byte-identical machine code against origin/master, so the CPU/golden lane cannot have moved. On the golden 576x324 pair with `adm_enhn_gain_limit=1.2`, the SYCL-vs-CPU adm gap drops from 1.175e-05 to 8.220e-07 on the Arc A380. `adm_angle_flag_i64()` was fuzzed against the golden expression over 200 M scale-0 quadruples and 104 M boundary-walk triples spanning all 62 magnitude classes, under gcc and clang at -O0/-O2/-O3: zero mismatches. Closes T-UPSTREAM-930-ADM-ANGLE-FLAG-PREDICATE-DIVERGENCE-2026-09-03. Refs Netflix/vmaf#930. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(state): move T-UPSTREAM-930 angle_flag divergence to Recently closed Fixed by PR #1342 (a3155b2, ADR-1194). ADR-0165 requires the ledger row to move in the same PR as the fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(state): drop the duplicate rows a keep-both rebase created Each dropped row restates one origin/master already carries; master is the authoritative record. Verified with scripts/ci/check-state-md-rows.sh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(adm): split the angle_flag round53 step out and finish the state.md move Two loose ends on top of the ADR-1194 change: 1. `adm_angle_flag_i64()` tripped `readability-function-size` (71 lines against the 60-line threshold) once clang-tidy was pointed at the new header with `-header-filter='adm_angle_flag\.h'` — the default filter is anchored at `^core/` and so misses it when the build dir is a sibling. ADR-0141 wants the file clean, not suppressed, so the right-hand-side rounding is now `adm_angle_flag_round53_v()`. Pure extraction: no expression changes, and `core/test/test_adm_angle_flag.c` still passes 7/7. `metal/integer_adm.metal` gets the same split so the manual MSL mirror stays line-for-line (the AGENTS.md lockstep invariant). 2. `docs/state.md` still carried T-UPSTREAM-930 under **Open bugs** with a comment claiming it had moved: an earlier duplicate-row cleanup dropped the Recently-closed copy instead of the stale open one. The open row is gone and the closed row is back at the head of Recently closed, citing PR #1342 and ADR-1194 (the previous text cited a commit sha that the rebase invalidated). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(adm): resolve the conflict markers left in the SYCL twin and AGENTS.md Two hunks in this branch had been committed with their conflict markers still in place — an `#include` block in `core/src/feature/sycl/integer_adm_sycl.cpp` that needed both `adm_csf_fixed_point.h` and `adm_angle_flag.h`, and an appended section in `core/src/feature/AGENTS.md` where both sides were wanted. Both are keep-both resolutions: includes sorted, sections concatenated. Rebasing onto master after #1340 landed added a third, in `core/test/meson.build`: master's new `test_pool_percentile` executable and this branch's `test_adm_angle_flag` claim the same position. Also keep-both — the two are unrelated tests, and master registers `test_pool_percentile` in the separate `test()` block further down, so only the `executable()` definitions collide. The diff against master for that file is now purely additive. Verified after the rebase: `meson test --suite=fast` is 119/119, with `test_adm_angle_flag` and `test_pool_percentile` both OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(test): make M_PI reach test_adm_angle_flag.c on MinGW64 The Windows MinGW64 lane failed to compile the new test: ../test/test_adm_angle_flag.c:108:30: error: 'M_PI' undeclared `M_PI` is not ISO C -- it is a POSIX/X-Open extension. glibc exposes it only under `__USE_MISC` / `__USE_XOPEN`, which `-std=c23` switches off by defining `__STRICT_ANSI__`; the Linux lanes only see it because meson adds `-D_GNU_SOURCE`, which turns those back on. MinGW64 does not honour `_GNU_SOURCE`, so on that lane the identifier simply does not exist. Every other file in the tree that wants `M_PI` already handles this the same way -- `_USE_MATH_DEFINES` before `<math.h>` for MSVC, then an `#ifndef M_PI` fallback for MinGW (core/src/feature/adm_csf_tools.h, adm_tools.h, adm_tools.c). This test was the one place that just included `<math.h>` and hoped. It now follows the same two-step, with the literal copied from adm_tools.h so `golden_cos_1deg_sq()` derives cos(1deg) from exactly the constant `integer_adm.c` uses. (The two spellings in the tree, `3.14159265358979323846` and `3.14159265358979323846264338327`, are the same IEEE double, so this is consistency rather than a numeric change.) Reproduced locally rather than inferred: compiling the pre-fix file with `gcc -std=c23` and no `-D_GNU_SOURCE` gives the identical error on the identical line, and the fixed file compiles clean under the same flags. `meson test --suite=fast` is 119/119 with test_adm_angle_flag OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(metal): rename the `half` local — it is a built-in MSL type The macOS Clang+Metal lane could not compile integer_adm.metal: integer_adm.metal:208:17: error: cannot combine with previous 'type-name' declaration specifier integer_adm.metal:209:20: error: expected '(' for function-style cast `half` is Metal Shading Language's built-in 16-bit float type, so `const ulong half = ...` is a redeclaration, and every later use parses as a type name rather than a variable -- which is why one bad declaration produced four errors across two lines. The name is fine in the C/CUDA/HIP twins this rounding helper was ported from, which is how it got here; master has no occurrence of it in any .metal file. Renamed to `halfway`, with a comment naming the trap so the next port does not repeat it. Swept the other 16 shaders for the same shape (a reserved MSL type name used as a variable) and found none. Also collapses a double blank line in docs/state.md that a keep-both conflict resolution on this branch left behind -- markdownlint MD012, which failed the required Pre-Commit check. `markdownlint-cli2 docs/state.md` now reports 0 issues. `meson test --suite=fast` remains 119/119. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(test): cite the reserved-identifier NOLINT the M_PI guard needs The Tidy Ratchet went 0 -> 1 on test_adm_angle_flag.c after the MinGW fix: declaration uses identifier '_USE_MATH_DEFINES', which is a reserved identifier [bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp] The leading underscore is not ours to choose -- `_USE_MATH_DEFINES` is the name MSVC's and MinGW's <math.h> look for, so renaming it defeats the entire point of defining it. That is a load-bearing platform contract, which is exactly the case ADR-1142 rule 12 reserves NOLINT for, and core/src/libvmaf.c already carries the same suppression for glibc's `__libc_single_threaded`. The comment is deliberately split: `NOLINTNEXTLINE` anchors to the line it appears on, so putting it at the top of a multi-line block points it at the block's second line and suppresses nothing. Prose first, then a one-line directive immediately above the `#define` -- the shape libvmaf.c uses. Verified with clang-tidy 22.1.8 (the version CI runs): 1 warning before, 0 after. M_PI still resolves under `gcc -std=c23` with no -D_GNU_SOURCE, and test_adm_angle_flag still passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Lusoris <lusoris@pm.me> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…GPU filters #1340 landed the percentile pooling C API (ADR-1188). This branch had implemented the same feature independently under ADR-1181 -- byte-identical enum names, order and semantics -- so its core half is now dead code that can never merge: it collides with master on libvmaf.h, libvmaf.c, output.cpp, predict.c and core/test/meson.build. Reduced to the consumer surfaces #1340 did not ship, which are genuinely additive: - pkg/libvmaf: a typed `PoolMethod` with a String() mapping to the on-the-wire names, so Go callers pick a pooling method without touching cgo enums. - ffmpeg-patches 0005 / 0006 / 0013: the libvmaf_sycl, libvmaf_vulkan and libvmaf_metal filters accept the four new `pool` values. The CPU libvmaf filter already did. - docs/usage/cli.md: documents them on the CLI. - python/test/command_line_test.py: end-to-end coverage through the CLI. Dropped: the duplicate core implementation, core/src/pooling_percentile.h, core/test/test_pooling_percentile.c, ADR-1181 and its index rows, and the docs/api, docs/state and rebase-notes edits master already carries from #1340. ADR-1181 is not superseded because it never landed -- ADR-1188 is the record. The changelog fragment now describes only the consumer wiring; master already carries `percentile-pooling-methods.md` for the API itself. Verified against master's implementation rather than its own: `go build` and `go vet ./pkg/libvmaf/` are clean and `gofmt -l` is empty, which also confirms the enum values agree. `go test ./pkg/libvmaf/` cannot link here for an unrelated reason -- the workstation has no DNN-enabled libvmaf installed, so cgo fails on vmaf_dnn_session_run; plain master fails identically, and CI's Go lane builds the library first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rc20) (ADR-1181) (#1392) * feat(pooling): wire percentile pooling into Go, the CLI docs and the GPU filters #1340 landed the percentile pooling C API (ADR-1188). This branch had implemented the same feature independently under ADR-1181 -- byte-identical enum names, order and semantics -- so its core half is now dead code that can never merge: it collides with master on libvmaf.h, libvmaf.c, output.cpp, predict.c and core/test/meson.build. Reduced to the consumer surfaces #1340 did not ship, which are genuinely additive: - pkg/libvmaf: a typed `PoolMethod` with a String() mapping to the on-the-wire names, so Go callers pick a pooling method without touching cgo enums. - ffmpeg-patches 0005 / 0006 / 0013: the libvmaf_sycl, libvmaf_vulkan and libvmaf_metal filters accept the four new `pool` values. The CPU libvmaf filter already did. - docs/usage/cli.md: documents them on the CLI. - python/test/command_line_test.py: end-to-end coverage through the CLI. Dropped: the duplicate core implementation, core/src/pooling_percentile.h, core/test/test_pooling_percentile.c, ADR-1181 and its index rows, and the docs/api, docs/state and rebase-notes edits master already carries from #1340. ADR-1181 is not superseded because it never landed -- ADR-1188 is the record. The changelog fragment now describes only the consumer wiring; master already carries `percentile-pooling-methods.md` for the API itself. Verified against master's implementation rather than its own: `go build` and `go vet ./pkg/libvmaf/` are clean and `gofmt -l` is empty, which also confirms the enum values agree. `go test ./pkg/libvmaf/` cannot link here for an unrelated reason -- the workstation has no DNN-enabled libvmaf installed, so cgo fails on vmaf_dnn_session_run; plain master fails identically, and CI's Go lane builds the library first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(core): restore command_line_test.py assertion strings to match ADR-1188 output ADR-1188 intentionally keeps pool_report_order limited to the historical four methods (min, max, mean, harmonic_mean) so the default XML output does not include median/perc5/perc10/perc20. Revert the speculative additions in command_line_test.py so vmafexec tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Lusoris <lusoris@pm.me> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Summary
enum VmafPoolingMethodexposed only{UNKNOWN, MIN, MAX, MEAN, HARMONIC_MEAN}, so aC-API, Rust-binding or FFmpeg caller could not ask for the
median/perc5/perc10/perc20summaries the Python harness has always offered — any discriminant pastHARMONIC_MEANwas rejected with-EINVAL. This appends the four order-statisticenumerators (ABI-safe: existing values are unchanged), computes them by sorting the pooled
per-frame scores and interpolating linearly between ranks — the same
numpy.percentile(method="linear")rule the harness uses — and leaves the goldenaccumulator path byte-identical. Closes the verified ledger row
T-UPSTREAM-818-POOLING-ENUM-NO-PERCENTILES-2026-09-03(upstreamNetflix/vmaf#818).Type
feat— new featureChecklist
make format && make lintis green locally.meson test -C build./cross-backend-diffand the worst ULP is ≤ 2..c/.cpp/.cu/.h/.hpp, it has the appropriate license header (seeCONTRIBUTING.md).!orBREAKING CHANGE:and the migration path is documented below.docs/adr/_index_fragments/<NNNN-slug>.mdand the slug is appended todocs/adr/_index_fragments/_order.txt.No SIMD/GPU code path is touched — pooling is backend-independent host code that reads the
feature collector, so there is no twin to update and no cross-backend ULP table to paste.
This is not a breaking change: the enum grows append-only and
VMAF_POOL_METHOD_NB(alreadydocumented as an unstable count sentinel) moves 5 → 9.
Bug-status hygiene (ADR-0165)
docs/state.mdupdated in this PR: theT-UPSTREAM-818-POOLING-ENUM-NO-PERCENTILES-2026-09-03row moves from Open bugs toRecently closed.
Netflix golden-data gate (ADR-0024)
assertAlmostEqual(...)score in the Netflix golden Python tests.The full gate was run locally on the CPU backend: 271 passed, 12 skipped across
quality_runner_test.py,feature_extractor_test.py,vmafexec_test.py,vmafexec_feature_extractor_test.pyandresult_test.py. The accumulator methods keeptheir exact upstream float expressions (ADR-1118 golden-gate isolation), and
vmaf_percentile()staysstatic inlinesopredict.c's golden-asserted bootstrapci_p95arithmetic is still compiled in its own translation unit.Cross-backend numerical results
Performance (if
perforfeat)MIN/MAX/MEAN/HARMONIC_MEANare unchanged: same expressions, O(1) space, zeroallocation. Only the new order-statistic methods allocate —
8 × n_framesbytes, growngeometrically, plus one
qsort.Deep-dive deliverables (ADR-0108)
docs/research/1188-percentile-pooling-methods.md.docs/adr/1188-percentile-pooling-methods.md## Alternatives considered(five options).AGENTS.mdinvariant note —core/src/AGENTS.md, "Pooling: accumulators stay O(1) and byte-identical; percentiles buffer (ADR-1188)".changelog.d/added/percentile-pooling-methods.md.docs/rebase-notes.md, entryfix/t-upstream-818-pooling-enum-no-percentil.Reproducer
Pre-fix evidence (
origin/mastersources, same probe binary, discriminants 5–8 passedthrough a cast because the enumerators did not exist yet):
Post-fix, same probe:
Known follow-ups
vmafCLI still has no--poolflag; its report carriesmin/max/mean/harmonic_meanand its stdout line reports the mean.docs/reference/faq.mdclaimed sucha flag existed and has been corrected. Adding one — and/or widening the
pooled_metricsschema to carry percentiles — is a deliberate output-surface decision left out of this PR
(ADR-1188 "Neutral / follow-ups").