Implements two ADR 0053 exit criteria (decision 1 and section 7) without changing what the manifest reports.
Schema
registry/support/schema/v1.json replaces its const pins with closed enums:
current_release.maturity:alphaorsupported(reuses the existingstatusvocabulary).$defs.maturity(componentcurrent_maturity) addssupported. The validator allows it only forblessed_corecomponents with target statussupportedin a production-ready release.current_release.production_ready: boolean.artifact_pinning:not_yet_publishedorpublished.production.status:blocked,required_before_release, orpassed.
Validator
scripts/validate_support_manifest.py enforces what the schema cannot:
production_ready: truerequires all five required gatespassedand everyblessed_coregate componentpassedornot_required.production.statusis derived:blockeduntil those gates pass,required_before_releasewhileproduction_readyis false, andpassedonly withproduction_ready: true.maturity: supportedexactly whenproduction_ready: true.- A gate component with no applicable gates must report
not_required, and it still needs checked evidence. Before this change it could only fail. - Release guard: a
current_release.versionat or above 1.0.0 is rejected unlessproduction_readyis true. Versions are parsed with the full PEP 440 grammar (spelling variants, epochs, local labels) and ordered as in PEP 440, so1.0.0rc1and1.0.0.dev1sort below 1.0.0 and are allowed, which matches the ADR's "explicit pre-release suffix" wording.1.0.0.post1and1.1.0rc1are rejected. An unparseable version also fails.
Where the guard runs
relx rewrites current_release.version in the release PR. The always-run ci-config step in ci.yml validates the manifest, and pr.yml runs it on that PR and in the merge queue. release_stage.py reserve requires a successful exact-SHA Main source health run, which reuses or reruns the same pr.yml checks. No workflow change was needed.
ReleaseX replacement
The current_release.version replacement in relx.toml now matches "version": "X",\n "maturity": " without the maturity value, so it still matches exactly once after the manifest flips to supported. A new test in tests/tooling/test_release_replacements.py covers both maturities. The versioning strategy is unchanged. docs/contributing/release-publication.md now says the readiness flip and regenerated reference docs land on main before the release PR.
Unchanged
registry/support/v1.json still reports alpha, production_ready: false, not_yet_published, and production.status: blocked, and it still validates. The relx replacement still matches exactly once.
Verification
make check: every lane passed on the final tree (exit 0).python3 -I scripts/validate_support_manifest.py,check_version_drift.py,check_ci_package_groups.py, andgenerate_reference_docs.py --checkall pass.- The new tests in
tests/tooling/test_support_manifest.pyfail against the previous validator: 13 failures before the review fixes. More cases were added afterwards.
Activity
316Reviewed 373e88c against ADR 0053 and the release tooling. The new validator rules match decision 1 on inspection, but the 1.0 release path has an integration break and two consistency gaps.
1. relx cannot generate a release PR once the readiness claim is true (blocking)
relx.toml#L18-L23 rewrites current_release.version with a literal search that includes "maturity": "alpha" and expected_matches = 1. The new rule at validate_support_manifest.py#L951-L954 requires maturity: supported whenever production_ready is true, and test_support_manifest.py#L729-L730 explicitly accepts a production-ready manifest at 0.18.0, so flipping readiness on main before the version bump is a supported state.
Once main carries "maturity": "supported", the relx search finds zero matches: the 1.0.0 release PR, and every release PR after it, fails expected_matches = 1. If the flip is deferred into the release PR instead, relx writes 1.0.0 with maturity: alpha and production_ready: false, and this PR's guard rejects the PR, leaving a manual edit that release-publication.md#L61 currently says is not required.
Please make the replacement maturity-agnostic (the current_release block is unique, so the version line can be matched without the maturity line), or update relx.toml as part of the 1.0 change, and document the readiness flip and doc regeneration step. The "still matches exactly once" note only holds while the manifest is alpha.
2. A 1.0 manifest still cannot report its components as supported
schema/v1.json#L69-L72 omits supported from $defs.maturity, and validate_support_manifest.py#L466-L474 maps target_status: supported to current_maturity: alpha (enforced at #L569-L573). A 1.0 manifest therefore either keeps every blessed component at alpha — and the generated matrix will say "Release 1.0.0 has supported maturity" next to "Current maturity: alpha" for each package (generate_reference_docs.py#L385, #L412) — or fails validation if a component is set to supported. If 1.0 is meant to cover those components, the enum and _EXPECTED_MATURITY need the same change; otherwise the generated page should distinguish release maturity from component maturity.
3. Version parsing is narrower than the documented PEP 440 contract (minor)
The regex at validate_support_manifest.py#L919 accepts only a subset of PEP 440. 1.0.0-rc.1 and 1.0.0_rc1 are valid PEP 440 pre-releases of 1.0.0 (normalizing to 1.0.0rc1) but are reported as "not a PEP 440 version"; 1.0.0.0rc1 is treated as at or above 1.0.0 because the release tuple is not exactly (1, 0, 0) and the suffix is ignored (#L923-L925). If those spellings can reach pyproject.toml, the guard blocks legitimate pre-releases; otherwise narrow the error wording and the generated docs to the grammar actually accepted.
Checked the schema, validator, generated docs, relx replacements, and the source-health/staging path. PR Validation run 41145946487 was still queued at review time, so the claimed make check result is not yet corroborated by CI. I did not execute PR code.
373e88c, the branch has moved onArchitecture
Data flow
Review
2 findings addressed · reviewed
373e88c·_version_is_at_least_1_0rejects valid PEP 440 pre-releases of 1.0.0scripts/validate_support_manifest.py:919· ✅ Addressed in ad94ce7·not_requiredgate component is documented as accepted but always failsscripts/validate_support_manifest.py:904-905· ✅ Addressed in ad94ce7🪧 More tips
npx skills add coldteadotai/pr-lens, then tell your coding agent: "Diagram the change you just made with PR Lens and attach it to the pull request."npx @coldtea/pr-lens-cli analyze --base origin/mainon a branch, thennpx @coldtea/pr-lens-cli render .pr-lens/graph.json. Same lenses, your own model key, before the pull request existsrenderreads.github/pr-lens.ymland applies your renames, exclusions and lane pins at draw timegithub.comment.collapsed: truein.github/pr-lens.ymlto fold the comment behind one View architecture… row. Drawing still runs as beforegithub.draw: on-demandin.github/pr-lens.ymland PR Lens stops drawing pull requests on its own. Comment@pr-lens drawon a pull request when you want that one drawn.github/workflows/pr-lens.ymlwithcoldteadotai/pr-lens/packages/action@v0and your model provider's key as itsapi-keyto run PR Lens from your own CI. Any/chat/completionsendpoint worksgithub.description: falsein.github/pr-lens.ymlto stop PR Lens adding buttons to your PR descriptionsThanks for using PR Lens! It's free for OSS. If it helped, a star helps other teams find it.