* feat(release): accept exact-job recorded flakes in release validation
A release lead can classify one failed Normal CI job of a Full Release
Validation run as a flake through the trusted classification workflow. The
receipt binds the exact job id and attempt, CI child run, FRV parent run and
attempt, and Release SHA, and carries a tracking issue or PR plus a reason.
Release Decision, the manifest, the publisher's live re-derivation, the step
summary, and the GitHub release notes tail treat it as a visible advisory.
Required classes and every other child stay blocking.
* docs(release): fold recorded flakes into the shared release boundaries
* fix(release): scope flake receipt discovery to the CI child run
* fix(release): require main lineage for flake receipt producers
* test(release): copy the flake classification module into tooling fixtures
* fix(release): keep advisory-only release notes verifiable
* fix(release): record dependency advisories without blocking releases
Release dependency evidence now blocks only on known malware. Vulnerability
advisories of every severity are recorded in the evidence summary and surfaced
as GitHub warning annotations, and CI dispatched by Full Release Validation or
release publication reports a failing production audit as a warning. The
per-release risk-acceptance table existed only to accept advisory blockers and
is removed.
The release skills also record that main CI health never gates a release and
that every failed test gets an explicit real-blocker-or-flake decision.
* fix(ci): keep release audit relaxation within the workflow size budget
ci.yml sits at the 480000-byte guard, so the release-dispatch check moves
into a trusted harness script that security-fast already checks out.
* test(ci): bound the Windows process census by its owning operation deadline
* fix(release): make Windows Node CI shards advisory for release validation
* fix(ci): keep the workflow below its size limit
Since #160224 the root package depends on npm, whose v3 lock lists bundled packages under node_modules/npm/node_modules/* with inBundle and no resolved/integrity. The dependency release evidence job rejected them as unsupported lock entries. Bundled entries are now accepted only when their nearest non-bundled carrier has a verified registry tarball, and each report entry records them as bundledDependencies with that parent. Ordinary entries without resolved/integrity stay fatal.
* chore(release): retire the Tideclaw alpha release track
Tideclaw alpha/nightly publication is retired. Alpha remains readable as
history (existing v*-alpha tags, published versions, changelog and
upgrade-survivor baselines, product version ordering), but it can no longer
authorize a release.
Every active release boundary now rejects an alpha version or -alpha.N tag,
the alpha npm dist-tag, and tideclaw/alpha/* workflow or tooling routes:
preparation, Full Release Validation publication selection, npm preflight,
approval receipts, core/plugin npm and ClawHub publication, native handoffs,
and finalization. Channel mappings throw for alpha instead of falling through
to latest. The Tideclaw branch routes, alpha dist-tag options, the alpha FRV
publication route, and the alpha-only Docker runtime-assets job are removed.
Beta, stable, extended-stable, and correction releases are unchanged.
The release-openclaw-nightly skill is deleted and the release skills and docs
no longer describe the alpha track.
* test(release): drop retired alpha preparation and finalization expectations
* test(release): drop remaining retired alpha references
* docs(release): restore the npm publication bookmark
Preserve the published publish-the-npm-packages fragment after the extended-stable heading rename. Keep the current release policy and canonical maintainer procedures unchanged.
* docs(reference): split the release runbook by reader job
docs/reference/RELEASING.md was 99,140 characters and mixed reference,
how-to, and explanation content for five release jobs on one page. It is
now a 4.6k index over nine pages under docs/reference/releasing/, one per
reader job, so an operator can complete one procedure on one page.
Children, in release order:
- releasing/versioning - version formats, git tags, npm dist-tags, cadence
- releasing/preflight - checks and generators to run before tagging
- releasing/regular-release - the twelve-step operator checklist
- releasing/test-boxes - Full Release Validation and the Vitest, Docker,
QA Lab, and Package boxes
- releasing/publish-automation - OpenClaw Release Publish order, tooling
tags, and Windows, Android, and ClawHub recovery
- releasing/beta-latest-sequence - the orchestrated stable sequence
- releasing/main-closeout - bringing main to the shipped state
- releasing/extended-stable - the monthly .33+ Gateway lane
- releasing/npm-workflow-inputs - operator-controlled workflow inputs
Anchor strategy. Per-anchor routes are impossible here: redirectSource()
in scripts/lib/docs-redirects.mjs rejects any source containing [?#]. So
every original anchor stays alive on the parent index, matching the
configuration-reference, Control UI, CI, protocol, and Slack splits: 18
authored <a id="..." /> stubs in a "Where each section moved" list, each
linking to /reference/releasing/<child>#<anchor>. The remaining two ids,
public-references and related, keep their sections on the index itself
and are deliberately not stubbed, so no duplicate authored/canonical ID
is raised.
Every id was computed with parseDocsDocument from
scripts/lib/docs-markdown.mjs, never a slug approximation. That matters
for "Regular beta/latest stable release sequence", which mints both the
percent-encoded canonical regular-beta%2Flatest-stable-release-sequence
and the compatibility alias regular-beta/latest-stable-release-sequence;
both are stubbed.
Anchor proof, run as a script rather than inferred from a passing audit
(a split rewrites the repo's own links, so docs-link-audit reads clean
even when every external deep link is broken): 20 pre-split ids
enumerated, 20 resolve against the parsed post-split index through
resolveDocsFragment, 18 stubs all point at an id that exists on the named
child, 0 collisions on the index or any child.
Losslessness, asserted mechanically by concatenating child bodies back
to the original section bodies: 0 divergences. Words 12,605 -> 13,045
(+440 from the index funnel, per-child frontmatter, and Related blocks).
Code fences 23 -> 23, unchanged. Links 23 -> 79 (+18 stubs, +9 index
bullets, +27 Related entries, +2 orphan repairs). Characters 98,834 ->
104,528.
Prose was not rewritten. The one declared exception is the cross-
reference repair the split requires: "see the dedicated workflow below"
in Version naming and "documented at the top of this page" in the
beta/latest sequence both pointed at content that now lives on another
page, so each became a real link to the extended-stable page.
Supporting changes:
- docs/docs.json gains a "Release runbook" nav group under "Release
process", mirroring the "CI" group under "Testing and CI".
- .github/CODEOWNERS extends @openclaw/openclaw-release-managers to
/docs/reference/releasing/, so the split does not silently drop
release-manager ownership of the runbook.
- test/scripts/package-acceptance-workflow.test.ts and
test/scripts/openclaw-npm-extended-stable-workflow.test.ts read
RELEASING.md plus docs/reference/releasing/*.md as one set, following
the pattern already used there for docs/ci.md plus docs/ci/*.md, so the
assertions follow the content instead of a single file path.
- test/scripts/docs-sync-publish.test.ts pins the nine new routes.
- docs/.i18n/glossary.zh-CN.json gains one entry per new page title.
The zh-CN targets are machine-written and unreviewed.
Closes audit findings: r3-0683, r3-0685
* Merge origin/main into docs-audit/split-releasing
Five commits changed docs/reference/RELEASING.md while this branch was
turning it into an index (#142195, #142291, #142260, #141786, #140672),
adding 98 lines. Resolved to the index, then re-extracted every child
section from main's current file: 15 sections refreshed across 9
children. Verified line by line that all 792 content lines present on
main survive the split.
Re-extraction reverted three of the split's own repairs, which is the
known cost of that approach:
- four cross-page links fell back to same-page fragments
(#regular-release-publish-automation, #stable-main-closeout); all
repointed at the children that own those headings
- versioning.md's "see the dedicated workflow below" lost its target
again and is a link to /reference/releasing/extended-stable once more
The link reverts are caught by docs-link-audit and markdownlint MD051.
The prose revert is caught by nothing and was found by hand.
Glossary: union keyed on source, 701 entries, 0 duplicate sources.
Full CI docs gate after staging: markdownlint 0 issues,
docs-link-audit --anchors 0 broken links, check-docs-mdx passed,
format-docs clean.
Still requires @openclaw/openclaw-release-managers approval.
* docs(reference): stub the anchors main added, and relink extended-stable
Both found by ClawSweeper on the rebased head.
Main added three headings to RELEASING.md while this branch was open:
Previous updater compatibility, Design proposal: immutable runtime
generations, and Required checks. Re-extracting moved their content to
preflight.md but added no compatibility stubs, so links such as
/reference/RELEASING#previous-updater-compatibility lost their target.
Added four stubs — the punctuated heading emits both an encoded and a
cleaned id, and both are now covered.
Anchor preservation applies to content main adds mid-flight, not only to
what existed when the split was planned. Verified against main's current
file: 24 pre-split ids, 24 resolving on the index, 0 lost.
Also restored the second extended-stable cross-page link. The earlier
rebase reverted two of them; I fixed versioning.md but missed
beta-latest-sequence.md, which still said the path was "documented at
the top of this page" after that path moved to its own child. An
orphaned directional phrase passes every validator, which is why this
one survived a full gate run.
markdownlint 0 issues, docs-link-audit --anchors 0 broken links,
check-docs-mdx passed, format-docs clean.
* Merge origin/main into docs-audit/split-releasing
Glossary conflict only; union keyed on source, 709 entries, 0 duplicate
sources. No page conflicted.
Ran the new .audit/check-orphan-refs.py over this tree: 0 directional
references remaining. That check exists because this branch shipped two
orphaned 'below' references past a full gate run, and they were found by
a reviewer both times.
markdownlint 0 issues, docs-link-audit --anchors 0 broken links,
format-docs clean.
Still requires @openclaw/openclaw-release-managers approval.
* Merge origin/main into docs-audit/split-releasing
This PR has been waiting on release-manager review, and main moved under
it. Refreshed so it is mergeable the moment the owners approve.
#142538 added 41 lines on extended-stable validation dispatch to
docs/reference/RELEASING.md. Resolved to the index, then re-extracted
five child sections from main's current file so that content survives.
Verified line by line: 817 content lines on main, all present after the
split. The one apparent gap is the Tideclaw alpha line, which is present
with its link repointed at the npm-workflow-inputs child.
Re-extraction reverted the split's own repairs again, both kinds:
- four cross-page links fell back to same-page fragments and were
repointed at the children owning those headings
- two orphaned directional references came back and were relinked,
in versioning.md and beta-latest-sequence.md
The link reverts are caught by docs-link-audit; the prose reverts are
caught by nothing and were found with .audit/check-orphan-refs.py.
Anchor check against main's current file: 24 ids, 24 resolving, 0 lost.
markdownlint 0 issues, format-docs clean, check-docs-mdx passed.
docs-link-audit --anchors reports only the 3 pre-existing maturity
failures that also fail on a clean origin/main.
Still requires @openclaw/openclaw-release-managers approval.
* Merge origin/main into docs-audit/split-releasing
Three conflicts, resolved as follows.
docs/reference/RELEASING.md: kept the index (ours). main's only change to
this page since the merge base is ca3bc36e1b, which rewrote one paragraph
of the `update-first-hop-compat` lane inside "Release preflight". That
section now lives in docs/reference/releasing/preflight.md, so main's hunk
was applied there verbatim rather than dropped.
test/scripts/package-acceptance-workflow.test.ts: took main's version of
both hunks -- the recursive docs/ci walk and the new set-read over
docs/reference/full-release-validation/ -- and kept readReleasingDocs() as
the reader for the release policy page. readReleasingDocs() now walks
docs/reference/releasing recursively with toSorted(), matching the pattern
and the rationale main established for docs/ci.
docs/.i18n/glossary.zh-CN.json: order-preserving union. 1119 sources from
main + 10 from this branch = 1129, 0 duplicates, both sides' orders
preserved as subsequences. The 10 new entries were moved out of the
end-of-array collision zone to sit beside the parent "Release policy"
entry.
Losslessness re-proved against current origin/main:docs/reference/RELEASING.md
(body sha256 9159abcad8cc2afe9a823570ca852fe912f66ed27c6c85a40d6576c595c51230):
all 12 top-level sections are byte-identical once the 6 declared link
rewrites are reversed; concatenated sections hash
66734f4ef0c88c6f2a7153de8708a5a58c058ed1561843babcdd0dec77410104 on both
sides. Code fences 25 -> 25 with an identical (info string, body sha256)
multiset; 0 tables; words 14,179 -> 15,020.
* Merge remote-tracking branch 'origin/main' into docs-audit/split-releasing
* origin/main:
fix(channels): preserve labels for unloaded plugins (#143416)
refactor(tests): share image resource acquisition setup (#143443)
refactor(hooks): consolidate source precedence policy (#143439)
* docs(release): retain the original split history
The canonical release-policy split landed in #156946. Preserve the original branch ancestry while retaining only its missing legacy publication anchor on current source.
* commit 'f478156122dcc285acb7413024c4ecfc3101e0c8':
docs(reference): stub the anchors main added, and relink extended-stable
docs(reference): split the release runbook by reader job
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(packaging): accept frozen releases with their shipped MCP patches
Select only trusted exact 1.8.0 and 1.9.0 artifact contracts from the package pin. Keep bootstrap policy and all byte, asset, manifest and CLI checks intact.
Co-authored-by: RomneyDa <6581799+RomneyDa@users.noreply.github.com>
Co-authored-by: vyctorbrzezowski <51521767+vyctorbrzezowski@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
* perf(models): correct discovery outcomes in lifecycle fixtures (#158115)
Report successful HTTP discovery and selected account provenance in the
catalog lifecycle fixtures. Account retention requires an observed ready
outcome; returned rows alone may be advisory static fallback.
The learned-row failure reproduced in 20/20 contended Testbox runs.
The repaired file passes 20/20 standalone runs, the contended replay,
and three complete original-shard replays. Repair the identical missing
outcome found by sibling freshness validation. All assertions are retained.
No production behavior changes.
Carries the already-landed owning fix from PR #158115 unchanged so the
packaging PR preserves its hosted ancestry while its failed CI is repaired.
Upstream: d5d4952c5b
Co-authored-by: RomneyDa <6581799+RomneyDa@users.noreply.github.com>
Co-authored-by: vyctorbrzezowski <51521767+vyctorbrzezowski@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
---------
Co-authored-by: RomneyDa <6581799+RomneyDa@users.noreply.github.com>
Co-authored-by: vyctorbrzezowski <51521767+vyctorbrzezowski@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
* feat(release): one approval per release via an attested parent approval receipt
The parent's npm-release approval mints an attested receipt that bot-dispatched
children verify in their trusted-tooling validation job. The ClawHub OIDC child
skips its clawhub-plugin-release gate on a verified receipt; npm children keep
npm-release (their npm trusted publishers are bound to it) and the parent
approves those gates with the RELEASE_CHILD_APPROVER_TOKEN environment secret.
* fix(release): keep the npm child gates manual instead of delegating a release-manager token
ClawSweeper P1: a persistent deployment-approval token inside the publish job,
which has already run release-candidate setup code, is a wider credential
boundary than the job token. Drop the delegated approval; the receipt still
lets the ClawHub child run without its gate.
* fix(release): make the ClawHub child wait for the parent's transaction authorization on the receipt route
Without the human gate the child's publish jobs would race the parent's
authorize step; block on the child-bound parent authorization artifact
(bounded, failing when the parent leaves in_progress) before publishing.
* docs(release): format the merged approval notes
* feat(ci): add the release-fast-lane label for release tooling pull requests
A canonical pull request labelled release-fast-lane whose changed paths are
all release tooling (.github/workflows, scripts, test/scripts, release
skills, RELEASING.md) or independently checked documentation keeps
security-fast, check-shard, check-docs and the changed Node rows, relaxes
only the compact packing-policy full-plan proof, and skips every other lane.
openclaw/ci-gate stays complete because skipped lanes are unselected. A
declined label warns with its reason and leaves ordinary selection
byte-identical. The preflight summary lists admitted and skipped lanes.
* fix(ci): decline release-fast-lane on fork heads and keep the native review path in the guidance
* test(ci): prove release-fast-lane declines fork heads before the aggregate gate
* fix(ci): keep release-fast-lane contract lanes skipped when the changed plan falls back
* feat(release): mint the protected tooling tag from a trusted main SHA
Let release:publish-preflight and release:candidate accept --workflow-sha
<main-ancestor>. The helper proves main ancestry, reuses the newest
lightweight release-publish/<sha12>-<epoch> tag at that SHA or creates one
through the git refs API, verifies the ref, and prints the dispatch with
--ref <tag>. The candidate helper pins its trusted tooling checkout to the
same SHA and refuses a checkout mismatch before minting.
* fix(release): keep the recorded tooling tag when a candidate resumes by SHA
A newer release-publish tag at the same tooling SHA must not fail state
reconciliation: a resumed candidate reuses the exact tag it saved (still
verified against the tooling SHA) instead of the newest tag at that SHA.
* fix(release): let one publish parent dispatch finish
Sweep a failed earlier parent's waiting children before every child
dispatch (reject gate, cancel, bounded wait), retry transient gh reads,
wait for the core package to be visible on the registry and run the
beta-to-stable dist-tag sync through a release-ledger app token before
verification, treat a run with a waiting gate as live in the tooling
identity check, and verify an already-public GitHub release instead of
failing to rewrite it.
* test(release): stub sleep in the Linux request dispatch fixture so gh read retries stay within its timeout
* fix(release): reclaim waiting plugin npm children only while no other publish parent is live
* feat(release): add the resumable release:stable orchestrator
pnpm release:stable <version> drives one regular stable release as a
resumable state machine (cut, validate, publish, sync-beta, flip-github,
macos, closeout) over the existing helpers, with two operator prompts,
--from/--status/--dry-run, capability probes for the concurrent publish
parent, approval receipt, and closeout changes, and Next: commands on
every refusal. RELEASING.md leads with it and keeps the manual fallback.
* fix(release): bind release:stable child gates to the tooling tag and lock the state directory
Sweep and approve only bot-dispatched children whose head_branch is this
release's protected tooling tag, selected by exact workflow path (the core
OpenClaw NPM Release child was missed by the name regex), and refuse a
second release:stable process on the same state directory.
* fix(release): stop release:stable from mutating child runs and bind dispatch reconciliation to the operator
The API cannot prove which publish parent dispatched a child, so the
orchestrator no longer approves or cancels children: it approves only the
recorded parent's npm-release gate and prints the exact child-approval and
stale-child sweep commands until the approval receipt and self-sweeping
parent are present at the tooling SHA. Runs dispatched on main are
reconciled by workflow path, ref, the operator's login, and a bounded
window, refusing on ambiguity; stale-lock takeover retries the exclusive
create.
* ci(release): schedule a nightly Full Release Validation of main
Dispatch full-release-validation.yml at 04:00 UTC for the scheduler's exact main
SHA with the stable profile, soak and blocking performance, reuse_evidence=true
and the main-qualification envelope, skipping only while a parent for that SHA
is active. Document what a same-day cut reuses from the sealed evidence today
and the verifier policy gap that remains.
* test(release): satisfy the workflow context types in the nightly dispatcher test
* ci(release): pin the nightly validation target and stop counting it toward the full sweep
Dispatch with ref and expected_sha both set to the scheduler's main SHA (plus
the explicit allow_unreleased_changelog the at-sha helper sends for main
targets) so a later main push cannot move the target; drop the run-list skip,
whose head_sha filter could not tell a focused or other-target parent from
nightly coverage, and let the SHA-specific FRV concurrency group queue
duplicates. The stable nightly is additional evidence, never the full/all
cadence.
* ci(release): route the publish path into the reserved runner group
OPENCLAW_RELEASE_RUNNER_GROUP already routes Full Release Validation and its
children; the Release Publish parent and every publish child still ran on plain
ubuntu-latest. Read the same variable there, forward it as runner_group into
docker-release.yml and vercel-container-registry-publish.yml (docker-image-refresh
keeps ordinary routing), and stop writing the legacy OPENCLAW_RELEASE_PRIORITY_RUN
variable from the validation dispatcher now that #157757 removed its gate.
* ci(release): keep credentialed publish jobs and the hourly plugin preview off the reserved group
npm trusted publishing rejects self-hosted runners, so approval and
credentialed publish jobs (environment, id-token, registry secrets) keep their
default GitHub-hosted labels; plugin-npm-release routes only when Release
Publish dispatches it (release_publish_run_id), never for its hourly preview.
The guard test encodes both rules.
* test(release): narrow the pinned credentialed job lookups
* fix(release): key stable closeout by resolved tag and accept publish-admitted waivers on replay
Push-triggered closeout runs were cancelled by later main pushes, and a
tag-only replay failed the version-prefix waiver rule that the publish
gate had not applied to the sealed 2026.9.6 soak waiver. Keep push runs
alive, serialize verification per resolved stable tag, forward the sealed
waiver text to the closeout gate, and admit exactly what the publish
accepted while new operator text still needs the target-version prefix.
* docs(release): qualify tag-only closeout replay when no lane acknowledgement was sealed
openclaw/releases now attaches macOS assets to a draft or public GitHub
release and re-dispatched preflights resume from per-variant checkpoints
unless ignore_checkpoints=true; align the mac skill, RELEASING.md and the
platform-publication reference with that default.
* fix(release): retry notarization transport failures
* fix(release): reconcile history from notarization upload start
* fix(release): retry unavailable notarization history before resubmitting
* fix(release): retain unknown state for malformed notarization history
* fix(release): drain codesign output in smoke signature check
* test(release): guard parallel validation dispatch
* feat(release): seal independent child workload evidence
Record immutable, attempt-aware child receipts independently of parent completion. Keep receipt collection advisory and preserve publisher-only retry evidence. Partial child-reuse discovery and consumption remain a follow-up.
* feat(release): reuse sealed child evidence independently
* fix(ci): plan frozen release shards with trusted tooling
* ci(release): generate hosted shard timing budgets
* fix(release): make non-proof validation lanes advisory
* feat(release): seal resolved publication inputs
* fix(release): accept candidate tags at the frozen target
* docs(release): record pending first-hop parallel lanes
Item 8: remote main d51f3607b9 does not contain bf7848ef23. The feat/first-hop-compat-parallel-lanes branch still owns that implementation. Verified remote refs read-only and inspected the main scenario source; do not duplicate it here. No source changes; prior item gates remain valid.
* ci(plugins): run release plugin coverage on relevant pull requests
* ci(release): support reserved validation runner groups
* docs(release): reconcile fast-path validation guidance
* test(release): reconcile final guards and record validation
* fix(release): retry transient GitHub API failures during evidence verification
* test(release): reconcile advisory Linux CI lane cases with the fast-path policy
* test(release): copy the sealed-evidence tooling closure into the frozen fixtures
* fix(release): keep package integrity blocking and require live operator authority for sealed SDK and soak inputs
* chore(release): record the landing follow-ups in the PR body
* test(ci): expect the four-hour Testbox lease default from #156614
* test(release): reconcile untouched release suites with the advisory policy and reserved runner groups
* fix(release): reconcile advisory-by-default with full coverage and strict stable defaults
Keep RomneyDa's coverage (nine cross-OS Gateway pairs, Linux Gateway lanes as
required proof, Windows/macOS recorded as advisory) and his strict stable
publication gates (stable-profile, soak, blocking performance) as the default,
while retaining Peter's operator fast path: stable_soak_waiver / lane_waiver
are the only way to publish a stable without soak/performance evidence or with
failed non-proof lanes, must name the target version, apply only while the
repository variable still holds them, and are recorded end to end. The stable
closeout accepts the same waivers so the 2026.9.6 closeout replay can proceed.
Adopt main's affected-consumer planner (#156729) with item 4's hosted-row
split re-applied.
* fix(release): revalidate sealed soak waivers at the plugin npm publish boundary
The stable bootstrap approval records whether its soak waiver was explicit or
sealed; the plugin npm child rereads the repository variable before its
token-backed publish and rejects a sealed waiver the variable no longer holds.
Read-only preflight reports sealed waivers with the same rule. Docs state the
nine-pair all-group cross-OS rule and the strict performance gate; the tracked
planner backup is removed and the fast-core worker keeps its runner-group
routing.
* fix(release): recheck sealed waivers before npm I/O and repair CI-surfaced drift
Assert a still-held sealed soak waiver immediately before the plugin
token-backed npm publish, carry the live variable into preflight's gate
evaluation, and state the strict performance gate in the fast-path guide.
Fold main-side drift the merge surfaced: the seal job waits for the new
baseline-ratchets worker, the wrapper closure lists the CLI root options chain,
the maturity publisher's runner-group route is evaluated rather than compared
literally, and two main-authored session test-support suppressions join the
allowlist.
* fix(release): fetch waiver authority live before the plugin npm publish
Read OPENCLAW_RELEASE_STABLE_SOAK_WAIVER from the repository immediately
before the token-backed npm publish (404 means revoked, other read errors
refuse to publish), keep a waiver-less recorded closeout manifest byte-identical
on replay, and describe release_profile=stable as the stable default with the
beta profile plus stable_soak_waiver as the explicit operator fast path.
* test(release): anchor the publish-boundary recheck to the npm publish command
* fix(release): fall back to the job-start waiver when the token cannot read Variables
Keep the live read before npm publish (404 means revoked) but warn and use
the job-start snapshot instead of refusing every bootstrap publish when the
job token lacks Variables access.
* fix(release): refuse the plugin npm publish when waiver authority cannot be read
Revoked (404) and unreadable variable states both stop the token-backed
publish; a job token without Variables read access fails loudly instead of
publishing on a job-start snapshot.
* refactor: retire pre-June config and upgrade test support
Retire obsolete Doctor keys and their runtime fallbacks. Older configurations use the documented 2026.9.5 Doctor bridge; current upgrade verification starts at June 2026 while historical receipts remain readable.
* fix: preserve retired config when the upgrade bridge is skipped
* test: align upgrade fixtures with retained migration contracts
Incoming release guidance still described automatic plugin publisher redispatch. Document terminal settlement and explicit recovery after owner diagnosis so the instructions match the removed retry owner.
Live, Docker, channel and release wrappers could repeat failed validation
or downgrade failed jobs automatically. Run each test invocation once,
remove known-flake redispatch, and require an explicit recorded waiver
when the release policy permits one.
Wait for the original plugin publisher to settle before reporting failure.
Keep bounded artifact-download recovery before tests. Read published
v2026.9.6 empty retry metadata without restoring executable allowances or
automatic waivers, preserving the sealed plan digest. Use the existing
fresh-read owner for release-priority cleanup.
Testbox owner/sibling proof and three CI-config replays passed. The two
freshness regressions passed 20 repetitions. Published evidence retained
its original digest; nonempty retry metadata remained rejected. The stale
Testbox assertion now matches its already-landed four-hour lease; this
change raises no runtime, test, hook or watchdog budget.
The update-first-hop-compat selection now expands at plan time into one
Docker lane per release recorded in scripts/lib/update-compat-inventory.json
(update-first-hop-compat-<version>), for both the Docker E2E pool and the
targeted GitHub matrix. Each lane runs the existing script with
OPENCLAW_UPDATE_FIRST_HOP_SOURCE_VERSIONS=<version>, writes its own
artifact directory, and carries a 25-minute budget at weight 1, so the
hops run concurrently instead of ~55 minutes serially.
Admin merge under the release-window "unrelated red must not block" steer (coordinator, 2026-09-23).
Red at merge: checks-node-compact-small-37/38/39/44 only, failing test/scripts/pr-wrappers.test.ts, eager-import-closure.test.ts, pr-wrapper-source-closure.test.ts, pr-main-refresh.test.ts. This PR has zero diff on scripts/pr, scripts/pr-lib, src/infra, or those tests. The same files fail on pristine origin/main in a clean clone: all four at 71875bf; pr-wrappers and eager-import-closure still fail (28 tests) at 0338fa2 "fix(ci): add sqlite schema-fact modules to the pr wrapper inventory" (merged 20:56Z), which repaired the other two. Search of open PRs found no further fix in flight. checks-ui (2/3) was a runner kill (exit 143) and passed on rerun; every other lane is green.
* fix(release): retry a pre-publish plugin child failure once instead of aborting the publish
* fix(release): dispatch a fresh plugin child after a pre-publish failure instead of rerunning it
* feat(release): operator lane waiver keeps non-proof lane failures advisory
* test(release): cover lane waiver gates and advisory evidence; document the waiver
* feat(release): carry the FRV lane waiver on a version-bound repository variable
* fix(release): keep Linux cross-OS and verifier failures blocking without a waiver
* test(release): align lane waiver advisory evidence expectations
* fix(release): build advisory job entries without map spread
* fix(release): type the advisory job entry for the test root
* fix(gateway): supply policyConfig in the placement lifecycle read view
Encode the release owner's directive: a cut candidate keeps its base unless
Peter explicitly asks for a re-cut in that release. Cherry-pick merged main
commits onto the release branch only for confirmed release blockers, each
named in the handoff record.
* docs(release): make the fast path the default stable release process
* docs(release): scope runner-priority cancellation and keep required-lane repairs on the fast path
* docs(release): name the frv rerun-failed and prioritize controllers on the fast path
* docs(release): keep the fast path on landed frv commands until #156305 merges
* docs(release): native app publication never blocks the npm/ClawHub release
* docs(release): keep required Windows CI and publisher prerequisites explicit in the decoupling rule
* refactor: retire pre-June import and verification compatibility
Remove pre-June task, flow, and plugin-state sidecar imports, obsolete
runtime chunks, package/installer validation exceptions, the old MCP
attachment fallback, and the April self-upgrade lane with its orphan helpers.
Leave retired data files untouched and document migration through 2026.6.1.
Preserve June-and-later contracts and September delivery recovery receipts.
Refs #156190
* docs: route legacy upgrades through 2026.9.5
* test: await Telegram fixture lifecycle events
Replace the setup stopwatch with the actual stop event or terminal run outcome. Keep cancellation assertions and outer execution bounds, and prove early terminal outcomes fail promptly.
* fix(release): preserve higher plugin API floors
Raise lower plugin API requirements during release alignment without lowering intentional floors for newer host APIs. Reuse the shared OpenClaw semver ordering for beta, RC, and correction releases, and preserve invalid declarations.
Add filesystem-boundary regression cases for check and write modes, and document floor preservation. The generator suite passes all 16 tests; focused cost is 3.01 seconds wall. P2 review and changed-file checks pass. Package versions, dependencies, host floors, manifests, and lockfiles are unchanged.
* chore: integrate main for plugin API floor validation
* test: retain PR controller output on close failure
Print the existing child output buffer if the fresh-main fixture cannot observe controller close, then rethrow the original error. Preserve the existing deadlines and joined cleanup. The earlier hosted timeouts remain unexplained.
* chore: integrate main after Gateway shard rebalance
Include the canonical worker-environments shard rebalance from #155734. Preserve the exact reviewed five-file API-floor and controller-output patch. The catalog timeout and earlier controller-close timeouts remain separately qualified.
* chore: integrate main after archive fixture repair
Include the canonical archive lifecycle fixture repair while preserving the exact reviewed five-file API-floor and controller-output patch. Retain prior failed CI and the noncausal catalog pass as qualified evidence.
* chore: preserve fixture diagnostics across main integration
Keep the upstream private-handoff setup and injection assertion alongside the unchanged controller-output catch. Preserve main and the original API-floor repair without adding timeout or retry policy.
* chore: integrate the canonical launcher fixture repair
* chore: integrate the canonical wrapper closure repair
* chore: integrate canonical wrapper and worker bundle fixes
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Three release-tooling fixes surfaced by the 2026.9.6 stable candidate (Full Release Validation run 35742760135). Each is a separate commit.
## 1. Forward the stable soak waiver through the candidate helper
**Problem.** `pnpm release:candidate` runs the publish preflight in-process with a hardcoded `stableSoakWaiver: ""`. For a stable tag (for example `v2026.9.6`) whose Full Release Validation ran with `release_profile=beta` and `run_release_soak=false`, the `<consumer>.soak` and `core-npm.performance` gates in `scripts/lib/release-publish-gates.mts` FAIL instead of WARN, so the helper throws `Publish preflight failed` even though `docs/reference/RELEASING.md` documents the operator `stable_soak_waiver` for exactly this case and `pnpm release:publish-preflight` already accepts `--stable-soak-waiver`.
**Solution.**
- Add `--stable-soak-waiver <reason>` to the candidate helper's option table and usage, mirroring the standalone preflight option name.
- Forward `options.stableSoakWaiver` into the embedded `runReleasePublishPreflight` call. The normal-route command is rendered by the existing `buildReleasePublishDispatchCommand`, which already emits `-f stable_soak_waiver=<reason>` when set; no duplication.
- Render the same input in the prepared-route `publish_inputs` payload (`buildPublishCommand`), which `scripts/openclaw-release-ready.mjs` already accepts.
- Document the option in `docs/reference/RELEASING.md` and the maintainer skill reference.
Without the option the behaviour is unchanged (empty waiver, soak required).
## 2. Pack bundled dependencies in the prepared npm bundle (unblocks 2026.9.6)
**Problem.** The "Prepare publishable npm package" job failed with `ERR_PNPM_BUNDLED_DEPENDENCIES_WITHOUT_HOISTED` from `pnpm --dir <root> pack`. Root `package.json` gained `bundleDependencies: ["chrome-devtools-mcp"]` in #154215, and pnpm refuses to pack bundled deps under the isolated linker. `scripts/package-openclaw-for-docker.mts` already passes `--config.node-linker=hoisted`; the default `runPack` in `scripts/npm-prepared-bundle.mjs` did not.
**Solution.** Add `--config.node-linker=hoisted` to the pnpm pack args. Scripts stay enabled (`prepack` must run; no `ignore-scripts`). Verified locally on the release candidate: `OPENCLAW_PREPACK_PREPARED=1 pnpm --dir . pack --config.node-linker=hoisted --pack-destination /tmp/x` succeeds and the tarball contains 346 `node_modules/chrome-devtools-mcp/` entries.
## 3. Raise the npm pack unpacked-size budget to 320 MiB
**Problem.** The release-checks job `install_smoke_release_checks / installer_smoke_update` failed with `candidate.tgz unpackedSize 312428525 bytes exceeds budget 246415360 bytes`. The 2026.9.6 package is 296.6 MiB unpacked vs 214.6 MiB for 2026.9.5.
**Why this is a budget bump, not a bloat fix.** The growth is intentional product work, not accidental duplication: +46.2 MiB `dist/worker/sqlite-store.worker.mjs` (portable cloud SQLite worker bundle, #154711) and +12.6 MiB bundled `node_modules/chrome-devtools-mcp` (#154215), plus ~4.6 MiB `worker.mjs` growth and 3.6 MiB `dist/state`. Operator-approved release-prep exception for 2026.9.6; a follow-up should shrink the sqlite-store worker bundle.
**Solution.** Raise both defaults from 235 MiB to 320 MiB, kept equal: `scripts/lib/npm-pack-budget.mts` and `scripts/test-install-sh-docker.sh` (the `OPENCLAW_INSTALL_SMOKE_PACK_UNPACKED_BUDGET_BYTES` override is unchanged).
## Impact
Stable candidates validated on the beta profile without soak can be completed by the candidate helper with the operator's approved waiver; the prepared npm bundle packs again with bundled dependencies; and the install smoke budget admits the 2026.9.6 package while still bounding accidental growth.
## Evidence
- `test/scripts/release-candidate-checklist.test.ts`: the coordinator matrix now passes `--stable-soak-waiver` for stable `latest` cases and asserts the waiver reaches the preflight input and the printed normal/prepared command; negative-checked (reverting the forwarding line fails 5 cases).
- `test/scripts/npm-prepared-bundle.test.ts`: new test intercepts the default `runPack`'s pnpm invocation and asserts the exact args include `--config.node-linker=hoisted` with `OPENCLAW_PREPACK_PREPARED=1` and no `ignore-scripts`.
- `test/release-check.test.ts` and `test/scripts/test-install-sh-docker.test.ts`: budget boundary cases updated to 320 MiB (exact budget passes, one byte over fails).
- `node scripts/run-vitest.mjs run` wall times (local, macOS): release-candidate-checklist + release-publish-gates + release-publish-preflight-interface + release-publish-preflight-evidence: 4 files, 189 passed in 16.71s; npm-prepared-bundle: 40 passed in 3.62s; release-check + test-install-sh-docker: 176 passed in 63.92s (57% transform). The new hoisted-linker test adds one in-process fixture pack (no real pnpm), well under a second. CI timings: the same files run inside the sharded `checks-node-compact-*` lanes on the PR head; no lane exceeded its budget (see PR checks).
- `OPENCLAW_TESTBOX=1 pnpm check:changed` (hosted Testbox) on head 7dfaf713a80: passed, all lanes including the test-root lint lane.
* fix(release): preserve plugin publish success during registry lag
Record published, visibility pending only after accepted plugin npm publication in a full parent release. The parent retains final registry authority; standalone repairs and identity, byte, malformed-selector, and ahead-selector conflicts remain strict. Reuse selector classification and remove the duplicate bootstrap selector readback. Related: #152176.
* fix(release): bind final plugin readback to publication evidence
Verify consumed qualification and planning receipts at the parent, including retained attempts. Require actual registry tarball integrity and archive identity on fresh-parent resumes that skip already-published versions; retain exact artifact byte checks for publisher jobs.
* fix(release): preserve qualified readback across failed child retries
Reconcile retained failed publishers with a verified newer skip plan and require their exact successful qualification-upload step. Keep original artifact byte verification. Register the dynamic verifier entrypoint and its isolated test inventory for CI.
Keep the original successful publication attempt after later child reruns. Carry its identity through recovery, final verification, diagnostics and release evidence while retaining all original publication trust checks. Related: #152434.
* fix(release): reclaim orphaned ClawHub publication children
* test(release): expect ClawHub child lifecycle coverage
The changed-target selector discovers the new child lifecycle test through its reference to the release publish workflow. Keep the strict expected target set in sync.
* fix(release): scope ClawHub recovery to the release tag
* fix(release): preserve independent ClawHub validation slots