API generation¶
One definition, core/api/vmafx.toml, describes the VMAFx C API, and a generator writes every surface from it (ADR-1852): the public headers, the linker version script and export lists, the ABI layout test, the libvmaf compatibility shims, the Python binding and the reference pages. The generated files are committed; a test fails when any of them differs from what the definition produces, so a hand edit of a generated file fails the build's tests.
A second definition, api/vmafx-platform.toml, describes the gRPC services and messages of the controller and the scoring server, and the Kubernetes custom resources of the platform (ADR-2350 D13); the same generator writes their protobuf files, Go types and the Helm chart's values and schema (Platform definition, Kubernetes resources, Helm chart values).
Change the API¶
- Edit
core/api/vmafx.toml. A new entry names its header (header) and the ABI minor that introduces it (since); raise[api] abi_version(see ABI rules for which part). -
Regenerate:
-
Implement what the definition declares (hand-written C lives in
core/src/vmafx/; ADR-1906 records the rules it follows for logging, struct sizes and references), build, and run the tests:python3 scripts/ci/run_meson_test.py -- -C build test_vmafx_abi_layout \ test_vmafx_api_slice test_vmafx_api_generated_current \ test_vmafx_api_abi_append_only test_vmafx_api_generator \ test_vmafx_python_binding check_exported_symbols \ test_vmafx_context test_vmafx_model test_vmafx_frame test_vmafx_score \ test_vmafx_bitexact test_vmafx_lifetime test_vmafx_sha256 -
Check that the new definition is an append-only successor of the one you started from, and draft the changelog fragment:
python3 scripts/codegen/vmafx-api.py --abi-check --against-ref origin/master python3 scripts/codegen/vmafx-api.py --changelog origin/master--changelogprints the text ofchangelog.d/added/api-<slug>.md(the symbols, types, fields, constants and options the definition gained) and ofchangelog.d/changed/api-<slug>.md(entries newly deprecated); pick the slug, edit the wording and commit the fragments yourself.
The generator needs Python 3.11 or newer and nothing else (tomllib from the standard library). It never runs during a normal build.
ABI rules¶
- Append-only within an ABI major (HISS-14): new functions, new fields at the end of a struct with
sized = true, new constants, new flag bits and new options. Removing or renaming anything, changing a parameter list or a callback signature, reordering, retyping or resizing a field, renumbering a constant or a bit, changingsince, changing an option's type or proto field number, or growing a struct that another struct embeds by value is a break. - Before
v1.0.0the ABI is 0.x (ADR-1852 decision D2): a break needs a higher minor (0.1.0to0.2.0), and the pull request lists every break--abi-checkreports as accepted. From1.0.0a break needs a higher major,!in the pull request title and aMigration:footer. - Additions raise
abi_version. A function'ssinceselects its linker version node (VMAFX_0.1,VMAFX_0.2, ...). Within 0.x an addition may join the current minor's node (a patch bump such as0.1.0to0.1.1is enough), so work packages that add functions in parallel do not each claim a minor; it may never join an older node. From1.0.0a node that shipped is frozen: an addition'ssinceis a newer minor than the ABI it is compared with. ADR-1897 records this rule and the alternative of a new minor per addition. - Deprecation:
deprecated = { since, replacement, removal }adds theVMAFX_DEPRECATED("...")attribute to a function (defineVMAFX_NO_DEPRECATION_WARNINGSto silence it), an@deprecatedline to the header documentation and a note to the reference page.replacementmust name a declared function, type, constant, field (Struct.field) or option.
What the definition holds¶
| Table | Generates | Rules the generator enforces |
|---|---|---|
[api] | ABI version macros (version_header), export and deprecation macros and status codes (base_header), hide_unlisted for the version script | schema = 2; abi_version is MAJOR.MINOR.PATCH; both named headers are core headers |
[[headers]] | One public header each under core/include/, its install line and its reference page | group is umbrella (exactly one; includes every core header and declares nothing), core, or optional (never included by the umbrella; includes names outside headers it needs) |
[[status]] | VmafxStatus codes, vmafx_status_name(), the status-to-errno map of the compat layer | The first code is the OK code; names and values unique |
[[enums]] | C enums, Python IntEnums | Names and values unique; fields carry them as u32 with enum = "..." |
[[flags]] | #define NAME (UINT32_C(1) << bitU) constants, Python IntFlags | type is u32 or u64; bits unique and inside the width; fields carry them with flags = "..." |
[[handles]] | Opaque types | Each names its declared release function |
[[callbacks]] | Function-pointer typedefs | Parameters are inputs; the last one is user of type ptr (void *user) |
[[structs]] | Structs, *_INIT macros, layout asserts | sized = true adds struct_size first; fields are fixed-width scalars, ptr, cstr, size, uptr, nested structs, handles or callbacks; count = N makes a fixed array (1 to 64); const = true on a handle field; a sized struct is never embedded in an unsized one; no by-value cycle |
[[functions]] | Declarations, version-script and export lines, Python signatures, reference rows | Known types and pass modes; the VmafxError ** parameter is last and the result is a status; the Python method is the C name without vmafx_context_ / vmafx_, or python = "<name>", and two functions with one method name on one Python class stop generation (the later one would hide the earlier) |
[[compat]] | libvmaf.h function bodies on the new API | The target exists; a build field map covers every field of the struct it fills |
[[option_groups]] | Every scoring surface: the vmaf option table and usage, the MCP schemas and argument-vector spec, ScoreOptions, the OpenAPI components, the vmafx filter's AVOption table, the documentation option tables (Option groups) | surfaces is a subset of cli, ffmpeg, mcp, proto; an option's surfaces are a subset of its group's and it has a spelling for each; defaults inside their range, enum or choices; spellings, short letters and proto field numbers (per message) unique; option names unique across groups |
Every top-level entry carries header (except status codes and option groups) and since. Enum values, flag bits, struct fields and options inherit their parent's since unless they name a later one. Each header includes the headers whose types its declarations use, computed from the definition; an include cycle stops generation.
Parameter pass modes: in (value; const T * for a struct; T * for a handle), in_const (const T *), out (T *), out_handle (T **), error (VmafxError **). Scalar types: u32, u64, i32, i64, f32, f64, uptr (uintptr_t), size (size_t), ptr (void *), cstr (const char *), status.
scripts/codegen/tests/fixtures/full.toml uses every feature of the format; the generator tests render it and compile its C output.
Outputs¶
| File | Content |
|---|---|
core/include/vmafx/*.h | Public headers: the umbrella vmafx.h, the core headers of the design's header layout, and optional headers such as libvmaf_bridge.h |
core/include/vmafx/meson.build | Install list of those headers |
core/src/vmafx.map | Linker version script, one node per ABI minor; libvmaf links it on ELF targets |
core/src/vmafx.def | Windows export list, for the shared library split |
core/src/vmafx_symbols.txt | Exported symbols and their version nodes, read by check_exported_symbols |
core/src/vmafx/status_gen.c, status_gen.h | Status names and errno maps |
core/src/compat/libvmaf/libvmaf_gen.c, status_errno_gen.c | The generated (shim, glue) libvmaf functions of the compat library libvmaf.so.3 and its status-to-errno map |
core/src/vmafx/engine_names_gen.h | Forced on every engine translation unit: the engine's own libvmaf bodies compile as vmaf_engine_<stem> |
core/src/vmafx_legacy_<backend>.map, core/src/libvmaf_symbols.txt | Version node of the libvmaf functions a built backend keeps in the engine (declared exceptions), and which library exports each libvmaf function in which build |
core/test/compat_conformance_gen.h, compat_conformance_table_gen.c | The two function tables (old libvmaf, compat library) and the coverage rule of test_compat_conformance |
core/test/test_vmafx_abi_layout.c | _Static_assert of every struct size, alignment, field offset, array length and constant |
bindings/python/vmafx/_api.py | ctypes binding; checks its layouts at import |
docs/api/vmafx/reference.md and one page per header | Reference index |
core/tools/cli_options.gen.inc | The vmaf short option string, long-only identifiers, long_opts[] and usage lines |
pkg/scoreopts/options.gen.json, mcp-server/vmaf-mcp/src/vmaf_mcp/options.gen.json | MCP tool input schemas, server-side options, argument-vector spec, command-line flags, library defaults (one text, two packages) |
proto/vmafx/v1/vmafx_api.proto | ScoreOptions and the messages of structs that name proto (Provenance) |
api/vmafx/v1/groupversion_info.go, api/vmafx/v1/<kind>_types.go | From api/vmafx-platform.toml: the Go types of the custom resources with their kubebuilder markers (Kubernetes resources) |
deploy/helm/vmafx/values.yaml, deploy/helm/vmafx/values.schema.json | From api/vmafx-platform.toml: the chart's default values with their comments, and their JSON schema (Helm chart values) |
cmd/<binary>/config_keys.gen.go, deploy/helm/vmafx/templates/_config.gen.tpl, the environment tables of the binaries' pages and docs/usage/env-vars.md | From api/vmafx-platform.toml: the Go binaries' CompoundKeys, their environment tables and the chart's VMAFX_* entries (Environment of the Go binaries) |
api/openapi/components.gen.yaml | The same messages as OpenAPI 3.0 schemas; also spliced into api/openapi/vmafx-server-v1.yaml |
ffmpeg-patches/src/vf_vmafx_options.h | The vmafx filter's context fields, AVOption table and value-name lists |
Regions of docs/usage/cli.md, docs/usage/ffmpeg.md, docs/mcp/tools.md, docs/server/api-contract.md | Option tables between BEGIN GENERATED / END GENERATED markers |
Every generated C file is already in the repository's clang-format style (long *_INIT macros sit between clang-format off / on markers) and the Python file in black's style, so formatter hooks never rewrite them.
Since the library split (ADR-1852 decision D3, ADR-2094), hide_unlisted = true: libvmafx.so.1 exports the vmafx_* functions and nothing the script does not list. The libvmaf functions live in libvmaf.so.3, generated (shim, glue) or hand-written (manual, in core/src/compat/libvmaf/) from the [[compat]] table; a backend's functions that still live in the engine are engine entries, exported through core/src/vmafx_legacy_<backend>.map in builds with that backend.
The compat table¶
| Key | Meaning |
|---|---|
kind | shim / glue (body generated from null_checks, context, build, out_handle, out_struct, args, post (asserted after success), store, return_expr or body), manual (hand-written), engine (no compat definition) |
target, calls | The VMAFx function the entry is built on; for manual, every vmafx_* function its file calls (a test compares them with the source) |
file | manual: the source under core/src/compat/libvmaf/ |
engine_with, until | A backend whose builds keep the engine's own definition, and what ends that exception |
when | A build feature the function exists in (mcp) |
platform | An operating system the function exists on (windows: declared under #ifdef _WIN32); its name stays out of the ELF version scripts and its row in core/src/libvmaf_symbols.txt ends in @windows |
note | One line for the migration table |
Every engine translation unit is compiled with the generated core/src/vmafx/engine_names_gen.h (vmaf_engine_name_args), which names the engine's own libvmaf bodies vmaf_engine_<stem>; code that uses the libvmaf API (the compat library, the tools, black-box tests) defines VMAF_PUBLIC_NAMES. test_compat_conformance compares every compat function with its engine body.
Option groups¶
Every scoring option of every surface is one entry of an option group (ADR-2044). Groups and options are TOML array tables:
[[option_groups]]
name = "threads"
since = "0.1"
doc = "Worker threads of the feature extractors."
surfaces = ["cli", "ffmpeg", "mcp", "proto"]
mcp_tools = ["vmaf_score", "vmaf_score_encoded"]
[[option_groups.options]]
name = "threads"
type = "uint"
doc = "Worker threads of the feature extractors, capped to the hardware threads (0: score in the calling thread)."
cli = ["--threads"]
ffmpeg = "threads"
aliases = ["n_threads"]
mcp = "threads"
proto = { field = 14 }
| Key | Meaning |
|---|---|
type | bool, int, uint, float, string, enum (enum = [...]) or flags (several values of enum = [...]) |
default | The value an unset option means; omitted when the consumer's own behaviour applies (documented in doc) |
default_macro | The default is the library's, named by this C macro (VMAF_DEFAULT_MODEL_VERSION); never a literal. Surfaces that cannot read a header get its value from the generated file, so the drift check fails when the header moves |
default_form | How the MCP tool schemas spell a default_macro default: "version={}" advertises version=<VMAF_DEFAULT_MODEL_VERSION> as the model default of every scoring tool, the value read from the header when the file is generated |
surface_defaults | Per-surface defaults ({ mcp = "json" }) |
range, choices | [min] or [min, max] of a number; the integers an integer option takes |
surfaces | The surfaces of this option (default: the group's) |
repeat | true or the surfaces on which the option is given several times |
cli, cli_short, cli_meta, cli_id, cli_values | Long spellings (the first is the usage name), short letter, usage placeholder, getopt identifier (default 'x' for a short option, ARG_<NAME> otherwise), one switch per enum value ({ xml = "--xml" }) |
ffmpeg, aliases | Filter option name and upstream aliases |
mcp, mcp_required | MCP argument name; required in the tools of the group's mcp_tools |
proto | { field = N }, unique in the group's proto_message (default ScoreOptions) |
argv, argv_flag, model_suffix | How a server passes it to vmaf: core (placed by the server), extra (appended in definition order) or none; the flag when not the first long spelling; a model-spec suffix (":adm.adm_norm_view_dist={}") instead of a flag |
reserved | Every surface accepts only the default; the text says why |
Order matters: vmaf --help lists options in definition order and both MCP servers append the extra flags in that order. A struct with proto = "Name" becomes a proto message and an OpenAPI schema with one field per struct field (numbers in field order, so they never change); a field with no proto form (a handle, a pointer, a callback) stops generation.
The generated proto needs buf generate proto afterwards (the template in buf.gen.yaml, then python3 scripts/proto/postprocess_gen_go.py) and the OpenAPI change needs the server stubs regenerated (gen/go/AGENTS.md). buf breaking proto --against '.git#ref=refs/remotes/origin/master,subdir=proto' must stay clean.
Platform definition¶
api/vmafx-platform.toml holds the services of the platform: the scoring service VmafxScoring (package vmafx.v1) and the controller VmafxController (package vmafx.controller.v1), and the custom resources of the operator (Kubernetes resources). The generator writes one protobuf file per [[files]] entry, and buf turns those into the Go bindings under gen/go:
| Table | What it declares |
|---|---|
[platform] | version = 1, the format of the definition |
[[files]] | A protobuf file: name, path (proto/<package as directories>/<file>.proto), package, go_package (the import path the bindings live under, then ; and the Go package name), doc |
[[services]] | A gRPC service in a file: rpcs with name, request, response, doc and client_stream / server_stream for streaming RPCs |
[[enums]] | An enum: values with name, number and an optional doc; the first value is number 0 |
[[messages]] | A message: fields with name, type, number, doc, and repeated = true or oneof = "<group>" |
A field's type is a protobuf scalar (string, double, int64, bytes, ...), map<K, V> (K an integer, bool or string), a message or enum of the platform definition, or a message the core definition generates: an option group's proto_message (ScoreOptions) or a struct's proto (Provenance). A type from another file is imported, a type from another package is written with its package. Documentation keeps its own line breaks and is wrapped at 96 columns.
Names and numbers are the wire contract. Within a v1 package a change only adds: a message, an RPC, a field or an enum value with a new number. Renaming or renumbering is a break, which buf breaking refuses (see below); a break needs a v2 package beside v1. Names that predate these rules and do not follow buf's style (the service names without Service, JobStatus values without the JOB_STATUS_ prefix, Job as the answer of two RPCs) are exempted by name in buf.yaml and stay as they are.
Change a service or message¶
- Edit
api/vmafx-platform.toml. -
Regenerate the protobuf files, then the Go bindings:
proto_generate.pyruns onebuf generatewith the repository'sbuf.yamlandbuf.gen.yaml. buf is the releaseBUF_VERSIONinbuild-config.env, run throughgo runso the Go module checksum database verifies it; theprotoc-gen-goandprotoc-gen-go-grpcplugins are the versionsgo.modpins as tools. It then adds the// SAFETY:proofs (scripts/proto/postprocess_gen_go.py) and writes every*.pb.goundergen/go, removing stale ones. Themodule=option puts each binding under the path of itsgo_package:gen/goforvmafx.v1,gen/go/controllerforvmafx.controller.v1. -
Check wire compatibility against the branch you started from:
buf breakingruns with theWIRE_JSONrules: what clients send and receive in binary and JSON form must stay readable. Moving a file or its Go package is not a break; a removed or renumbered field, a changed type or a renamed enum value is.
Kubernetes resources¶
The same file declares the custom resources of the vmafx.dev/v1 API group: VmafxJob, VmafxNode, VmafxModelTraining and VmafxTenant. A [[messages]] or [[enums]] entry that names a group instead of a protobuf file is a Kubernetes type.
| Table | What it declares |
|---|---|
[[groups]] | An API group version: name (what entries refer to), group, version, path (the Go package directory), go_package, doc |
[[resources]] | A custom resource: kind, group, doc, spec and status (message names), short_names, scope (Namespaced, the default, or Cluster), status_subresource (default true), spec_required (default false), printer_columns with name, type (string, number, integer, boolean, date) and json_path |
[[enums]] with group | A string enum: values with name and an optional doc |
[[messages]] with group | A struct: fields with name (the JSON name, lowerCamelCase), type, doc, and optionally go, optional, repeated, pointer, default and validation keys |
A field's type is string, bool, int, int32, int64, float64, Time (*metav1.Time), map<string, string>, or an enum or message of the same group. The Go name is derived from the JSON name (tenantId becomes TenantID; id, gpu, uri, url, oidc and rbac are written in capitals); go overrides it. pointer = true makes a single value a pointer, so that an explicit false or 0 survives a default. A field with a default must be optional. The validation keys become kubebuilder markers and from those the CRD schema: enum, items_enum, minimum, min_length, items_min_length, max_items, pattern, format. An enum type carries its own values, so a field of that type takes no enum.
Within v1 a resource only grows. Adding a resource, an optional field, an enum value or a short name, or widening a bound, is compatible; removing a field, version, short name or the status subresource, adding a required field, narrowing an enum, a bound, a type or a format, or changing a pattern or a default is not, and needs a new version.
Change a custom resource¶
- Edit
api/vmafx-platform.toml. -
Regenerate the Go types, then the deepcopy code, the CRDs and the RBAC role:
vmafx-api.pywritesapi/vmafx/v1/groupversion_info.goand one<kind>_types.goper resource, gofmt-clean.crd_generate.pyruns controller-gen, the versiongo.modpins as a tool, three times:objectwritesapi/vmafx/v1/zz_generated.deepcopy.go,crdwritesdeploy/helm/vmafx/crds/vmafx.dev_<plural>.yaml(the only CRD tree: the chart installs it and the operator's envtest suite loads it), andrbacwritesconfig/rbac/role.yamlfrom the+kubebuilder:rbacmarkers ofcmd/vmafx-operator. It adds the SPDX header and removes stale files. -
Check compatibility against the branch you started from:
-
A new RBAC marker on a reconciler changes
config/rbac/role.yaml; the chart'sdeploy/helm/vmafx/templates/operator-rbac.yamlmust then grant it too, whichscripts/ci/tests/test_helm_operator_rbac.pychecks.
Helm chart values¶
The same file holds the chart's values: one [[chart]] entry per key of deploy/helm/vmafx/values.yaml, in the order of that file. The generator writes values.yaml and values.schema.json from them; neither is edited by hand.
| Key | What it holds |
|---|---|
path | The dotted key, such as controller.store.backend; a key that contains a dot is written in double quotes (matchLabels."kubernetes.io/metadata.name") |
value | The default. Absent for a mapping whose keys follow as their own entries, and for a key only the schema has |
lead | The comment and blank lines written above the key, verbatim with their indentation |
note, note_column | A comment on the key's line and the column of its #; without a column, two spaces after the value |
quoted | Write a string in double quotes although YAML would read it plain; strings that need quotes get them anyway |
literal | Write a multi-line string as a \| block |
[chart.schema] | The key's JSON schema, every keyword but properties, which the generator builds from the entries below the key |
schema_order | The order of a mapping's schema properties, where it differs from the order of values.yaml |
[chart_root] holds the schema's root keywords ([chart_root.schema]), the order of the top-level properties and the comment lines after the last key (values_tail); [[chart_defs]] are the schema's own $defs. The schema file has one layout: an object or array that fits on its line within 100 columns is written on one line, any other is expanded.
A $ref of k8s:<name> refers to a Kubernetes type, such as k8s:io.k8s.api.core.v1.Toleration, as the chart's minimum supported Kubernetes minor defines it. build-config.env pins that release (K8S_SCHEMA_VERSION, the last patch of the minor the deployment guide names) and the SHA-256 of each OpenAPI v3 file of its tag. scripts/codegen/k8s_openapi.py --write downloads them, checks the digests, and writes every type the definition names, and every type those reach, to api/kubernetes/openapi-subset.json, without descriptions and x-kubernetes-* extensions. The generator copies the types a schema reaches into its $defs. Kubernetes accepts fields it does not know in these types, so the schema does too; a known field must have its type, and a required field must be there.
To change a value or its schema:
- Edit the entry in
api/vmafx-platform.toml. A new key gets a new entry at its place in the file. - If the entry names a Kubernetes type the subset does not hold yet, run
python3 scripts/codegen/k8s_openapi.py --write. - Regenerate:
python3 scripts/codegen/vmafx-api.py --write.
Environment of the Go binaries¶
The same file lists every environment variable the Go binaries read and how the chart sets it.
| Table | What it holds |
|---|---|
[[config_binaries]] | A Go binary: name, package dir, the page with its environment table, and the chart workloads that run it |
[[config]] | One variable: env (its name), key (the golusoris configuration key it maps to; none for a variable the binary reads directly), binaries, type, default, doc, secret; [config.<binary>] overrides type, default or doc for one binary |
[[chart_workloads]] | An environment list in the chart's templates: name and the indent of its entries |
[[chart_env]] | One VMAFX_* entry of those lists, in order: env, workloads, the YAML comment lines above it, a when condition (a template expression), and one value source: value (a template expression), field_ref or secret_ref (name and key expressions) |
[[chart_maps]] | A value helper: source compared with each of cases, default otherwise (the backend of each GPU vendor, vmafx.backendEnvValue) |
The generator writes:
cmd/<binary>/config_keys.gen.go: the binary's golusoris CompoundKeys, everykeywith an underscore inside a segment. golusoris turns each underscore of aVMAFX_name into the key delimiter except in these keys.- One table per binary, with the same columns everywhere, into the binary's page and into the Go services section of the environment reference. The chart value column lists the values the chart's entries read.
deploy/helm/vmafx/templates/_config.gen.tpl: a helpervmafx.env.<workload>per workload holding itsVMAFX_*entries with their comments and conditions at the list's indentation, and the value helpers. A template includes the helper where its environment list holds them; no other template writes aVMAFX_*entry.
To add or change a variable: edit its [[config]] entry (and the [[chart_env]] entry when the chart sets it), then run python3 scripts/codegen/vmafx-api.py --write. A variable a binary reads but the definition lacks is a missing row in every table; the binary's environment tests (env_test.go, main_test.go) read the generated compoundKeys.
Gates¶
| Gate | Fails when | Shown failing by |
|---|---|---|
test_vmafx_api_generated_current (Meson, fast) | A generated file differs from the definition | The generator tests edit a generated header, delete the binding and a reference page, and rewrite the version script in a copy |
test_vmafx_abi_layout (Meson, fast) | The compiler lays a struct out differently from the definition, an array has another length, or a constant changed | The generator tests compile the fixture's layout test, then a copy with plane[3] made plane[4] and one with a field widened |
test_vmafx_api_abi_append_only (Meson, fast) | The definition is not an append-only successor of the one at the merge base with origin/master; skipped (exit 77, reason printed) without git, without that ref, or when the merge base has no definition | The generator tests run it in a scratch repository with a renumbered constant |
--abi-check | A break without the version bump the ABI rules ask for; an addition in a version node that shipped; an addition without a version bump | Planted changes in test_vmafx_api_generator.py and test_vmafx_api_abi_features.py |
check_exported_symbols (Meson, fast) | The library exports a vmafx_ symbol missing from vmafx_symbols.txt, does not export a listed one, or exports one in another version node | test_vmafx_api_symbols.py builds a small library and plants each defect |
Link of libvmaf.so | The version script names a function no source defines (--no-undefined-version) | test_vmafx_api_symbols.py links without one listed function |
| Validation (every run) | Any rule in the table above | Planted definitions in the generator tests |
test_vmafx_api_generator (Meson, fast) | Any of the generator tests fails | Runs scripts/codegen/tests/test_*.py |
test_cli_option_table (Meson, fast) | A long spelling or short option the hand-written CLI table accepted is gone, takes or drops an argument, or no longer reaches its short option | Removing --tiny_model from the definition |
test_vmafx_score_contract (Meson, contract) | The CLI, the C API, gRPC Score and POST /v1/score disagree on a score or on the library build | A server mapping that drops subsample |
TestEmbeddedFileEqualsThePythonServerCopy (go test ./pkg/scoreopts) | The two copies of options.gen.json differ | An edited copy |
test_proto_generated_current (Meson, fast) | buf lint reports a protobuf file, or a *.pb.go under gen/go differs from what buf generate and the proofs produce; skipped (exit 77, reason printed) without Go or the module proxy | A hand edit of gen/go/vmafx.pb.go, and a buf.yaml without the exemption of the service names |
proto_generate.py --breaking-against REF | buf breaking (WIRE_JSON) finds an incompatible change against REF | A renumbered field in a copy |
| Platform validation (every run) | A duplicate name or number, an unknown type or file, a field number outside 1 to 536870911 or in 19000 to 19999, an enum without value 0, a map key that is not an integer, bool or string, a repeated oneof member, a path outside its package directory | scripts/codegen/tests/test_vmafx_platform.py |
| Kubernetes validation (every run) | An unknown type or group, a duplicate type, field or Go name, a default on a required field, a pointer to a list or map, enum on an enum-typed field, a scope other than Namespaced or Cluster, a spec or status that is not a message, an unknown printer column type, a name that is both a protobuf and a Kubernetes type | scripts/codegen/tests/test_vmafx_platform_kube.py |
test_crd_generated_current (Meson, fast) | zz_generated.deepcopy.go, a CRD under deploy/helm/vmafx/crds or config/rbac/role.yaml differs from what controller-gen writes, or a generated file is missing or left over; skipped (exit 77, reason printed) without Go | A hand edit of a CRD, an extra and a missing file, in scripts/codegen/tests/test_crd_generate.py |
test_crd_compat (Meson, fast) | A generated CRD narrows the one at the merge base with origin/master (see Kubernetes resources); skipped (exit 77, reason printed) without Go, git or that ref | Every narrowing planted in test_crd_generate.py, and max_items = 16 for the tenant roots in the definition |
test_helm_operator_rbac.py (Helm Chart workflow) | The chart does not bind the operator's service account to every rule of config/rbac/role.yaml | A chart without the lease rule, and a marker for a resource the chart does not grant |
| Chart validation (every run) | A path twice or below a missing parent, a key with a value above keys with values, an entry with neither a value nor a schema, a lead with a non-comment line, quoted or literal on a non-string, a note without a value, properties written by hand, a $ref that is neither a chart_defs name nor k8s:<type>, a schema_order that is not a permutation | scripts/codegen/tests/test_vmafx_platform_chart.py |
test_k8s_openapi_subset_current (Meson, fast) | api/kubernetes/openapi-subset.json differs from the types the definition reaches in the pinned release, or a downloaded file has another SHA-256; skipped (exit 77, reason printed) when the files cannot be downloaded | A stale subset and a wrong digest in scripts/codegen/tests/test_k8s_openapi.py |
test_helm_values_schema.py (Helm Chart workflow) | The chart renders a value Kubernetes 1.26 refuses in a Kubernetes-typed key, or refuses a valid one | 14 planted values (a toleration with tolerationSeconds: "60", a spread constraint without topologyKey, a volume without a name, ...), each accepted by the schema before the Kubernetes types |
The compiler, clang-format and linker cases of the generator tests skip, with the reason, when the tool is not installed.
The format case compares against one clang-format major only: the one the clang-format hook pins in .pre-commit-config.yaml, because other releases align macros differently (clang-format 18.1.3, the ubuntu-24.04 runner's, and 17 reject output that 18.1.8 and 19 to 23 accept). It uses VMAFX_CLANG_FORMAT when set, which must be that major or the test fails, else clang-format-<major> or clang-format on PATH; any other major makes it skip and name the version it found. The Tooling Tests job installs the pinned release from requirements/locks/tooling-tests.txt and sets VMAFX_CLANG_FORMAT, so the case always runs there. To run it locally with another system version: