OpenClaw Release CI
Use this with $release-openclaw-maintainer and $openclaw-testing when a release candidate needs full validation, install/update proof, live provider checks, or CI recovery.
Guardrails
- No version bump, tag, npm publish, GitHub release, or release promotion without explicit operator approval.
- Hold the release scope once a release branch or Code SHA exists. Validate and
ship that exact release; do not turn moving
main into a second work queue.
- Use trusted
main workflow revisions as immutable dispatch sources. Do not
adopt newer main code, repair unrelated main CI, wait for broad main health,
or expand a release fix because the workflow source lives on main.
- Touch
main only for an operator-requested change or the smallest critical
main-owned blocker that prevents this release and cannot be handled from the
release branch. If the required main landing policy is blocked by unrelated
main failures, report that blocker and keep independent release work moving
instead of healing broader main.
- Validate provider secrets before dispatching expensive full release matrices.
- Do not set GitHub secrets from unvalidated 1Password candidates. If a candidate returns 401/403, leave the existing secret alone and report the exact missing provider.
- Use
$one-password for secret reads/writes: one persistent tmux session, targeted items only, no secret output.
- Watch one parent run plus compact child summaries. Avoid broad
gh run view polling loops; REST quota is easy to burn.
- Fetch logs only for failed or currently-blocking jobs. If quota is low, stop polling and wait for reset.
- Treat live-provider flakes separately from code failures: prove key validity, provider HTTP status, retry evidence, and exact failing lane before editing code.
- A model-list response proves authentication, not billing or inference
entitlement. Mandatory live providers must pass a real completion probe
before release dispatch. Fix the credential first; do not add an alternate
auth path merely to bypass a failed release credential.
- Full Release Validation collects independent child failures to terminal
completion by default. Pass
fail_fast=true only when the shorter
first-failure cancellation path is preferable.
- For regular beta/stable releases, treat the product-complete pre-changelog
commit as the Code SHA. Full product validation and performance evidence bind
to that SHA. The later Release SHA may reuse those results only when it is a
descendant whose complete changed path set is exactly
CHANGELOG.md.
- Extended-stable validates one exact branch tip; it does not reuse the regular
Code-SHA/Release-SHA evidence model.
- In a sparse worktree or Testbox source sync, first confirm
package.json,
pnpm-lock.yaml, and every source path the selected check reads. If any are
absent, that checkout cannot validate a release dependency or Docker lane:
stop and use the repo remote changed gate or a full task worktree. When the
inputs are present and a release fix changes package.json or
pnpm-lock.yaml, rebuild only the task-owned disposable box with
CI=true pnpm install --frozen-lockfile, then run an explicit
require.resolve() probe before Docker or focused tests. The CI flag permits
pnpm to recreate a prewarmed modules directory without an interactive
confirmation. Do not weaken the lockfile or label sparse-checkout failures
as product/Docker failures.
- If the candidate is rebased or its base SHA changes after warmup, stop the
task-owned box and warm a fresh one before testing. Testbox source sync is
relative to the warmed source tree; continuing can mix an old base file with
a new candidate diff and produce false lockfile or Docker failures.
- Reused Testboxes are provenance-gated after their first successful run.
Source-only edits may reuse the lease; base, dependency, wrapper, or Testbox
workflow drift requires a fresh lease. Do not set
OPENCLAW_TESTBOX_ALLOW_STALE=1 for release evidence.
- For a committed release candidate, warm the box with
blacksmith testbox warmup ... --ref <candidate-branch-or-sha>. Do not rely
on source sync to overlay committed branch changes onto the workflow's
default ref.
Run identity and retry budget
Record the target SHA, target ref, parent run id, attempt, and effective
workflow SHA before watching or recovering Full Release Validation.
- One target SHA has one active canonical
rerun_group=all parent run by
default.
- Use GitHub's failed-job rerun on the same parent when its original inputs
still select the correct work.
- A new parent for the same target SHA is allowed only when no usable parent
exists, the existing run cannot consume a required trusted-workflow fix, its
evidence identity is invalid, or the operator explicitly requests a fresh
run. The replacement must also use
rerun_group=all; record which terminal
parent it supersedes and why.
- A narrow
rerun_group dispatch is supplemental diagnostic proof only. It
never supersedes the canonical parent and cannot satisfy publish evidence.
Run it only after the canonical parent is terminal, then obtain green
rerun_group=all evidence before publish.
- Never keep two parents active for the same SHA. Cancel only the superseded
task-owned run after the replacement is identified.
- After two unchanged retries of the same failure, stop repeating it. Recheck
classification and report one precise blocker or the missing evidence needed
for a different action.
Preflight
Before full release validation:
node .agents/skills/release-openclaw-ci/scripts/verify-provider-secrets.mjs --required openai,anthropic,fireworks
gh api rate_limit --jq '.resources.core'
git status --short --branch
git rev-parse HEAD
1Password service-account values are the first source for release provider
preflight. Inject those exact targeted keys first, then run the verifier; use
ambient env only when it was already intentionally injected for this release.
The script prints only provider status and HTTP class, never tokens.
The Anthropic check performs a tiny message completion so exhausted or
non-billable credentials fail before the expensive release matrix.
Dispatch
Start product performance evidence as early as the Code SHA exists, in
parallel with other release work:
gh workflow run openclaw-performance.yml \
--repo openclaw/openclaw \
--ref main \
-f target_ref=<code-sha> \
-f profile=release \
-f repeat=3 \
-f deep_profile=false \
-f live_openai_candidate=false \
-f fail_on_regression=true
- Do not wait for full release validation to start this early perf signal.
- Compare available Kova, gateway startup, and CLI startup metrics with earlier
release evidence or clawgrit reports before publish/closeout.
- Call out any regression in the release proof. Treat a major regression as a
release blocker until it is fixed, waived by the operator, or proven to be
infrastructure noise.
- Full Release Validation records blocking product-performance evidence. The
early standalone run is for overlap and faster regression discovery, but a
regression or missing child run blocks the parent validation.
Prefer an immutable trusted-main workflow revision, target the exact Code SHA:
- Keep trusted-workflow checks compatible with frozen release targets. If
main adds a target-owned guard script or package command after the release
branch cut, make the trusted workflow skip only when that target surface is
absent. Repair the smallest trusted-workflow compatibility issue only when it
blocks the release, then rerun validation. Do not port an unrelated runtime
refactor, heal other main failures, or mutate the release candidate just to
satisfy a newer main-only check.
node scripts/full-release-validation-at-sha.mjs \
--sha <code-sha> \
--target-ref release/YYYY.M.PATCH
For immutable workflow proof on a moving main, use
pnpm ci:full-release --sha <code-sha> --target-ref release/YYYY.M.PATCH. Its canonical release-ci/* ref keeps evidence reuse
enabled after proving the workflow commit is still on trusted main lineage.
Pass -f reuse_evidence=false only when the operator intentionally needs a
fresh full run.
After the Code SHA is green, commit only CHANGELOG.md and run the same helper
against the Release SHA. The parent must report
policy=changelog-only-release-v1, evidenceSha=<code-sha>, and
changedPaths=["CHANGELOG.md"]; it should reuse the product matrix instead of
dispatching child lanes. Npm preflight and package/install acceptance still run
against the exact Release SHA and its new tarball bytes.
The SHA-pinned helper infers beta for alpha/beta package versions and stable
for stable/correction versions. Pass release_profile=full only when the
operator explicitly asks for the broad advisory provider/media matrix. Stable
and full profiles force the release soak; the beta profile may opt in with
run_release_soak=true. Use narrow rerun_group after focused fixes.
Publish with openclaw-release-publish.yml using release_profile=from-validation
unless a maintainer intentionally wants to cross-check a specific profile; the
publish workflow reads the effective profile from the full-validation manifest.
Extended-stable validation
For .33+, dispatch from and target the canonical branch; the regular
SHA-pinned helper would produce a rejected release-ci/* identity:
gh workflow run full-release-validation.yml \
--ref extended-stable/YYYY.M.33 \
-f ref=extended-stable/YYYY.M.33 \
-f release_profile=stable
Accept only a complete rerun_group=all run whose branch, head/target SHAs,
manifest workflowRef, and package versions identify the same commit. Save its
successful run_attempt and require the final tag to resolve there. Reject
release-ci/*, current-main, narrow, and earlier-attempt evidence.
Product failures need an approved backport. Frozen-target tooling failures need
the smallest behavior-preserving repair. Provider, approval, runner, or log
races keep the candidate unchanged. Record repairs and superseded runs; any
branch change requires a new complete parent. Omit only an explicitly
unsupported frozen-target scenario, never a required behavior or package.
Watch
Use the transition-only summary watcher instead of repeated raw polling:
node scripts/release-ci-summary.mjs <full-release-run-id> --watch
For a one-shot snapshot:
node scripts/release-ci-summary.mjs <full-release-run-id>
Stop watchers before ending the turn or switching strategy.
Failure Triage
- Confirm parent SHA and child run IDs.
- List failed jobs only:
gh run view <child-run-id> --repo openclaw/openclaw --json jobs \
--jq '.jobs[] | select(.conclusion=="failure" or .conclusion=="timed_out" or .conclusion=="cancelled") | [.databaseId,.name,.conclusion,.url] | @tsv'
- Fetch one failed job log. If rate-limited, note reset time and avoid more REST calls.
- For secret-looking failures, validate a real completion from the same secret source before editing code. A successful model-list request is insufficient.
Claude CLI subscription credentials are a separate native auth path; prove
them in a clean-home CLI probe, never as a substitute for a required
Anthropic API-key lane.
- For live-cache failures, inspect whether it is missing/invalid key, empty text, provider refusal, timeout, or baseline miss. Do not weaken release gates without clear provider evidence.
- Classify before editing:
- product/code failure: fix the release branch, freeze a new Code SHA, run
focused proof, then obtain green full validation for that new SHA
- workflow/harness/infrastructure/credential failure: fix the smallest
owning surface and rerun failed jobs on the current parent when its inputs
still select the correct work; otherwise supersede the terminal parent once
with a new
rerun_group=all parent on the required trusted-workflow
revision. Keep the same Code SHA; touching main still requires the active
release scope lock
- changelog/release-note failure: change only
CHANGELOG.md, keep Code SHA
evidence, and repeat Release SHA proof
- publish child/registry selector failure: keep Release SHA and resume the
failed child; never rebuild an immutable version that already published
- If a required PR CI run is capacity-stalled with queued jobs and no active
jobs, do not cancel unrelated work or accept a generic manual dispatch.
First verify the PR head carries the current fallback schema:
gh api 'repos/openclaw/openclaw/contents/.github/workflows/ci.yml?ref=<pr-head-branch>' --jq .content | base64 --decode | rg -q 'pull_request_number:'. If absent,
refresh the PR head from main and use the new head SHA; let normal CI run
before considering another fallback.
From the PR head branch, dispatch the explicit exact-SHA fallback:
gh workflow run ci.yml --repo openclaw/openclaw --ref <pr-head-branch> -f target_ref=<full-pr-sha> -f pull_request_number=<pr-number> -f include_android=true -f release_gate=true.
It runs on GitHub-hosted runners and is accepted only when its run title is
CI release gate <full-pr-sha>. Record the stalled Blacksmith run and the
fallback run in release evidence.
If Blacksmith Build Artifacts Testbox is the only remaining required gate
and remains queued without a runner, that completed exact fallback may cover
it because CI's build-artifacts job already builds, packages, and smoke
tests the artifacts. Do not use this coverage after the artifact workflow
starts or completes non-successfully.
Evidence
Record:
- release identity: Code/Release SHAs for regular releases; canonical branch,
exact SHA, and immutable tag for extended-stable
- evidence-reuse policy and complete changed-path set
- active full parent run URL, attempt, workflow SHA, and any superseded parent
with the exact replacement reason
- child run IDs and conclusions: CI, Release Checks, Plugin Prerelease, NPM Telegram, Product Performance
- performance comparison result versus earlier releases when available
- targeted local proof commands
- provider-secret preflight result
- frozen-target compatibility repairs or omitted inapplicable scenarios, with
their source PRs and invariant
- known gaps or unrelated failures
For lessons and recovery patterns, read references/release-ci-notes.md.
1---2name: release-openclaw-ci3description: Run, watch, debug, and summarize OpenClaw full release CI, release checks, live provider gates, install/update proofs, and release-secret preflights.4---56# OpenClaw Release CI78Use this with `$release-openclaw-maintainer` and `$openclaw-testing` when a release candidate needs full validation, install/update proof, live provider checks, or CI recovery.910## Guardrails1112- No version bump, tag, npm publish, GitHub release, or release promotion without explicit operator approval.13- Hold the release scope once a release branch or Code SHA exists. Validate and14 ship that exact release; do not turn moving `main` into a second work queue.15- Use trusted `main` workflow revisions as immutable dispatch sources. Do not16 adopt newer main code, repair unrelated main CI, wait for broad main health,17 or expand a release fix because the workflow source lives on `main`.18- Touch `main` only for an operator-requested change or the smallest critical19 main-owned blocker that prevents this release and cannot be handled from the20 release branch. If the required main landing policy is blocked by unrelated21 main failures, report that blocker and keep independent release work moving22 instead of healing broader main.23- Validate provider secrets before dispatching expensive full release matrices.24- Do not set GitHub secrets from unvalidated 1Password candidates. If a candidate returns 401/403, leave the existing secret alone and report the exact missing provider.25- Use `$one-password` for secret reads/writes: one persistent tmux session, targeted items only, no secret output.26- Watch one parent run plus compact child summaries. Avoid broad `gh run view` polling loops; REST quota is easy to burn.27- Fetch logs only for failed or currently-blocking jobs. If quota is low, stop polling and wait for reset.28- Treat live-provider flakes separately from code failures: prove key validity, provider HTTP status, retry evidence, and exact failing lane before editing code.29- A model-list response proves authentication, not billing or inference30 entitlement. Mandatory live providers must pass a real completion probe31 before release dispatch. Fix the credential first; do not add an alternate32 auth path merely to bypass a failed release credential.33- Full Release Validation collects independent child failures to terminal34 completion by default. Pass `fail_fast=true` only when the shorter35 first-failure cancellation path is preferable.36- For regular beta/stable releases, treat the product-complete pre-changelog37 commit as the Code SHA. Full product validation and performance evidence bind38 to that SHA. The later Release SHA may reuse those results only when it is a39 descendant whose complete changed path set is exactly `CHANGELOG.md`.40- Extended-stable validates one exact branch tip; it does not reuse the regular41 Code-SHA/Release-SHA evidence model.42- In a sparse worktree or Testbox source sync, first confirm `package.json`,43 `pnpm-lock.yaml`, and every source path the selected check reads. If any are44 absent, that checkout cannot validate a release dependency or Docker lane:45 stop and use the repo remote changed gate or a full task worktree. When the46 inputs are present and a release fix changes `package.json` or47 `pnpm-lock.yaml`, rebuild only the task-owned disposable box with48 `CI=true pnpm install --frozen-lockfile`, then run an explicit49 `require.resolve()` probe before Docker or focused tests. The CI flag permits50 pnpm to recreate a prewarmed modules directory without an interactive51 confirmation. Do not weaken the lockfile or label sparse-checkout failures52 as product/Docker failures.53- If the candidate is rebased or its base SHA changes after warmup, stop the54 task-owned box and warm a fresh one before testing. Testbox source sync is55 relative to the warmed source tree; continuing can mix an old base file with56 a new candidate diff and produce false lockfile or Docker failures.57- Reused Testboxes are provenance-gated after their first successful run.58 Source-only edits may reuse the lease; base, dependency, wrapper, or Testbox59 workflow drift requires a fresh lease. Do not set60 `OPENCLAW_TESTBOX_ALLOW_STALE=1` for release evidence.61- For a committed release candidate, warm the box with62 `blacksmith testbox warmup ... --ref <candidate-branch-or-sha>`. Do not rely63 on source sync to overlay committed branch changes onto the workflow's64 default ref.6566## Run identity and retry budget6768Record the target SHA, target ref, parent run id, attempt, and effective69workflow SHA before watching or recovering Full Release Validation.7071- One target SHA has one active canonical `rerun_group=all` parent run by72 default.73- Use GitHub's failed-job rerun on the same parent when its original inputs74 still select the correct work.75- A new parent for the same target SHA is allowed only when no usable parent76 exists, the existing run cannot consume a required trusted-workflow fix, its77 evidence identity is invalid, or the operator explicitly requests a fresh78 run. The replacement must also use `rerun_group=all`; record which terminal79 parent it supersedes and why.80- A narrow `rerun_group` dispatch is supplemental diagnostic proof only. It81 never supersedes the canonical parent and cannot satisfy publish evidence.82 Run it only after the canonical parent is terminal, then obtain green83 `rerun_group=all` evidence before publish.84- Never keep two parents active for the same SHA. Cancel only the superseded85 task-owned run after the replacement is identified.86- After two unchanged retries of the same failure, stop repeating it. Recheck87 classification and report one precise blocker or the missing evidence needed88 for a different action.8990## Preflight9192Before full release validation:9394```bash95node .agents/skills/release-openclaw-ci/scripts/verify-provider-secrets.mjs --required openai,anthropic,fireworks96gh api rate_limit --jq '.resources.core'97git status --short --branch98git rev-parse HEAD99```1001011Password service-account values are the first source for release provider102preflight. Inject those exact targeted keys first, then run the verifier; use103ambient env only when it was already intentionally injected for this release.104The script prints only provider status and HTTP class, never tokens.105The Anthropic check performs a tiny message completion so exhausted or106non-billable credentials fail before the expensive release matrix.107108## Dispatch109110Start product performance evidence as early as the Code SHA exists, in111parallel with other release work:112113```bash114gh workflow run openclaw-performance.yml \115 --repo openclaw/openclaw \116 --ref main \117 -f target_ref=<code-sha> \118 -f profile=release \119 -f repeat=3 \120 -f deep_profile=false \121 -f live_openai_candidate=false \122 -f fail_on_regression=true123```124125- Do not wait for full release validation to start this early perf signal.126- Compare available Kova, gateway startup, and CLI startup metrics with earlier127 release evidence or clawgrit reports before publish/closeout.128- Call out any regression in the release proof. Treat a major regression as a129 release blocker until it is fixed, waived by the operator, or proven to be130 infrastructure noise.131- Full Release Validation records blocking product-performance evidence. The132 early standalone run is for overlap and faster regression discovery, but a133 regression or missing child run blocks the parent validation.134135Prefer an immutable trusted-main workflow revision, target the exact Code SHA:136137- Keep trusted-workflow checks compatible with frozen release targets. If138 `main` adds a target-owned guard script or package command after the release139 branch cut, make the trusted workflow skip only when that target surface is140 absent. Repair the smallest trusted-workflow compatibility issue only when it141 blocks the release, then rerun validation. Do not port an unrelated runtime142 refactor, heal other main failures, or mutate the release candidate just to143 satisfy a newer `main`-only check.144145```bash146node scripts/full-release-validation-at-sha.mjs \147 --sha <code-sha> \148 --target-ref release/YYYY.M.PATCH149```150151For immutable workflow proof on a moving `main`, use152`pnpm ci:full-release --sha <code-sha> --target-ref153release/YYYY.M.PATCH`. Its canonical `release-ci/*` ref keeps evidence reuse154enabled after proving the workflow commit is still on trusted `main` lineage.155Pass `-f reuse_evidence=false` only when the operator intentionally needs a156fresh full run.157158After the Code SHA is green, commit only `CHANGELOG.md` and run the same helper159against the Release SHA. The parent must report160`policy=changelog-only-release-v1`, `evidenceSha=<code-sha>`, and161`changedPaths=["CHANGELOG.md"]`; it should reuse the product matrix instead of162dispatching child lanes. Npm preflight and package/install acceptance still run163against the exact Release SHA and its new tarball bytes.164165The SHA-pinned helper infers `beta` for alpha/beta package versions and `stable`166for stable/correction versions. Pass `release_profile=full` only when the167operator explicitly asks for the broad advisory provider/media matrix. Stable168and full profiles force the release soak; the beta profile may opt in with169`run_release_soak=true`. Use narrow `rerun_group` after focused fixes.170Publish with `openclaw-release-publish.yml` using `release_profile=from-validation`171unless a maintainer intentionally wants to cross-check a specific profile; the172publish workflow reads the effective profile from the full-validation manifest.173174### Extended-stable validation175176For `.33+`, dispatch from and target the canonical branch; the regular177SHA-pinned helper would produce a rejected `release-ci/*` identity:178179```bash180gh workflow run full-release-validation.yml \181 --ref extended-stable/YYYY.M.33 \182 -f ref=extended-stable/YYYY.M.33 \183 -f release_profile=stable184```185186Accept only a complete `rerun_group=all` run whose branch, head/target SHAs,187manifest `workflowRef`, and package versions identify the same commit. Save its188successful `run_attempt` and require the final tag to resolve there. Reject189`release-ci/*`, current-main, narrow, and earlier-attempt evidence.190191Product failures need an approved backport. Frozen-target tooling failures need192the smallest behavior-preserving repair. Provider, approval, runner, or log193races keep the candidate unchanged. Record repairs and superseded runs; any194branch change requires a new complete parent. Omit only an explicitly195unsupported frozen-target scenario, never a required behavior or package.196197## Watch198199Use the transition-only summary watcher instead of repeated raw polling:200201```bash202node scripts/release-ci-summary.mjs <full-release-run-id> --watch203```204205For a one-shot snapshot:206207```bash208node scripts/release-ci-summary.mjs <full-release-run-id>209```210211Stop watchers before ending the turn or switching strategy.212213## Failure Triage2142151. Confirm parent SHA and child run IDs.2162. List failed jobs only:217 ```bash218 gh run view <child-run-id> --repo openclaw/openclaw --json jobs \219 --jq '.jobs[] | select(.conclusion=="failure" or .conclusion=="timed_out" or .conclusion=="cancelled") | [.databaseId,.name,.conclusion,.url] | @tsv'220 ```2213. Fetch one failed job log. If rate-limited, note reset time and avoid more REST calls.2224. For secret-looking failures, validate a real completion from the same secret source before editing code. A successful model-list request is insufficient.223 Claude CLI subscription credentials are a separate native auth path; prove224 them in a clean-home CLI probe, never as a substitute for a required225 Anthropic API-key lane.2265. For live-cache failures, inspect whether it is missing/invalid key, empty text, provider refusal, timeout, or baseline miss. Do not weaken release gates without clear provider evidence.2276. Classify before editing:228 - product/code failure: fix the release branch, freeze a new Code SHA, run229 focused proof, then obtain green full validation for that new SHA230 - workflow/harness/infrastructure/credential failure: fix the smallest231 owning surface and rerun failed jobs on the current parent when its inputs232 still select the correct work; otherwise supersede the terminal parent once233 with a new `rerun_group=all` parent on the required trusted-workflow234 revision. Keep the same Code SHA; touching `main` still requires the active235 release scope lock236 - changelog/release-note failure: change only `CHANGELOG.md`, keep Code SHA237 evidence, and repeat Release SHA proof238 - publish child/registry selector failure: keep Release SHA and resume the239 failed child; never rebuild an immutable version that already published2407. If a required PR CI run is capacity-stalled with queued jobs and no active241 jobs, do not cancel unrelated work or accept a generic manual dispatch.242 First verify the PR head carries the current fallback schema:243 `gh api 'repos/openclaw/openclaw/contents/.github/workflows/ci.yml?ref=<pr-head-branch>'244--jq .content | base64 --decode | rg -q 'pull_request_number:'`. If absent,245 refresh the PR head from `main` and use the new head SHA; let normal CI run246 before considering another fallback.247 From the PR head branch, dispatch the explicit exact-SHA fallback:248 `gh workflow run ci.yml --repo openclaw/openclaw --ref <pr-head-branch> -f249target_ref=<full-pr-sha> -f pull_request_number=<pr-number> -f250include_android=true -f release_gate=true`.251 It runs on GitHub-hosted runners and is accepted only when its run title is252 `CI release gate <full-pr-sha>`. Record the stalled Blacksmith run and the253 fallback run in release evidence.254 If `Blacksmith Build Artifacts Testbox` is the only remaining required gate255 and remains queued without a runner, that completed exact fallback may cover256 it because CI's `build-artifacts` job already builds, packages, and smoke257 tests the artifacts. Do not use this coverage after the artifact workflow258 starts or completes non-successfully.259260## Evidence261262Record:263264- release identity: Code/Release SHAs for regular releases; canonical branch,265 exact SHA, and immutable tag for extended-stable266- evidence-reuse policy and complete changed-path set267- active full parent run URL, attempt, workflow SHA, and any superseded parent268 with the exact replacement reason269- child run IDs and conclusions: CI, Release Checks, Plugin Prerelease, NPM Telegram, Product Performance270- performance comparison result versus earlier releases when available271- targeted local proof commands272- provider-secret preflight result273- frozen-target compatibility repairs or omitted inapplicable scenarios, with274 their source PRs and invariant275- known gaps or unrelated failures276277For lessons and recovery patterns, read `references/release-ci-notes.md`.