ADR-1699: The root licence files state ADR-1250's terms, and every package manifest declares the licences of the files it ships¶
- Status: Accepted (Helm chart row amended by ADR-2673)
- Date: 2026-10-05
- Deciders: maintainer, agent
- Tags: license, compliance, docs, ci, rust, helm, python, go, fork-local
Context¶
ADR-1250 licensed fork-authored code under EUPL-1.2, left code that carries Netflix's or another project's work on its terms, and made each file's SPDX header the authority. It dropped the MIT alternative of 123 Go files on purpose: an MIT option lets a downstream take the permissive branch and defeat the reciprocity the decision exists for.
The repository root did not follow. It held LICENSE, Netflix's BSD-2-Clause-Patent text ("Copyright (c) 2020 Netflix, Inc."), and LICENSE-MIT ("Copyright (c) 2026 Lusoris"), which ADR-0686 added when it proposed dual-licensing fork code under the Netflix licence or MIT. The EUPL-1.2 text existed only as LICENSES/EUPL-1.2.txt. GitHub's licence detector (licensee) matched LICENSE-MIT exactly and LICENSE not at all, so the repository sidebar reported "MIT licenses found" and the repository API reports NOASSERTION. No licence check read the root.
Package manifests restated the same stale terms. Every Rust source file is EUPL-1.2, yet the workspace Cargo.toml (inherited by vmafx-sys and vmafx-tad) and bindings/rust/vmafx/Cargo.toml declared BSD-2-Clause-Patent; the Helm chart's artifacthub.io/license did too, for a chart whose files are all EUPL-1.2; tools/rc1-tester declared EUPL-1.2 while its sdist carries two MIT third-party notices. REUSE.toml recorded the vendored Prometheus Pushgateway chart archive under the fork's EUPL-1.2 default, although that archive's own Chart.yaml declares Apache-2.0. ADR-1560 already held seven Python packages to the files they ship; nothing held the others. The .toml manifests themselves were outside the provenance tool of ADR-1250: it skipped every file type it could not comment, so 13 fork .toml files had no header and two fork pyproject.toml files still carried BSD-2-Clause-Patent.
Research-2143 records the measurements and which published artifacts contained LICENSE-MIT.
Decision¶
The repository root holds one licence file and Netflix's notice, as part of ADR-1250's policy:
LICENSEis the EUPL-1.2, byte for byteLICENSES/EUPL-1.2.txt, the licence of fork-authored code. licensee 10.1.0 identifies it asEUPL-1.2(Dice similarity 99.20 %, threshold 98 %).NOTICEis the formerLICENSE, unchanged: Netflix's BSD-2-Clause-Patent text with its copyright notice, moved withgit mv. licensee does not score a file of this name as a licence file, soLICENSEis the only root licence file. licensee 9.18.0, which reads the root only, reports the project asEUPL-1.2(with the Netflix text under a licence-file name, firstLICENSE-BSD-2-Clause-Patenton this branch, it reportedNOASSERTION). licensee 9.19.0 and later also readLICENSES/, whose 15 texts make it reportNOASSERTIONfor this tree, as it does foreza-community/eza, which GitHub reports aseupl-1.2. GitHub's licence API returnseupl-1.2for this layout (?ref=of the pull-request branch, 2026-10-05) and returnedotherfor theLICENSE-BSD-2-Clause-Patentrevision.REUSE.tomlannotatesNOTICEwith its own terms (BSD-2-Clause-Patent, 2020 Netflix). The artifact gates of ADR-1503 and ADR-1513 take the BSD-2-Clause-Patent text from it (licensing.jsonspdx_texts), so every shipped artifact keeps carrying the same bytes.LICENSE-MITis removed. This supersedes theLICENSE-MITline of ADR-0686, which is Proposed; ADR-1250 had already replaced its dual-licence policy.
Per-file SPDX headers stay authoritative and LICENSES/ is unchanged. The README's licence section names which code carries which licence and points to the headers.
The two tags whose tree held LICENSE-MIT and that the Go module proxy serves, v1.0.0-rc.1 and v1.0.0-rc.2, are retracted in the root go.mod (retract [v1.0.0-rc.1, v1.0.0-rc.2], rationale "contained a stale root LICENSE-MIT; licensing is per-file SPDX ..."). The tags stay. The licensing page and the release notes of the next candidate state the same facts: the file was a leftover of ADR-0686, ADR-1250 governs, the per-file headers decide.
Every package manifest that declares a licence declares the SPDX identifiers of exactly the files its package ships (an AND expression; an OR is refused for the reason ADR-1250 gives): pyproject.toml (ADR-1560's model), Cargo.toml (the tracked files of the crate outside nested packages, the workspace Cargo.lock, the workspace manifest whose fields it inherits, and a readme copied from outside, as cargo package --list reports them), Helm Chart.yaml (the chart's own files; a subchart archive is a package of its own whose Chart.yaml declaration must equal its REUSE.toml record) and package.json (a manifest without a licence must be private). A configuration the model does not describe (include, exclude, license-file, .helmignore, files) fails rather than being guessed. The manifests now declare:
| Package | Field | Value |
|---|---|---|
vmafx-sys, vmafx | license | EUPL-1.2 |
vmafx-tad (not published) | license | EUPL-1.2 AND BSD-2-Clause-Patent (it ships the root README.md, BSD-2-Clause-Patent in REUSE.toml) |
Helm chart vmafx | artifacthub.io/license | EUPL-1.2 |
vmafx-rc1-tester | license | EUPL-1.2 AND MIT, with license-files |
scripts/ci/check_licence_metadata.py enforces the root layout and the manifest rule. It refuses a second root licence file (every name licensee 10.1.0 scores: LICENSE*, COPYING*, COPYRIGHT*, OFL*, PATENTS*, <x>-LICENSE*), a LICENSE that is not the EUPL-1.2 text, a missing NOTICE and a NOTICE without Netflix's copyright line. It runs in the required Licence Provenance job, on every commit (pre-commit hook check-licence-metadata), and its tests run in the tooling suite, which root licence changes now select.
scripts/dev/relicense_fork_files.py classifies .toml files like the other commentable types, so the Licence Provenance job holds a fork manifest or configuration file to an EUPL-1.2 header. pyproject.toml joins the names with no provenance signal (ADR-1250 veto 3): upstream's python/pyproject.toml does not make a fork package's manifest Netflix's. praetor's Codex projections under .codex/agents/ are not candidates; the engine writes them from .agents/agents/. The dev image states the licences of the VMAFx files its published stage copies, not BSD-2-Clause-Patent.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
EUPL-1.2 as LICENSE, Netflix's text as NOTICE, LICENSE-MIT removed (chosen) | LICENSE is the only root licence file, and a root-only detector reports EUPL-1.2; Netflix's notice stays at the root, where its licence asks for it in source distributions; artifact texts unchanged | NOTICE is a convention name, not a licence-file name; a reader has to follow the README to find Netflix's terms | The maintainer's decision (second popup); the only layout of the three where a root-only detector reports one project licence |
EUPL-1.2 as LICENSE, Netflix's text as LICENSE-BSD-2-Clause-Patent | The file name states the licence | licensee scores two licence files with different licences and reports NOASSERTION (measured) | The first revision of this ADR; replaced after the measurement |
An overview file at the root (LICENSE explaining the per-file rule, texts under LICENSES/) | One file states the whole rule | licensee matches no licence in prose, so GitHub reports nothing; an explanation is not a licence text and duplicates the README | The EUPL-1.2 text must be detectable as such |
Only remove LICENSE-MIT | Smallest change | The root would still present BSD-2-Clause-Patent as the project licence while 1,514 fork files are EUPL-1.2 | Leaves the contradiction ADR-1250 created half-fixed |
| Leave rc.1 and rc.2 unretracted, or delete their tags | No go.mod change; deletion removes the archives GitHub builds | Unretracted, nothing in the module records that the file was stale; deleting tags breaks every consumer of the release candidates and does not remove the proxy's copies | The maintainer chose "Retract + state it": tags stay |
Declare EUPL-1.2 AND Apache-2.0 for the Helm chart, counting the subchart archive | One number for everything helm package puts in the archive | Artifact Hub requires a single SPDX identifier in artifacthub.io/license; the subchart is a chart with its own declared licence | Each chart declares its own files; the subchart's record is checked against its declaration |
| Hold manifests only to "includes every licence its files carry" | Tolerates an over-broad declaration | A manifest that keeps BSD-2-Clause-Patent next to EUPL-1.2 for EUPL-only files still misstates the terms | ADR-1560 already requires equality for Python packages; one rule for all manifests |
Exempt .toml from the provenance tool with a dated exception | No header churn | 13 fork files without a header, and the next manifest arrives without one too | A header is one comment line in TOML; the tool already writes it |
Consequences¶
- Positive: GitHub, scanners and readers find the EUPL-1.2 as the only root licence file (licensee 9.18.0 reports
EUPL-1.2for the project); no root file offers a permissive branch for fork code; every manifest restates what the files say, and a new file with another licence fails the commit that adds it to a package. - Negative: an upstream sync that touches Netflix's
LICENSEmust land the change inNOTICE(rebase notes). Thego.modretraction is not read by Go clients while this module path's latest version is Netflix's tagv3.0.0+incompatible: the go command loads retractions from thego.modof@latest, and that version has none (measured with a local module proxy: with rc.3 carrying the directive,go list -m -versionsstill lists rc.1 and rc.2; only a release abovev1.5.3with the directive makes@latestresolve to it). History still follows the move:git log --follow NOTICElists the oldLICENSEcommits after a squash that also rewritesLICENSE(checked on a throwaway repository). - Neutral / follow-ups:
LICENSE-MITremains in published artifacts built before this change (Research-2143: the Go module proxy's zips ofv1.0.0-rc.1andv1.0.0-rc.2and GitHub's source archives of tags from 2026-05-28 on). The crates ship no licence text; none has been published to crates.io. The dev image label is not yet derived by a check. Should GitHub move to a licensee that readsLICENSES/(9.19.0 or later), the repository field would readNOASSERTIONagain, as it would for every REUSE-layout repository with more than one licence text.
References¶
- ADR-1250, ADR-0686, ADR-1503, ADR-1513, ADR-1560, ADR-1564, Research-2143.
- licensee 10.1.0 (
gem install licensee,licensee detect), run 2026-10-05; itsLicensee::ProjectFiles::LicenseFile::FILENAME_REGEXES. - Go modules reference,
retractdirective and@latestresolution (https://go.dev/ref/mod), read 2026-10-05; go 1.27.1. - Artifact Hub
docs/helm_annotations.md:artifacthub.io/license"must be a valid SPDX identifier", read 2026-10-05. - req: "i guess tags and description need an update as well" (with a screenshot of the repository sidebar showing "License, MIT licenses found").
- Q (popup, 2026-10-05): "EUPL at root, Netflix kept (Recommended)".
- Q (popup, 2026-10-05): "Rename to NOTICE (Recommended)".
- Q (popup, 2026-10-05): "Retract + state it (Recommended)".