Repository navigation
fix(release): repair the release-please pipeline onto the 1.0.0 line (ADR-1151) - #1216
Merged
Merged
Conversation
lusoris
added a commit
that referenced
this pull request
Sep 2, 2026
The ADR-0334 state.md convention wants the merged PR number, not a branch name or a placeholder. Backfilled now that gh pr create has returned the number. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lusoris
added a commit
that referenced
this pull request
Sep 2, 2026
The ADR-0334 state.md convention wants the merged PR number, not a branch name or a placeholder. Backfilled now that gh pr create has returned the number. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lusoris
force-pushed
the
fix/release-please-setup
branch
from
September 2, 2026 22:51
98149a4 to
efdd410
Compare
lusoris
marked this pull request as ready for review
September 3, 2026 02:02
…(ADR-1151) The fork has never released: zero GitHub releases, zero fork-made tags, and every `vX.Y.Z` tag reachable from master belongs to Netflix upstream history (`git merge-base --is-ancestor v3.2.0 origin/master` is false). ADR-1127's "first release is v3.2.1" rested on the 3.2.x manifest baseline, which was a source-version alignment with Netflix's SONAME, not a release. ADR-1151 supersedes that choice: the first release is v1.0.0 on a fresh number line. An audit of the pipeline that would have produced that tag found it unable to release correctly at all. This change repairs it and leaves it idle. - Retarget the cut: one-shot `release-as: "1.0.0"` on a `0.0.0` manifest, so 0.0.0 -> 1.0.0 is a monotone forward bump. Both one-shot cutover fields carry an inline `_comment_*` explaining that they are deleted by the rollover, and the rollover now deletes those comments with them. - Prove the changelog cut ran. `verify-release-version.sh` (the tag-time preflight for all three publication workflows) gains five fail-closed assertions: exactly one `## [X.Y.Z] - YYYY-MM-DD` heading, a matching `changelog.d/releases/X.Y.Z.json` receipt, zero active fragments, no `_pre_fragment_legacy.md`, and no surviving `release-as` / `bootstrap-sha`. Nothing checked this before — `concat --check` passes identically before and after a cut, so a tag could have published a CHANGELOG whose newest section was still `## [Unreleased]` over 1,550 live fragments. - Stop `release-as` from rotting. The `Release Script Contract (ADR-1128)` job fails if either one-shot field survives once the manifest reaches 1.0.0. It is a persistent, deprecated override applied after commit analysis; left in place it pins every future release. - Stop the release branch being force-rewritten mid-cut. release-please recreates `release-please--branches--...` on every push to master, which would destroy the hand-added rollover commits. The PR-update invocation is now skipped while the PR carries `autorelease: cut`. - Make the release-critical gates actually required. Six rule-enforcement jobs (including Release Script Contract) were reporting but absent from the aggregator's `required` array, so a red release-script contract blocked nothing. A release PR's manifest-only diff also let every gate resolve absent-or-skipped, so the aggregator gains a `release-please--` `mustReport` list and both release-please files join the `c_core` selector. - Require the publication environments to exist. Twelve write-bearing jobs name `release-publish`; GitHub auto-creates a referenced environment with an empty rule set, so they ran with no approval gate. `supply-chain.yml` now queries both environments and fails closed without a required reviewer. - Make the `latest` container tag tag-aware at all four sites, so a recovery dispatch no longer leaves `latest` on a broken digest. - Hygiene: `pkg/version/version.go` documented a repo-root VERSION file that does not exist; `docker/Dockerfile.node` baked a coordinated version marker nothing in the release path reads; the SONAME / product-version split and the deliberately-independent Cargo / Helm-chart / root-pyproject versions now carry ADR-citing comments at the source. Docs: `docs/development/release.md` rewritten (1.0.0 first cut, product version vs `libvmaf.so.3` SONAME, corrected 34-entry required-check inventory, the `autorelease: cut` freeze procedure, the release-bot and environment prerequisites). Research digest, rebase note, state.md rows and a changelog fragment ship with it. Does not tag, publish, merge, or trigger any release workflow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ADR-0334 state.md convention wants the merged PR number, not a branch name or a placeholder. Backfilled now that gh pr create has returned the number. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lease PR Two repairs on top of the ADR-1151 pipeline work. 1. Finding 1 was documented but not implemented. `release-please.yml` still passed `secrets.GITHUB_TOKEN` to both release-please invocations and held `contents: write`. GitHub suppresses follow-on workflow events for anything that token creates, so release PRs received zero check runs and the sole required context could never report. The job now mints a scoped installation token with SHA-pinned `actions/create-github-app-token` v3.2.0 and routes both release-please steps and both read-only `gh api` probes through it; the job's own token drops to `contents: read`. A preflight step fails with a remediation message when `RELEASE_BOT_APP_ID` or `RELEASE_BOT_PRIVATE_KEY` is absent, so the workflow can never silently fall back. 2. Promoting the six rule-enforcement gates into the aggregator's `required` array made two of them permanently red on a release PR — the same unmergeable-without-admin-bypass outcome the change exists to remove. Reproduced: `deliverables-check.sh` exits 1 with six missing-deliverable errors on a release-please-shaped body (its only exemption was `port:`), and the doc-substance gate path-maps the `mcp-server/vmaf-mcp/pyproject.toml` version marker to a mandatory `docs/mcp/` edit a release PR never has. The four authoring-discipline gates now consult the new `scripts/ci/release-pr-exempt.sh` and skip their work step on a machine-generated release PR, reporting green rather than absent. The predicate requires a bot author as well as a `release-please--` head ref, so branch naming alone cannot disarm a required gate. `Release Script Contract` and `ADR Number Collision Guard` stay armed there, and the former runs the predicate's own 9-case test suite. Docs: `docs/development/release.md` gains "Release-bot identity" (the one-time App setup) and "Process gates on the release PR" (which four stand down, why, and the local dry-run command); ADR-1151 gains the decision text plus six alternatives rows; the research digest gains a review-round addendum recording both the unimplemented half and the regression; `scripts/ci/AGENTS.md` records the predicate's invariants. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ADR-1151 explanatory comment spelled out the literal x-release-please-version token while explaining that the packaging version deliberately does not carry it. verify-release-version.sh and rollover-changelog-fragments.sh both count marker occurrences per file, so the comment itself registered as a second marker and would have hard-failed every release preflight — the exact failure the comment warned about. Reworded so the file carries exactly one marker, on appVersion. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lusoris
force-pushed
the
fix/release-please-setup
branch
from
September 3, 2026 05:14
64150bb to
8fd1f7a
Compare
5 of 7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Repairs the release-please pipeline and retargets it onto a fresh VMAFx number line. The fork has never released — zero GitHub releases, zero fork-made tags, and every
vX.Y.Ztag reachable frommasterbelongs to Netflix upstream history (git merge-base --is-ancestor v3.2.0 origin/masteris false). ADR-1127's "first release is v3.2.1" rested on the 3.2.x manifest baseline, which was a source-version alignment with Netflix's SONAME, not a release. ADR-1151 supersedes that choice: the first release isv1.0.0.An audit of the pipeline that would have produced that tag found it unable to release correctly at all — four P0s. This PR fixes what a code change can fix and leaves the pipeline correct and idle. It does not tag, publish, merge, reopen #1175, or trigger
supply-chain.yml/docker-publish-*. It stays DRAFT until the open questions below are answered.Maintainer-requested evidence — the dry run now reads 1.0.0
--config-fileis resolved on the remote branch, so a local edit cannot be dry-run tested. Run against this pushed branch:Exit 0. The component in the title is the
--target-branchargument; onmasterit renderschore(master): release 1.0.0. Before this PR the same command emittedtitle: chore(master): release 3.2.1.The same log also confirms
docker/Dockerfile.nodehas left the coordinated-marker set (it no longer appears in the updater list) and that release-please parses the config unchanged with the new_comment_*keys present.Type
feat— new featurefix— bug fixperf— performance improvementrefactor— no behavior changedocs— documentation onlytest— test-onlybuild/ci— tooling / infraport— cherry-pick from upstream Netflix/vmafsycl/cuda/simd— backend-specificFinding → fix mapping
release-please.ymlauthenticated withsecrets.GITHUB_TOKEN, GitHub suppresses follow-on workflow events from it, so the sole required context could never report and the PR satBLOCKED.actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1(v3.2.0); both release-please invocations and both read-onlygh apiprobes consumesteps.app-token.outputs.token, and the job's ownGITHUB_TOKENdrops fromcontents: writetocontents: read. Creating the App and its two secrets stays a repo-admin action (Q6), and a preflight step fails the job with a remediation message whileRELEASE_BOT_APP_ID/RELEASE_BOT_PRIVATE_KEYare absent — the audit's explicit "fail loudly rather than fall back" requirement. Documented indocs/development/release.md§Release-bot identity; the remaining admin half is tracked asT-RELEASE-BOT-IDENTITY-2026-09-03indocs/state.md.release-as→"1.0.0", manifest →"0.0.0"so0.0.0 → 1.0.0is a monotone forward bump. Proven by the dry run above.CHANGELOG.mdwhose newest section was still## [Unreleased]over 1,550 live fragments.scripts/release/verify-release-version.sh(the tag-time preflight all three publication workflows run) gains five fail-closed assertions: exactly one## [X.Y.Z] - YYYY-MM-DDheading;changelog.d/releases/X.Y.Z.jsonexists with matching.version; zero active fragments across the six section dirs; no_pre_fragment_legacy.md; no survivingrelease-as/bootstrap-sha. 11 new regression cases.release-publishdoes not exist andpypi-publishhas no rules; GitHub auto-creates a referenced environment with an empty rule set, so twelve write-bearing jobs ran with no approval gate — whilerelease.md:56claimed the opposite.supply-chain.yml'svalidate-releasegains a read-onlygh api .../environments/{release-publish,pypi-publish}preflight that fails closed unless each carries arequired_reviewersrule.release.mdcorrected. Creating the environments is a repo-admin action (T-RELEASE-PUBLISH-ENVIRONMENTS-MISSING-2026-09-03).release-asis a deprecated, persistent override applied after commit analysis — left in place it pins every future release._comment_release_asnaming it one-shot. TheRelease Script Contract (ADR-1128)job now fails if either one-shot field survives once the manifest reaches 1.0.0 (inert at 0.0.0, arms the moment the first release lands).rollover-changelog-fragments.shnow also deletes the two_comment_*keys so no orphan explanation survives.Release Script Contract (ADR-1128)and five sibling rule-enforcement gates were reporting but not required — a red release-script contract blocked nothing, and no admin bypass was needed to merge past them.requiredarray. They trigger onpull_requestand carry the same draft gate as the existing entries, so they genuinely report on every non-draft PR. Required-check inventory inrelease.mdcorrected (it claimed 25 named contexts; protection names exactly one, and the aggregator's own list is the real 34-entry inventory).release-as.Detect a hand-finished release PR frozen for mergestep; the PR-update invocation is skipped while anyrelease-please--PR carries theautorelease: cutlabel. Freeze procedure documented inrelease.md.mustReportlist —Release Script Contract (ADR-1128),Netflix CPU Golden Tests (D24),Build — Ubuntu gcc (CPU) + DNN— that fails on absence when the head ref starts withrelease-please--..release-please-manifest.jsonandrelease-please-config.jsonjoined thec_coreselector in.github/ci-impact.jsonso those jobs do real work instead of a no-op success. False claim atrelease.md:53-54corrected.release.mdtable, and in an ADR-citing comment directly abovevmaf_soname_versionatcore/meson.build:19.T-RELEASE-MASTER-MARKERS-3-2-1-2026-09-03.bootstrap-shatruncates the first release's generated notes to 31 commits._comment_bootstrap_shaciting ADR-1151, and is covered by the finding-5 guard. Blast radius stays bounded byskip-changelog: true: only the PR/draft body, neverCHANGELOG.md.+refs/tags/*:refs/tags/upstream/*plus a "tag must not exist on Netflix/vmaf" guard is a policy call. Tracked asT-RELEASE-NETFLIX-TAG-NAMESPACE-2026-09-03.sentence-caseplugin mangles camelCase identifiers in published release notes.specialWordsis a policy call; a custom list replaces the built-in['gRPC','npm']defaults.workflow_dispatchnever restores thelatestcontainer tags.enable=sites now read a newvalidate-releaseoutput resolved fromgh api repos/$GITHUB_REPOSITORY/releases/latest, so the guard is identical on both trigger paths. Documented inrelease.md's recovery section.release-type: simplewarns on a missingversion.txtevery run.extra-files.pkg/version/version.godocuments a repo-rootVERSIONfile that does not exist.VMAFX_VERSIONbuild-arg →-ldflags -Xflow; the stalev3.x.yexample updated tov1.x.y.docker/Dockerfile.nodeis the only annotated Dockerfile; its siblings default todev.ARG VMAFX_VERSION=devlike its siblings, marker comment removed, and itsextra-filesrow dropped —verify-release-version.shderives its list from that array, so the two stay consistent automatically. Ten coordinated markers → nine.version, threeCargo.tomls and the rootpyproject.tomlare uncoupled and unexplained.version:alongsideappVersion:would hard-fail every release preflight (both scripts require exactly one marker per file).Open policy questions (why this stays DRAFT)
Each was listed as not-for-implementation in the brief. None is implemented; all are documented here, in ADR-1151's follow-ups, and in
docs/state.md.0.0.0(the audit's recommendation) so0.0.0 → 1.0.0is a monotone forward bump rather than arelease-as-forced downgrade from3.2.0. The maintainer's binding decision required some value that makes release-please compute 1.0.0, so a value had to be chosen to produce the requested evidence; the dry run above proves this one works. Say the word and it flips to3.2.0.bootstrap-shafor the 1.0.0 cut. Kept at98dc0b2b, so generated notes cover ~31 commits from 2026-08-31 and the fragment-rendered## [1.0.0]section is the authoritative notes. Repoint further back, or remove it and let release-please walk the whole fork history?v4.0.0-lusoris.0artefacts. No such git tag exists onoriginor locally, and there have been zero GitHub releases, so nothing to delete on those surfaces. GHCR could not be checked — this token lacksread:packages(HTTP 403). Shouldghcr.io/vmafx/*be enumerated and any4.0.0-lusoris.0image (plus anylatestpointing at it) deleted, and by whom?+refs/tags/*:refs/tags/upstream/*withtagOpt = --no-tagsplus a "tag must not exist on Netflix/vmaf" guard, or accept the shared namespace and rely on 1.x-vs-3.x divergence?RELEASE_BOT_APP_ID/RELEASE_BOT_PRIVATE_KEYis the maintainer action that remains;release-please.ymlis deliberately hard-down until then. Say so if you would rather use a PAT and the twowith:inputs change; the rest of the wiring is identical.sentence-caseplugin. Drop it ("plugins": []), or keep it with an explicitspecialWordslist that must re-listgRPCandnpmbecause a custom list replaces the defaults (and will raise an editor schema warning, sincespecialWordsis documented only underlinked-versions)?version.txt. Add a real one-liner (silences the every-run⚠ file version.txt did not exist, but becomes an eleventh coordinated marker), or leave it absent and document the warning as expected output?Deliberately out of scope
Repo-admin or live-release actions, not code: creating the GitHub App and its two secrets; creating
release-publish/pypi-publishwith a required reviewer and av*tag policy; any tag / release / publish action.Checklist
make format && make lintis green locally —pre-commit run --filesover all 34 changed paths is green (shfmt, shellcheck, markdownlint-cli2, check-json/yaml/toml, gitleaks, ADR collision guard). No C/C++/Python source changed, so the clang-tidy / cppcheck / ruff / black / semgrep lanes have no files to check.test-verify-release-version.sh18/18,test-rollover-changelog-fragments.sh11/11,test-concat-changelog-fragments.sh5/5,test-verify-native-release-artifacts.sh7/7, plustest-docker-publish-source-binding.shandtest-publication-environment-binding.sh. No C is touched, someson test -C buildis unaffected./cross-backend-diffand the worst ULP is ≤ 2 — N/A, no SIMD/GPU code path touched (core/meson.buildgains a comment block only)..c/.cpp/.cu/.h/.hpp, it has the appropriate license header — N/A, no new source files.!orBREAKING CHANGE:and the migration path is documented below — not a code-breaking change; the version-line change is documented in ADR-1151 andrelease.md.docs/adr/_index_fragments/<NNNN-slug>.mdand the slug is appended todocs/adr/_index_fragments/_order.txt—1151-vmafx-first-release-1-0-0;docs/adr/README.mdregenerated withscripts/docs/concat-adr-index.sh --write(--checkgreen).Bug-status hygiene (ADR-0165)
docs/state.mdupdated in this PR — two rows under Recently closed (T-RELEASE-PIPELINE-1-0-0-LINE-2026-09-03,T-RELEASE-STALE-VERSION-DOCS-2026-09-03) and four under Deferred (waiting on external trigger) for the repo-admin blockers and open policy questions (T-RELEASE-BOT-IDENTITY-2026-09-03,T-RELEASE-PUBLISH-ENVIRONMENTS-MISSING-2026-09-03,T-RELEASE-MASTER-MARKERS-3-2-1-2026-09-03,T-RELEASE-NETFLIX-TAG-NAMESPACE-2026-09-03).Netflix golden-data gate (ADR-0024)
assertAlmostEqual(...)score in the Netflix golden Python tests.Cross-backend numerical results
Not applicable — no SIMD, GPU, or numeric code path is touched by this PR.
Deep-dive deliverables (ADR-0108)
docs/research/1151-release-please-audit-2026-09-02.md(the full 18-finding read-only audit, preserved verbatim as the audit trail).docs/adr/1151-vmafx-first-release-1-0-0.md## Alternatives considered(v1.0.0 / continue v3.2.1 / start v4.0.0 / keep-lusoris.N).AGENTS.mdinvariant note —scripts/release/AGENTS.mdgains a "Release-line invariants (ADR-1151)" section: the 1.0.0 line,release-as/bootstrap-shaare one-shot, product version vs ABI SONAME,extra-filesis the single marker list with exactly one marker per file, and release-please force-recreates its own branch.changelog.d/fixed/1151-release-please-setup.md;CHANGELOG.mdregenerated viascripts/release/concat-changelog-fragments.sh --write(--checkgreen).docs/rebase-notes.mdentryfix/release-please-setup — 1.0.0 release line + pipeline repair (2026-09-03).core/meson.buildis the only upstream-mirrored file touched (a comment block abovevmaf_soname_version, plus the pre-existing release marker on line 2); everything else is fork-only release tooling with no upstream counterpart.Reproducer
Review round 2 (2026-09-03)
Two defects found reviewing the first push, both fixed at the root cause.
Finding 1 was prose-only.
release-please.ymlstill carriedtoken: ${{ secrets.GITHUB_TOKEN }}at both release-please steps andcontents: writeon the job;grep -rn create-github-app-token .github/matched nothing. The App-token step is now actually there, SHA-pinned, with
both
gh apiprobes routed through it and a fail-loud preflight.The required-array promotion was a regression. Making
Deep-Dive Deliverables Checklist (ADR-0108)andDoc-Substance Gate (ADR-0100 / 0167)required guarantees a red check onevery release PR — the exact unmergeable-without-admin-bypass outcome this
PR claims to remove. Proven, not inferred:
deliverables-check.shexits 1with all six missing-deliverable errors on a release-please-shaped body (its
only exemption was a
port:title /port/branch), and the release PRupdates
mcp-server/vmaf-mcp/pyproject.toml, which doc-substance path-mapsto a mandatory
^docs/mcp/edit. Two more of the six are latent: thedocs/state.mdgate trips on acloses #Na changelog entry can inheritfrom a commit subject, and the ffmpeg-patch gate is diff-driven over a
surface list a future marker could intersect.
All four authoring-discipline gates now call the new
scripts/ci/release-pr-exempt.shfirst and skip their work step on amachine-generated release PR — reporting green, not absent, so a genuine
path-filter skip stays distinguishable. The predicate needs a bot author as
well as a
release-please--head ref, so nobody disarms a required gate bynaming a branch.
Release Script ContractandADR Number Collision Guardstay armed on release PRs, and the former runs the predicate's own 9-case
test suite, so the exemption cannot rot unnoticed. Documented in
docs/development/release.md§"Process gates on the release PR",docs/adr/1151-*.md(decision text + six alternatives rows),scripts/ci/AGENTS.md(invariants), and an addendum to the research digest.Rebased onto
origin/master(was two commits behind andCONFLICTING;conflicts were
docs/adr/README.mdanddocs/adr/_index_fragments/_order.txt,both additive index rows — kept both, in ADR-number order).
concat-adr-index.sh --checkandconcat-changelog-fragments.sh --checkaregreen on the rebased tree, and the dry run still reads
title: chore(fix/release-please-setup): release 1.0.0,updates: 11.Known follow-ups
supply-chain.ymlfails closed by design — that is the intended state while the release is deferred.git rev-parse --is-shallow-repository→true), which distorts everyv3.2.0..HEADrange query; it was unshallowed before the history claims above were made (4,520 commits reachable).