Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/AGENTS.d/security-scans.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ category without superseding ADR that provides reproducibly pinned policy.
Security Scans concurrency group includes `github.event_name` between
workflow name and ref. Scheduled scan and master push both use
`refs/heads/master`; without event discriminator, either can cancel
other's CodeQL coverage. Preserve `cancel-in-progress: true` so superseded
runs of same event/ref still collapse, keep
other's CodeQL coverage. On master the ref slot is the SHA and
`cancel-in-progress` is `github.ref != 'refs/heads/master'` (ADR-1673), so
only superseded PR runs collapse; keep
`scripts/ci/test_security_workflow_contract.py` in always-on Rules gate.

## Meson configure precedes CodeQL extraction (ADR-1222 / Alert 1279)
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ permissions:
contents: read

concurrency:
group: build-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: build-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

env:
DEBIAN_FRONTEND: noninteractive
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/dev-container-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ permissions:
contents: read

concurrency:
group: dev-container-build-${{ github.ref }}
cancel-in-progress: true
group: dev-container-build-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
impact:
Expand Down
10 changes: 6 additions & 4 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ permissions:
contents: read

concurrency:
group: docker-image-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: docker-image-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
impact:
Expand Down Expand Up @@ -93,8 +93,10 @@ jobs:
>"$out_dir/stdout.log" 2>"$out_dir/stderr.log" || rc=$?
if [ "$rc" -ne 0 ]; then
echo "::error::vmaf exited $rc inside the image"
echo "----- vmaf stdout -----"; cat "$out_dir/stdout.log" || true
echo "----- vmaf stderr -----"; cat "$out_dir/stderr.log" || true
for log in stdout stderr; do
echo "----- vmaf $log -----"
if [ -f "$out_dir/$log.log" ]; then cat "$out_dir/$log.log"; fi
done
exit 1
fi
python3 - "$out_dir/result.json" <<'PYEOF'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ jobs:
# Ref-scoped: one docs build per branch, superseded only by a newer push to
# that same branch. No cross-PR contention.
concurrency:
group: docs-build-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: docs-build-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/doxygen-public-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ permissions:
contents: read

concurrency:
group: doxygen-public-api-${{ github.ref }}
cancel-in-progress: true
group: doxygen-public-api-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
impact:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ffmpeg-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ permissions:
contents: read

concurrency:
group: ffmpeg-integration-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: ffmpeg-integration-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

env:
DEBIAN_FRONTEND: noninteractive
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ffmpeg-patch-stack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ permissions:
contents: read

