On this page
On this page
Testing and CI
Package Acceptance
Package Acceptance jobs, candidate sources, suite profiles, compatibility windows, and dispatch examples. Part of the Release validation workflows index.
Package Acceptance
Use Package Acceptance when the question is "does this installable OpenClaw package work as a product?" It is different from normal CI: normal CI validates the source tree, while package acceptance validates a single tarball through the same Docker E2E harness users exercise after install or update.
Jobs
resolve_packagechecks outworkflow_ref, resolves one package candidate, writes.artifacts/docker-e2e-package/openclaw-current.tgz, writes.artifacts/docker-e2e-package/package-candidate.json, uploads both as thepackage-under-testartifact, and prints the source, workflow ref, package ref, version, SHA-256, and profile in the GitHub step summary.package_integritydownloads thepackage-under-testartifact and enforces the public package tarball contract withscripts/check-openclaw-package-tarball.mjs.npm_12_install_shinstalls that exact artifact through the public Linux installer under npm 12 in an isolated home/prefix, then verifies the CLI version and lifecycle-completion guard and enforces the installed-package tree budget.docker_acceptancecallsopenclaw-live-and-e2e-checks-reusable.ymlwith the resolved package source SHA (falling back toworkflow_ref) andpackage_artifact_name=package-under-test. The reusable workflow downloads that artifact, validates the tarball inventory, prepares package-digest Docker images when needed, and runs the selected Docker lanes against that package instead of packing the workflow checkout. When a profile selects multiple targeteddocker_lanes, the reusable workflow prepares the package and shared images once, then fans those lanes out as parallel targeted Docker jobs with unique artifacts.package_telegramoptionally callsNPM Telegram Beta E2E. It runs whentelegram_modeis notnoneand installs the samepackage-under-testartifact when Package Acceptance resolved one; standalone Telegram dispatch can still install a published npm spec.summaryfails the workflow if package resolution, integrity, npm 12 installer acceptance, Docker acceptance, or the optional Telegram lane failed. Selected lanes keep their first failure; callers cannot downgrade a failing test to a warning.
Installed package tree budget
scripts/check-openclaw-installed-package-budget.mts measures the npm-installed
package tree, including dependencies that the tarball check cannot see. It counts
the root and every directory entry without following symlinks, and sums every
regular file's size, including npm's hidden node_modules/.package-lock.json
files, because published updaters charge those bytes too. Hardlinked paths count
separately. The report lists the largest contributors by entry count and adds the
totals to the GitHub step summary.
Published 2026.9.3–2026.9.8 updaters freeze caps of 50,000 entries / 1 GiB. The release budgets are 47,500 entries / 900 MiB: the 2,500-entry reserve (5%) covers npm-version, hoisting, and per-platform optional-dependency variance and is larger than routine dependency bumps, so the check fails while every shipped updater can still install the candidate. Bytes are far from the cap but vary more with platform native prebuilds, so the byte budget keeps roughly 12% in reserve.
Newer updaters allow 500,000 entries / 8 GiB and continue candidate activation
and publication with directory identity, version, and launcher checks if a scan
reaches those resource limits, warning that full package contents are unverified.
This does not change the release budgets or the already-installed drivers.
Candidate admission under a supervisor version of 2026.9.8 or earlier refuses
trees with more than 50,000 entries and gives a manual npm i -g openclaw@latest
command (preserving the requested version or tag when specified); it cannot
bypass the old driver's walk.
To reproduce locally with a candidate tarball:
On failure, reduce installed entries by trimming the largest dependencies or dist chunk and precompressed asset counts; reduce large files for a byte-budget failure. Do not raise the budgets: caps cannot change in already-shipped updaters.
Candidate sources
source=npmaccepts onlyopenclaw@extended-stable,openclaw@beta,openclaw@latest, or an exact OpenClaw release version such asopenclaw@2026.9.5. Use this for published extended-stable, prerelease, or stable acceptance.source=refpacks a trustedpackage_refbranch, tag, or full commit SHA. The resolver fetches OpenClaw branches/tags, verifies the selected commit is reachable from repository branch history or a release tag, installs deps in a detached worktree, and packs it withscripts/package-openclaw-for-docker.mjs.source=urldownloads a public HTTPS.tgz;package_sha256is required. This path rejects URL credentials, non-default HTTPS ports, private/internal/special-use hostnames or resolved IPs, and redirects outside the same public safety policy.source=trusted-urldownloads an HTTPS.tgzfrom a named trusted-source policy in.github/package-trusted-sources.json;package_sha256andtrusted_source_idare required. Use this only for maintainer-owned enterprise mirrors or private package repositories that need configured hosts, ports, path prefixes, redirect hosts, or private-network resolution. If the policy declares bearer auth, the workflow uses the fixedOPENCLAW_TRUSTED_PACKAGE_TOKENsecret; URL-embedded credentials are still rejected.source=artifactdownloads one.tgzfromartifact_run_idandartifact_name;package_sha256is optional but should be supplied for externally shared artifacts.
Keep workflow_ref and package_ref separate. workflow_ref is the trusted workflow/harness code that runs the test. package_ref is the source commit that gets packed when source=ref. This lets the current test harness validate older trusted source commits without running old workflow logic.
Suite profiles
smoke—npm-onboard-channel-agent,gateway-network,config-reloadpackage—npm-onboard-channel-agent,doctor-switch,update-channel-switch,skill-install,update-corrupt-plugin,upgrade-survivor,published-upgrade-survivor,root-managed-vps-upgrade,update-restart-auth,plugins-offline,plugin-updateproduct— thepackageset with livepluginscoverage instead ofplugins-offline, plusmcp-channels,cron-mcp-cleanup,openai-web-search-minimal,openwebuifull— full Docker release-path chunks with OpenWebUIcustom— exactdocker_lanes; required whensuite_profile=custom
The package profile uses offline plugin coverage so published-package validation is not gated on live ClawHub availability. The optional Telegram lane reuses the package-under-test artifact in NPM Telegram Beta E2E, with the published npm spec path kept for standalone dispatches.
For the dedicated update and plugin testing policy, including local commands, Docker lanes, Package Acceptance inputs, release defaults, and failure triage, see Testing updates and plugins.
Release checks call Package Acceptance with source=artifact, the prepared release package artifact, suite_profile=custom, docker_lanes='doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor root-managed-vps-upgrade update-restart-auth plugins-offline plugin-update plugin-binding-command-escape', and telegram_mode=mock-openai. This keeps package migration, update, live ClawHub skill install, stale-plugin-dependency cleanup, configured-plugin install repair, offline plugin, plugin-update, and Telegram proof on the same resolved package tarball. Set release_package_spec on Full Release Validation or OpenClaw Release Checks after publishing a beta to run the same matrix against the shipped npm package without rebuilding; set package_acceptance_package_spec only when Package Acceptance needs a different package from the rest of release validation. Cross-OS release checks still cover OS-specific onboarding, installer, and platform behavior; package/update product validation should start with Package Acceptance.
Upgrade-survivor assertion ownership follows the selected target's release train, read from its immutable package metadata after source-identity validation. Extended-stable targets retain their shipped scenario runner, assertions, and fixtures; regular targets keep the trusted scenario together, including its serving-turn/post-inference assertions. The historical baseline does not select the assertion owner. Invalid target versions and unsupported extended-stable correction versions fail before Docker.
Docker seed CI resolves an exact published stable predecessor of the selected source package version before running published-upgrade-survivor. It uses the release baseline resolver and selected release context, so publishing latest never turns the first upgrade into an already-current operation. Missing predecessors fail before Docker starts; the separate already-current control remains unchanged.
The published-upgrade-survivor Docker lane validates one published package baseline per scenario. In Package Acceptance, the resolved package-under-test tarball is always the candidate and published_upgrade_survivor_baseline selects the fallback published baseline, defaulting to openclaw@latest; failed-lane rerun commands preserve that baseline. Current source release checks set published_upgrade_survivor_baselines=supported-lines for legacy-operator-state: npm's current latest, the preceding stable version, extended-stable when that tag exists, and the documented oldest supported baseline 2026.8.33. The resolver reads npm view openclaw versions and npm view openclaw dist-tags at run time, pins exact versions before fanout, and deduplicates overlapping lines. Normal current-source release checks retain base and add legacy-operator-state and custom-plugin-siblings; release soak selects reported-issues, including these and the existing issue-shaped fixtures. The sibling-source scenario uses baselines from 2026.9.4 onward and requires actual custom-plugin Doctor contract execution from the private update canary, plus intact source files and plugin loading after the update.
Before targeted Docker fanout, the trusted group planner installs each distinct published baseline in a throwaway npm prefix and checks openclaw --version plus openclaw config set gateway.mode local against synthetic isolated state. The config write loads the CLI setup path because version/help and config reads can use fast paths. An installed CLI that exits unsuccessfully is recorded as an unusable published baseline, with its skipped scenarios and captured error in the job summary and upgrade-baseline-checks-* artifact. Skipped scenarios are never counted as successful upgrades. Install errors, check timeouts, and process-launch failures fail planning. Candidate installs and upgrades retain their existing failure gates.
When a prerelease registry is mounted, the baseline package install and the initial manual baseline Gateway start use the configured published upstream. Published and candidate packages can share an exact version while containing different bytes; preserving published dist-tags alone does not isolate them. After those baseline commands, candidate installs keep using the verified candidate registry, including its exact-version dependencies.
The legacy-operator-state companion fixture preserves the published archive
for its package name/version across both registry phases.
When the candidate companion has that same version, installation assertions
require the retained published bytes. A different version selects and verifies
the prepared candidate archive. This keeps same-version core update proof from
simulating an npm republish; testing changed companion bytes requires a distinct
companion version.
Expanded release qualification requires the candidate's YYYY.M.PATCH base version
to be at least the trusted workflow package's base version, ignoring prerelease
suffixes for this comparison. It then reads immutable source-directory metadata for
the operator-state harness. Older source targets and extended-stable contexts
or branches keep the validated candidate-relative predecessor. Published candidates retain that predecessor and the preexisting synthetic
scenario inventory because their qualification path does not prepare the
registry required by the operator-state fixture.
A separate package_acceptance_package_spec override resolves its predecessor
from the override's actual package version inside Package Acceptance.
Within the supported-lines release profile, custom-plugin-siblings always uses
the exact published openclaw@2026.9.4 regression driver. This retains the
reported first hop when the source candidate has the same version; base and
legacy-operator scenarios keep their existing baseline selection.
The child workflow prepares or reuses the prerelease plugin registry required
by the new scenario's artifact assertions, so that scenario runs only for
qualifying unpublished candidates. Published requalification retains base, or every preexisting
reported-issue scenario for soak, because its package path does not prepare
that registry. Historical qualification likewise excludes only the newly added
operator-state scenario. Existing frozen-target compatibility checks and the
explicit scenario-omission opt-in remain unchanged; candidate source code is
never executed to choose this profile.
For the standalone supported-lines selector, the group planner runs every
preexisting synthetic scenario only against that separately resolved
predecessor, and runs legacy-operator-state against each supported baseline.
It merges overlapping groups and retains every requested fixture; a missing
or moving-tag predecessor fails planning. Comma and whitespace delimiters and
repeated standalone selectors use the resolver's normal token grammar. Explicit version lists and mixed selector/version lists retain the
full Cartesian baseline/scenario matrix for deliberate manual proof. The
selector provenance travels only as internal reusable-workflow metadata;
there is no new manual-dispatch input.
Expanded published-upgrade survivor and update-migration selections use one job per supported baseline/scenario pair, with at most 32 targeted Docker jobs active per matrix. The planner admits existing groups containing update-restart-auth, plugin-update, and root-managed-vps-upgrade first so those long update jobs do not wait behind the expanded scenario matrix. Within each expanded upgrade family, exact baseline cohorts run newest first, putting the measured slower recent upgrades ahead of older baselines. Scenarios within a cohort and other groups retain their input order; unresolved baseline tags preserve caller order. Grouping shares the execution planner's baseline-compatibility policy, so every supported scenario runs exactly once without creating empty shards for old baselines. Each scenario owns a fresh container and the unchanged npm resource limit; package and image identities remain shared across the matrix. Update Migration runs weekly on Sunday at 03:17 UTC and on manual dispatch. It defaults to supported-lines with both plugin-deps-cleanup and legacy-operator-state, keeps the existing cleanup coverage, and forwards no provider secrets. The weekly run keeps cleanup on the candidate-relative predecessor and exercises native operator state on each supported baseline. A planning allowance of 12 minutes per scenario plus 30 minutes for shared package/image preparation and controls gives about 78 runner-minutes weekly with three distinct baselines, or 90 with four; actual timing artifacts determine the observed cost.
Pass baselines=all-since-2026.6.1 for exhaustive historical cleanup; last-stable-4, release-history, and exact historical versions remain explicit manual selections. Local aggregate runs can pass the resolved exact specs through OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS, keep a single lane with OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC, or set OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS for the scenario matrix. Existing scenarios retain their baked openclaw config set recipes and summary records. The new operator-state scenario instead uses the baseline's own agent, exec-approvals, cron, and plugin CLIs, then verifies preserved state and a mock-provider turn after upgrade. Gateway checks include /healthz, /readyz, and RPC status. See Testing updates and plugins for the preserved-state and successful-upgrade requirements.
All supported baseline rows require successful updates. Existing synthetic
base and reported-issue fixtures retain their success assertions and run once
on the candidate-relative predecessor. The lane does not run an extra Doctor or
omit those fixtures to turn a failed schema upgrade into a pass.
Current cross-OS tooling runs packaged fresh-install and upgrade checks on both
Node 24.21.0 and the Node 26.1.0 support floor across Linux, Windows, and macOS.
Windows packaged fresh-install retains Node 24.16.0 for its Node 24 cell because
of the later libuv file-watcher regression. Both runtime variants consume the
same prepared candidate tarball. A focused suite_filter selects both Node
variants; the Node 26 jobs and artifacts have distinct names. Installer and
source-update lanes keep their existing Node 24 coverage. Explicitly selecting
older workflow_ref tooling retains that revision's historical matrix.
The Windows packaged and installer fresh lanes also verify that an installed package can import a browser-control override from a raw absolute Windows path. The OpenAI cross-OS agent-turn smoke defaults to OPENCLAW_CROSS_OS_OPENAI_MODEL when set, otherwise openai/gpt-5.6-luna, so the install and gateway proof uses the lower-cost GPT-5.6 test tier.
Legacy compatibility windows
Current upgrade-survivor execution requires a published baseline of 2026.6.1
or newer. Historical selectors filter out earlier releases; release-history
selects the six most recent supported stable releases. Exact pre-June baselines
are rejected, including when a dist-tag resolves to one. Use matching historical
workflow_ref tooling to replay older upgrades. Existing historical receipts
remain readable.
Package Acceptance no longer relaxes assertions for pre-June 2026 candidates.
Missing inventory entries, shipped local build metadata, missing service-wrapper
support, and incomplete update or plugin install-record persistence fail the
current contracts. Current package validators also require both npm lockfile
formats to be absent from new tarballs. To reproduce historical acceptance
results, select the matching historical workflow_ref tooling.
Examples
When debugging a failed package acceptance run, start at the resolve_package summary to confirm the package source, version, and SHA-256. Then inspect the docker_acceptance child run and its Docker artifacts: .artifacts/docker-tests/**/summary.json, failures.json, lane logs, phase timings, and rerun commands. Prefer rerunning the failed package profile or exact Docker lanes instead of rerunning full release validation.