VMAF Fork — Engineering Principles¶
This page defines the non-negotiable standards for code merged to master. Read it before writing C.
Requirements are codified in one of .clang-tidy, .cppcheck-suppressions.txt, .semgrep.yml, .pre-commit-config.yaml or .github/workflows/{lint-and-format,security-scans,supply-chain}.yml. A rule that is not yet codified in tooling is marked as a target on this page and tracked as an open row in the repository's versioned docs/state.md register.
Scope (ADR-1142). Every principle and every gate below applies to the whole tree — upstream-mirror Netflix code, vendored libraries, fork-added code, CUDA / HIP / SYCL / Metal kernels, SIMD paths, tests, tools and scripts alike. There is no origin-, language- or backend-based tier. The one invariant that outranks the standards is numerical correctness as pinned by the Netflix golden assertions (section 8 of AGENTS.md, and section 3.1 below). Whole-tree lint debt is measured and may only decrease (make tidy-ratchet, see docs/development/ci.md).
1. Coding¶
1.1 NASA/JPL "Power of 10" rules (adapted for C)¶
- Simple control flow. No
goto, nosetjmp/longjmp, no recursion (static or dynamic). - Bounded loops. Every loop has a statically-verifiable upper bound on iterations.
- No dynamic allocation in hot paths.
malloc/calloc/reallocare permitted at initialization only; frame-loop code paths are allocation-free. - Short functions. Function bodies ≤ 60 lines (a single printed page). Enforced by
readability-function-sizein clang-tidy withLineThreshold: 60. - Assertion density. ≥ 2 runtime assertions per function on average. Use
assert()for invariants; in hot loops whereassert()cost matters, useVMAF_ASSERT_DEBUG()which compiles away in release. - Minimal scope. Declare variables at the smallest possible scope.
- Check return values. Every non-void function return must be checked and handled. Casting a result to
voiddoes not handle an error. Enforced bycert-err33-c. - Preprocessor restraint. Only header inclusion (
#include) and simple macros. No token pasting, no recursive macros, no conditional compilation beyond platform/feature toggles established at build-system level. - Pointer restraint. Single level of dereferencing in most cases. No function pointers except where essential for dispatch (feature extractor registry, SIMD runtime selection).
- Max strictness. Zero compiler warnings (HISS-10).
core/meson.buildbuilds atwarning_level=2(-Wall -Wextra); it does not set-Wpedanticor-Werror. The checks listed underWarningsAsErrorsin.clang-tidyfail the build. Static analyzers (clang-tidy, cppcheck, scan-build) must finish with zero findings at enabled levels.
1.2 JPL Institutional Coding Standard for C — applicable subset¶
The JPL-C-STD is the 31-rule superset of Power of 10. The following rules extend 1.1 and are additionally enforced. The rule numbers are the JPL numbers.
Preprocessor and headers¶
- Rule 11. Place
#includedirectives only at the top of a file. - Rule 12. Do not place executable code inside a
#included file. - Rule 13. Do not use reserved names (names beginning with
_followed by uppercase letter, or__). - Rule 19. All non-trivial types used in a function's public interface must be defined in a header.
- Rule 31. All headers must be self-contained (include what they need) and include-guard protected.
Casts, expressions and initialisation¶
- Rule 14. All type casts must be explicit.
- Rule 15. The evaluation order of operands must not matter. No
i++or++iused within a larger expression; split into separate statements. - Rule 16. No assignments inside expressions.
- Rule 17. All variables must be initialized before use.
- Rule 22. No side effects in conditional expressions.
- Rule 20. Use
constaggressively. Anything not modified isconst.
Globals and linkage¶
- Rule 18. All global variables must have a single declaration, and it must be in the file that owns them.
- Rule 21. Use
staticon every symbol not referenced outside its translation unit.
Switch and control flow¶
- Rule 23. All switch statements must have a default case.
- Rule 24. No fall-through in switch statements except where explicitly marked with
/* FALLTHROUGH */or__attribute__((fallthrough)). - Rule 25. Functions must have a single exit point where practical. Early returns are permitted for validation at function entry.
- Rule 26. Use of pointer arithmetic is restricted to array traversal within bounded loops.
Signals, variadics and library functions¶
- Rule 27. No use of
<setjmp.h>,<signal.h>handlers that do real work, or any non-async-signal-safe function inside a signal handler. - Rule 28. No variadic functions except standard
printf/scanffamily. - Rule 29. No use of
<stdarg.h>macros outside of printf/scanf wrappers. - Rule 30. Banned functions:
gets,strcpy,strcat,sprintf,strtok(non-reentrant),atoi,atol,atof(no error reporting),rand(non-cryptographic and non-reproducible),system(outside build scripts). Use:fgets,strncpy(with explicit null-termination) /snprintf/strlcpy,snprintf,strtok_r,strtolerrno checking,arc4randomor a seededxorshift, direct process calls with arg arrays.
1.3 SEI CERT C & CERT C++¶
Full compliance required for:
- INT (Integers) — no signed overflow, always check
size_tarithmetic, narrow casts - STR (Strings) — no off-by-one, always check buffer bounds
- MEM (Memory management) — every
mallochas a matchingfree; no double-free; no use-after-free (ASan enforced) - FIO (I/O) — check every
fopen,fread,fwrite,fclosereturn - EXP (Expressions) — no undefined behavior; no sequence-point violations
- CON (Concurrency) — use atomics correctly (
_Atomic); no data races (TSan nightly) - ENV (Environment) — never trust
getenvinput without validation
Enforcement: cert-* checks in .clang-tidy all enabled. The noisy clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling subset (Microsoft C11 _s functions) is explicitly disabled — it does not map to any portable POSIX API.
1.4 MISRA C:2012 (informative subset)¶
Applied where it does not conflict with existing libvmaf conventions:
- Rule 8.5 (one external declaration per identifier in a single file)
- Rule 10.1–10.8 (essential type rules — stricter than standard C integer promotions)
- Rule 17.7 (function return values must be used) — matches Power of 10 #7. MISRA allows an explicit
voiddiscard; the project rule does not (section 1.1, rule 7). - Rule 21.x (banned functions) — matches JPL rule 30
Not enforced as PR-blocking; informational in review.
1.5 Style¶
- C: Existing libvmaf conventions preserved (K&R braces, 4-space indent, 100-char columns). Codified in .clang-format.
- C++ (SYCL code): same as C where applicable; RAII encouraged for queue/context wrappers; no exceptions in hot paths.
- Python: PEP 8 + black (line-length 100) + ruff (import sorting via ruff's
Iruleset — ADR-1126). Codified in pyproject.toml. - CUDA (
.cu): follows C style; kernel nameskernel_*; device helpersdevice_*. - Shell: shfmt + shellcheck;
#!/usr/bin/env bash;set -euo pipefail.
1.6 Headers shared by C and C++¶
Rule. A type that both a C and a C++ translation unit read has one definition, in the C form. An enum in such a header does not get a fixed underlying type for C++ only (#ifdef __cplusplus / enum E : uint8_t).
Why. C cannot spell the fixed type on the required MSVC lane, so the enum would be int-sized in C and narrower in C++. A value passed by value, stored in a shared struct or read through a pointer would then be read with the wrong size (ADR-1470).
Instead. Suppress performance-enum-size and modernize-use-using on the definition with a citation.
Exception. An enum whose size is part of an ABI may state : unsigned int for C++ when it carries a UINT_MAX enumerator that holds the C enum to the same four bytes (core/src/model.h).
Guard. core/test/test_c_cxx_enum_definition_contract.py checks every header a .c file under core/ includes.
2. Security¶
See SECURITY.md for reporting policy.
2.1 Input validation at boundaries¶
- All CLI inputs validated at parse time (see
core/tools/cli_parse.cpp). - All public libvmaf API entry points validate pointer non-null + struct version.
- Video frame dimensions bounded; no negative or zero-size frames accepted.
- File paths validated for NULL and checked with
access()before open.
2.2 Memory safety¶
Enforced today (.github/workflows/sanitizers.yml):
- ASan + UBSan on every PR (required contexts
Sanitizers (address),Sanitizers (undefined)andSanitizers ASan+UBSan). - TSan (
Sanitizers (thread)) on pushes tomaster. - libFuzzer + ASan nightly at 04:30 UTC.
Target hardening flags. These are the intended release-build settings; none of them is defined in core/meson.build, core/src/meson.build or the container build files yet:
_FORTIFY_SOURCE=3in release builds.- Stack protector
-fstack-protector-strong. - PIE (
-fPIE,-pie) for all binaries. - RELRO + BIND_NOW:
-Wl,-z,relro,-z,now. - valgrind memcheck on release-candidate audit.
2.3 Banned functions¶
See JPL rule 30 above — enforced by .semgrep.yml custom rules + bugprone-unsafe-functions in clang-tidy.
2.4 Dependency auditing¶
Enforced today:
- Dependency Review, Gitleaks, Semgrep and CodeQL run on every PR (
.github/workflows/security-scans.yml; CodeQL uses thesecurity-extendedandsecurity-and-qualitysuites from.github/codeql-config.yml). - Renovate (
renovate.json) opens dependency PRs on weekdays before 06:00 Europe/Vienna and pins GitHub Actions to digests. osv-scanner.tomlconfigures the OSV scanner.
Target scanners. These are named as goals; no workflow in the tree runs them as a PR gate yet: trivy (Dockerfile and filesystem CVEs) and pip-audit (Python dependencies).
3. Quality gates (required for PR merge to master)¶
- ✅
make lint— zero clang-tidy / cppcheck / ruff / black findings - ✅
make test— all unit + integration tests pass with ASan + UBSan - ✅
make sec— zero semgrep findings (it runssemgrepwith.semgrep.yml, thep/cwe-top-25andp/cert-c-strictrule sets). Gitleaks runs as theGitleaksCI gate and as a pre-commit hook; bandit runs through the Python lint configuration. - ✅ CodeQL — zero security-and-quality issues at
security-extendedsuite - ✅ Conventional commit messages (enforced by commit-msg hook)
- ✅ CI matrix green on Linux/macOS/Windows
- ✅ Netflix source-of-truth golden tests pass (CPU, 3 pairs: 1 normal + 2 checkerboard)
- ✅ SYCL parity (ADR-1177) — when
SYCL_ARC_RUNNER_ENABLED=true, the required Arc A380 lane runs the SYCL unit suite and the CPU↔SYCLfloat_ssimmatrix cell; a missing or offline enabled runner fails loudly. Broader CUDA/SYCL sweeps remain explicit local or backend-specific test runs. See development/cross-backend-gate.md. - ✅ Coverage ≥ 70% overall, ≥ 90% for critical code (validation, parsing, crypto-adjacent); floors live in
scripts/ci/coverage-check.sh(ADR-0922) - ✅ Touched-file lint-clean rule (ADR-0141) — every hunk in the PR's diff against its merge base must be lint-clean to the fork's strictest profile;
// NOLINTis reserved for load-bearing invariants and must cite the ADR or digest that forces it. - ✅ State-tracking rule (ADR-0165) — every PR that opens, closes, or rules out a Netflix upstream report against the fork updates
state.mdin the same PR. - ✅ FFmpeg-patches sync rule (ADR-1240, rule 11 of the agent hard rules) — every PR touching a libvmaf C-API surface, CLI flag,
meson_options.txtentry, or any other interface that the in-treeffmpeg-patches/patches consume updates the relevant patch file in the same PR.
3.1 Netflix golden-data gate¶
The fork preserves the three Netflix-authored reference test pairs as the canonical ground-truth gate for VMAF numerical correctness (CPU only):
| # | Type | Reference | Distorted |
|---|---|---|---|
| 1 | normal | src01_hrc00_576x324.yuv | src01_hrc01_576x324.yuv |
| 2 | checkerboard | checkerboard_1920_1080_10_3_0_0.yuv | checkerboard_1920_1080_10_3_1_0.yuv (1-px) |
| 3 | checkerboard | checkerboard_1920_1080_10_3_0_0.yuv | checkerboard_1920_1080_10_3_10_0.yuv (10-px) |
YUVs live in python/test/resource/yuv/ (gitignored; provision them with scripts/test/fetch-test-yuvs.sh). Golden expected scores are hardcoded assertAlmostEqual assertions in python/test/ (primarily quality_runner_test.py, vmafexec_test.py, vmafexec_feature_extractor_test.py, feature_extractor_test.py, result_test.py). These assertions are never modified. They run in CI as a required status check on every PR. They are not run as a pre-commit hook because their runtime is longer than the acceptable pre-commit latency budget.
make test-netflix-golden runs them against an isolated native build (ADR-1317). make test-netflix-golden-arm64 runs the same assertions against an aarch64 cross build under qemu-user, with GCC or clang (ADR-1461, ARM backend guide).
Fork-added tests (SYCL, CUDA, SIMD snapshots, performance benchmarks) live in separate files and directories, and must not modify or override Netflix golden behavior.
4. Deterministic builds¶
SOURCE_DATE_EPOCHrespected throughout the build- All build-time random data (tempdir names, etc.) is seeded from
SOURCE_DATE_EPOCH - Meson pinned to a specific minor version via
dev-setupscripts - Compiler/linker flags logged and archived per release
5. Supply chain¶
See the tracked release and repository-security runbooks:
- SLSA v1 build provenance on every release: a GitHub artifact attestation signed through Sigstore (ADR-1356)
- CycloneDX + SPDX SBOMs on every release
- Keyless cosign signatures via Sigstore / GitHub OIDC
- Transparency log (Rekor) makes signatures publicly verifiable
6. Compliance targets¶
- OpenSSF Best Practices — truthful Passing assessment first; Silver/Gold are later goals, not earned status. Registration and evidence are active work.
- OpenSSF Scorecard — unrounded ≥ 8.5 required on master, with exact-head full-report verification and explicitly separate PR file checks per ADR-1247 and the operator guide. Scanner errors fail; the precise no-release state remains visibly unassessed, never signed.
- OWASP ASVS — Level 2 applicable controls (auth/authz not applicable — library)
- NIST SSDF — PW.4 (design), PW.5 (implement), PW.7 (review), PW.9 (archive) aligned
7. Non-goals¶
We explicitly do not pursue:
- Full MISRA C compliance (too restrictive for numerical code — informative subset only)
- Claiming a Best Practices badge before its criteria and external status are verified; no calendar deadline substitutes for that evidence
- FIPS 140 (no cryptography in this library)
- DO-178C (aerospace software — out of scope)
8. Multi-language policy (ADR-0702)¶
VMAFX uses multiple languages. Each has a clearly bounded role:
| Language | Role | Constraint |
|---|---|---|
| C / C++23 | Core library (core/) — metric engine, feature extractors, GPU backend runtimes | All of §1–§7 apply. C ABI at core/include/libvmaf/ is frozen. New fork-added C files target C23; C++ files target C++23. Netflix-inherited C files are migrated per-TU only when a PR already touches the file. |
| Go (1.27) | Production CLI binaries and servers (cmd/) | Module root github.com/VMAFx/vmafx. go vet is a required CI gate. New packages must have _test.go coverage before merging. |
| Rust (stable) | libvmaf FFI bindings (bindings/rust/vmafx-sys) and optional feature-extractor pilots (core/src/feature/rust/) | cargo clippy + cargo test are required CI gates. unsafe blocks must be audited and explained in a doc comment. |
| Python | ML training (ai/), dev scripts (scripts/), MCP server scaffolding (mcp-server/), vmaf-tune Python harness (tools/vmaf-tune/) | ruff + mypy strict. No Python in hot-path scoring code. |
| CUDA / SYCL / HIP / Metal | GPU compute kernels, inside the C core | Language-specific style rules in docs/backends/. |
Cross-language invariants:
- The C ABI at
core/include/libvmaf/is the single stable interface boundary. Go, Rust, and Python all consume it; none of them may call each other directly. - A new language is never added to the project without a per-language CI gate (compile check + fast tests) and an ADR documenting the role.
- No production tooling binary embeds ML model weights or training code. That stays in
ai/(Python only).
9. Revising this document¶
Changes to this document require:
- A dedicated PR titled
docs(principles): <summary> - One independent human approval after the latest push, as for every PR to
master(.github/CODEOWNERSnames a single owner; see repository security) - A corresponding change to tooling if the standard is newly enforceable in CI
- Linked rationale — either a design doc, a referenced security incident, or a standards-body update