concurrency:
group: ffmpeg-patch-stack-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true
group: ffmpeg-patch-stack-${{ github.event_name }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
check:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/go-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ on:
workflow_dispatch:

concurrency:
group: go-ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: go-ci-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

# Least-privilege default for the whole workflow (ADR-0875).
# Jobs widen only if they need to publish artefacts or push.
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/helm-chart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ on:
workflow_dispatch:

concurrency:
group: helm-chart-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: helm-chart-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

# Least-privilege default for the whole workflow (ADR-0875).
permissions:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/libvmaf-build-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ permissions:
# Ported from the now-deleted windows.yml (ADR-0115). Cancels superseded
# runs on the same ref so a force-push doesn't queue duplicate matrix runs.
concurrency:
group: libvmaf-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: libvmaf-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

env:
DEBIAN_FRONTEND: noninteractive
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/lint-and-format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ permissions:
contents: read

concurrency:
group: lint-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: lint-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
pre-commit:
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/required-aggregator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ permissions:
checks: read
pull-requests: read

# Master pushes: SHA-scoped group, never cancelled (docs/development/ci.md,
# "Master push runs"). A re-run of an older master head therefore cannot cancel
# the aggregator of a newer one. PR refs keep one group per ref with
# cancel-in-progress: re-running an older PR head still cancels the current one.
concurrency:
group: required-aggregator-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: required-aggregator-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
aggregator:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ on:
workflow_dispatch:

concurrency:
group: rust-ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: rust-ci-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

# Least-privilege default for the whole workflow (ADR-0875).
# Jobs widen only if they need to publish artefacts or push.
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sanitizers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ permissions:
contents: read

concurrency:
group: sanitizers-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: sanitizers-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

env:
DEBIAN_FRONTEND: noninteractive
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/security-scans.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ concurrency:
# A weekly schedule and a master push share github.ref. Keep cancellation for
# superseded runs of the same trigger, but never let one event class cancel
# CodeQL coverage for the other.
group: security-${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true
group: security-${{ github.workflow }}-${{ github.event_name }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
semgrep:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/standards-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ on:
types: [opened, synchronize, reopened, ready_for_review]

concurrency:
group: standards-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: standards-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

# Least-privilege default for the whole workflow (ADR-0875).
permissions:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sycl-parity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ permissions:
contents: read

concurrency:
group: sycl-parity-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: sycl-parity-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
runner-available:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests-and-quality-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: ci-${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

env:
DEBIAN_FRONTEND: noninteractive
Expand Down
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,13 @@ repos:
files: '^(scripts/ci/(check_licence_metadata\.py|tests/test_check_licence_metadata\.py)|tools/rc1-tester/image/licensing\.(py|json)|LICENSE[^/]*|LICENSES/.*)$'
pass_filenames: false

- id: test-master-concurrency-contract
name: A push to master never cancels an earlier master run (ADR-1673)
entry: bash -c 'python3 -B scripts/ci/tests/test_master_concurrency_contract.py && python3 -B scripts/ci/test_security_workflow_contract.py'
language: system
files: '^(\.github/workflows/.*\.yml|scripts/ci/(tests/test_master_concurrency_contract|test_security_workflow_contract)\.py)$'
pass_filenames: false

- id: test-upstream-parity-pin
name: Recorded upstream head parses and the Licence Provenance job reads it (ADR-1474)
entry: python3 -B scripts/ci/tests/test_upstream_parity_pin.py
Expand Down
22 changes: 3 additions & 19 deletions .standards-baseline.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
{
"version": 1,
"generated_at": "2026-10-05T17:51:49Z",
"generated_at": "2026-10-05T21:10:57Z",
"repository": "VMAFx/vmafx",
"commit_sha": "0cf544c542466e67e5339ec6459349f0fa21cfb0",
"total_infractions": 6,
"commit_sha": "e3b42ece57190544919f6437bb02017e9fe49d94",
"total_infractions": 4,
"infractions": [
{
"rule_id": "HISS-07",
"file_path": ".github/workflows/docker-image.yml",
"line_number": 96,
"message": "'|| true' discards the command's failure; handle the exit status or test the condition instead",
"anchor": "text:0384c48dc174",
"fingerprint": ".github/workflows/docker-image.yml:HISS-07:text:0384c48dc174#1"
},
{
"rule_id": "HISS-07",
"file_path": ".github/workflows/docker-image.yml",
"line_number": 97,
"message": "'|| true' discards the command's failure; handle the exit status or test the condition instead",
"anchor": "text:90891aa10dd2",
"fingerprint": ".github/workflows/docker-image.yml:HISS-07:text:90891aa10dd2#1"
},
{
"rule_id": "HISS-07",
"file_path": ".github/workflows/pr-type-label.yml",
Expand Down
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,14 @@ make `core/AGENTS.md` a generated index over `AGENTS.d/` topic pages ([ADR-1454]
[known upstream bugs](docs/development/known-upstream-bugs.md#upstream-gpu-defects-checked-against-the-fork-2026-10-05).


- CI: a push to `master` no longer cancels the workflow runs of the previous
master commit. The concurrency group of every push-to-master workflow carries
the commit SHA on master and `cancel-in-progress` stays on for pull request
refs; publish, release, Scorecard and Pages deploy stay serialised. A contract
test (`scripts/ci/tests/test_master_concurrency_contract.py`) enforces it
(ADR-1673).


- **Metal kernels compile without fast math or FP contraction**
(ADR-1498): every `.metal` file takes `-fno-fast-math -ffp-contract=off`,
so fp32 `+ - * /`, `sqrt` and `fma` are correctly rounded and no `a * b + c`
Expand Down Expand Up @@ -3567,6 +3575,17 @@ make `core/AGENTS.md` a generated index over `AGENTS.d/` topic pages ([ADR-1454]
section changed.


- **The FFmpeg `libvmaf` and `libvmaf_cuda` filters no longer print a score
after a mid-run error.** When a frame could not be copied or read, the run
failed, but the filter still printed a `VMAF score:` line pooled over fewer
frames than were decoded. Usually that line was an uninitialised
`0.000000`. The filter now logs one error naming the frame and the cause,
exits non-zero, and prints no score and writes no report. A failed flush or
a failed pooled score prints no score line either. This differs from
upstream FFmpeg on purpose
([ADR-1768](docs/adr/1768-ffmpeg-libvmaf-no-score-after-error.md)).


- **The FFmpeg `libvmaf_sycl` filter no longer scores fewer frames than it
decoded, or the wrong surfaces.**
- When a VA surface import failed, the filter used to pass the frame on
Expand Down Expand Up @@ -4240,6 +4259,16 @@ make `core/AGENTS.md` a generated index over `AGENTS.d/` topic pages ([ADR-1454]
this change.


- **Integer ADM scores pictures whose contrast-masking row passes INT64_MAX.**
The scale-0 masking reduction summed each row of non-negative cubes in a
signed 64-bit integer. A 64-pixel-wide picture with full-range detail and no
distortion took one row past INT64_MAX at the default settings, and any
width did with a CSF weight near its limit: the sum wrapped and the frame
failed with `invalid ADM reduction`. The CPU extractor, its AVX2 / AVX-512
paths and the CUDA, HIP, SYCL and Metal twins sum the scale-0 rows unsigned
now; scores that did not overflow are unchanged.


- **Integer VIF no longer converts an out-of-range `double` to `int32_t`
([ADR-1561](docs/adr/1561-integer-vif-sv-sq-defined.md)).** The residual
variance of the gain model, `sigma2_sq - g * sigma12`, reaches about -2^45,
Expand Down Expand Up @@ -5568,6 +5597,18 @@ make `core/AGENTS.md` a generated index over `AGENTS.d/` topic pages ([ADR-1454]
(`T-SYCL-TIDY-OVERRIDING-OPTION-2026-10-02`).


- **`vmaf_sycl_upload_plane()` returns only after its copy has completed.**
It used to return with the host-to-device copy still in flight. Nothing
ordered the copy before the frame's compute, and the caller could free the
source while the copy was still reading it. On an Arc A380, 3840x2160 frames
uploaded with it and read at once scored the wrong pixels on every frame
(`psnr_y` 4.9 to 6.1 where the CPU gives about 7.1). The function now waits
for the copy, after ordering it behind the slot's previous readers, so the
scores equal the CPU's. The Windows D3D11 import, which unmaps its staging
texture right after the call, uses this function. The SYCL runtime's debug
environment variables are now read through the thread-safe snapshot helper.


- **A SYCL error while de-tiling a VA surface no longer ends the process.**
`vmaf_sycl_import_va_surface()` submitted its de-tile copy or kernel outside
any `try`, so a synchronous `sycl::exception` (a kernel the device cannot
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ generated agent context against `AGENTS.md`.
private scratch-link policy.

**Debt Baseline**: `.standards-baseline.json` anchors the debt ratchet at
6 recorded infractions; audit forbids growth.
4 recorded infractions; audit forbids growth.

[praetor-docs-badge]: https://github.com/vmafx/vmafx/actions/workflows/praetor-docs.yml/badge.svg
[praetor-docs-runs]: https://github.com/vmafx/vmafx/actions/workflows/praetor-docs.yml
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- CI: a push to `master` no longer cancels the workflow runs of the previous
master commit. The concurrency group of every push-to-master workflow carries
the commit SHA on master and `cancel-in-progress` stays on for pull request
refs; publish, release, Scorecard and Pages deploy stay serialised. A contract
test (`scripts/ci/tests/test_master_concurrency_contract.py`) enforces it
(ADR-1673).
9 changes: 9 additions & 0 deletions changelog.d/fixed/ffmpeg-libvmaf-no-score-after-error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- **The FFmpeg `libvmaf` and `libvmaf_cuda` filters no longer print a score
after a mid-run error.** When a frame could not be copied or read, the run
failed, but the filter still printed a `VMAF score:` line pooled over fewer
frames than were decoded. Usually that line was an uninitialised
`0.000000`. The filter now logs one error naming the frame and the cause,
exits non-zero, and prints no score and writes no report. A failed flush or
a failed pooled score prints no score line either. This differs from
upstream FFmpeg on purpose
([ADR-1768](docs/adr/1768-ffmpeg-libvmaf-no-score-after-error.md)).
8 changes: 8 additions & 0 deletions changelog.d/fixed/integer-adm-scale0-row-past-int64-max.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- **Integer ADM scores pictures whose contrast-masking row passes INT64_MAX.**
The scale-0 masking reduction summed each row of non-negative cubes in a
signed 64-bit integer. A 64-pixel-wide picture with full-range detail and no
distortion took one row past INT64_MAX at the default settings, and any
width did with a CSF weight near its limit: the sum wrapped and the frame
failed with `invalid ADM reduction`. The CPU extractor, its AVX2 / AVX-512
paths and the CUDA, HIP, SYCL and Metal twins sum the scale-0 rows unsigned
now; scores that did not overflow are unchanged.
10 changes: 10 additions & 0 deletions changelog.d/fixed/sycl-upload-plane-waits-for-copy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- **`vmaf_sycl_upload_plane()` returns only after its copy has completed.**
It used to return with the host-to-device copy still in flight. Nothing
ordered the copy before the frame's compute, and the caller could free the
source while the copy was still reading it. On an Arc A380, 3840x2160 frames
uploaded with it and read at once scored the wrong pixels on every frame
(`psnr_y` 4.9 to 6.1 where the CPU gives about 7.1). The function now waits
for the copy, after ordering it behind the slot's previous readers, so the
scores equal the CPU's. The Windows D3D11 import, which unmaps its staging
texture right after the call, uses this function. The SYCL runtime's debug
environment variables are now read through the thread-safe snapshot helper.
4 changes: 3 additions & 1 deletion core/include/libvmaf/libvmaf_sycl.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,9 @@ VMAF_EXPORT int vmaf_sycl_import_va_surface(VmafSyclState *sycl_state, void *va_
/**
* Upload a raw Y-plane from host memory into a shared frame buffer.
* Platform-agnostic path: copies from a host pointer (with pitch) to the
* SYCL shared ref or dis buffer via H2D memcpy.
* SYCL shared ref or dis buffer via H2D memcpy. Returns once the copy
* has completed: the caller may free or reuse @p src afterwards, and the
* frame's compute in vmaf_read_pictures_sycl() reads the uploaded data.
*
* @param sycl_state The SYCL state.
* @param src Pointer to the Y-plane in host memory.
Expand Down
Loading
Loading