docs/help/testing-updates-plugins.md
This is the dedicated checklist for update and plugin validation. The goal is
simple: prove the installable package can update real user state, repair stale
legacy state through doctor, and still install, load, update, and uninstall
plugins from the supported sources.
For the broader test runner map, see Testing. For live provider keys and network-touching suites, see Testing live.
Update and plugin tests protect these contracts:
dist/postinstall-inventory.json,
and does not depend on unpacked repo files.openclaw doctor --fix --non-interactive owns legacy cleanup and repair
paths. Startup should not grow hidden compatibility migrations for stale
plugin state.Start narrow:
pnpm changed:lanes --json
pnpm check:changed
pnpm test:changed
For plugin install, uninstall, dependency, or package-inventory changes, also run the focused tests that cover the edited seam:
pnpm test src/plugins/uninstall.test.ts src/infra/package-dist-inventory.test.ts test/scripts/package-acceptance-workflow.test.ts
Before any package Docker lane consumes a tarball, prove the package artifact:
pnpm release:check
release:check runs config/docs/API drift checks, writes the package dist
inventory, runs npm pack --dry-run, rejects forbidden packed files, installs
the tarball into a temp prefix, runs postinstall, and smokes bundled channel
entrypoints.
The Docker lanes are the product-level proof. They install or update a real package inside Linux containers and assert behavior through CLI commands, Gateway startup, HTTP probes, RPC status, and filesystem state.
Use focused lanes while iterating:
pnpm test:docker:plugins
pnpm test:docker:plugin-lifecycle-matrix
pnpm test:docker:plugin-update
pnpm test:docker:upgrade-survivor
pnpm test:docker:published-upgrade-survivor
pnpm test:docker:update-migration
Important lanes:
test:docker:plugins validates plugin install smoke, local folder installs,
local folder update skip behavior, local folders with preinstalled
dependencies, file: package installs, git installs with CLI execution, git
moving-ref updates, npm registry installs with hoisted transitive
dependencies, npm update no-ops, local ClawHub fixture installs and update
no-ops, marketplace update behavior, and Claude-bundle enable/inspect. Set
OPENCLAW_PLUGINS_E2E_CLAWHUB=0 to keep the ClawHub block hermetic/offline.test:docker:plugin-lifecycle-matrix installs the candidate package in a bare
container, runs an npm plugin through install, inspect, disable, enable,
explicit upgrade, explicit downgrade, and uninstall after deleting the plugin
code. It logs RSS and CPU metrics for each phase.test:docker:plugin-update validates that an unchanged installed plugin does
not reinstall or lose install metadata during openclaw plugins update.test:docker:upgrade-survivor installs the candidate tarball over a dirty
old-user fixture, runs package update plus non-interactive doctor, then starts
a loopback Gateway and checks state preservation.test:docker:published-upgrade-survivor first installs a published baseline,
configures it through a baked openclaw config set recipe, updates it to the
candidate tarball, runs doctor, checks legacy cleanup, starts the Gateway, and
probes /healthz, /readyz, and RPC status.test:docker:update-migration is the cleanup-heavy published-update lane. It
starts from a configured Discord/Telegram-style user state, runs baseline
doctor so configured plugin dependencies have a chance to materialize, seeds
legacy plugin dependency debris for a configured packaged plugin, updates to
the candidate tarball, and requires post-update doctor to remove the legacy
dependency roots.Useful published-upgrade survivor variants:
[email protected] \
OPENCLAW_UPGRADE_SURVIVOR_SCENARIO=versioned-runtime-deps \
pnpm test:docker:published-upgrade-survivor
OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC=openclaw@latest \
OPENCLAW_UPGRADE_SURVIVOR_SCENARIO=bootstrap-persona \
pnpm test:docker:published-upgrade-survivor
Available scenarios are base, feishu-channel, bootstrap-persona,
plugin-deps-cleanup, configured-plugin-installs,
stale-source-plugin-shadow, tilde-log-path, and versioned-runtime-deps. In aggregate runs,
OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS=reported-issues expands to all reported
issue-shaped scenarios, including the configured-plugin install migration.
Full update migration is intentionally separate from Full Release CI. Use the
manual Update Migration workflow when the release question is "can every
published stable release from 2026.4.23 onward update to this candidate and
clean up plugin dependency debris?":
gh workflow run update-migration.yml \
--ref main \
-f workflow_ref=main \
-f package_ref=main \
-f baselines=all-since-2026.4.23 \
-f scenarios=plugin-deps-cleanup
Package Acceptance is the GitHub-native package gate. It resolves one candidate
package into a package-under-test tarball, records version and SHA-256, then
runs reusable Docker E2E lanes against that exact tarball. The workflow harness
ref is separate from the package source ref, so current test logic can validate
older trusted releases.
Candidate sources:
source=npm: validate openclaw@beta, openclaw@latest, or an exact
published version.source=ref: pack a trusted branch, tag, or commit with the selected current
harness.source=url: validate an HTTPS tarball with required package_sha256.source=artifact: reuse a tarball uploaded by another Actions run.Full Release Validation uses source=artifact by default, built from the
resolved release SHA. For post-publish proof, pass
[email protected] so the same upgrade matrix
targets the shipped npm package instead.
Release checks call Package Acceptance with the package/update/plugin set:
doctor-switch update-channel-switch update-corrupt-plugin upgrade-survivor published-upgrade-survivor plugins-offline plugin-update
They also pass:
published_upgrade_survivor_baselines=all-since-2026.4.23
published_upgrade_survivor_scenarios=reported-issues
telegram_mode=mock-openai
This keeps package migration, update channel switching, corrupt managed-plugin tolerance, stale plugin dependency cleanup, offline plugin coverage, plugin update behavior, and Telegram package QA on the same resolved artifact without making the default release package gate walk every published release.
all-since-2026.4.23 is the Full Release CI upgrade sample: every stable npm-published release from 2026.4.23 through latest. For exhaustive published
update migration coverage, use all-since-2026.4.23 in the separate Update
Migration workflow instead of Full Release CI. release-history remains
available for manual wider sampling when you also want the legacy pre-date
anchor.
Run a package profile manually when validating a candidate before release:
gh workflow run package-acceptance.yml \
--ref main \
-f workflow_ref=main \
-f source=npm \
-f package_spec=openclaw@beta \
-f suite_profile=package \
-f published_upgrade_survivor_baselines=all-since-2026.4.23 \
-f published_upgrade_survivor_scenarios=reported-issues \
-f telegram_mode=mock-openai
Use suite_profile=product when the release question includes MCP channels,
cron/subagent cleanup, OpenAI web search, or OpenWebUI. Use suite_profile=full
only when you need full Docker release-path coverage.
For release candidates, the default proof stack is:
pnpm check:changed and pnpm test:changed for source-level regressions.pnpm release:check for package artifact integrity.package profile or the release-check custom package
lanes for install/update/plugin contracts.On maintainer machines, broad gates and Docker/package product proof should run in Testbox unless explicitly doing local proof.
Compatibility leniency is narrow and time boxed:
2026.4.25, including 2026.4.25-beta.*, may tolerate
already-shipped package metadata gaps in Package Acceptance.2026.4.26 package may warn for local build metadata stamp
files already shipped.Do not add new startup migrations for these old shapes. Add or extend a doctor
repair, then prove it with upgrade-survivor or published-upgrade-survivor.
When changing update or plugin behavior, add coverage at the lowest layer that can fail for the right reason:
package-dist-inventory or tarball
checker test.published-upgrade-survivor scenario.test:docker:plugins fixture or ClawHub
fixture server.node_modules tree.Keep new Docker fixtures hermetic by default. Use local fixture registries and fake packages unless the point of the test is live registry behavior.
Start with the artifact identity:
resolve_package summary: source, version, SHA-256, and
artifact name..artifacts/docker-tests/**/summary.json,
failures.json, lane logs, and rerun commands..artifacts/upgrade-survivor/summary.json,
including baseline version, candidate version, scenario, phase timings, and
recipe steps.Prefer rerunning the failed exact lane with the same package artifact over rerunning the whole release umbrella.