Restore the compatible npm plugin cohort and its settings when an update rolls core back after replacing plugins. Preserve later independent plugin/config changes and keep recovery under the existing update owner.
Validation: all 21 PR-caused errors fixed; fresh independent canonical Codex P0-P2 review clean; focused rollback, authority, candidate, lease, Windows, terminal and consumer checks pass. Parent runtime GREEN covers registered rollback, restored Gateway, foreground update.run, published-2026.10.9 upgrade, container death/reopen and 16,826-file payload matches. The older-released-parent gap remains documented.
Landing ruling, 2026-10-31 10:53Z: seven remaining CI failures are inherited and admitted through the native inherited-failure route. Root-help timeout and service-authority each PASSED one exact-head rerun; no main match was found. They are one-off flakes: not PR-caused, and not waived as inherited. The failed broad CI result is retained.
Root-help rerun: https://github.com/openclaw/openclaw/actions/runs/41189435747/job/124509785351
Service-authority rerun: https://github.com/openclaw/openclaw/actions/runs/41189435747/job/124512997230
Full attribution: https://github.com/openclaw/openclaw/pull/188978
Work sessions:
- Implementation and verification: https://team.openclaw.ai/chat/roboclaw/~key/dashboard/78580230-7d1b-4329-a7dd-72554eb66323
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Initialize the canonical state schema before the unchanged-update fixture writes its plugin install record.
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: RomneyDa <6581799+RomneyDa@users.noreply.github.com>
* fix(e2e): switch extended-stable first-hop and plugin-update tag updates to stable
* fix(release): omit waived live files for extended-stable 2026.9.33
* test(e2e): seed the consent scenario host manifest and cover extended-stable hosts
## What Problem This Solves
Repository scripts retain private copies of shared tooling helpers and an unused translation subprocess runner, increasing maintenance work across sibling scripts.
## User Impact
Internal tooling cleanup: existing flags, diagnostics, generated bytes, JSON formats, exit codes, and cleanup policies stay the same. The build wrapper additionally detects forbidden dynamic-import warnings when compiler output splits the warning marker across chunks.
## Why This Change Was Made
- Remove the retired i18n process runner. Its final production caller moved to the shared formatter in #95534; retain real CLI/privacy/provider tests and run their subprocesses with the existing dependency.
- Share Docker resource, signal-trap, platform, workspace-staging, and plugin-selection helpers while retaining each caller's environment precedence and lifecycle decisions.
- Reuse existing E2E fixture JSON/assertion and package-path helpers; retain distinct write modes, recovery ordering, and mounted/frozen harness contracts.
- Share macOS guest desktop-user/home resolution through its existing owner while preserving per-caller timeout policy.
- Route release/mobile flags through the existing version flag specifications, preserving split-only values, duplicate/mode rules, help timing, and error text. Reuse existing retry sleep and comparator owners and remove an unreachable iOS output branch.
- Reuse existing guard entrypoint, failure-trailer, diagnostic-line, and metadata-normalization owners.
Measured reduction: **732 net production lines**, with test changes counted separately. PR tooling and its protected import closure, CI planners/shards, baselines, and generated artifacts are unchanged.
## Fixes Found Along the Way
The tsdown scanner checked each raw output chunk for its warning marker. It now checks the existing combined-line buffer. The regression exercises every split inside the marker and fails on the original source for the intended missing-warning assertion.
## Evidence
- Blacksmith Testbox `tbx_01m3tp4sabwd0807kj9jkqqmbr`: frozen dependency install and candidate source-byte verification; all nine changed test files and 59 selected sibling files passed, including real CLI, package fixture, recovery, Docker harness, and Parallels transport contracts.
- Generated channel metadata is byte-identical; differential metadata normalization cases passed.
- SDK surface check passed. Independent isolated Codex review completed with no P0–P2 findings.
- Initial changed checks caught an invalid direct source import in a proposed snapshot-distance consolidation; that independent change was withdrawn. No boundary exception was added. The final changed checks pass, including script/test lint and Docker shell/scheduler checks; madge reports 0 cycles and the runtime import check reports 0 cycles.
- Per-file single-worker wall time for changed suites: translation 9.92s; Docker helper 38.88s; live Docker auth 1.71s; mobile ref 2.36s; mobile release 6.23s; release preparation 2.42s; version 2.04s; installer 15.01s; tsdown 2.70s. The existing Docker helper suite executes shell/process cleanup and container-command boundary fixtures; new assertions reuse those fixtures. New parser/scanner cases use no sleeps or polling.
Hosted CI will be verified against this PR's exact pushed head. No live deployment or release was performed.
Fixes four release-lane harness bugs that failed 2026.9.7 Full Release Validation independently of the product:
- openai-web-search-minimal selects the agent request by model and exact success prompt instead of the first request quoting the marker (Activity recaps quote it since #147441).
- plugin-update consent package updates use the existing 900 s update-lane budget; timeouts are reported as timeouts with stdout/stderr/ledger paths before JSON parsing.
- Windows packaged upgrade lanes pass the long spelling of the inherited TEMP/TMP/TMPDIR to published updaters (the immutable 2026.9.5 driver mis-compares 8.3 short paths; fixed on main by #151157).
- The QA mock calls session_status through dispatcher-aware capability detection, so the Telegram current-session scenario works under default Tool Search.
Each regression fails on the original harness code and passes with the fix (Testbox).
* 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.
## Summary
`openclaw update` retains the running updater's package tree so its workers survive the installer's replacement (#153764). That retention byte-copied the entire package root (`package.json`, `dist/`, `node_modules/`, 37,309 files / 625 MB for 2026.9.6) with three full `lstat` passes plus a per-file copy and verify. On the release Docker host this ran at ~12 files/s, so every in-place global update stalled in the `validating` phase for well over the E2E harness's 300 s command budget. `Plugin Prerelease` lane `plugin-update` (Full Release Validation 35775979903 → run 35779065106) then reported `update-denied did not return JSON: Unexpected end of JSON input` because `timeout` killed the command before any output.
This keeps the retention semantics and makes it cheap:
- Files are hard-linked into the private runtime directory (`fs.link`), so the inventoried inodes outlive npm's rename/unlink without copying bytes. Bytes are copied only when the filesystem refuses the link (`EXDEV`, `EPERM`, `ENOTSUP`, ...) or when relocation must rewrite the member in place (`.modules.yaml`, `.bin` launchers), so the live package is never edited through a shared inode.
- One walk performs the inventory check, publication, relocation and escape check per entry (was: pre-check pass, directory pass, file pass with two checks, symlink pass, post-check pass, relocation pass, full verify walk).
- After each link the private name is checked to reference the inventoried `dev:ino`; entries sharing an already linked inode (pnpm store hard links) keep every fingerprint field except the change time that the link itself bumps.
- The IO budget watchdog around retention is unchanged.
- `node_modules` stays in the retained tree: retained workers (`dist/**` entrypoints) resolve their dependencies from it.
- The shared copy path used for candidate rehearsal snapshots is unchanged in behavior; its plan rebasing, host-link/alias publication and verification moved to `update-candidate-plugin-tree-links.ts` so both materializers share them.
- Harness: the consent scenario's "did not return JSON" assertion now includes the command's exit code so a `timeout` kill (124) is visible in CI.
## Evidence
- Root cause repro on the exact CI candidate bytes (artifacts `docker-e2e-package-35777886894-1` + `docker-e2e-prepublish-plugin-registry-35777886894-1`): `update --tag core-denied-future.tgz --yes --json` finished `npm i` in 2 min, then sat in `validating` copying `openclaw-update-runtime-*` at 5,264 → 5,513 files in 20 s (~12 files/s); 6,402 files / 102 MB after 9 min; SQLite `update_runs` row `failed/interrupted` when the harness killed it.
- With this change: the same repro (same host, load average ~34) returns the denial payload on stdout with exit 0 (`status: ok`, `postUpdate.plugins.status: warning`, `PLUGIN_CAPABILITY_CONSENT_REQUIRED`, `after.version: 2026.9.99-first-hop.0`) and the whole `update --tag` command completes in 3.5 min end to end (npm install 28 s, canary validation, activation, Doctor). Retention alone, measured directly on the installed 38,678-file package with `withRetainedUpdateRuntime`: 33.9 s to retain (about 1,140 files/s, roughly 95x faster than the copy) and 4.6 s to release.
- Unit tests: `src/infra/update-retained-runtime-tree.test.ts` (link path shares inodes and survives source replacement, `EXDEV` fallback copies bytes with the inventoried mode, changed entries are refused before any link, relocated launcher is copied so the live file is untouched); existing `update-retained-runtime.test.ts` layouts (npm/pnpm/pnpm-workspace/git/git-linked) and `update-candidate-plugin-tree.test.ts` pass.
- `OPENCLAW_TESTBOX=1 pnpm check:changed` and the `plugin-update` Docker lane on the packed candidate: results in the PR comments.
* fix(e2e): align release fixture contracts
Preserve consent refusal and diagnostic boundaries, model the stopped Doctor fixture through real read contracts, and handle the explicit single-agent onboarding menu without changing legacy flow or timeout budgets.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: RomneyDa <6581799+RomneyDa@users.noreply.github.com>
* test(e2e): handle absent consent fixture tag lookup
Keep an absent tag on the existing unprepared-update rejection path while satisfying the strict indexed-access typecheck.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: RomneyDa <6581799+RomneyDa@users.noreply.github.com>
---------
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: RomneyDa <6581799+RomneyDa@users.noreply.github.com>
Keep an explicit unavailable-target refusal case with unchanged core, config, install records and corrupt payload. Then serve the original plugin archive from an owned registry and retain the successful corrupt-recovery and policy assertions. This preserves the documented plugin availability gate instead of accepting unknown target metadata or bypassing admission.
* fix(qa): verify leased Telegram tester group access
Check tester membership and effective text permission in the leased user driver before group readiness. Reuse the check in doctor and select trusted skill scripts for frozen release candidate QA. Preserve supported private DM turns and leave credential repair to the pool owner.
* ci: install Chromium for native live browser tests
The native-live-test shard includes the real Gateway widget restart proof,
which launches Playwright after restoring the interrupted session. Chromium
was installed only in separate Repo E2E jobs, leaving the live shard without
its required executable.
Install the candidate UI's pinned Chromium and system dependencies only for
the selected native-live-test row. Preserve profile selection and all test
gates. Verified the unchanged dc420 widget restart test with real OpenAI,
Gateway process replacement, and interactive Chromium dashboard assertions
on Blacksmith Testbox; canonical workflow checks and formatting also pass.
* test(release): prove supported cross-OS 9.2 transition
Select the explicitly supported external package-manager and fresh Doctor
transition only for 2026.9.2 to 2026.9.3. Preserve the old updater's safe
schema-15 refusal as negative evidence and never report self-update passed.
Verify backup, exact package identity, schema migration, retained settings
and session history, candidate serving version, and a fresh persisted turn.
Keep credential-bearing backup archives out of CI evidence and remove them
on both successful and failed runs. Other release pairs retain existing
updater and Windows fallback behavior.
Validation: 13 cross-OS upgrade lane tests, two pre-fix regression failures,
full changed checks, and independent review. Real packaged cross-OS/live
qualification remains required against the aggregate candidate.
* test(installer): prove supported historical package transitions
* test(release): exercise same-schema updater boundaries
Keep updater-specific plugin repair and consent checks on the prepared
candidate, then target explicit synthetic later versions with the same
runtime and storage schema. Retain installed-version and plugin-policy
assertions, and remove the obsolete legacy post-update fallback.
Add versioned future-tarball generation to the existing first-hop fixture
owner, with immutable input and source/target digest receipts. Restore the
reserved runtime-promotion staging ignore in package-derived Git fixtures
so the updater's unchanged-source check stays meaningful.
Validation: 26 focused tests, a pre-fix Git staging regression, full changed
checks, exact candidate tarball fixture generation, and P2 review. Actual
Docker update/consent/channel qualification remains required in aggregate CI.
* test(release): verify channel update staging cleanup
Assert the real channel flow refuses ordinary untracked user files without changing source, then require successful channel updates to remove every reserved runtime staging entry. Preserve recovery data when the assertion detects leftovers. No ignore or production cleanup policy is broadened.
* test(onboard): select configured model through explicit picker
* ci: pin release performance checks to reviewed Kova accounting
Select the reviewed Linux process-lifetime CPU accounting and bounded worker-watchdog implementation from Kova PR #110 for canonical, legacy-list, and trusted live fixtures. Keep existing trust classification, timeout values, and performance thresholds.
* fix(ci): distinguish bundle build modes in job names
* test(release): build matching future runtime fixtures
Derive a synthetic Codex runtime cohort from its verified candidate package by changing only package.version and openclaw.build.openclawVersion. Require matching source metadata and preserve payload, constraints, immutable input, and source/target digest receipts. Reuse the existing private tarball lifecycle and sequence validation. Validated 11 focused tests, pre-change CLI failures, full changed checks, and P2 review.
* docs(release): prepare private QA before local E2E
* fix(release): admit package metadata before validation dispatch
Port the reviewed early source admission into trusted Tooling, preserving the current selected REST transport. Reject invalid version notes and misaligned core packages before any Git push, non-GET API write, or workflow dispatch; retain explicitly allowed substantive draft notes.
* test(release): qualify supported historical upgrade transitions
Prove the published 2026.8.2/2026.9.2 to 2026.9.3 external package-manager and fresh Doctor contract through one shared helper. Preserve the old in-process updater refusal and schema 15, require owner-stopped migration with a verified private backup, and verify schema 16 plus retained Gateway history afterward.
Keep current-runtime update coverage distinct: managed restart uses separately identified future core and matching runtime fixtures, with real updater, canary, service replacement, authentication, and serving checks. Fix fixture-only channel environment pollution and mock serving nonce responses.
Sealed Docker journey, historical first-hop, current-candidate survivor, root-managed VPS, and onboarding pass. Managed-auth historical preservation passes; its future canary exposes an independent existing plugin projection blocker, retained as failing proof for the candidate repair owner. No product schema or refusal guard changes.
* test(release): narrow recorded update command before indexing
* fix(ci): align historical upgrade fixture ownership
Keep all seven external transition assertion cases with the first-hop package fixtures: both own the historical upgrade boundary and now share its temporary-state lifecycle. Preserve helper test selection and all assertions while avoiding an additional standalone tooling group.
Provide the new inference and future-package preparation boundaries in isolated service, mobile, and cron bootstrap probes, and verify each updater argument without changing readiness or migration assertions. Register the path-launched assertion CLI as a Knip entry.
Validation: 67 related tests; 70 exact-merge planner and combined-suite tests; five 80-job stress plans; full Knip unused-file scans; scoped checks and P2 review.
* fix(ci): model upgrade preparation in isolated probes
Complete the companion fixture and Knip repairs for the preceding transition-test consolidation. Model the independent inference and future-package preparation producers, verify exact updater argument boundaries, and retain service-readiness, authored-state, and cron migration assertions. Declare the path-launched transition assertion CLI in the existing Knip entrypoint list.
* test(release): preserve fixture registry on managed restart
Capture the fake service manager registry alongside its endpoint paths, then refresh that owned context after preparing the future cohort. Projected native service callers cannot drop or replace it; transient update state still stays outside the managed child.
The executable service regression fails on the original shim and passes with missing and conflicting caller registries. Four focused tests, the changed gate, and P2 review pass. Reuse the existing d928 package for the final managed-upgrade replay.
* test(release): preserve prepared UI identity in future fixtures
Advance synthetic package versions while retaining the opaque build ID already embedded in unchanged Control UI assets. The canonical asset-health regression fails the prior builder as stale, then verifies readiness and unchanged UI bytes for both future fixture sequences. Package-version update admission and managed-restart proof remain unchanged.
* test(release): retain manager-owned fixture policy
Capture the existing automation and offline-channel policy with registry identity when generating the manager shim. Native service clients project these values away; losing them activated retained synthetic channel credentials and correctly failed readiness. Restore only this explicit manager allowlist and keep transient update/compatibility state excluded.
The executable service regression fails on missing manager flags and passes across projected or conflicting caller environments. Four focused tests, the full changed gate, and fresh P2 review pass. Actual corrected managed Docker proof remains pending.
* docs(ci): keep bundle identity with routing guidance
* fix(release): retry transient GraphQL EOF failures
Classify the observed gh unexpected EOF transport failure within the existing five-attempt retry budget. Preserve authentication, invalid-response, inventory and snapshot handling. Exercise recovery, exhaustion and fail-fast errors through the real verifier CLI with a fake gh transport; also modernize the existing disposable-array sort required by touched-test lint.
* test(release): align survivor fixtures with manager preparation
Supply manager environment JSON to directly launched supervisors, and model the independent manager preparation phase in config-parking and companion fixtures. Preserve service readiness, restart, diagnostics, and strict phase-order assertions without changing production behavior or test limits.
* test(release): align upgrades with deferred schema publication
Restore installed-updater survivor and first-hop coverage after shared migration ownership moved into the durable update ledger. Record applied schema content separately from published schema version, retain the genuine missing-chunk negative control, and label external installation as an alternate with no self-update attempt. Preserve production-owned unsupported migration refusals.
* test(release): restore supported packaged upgrade coverage
Restore real 2026.9.2 to 2026.9.3 self-update after ledger-driven schema migration support. Keep retained conversations, private backup, settings, candidate identity, and serving inference proof. Require migrated content independently of publication grace and remove obsolete external-install diversion from cross-OS and installer update smoke. Shared external helper remains separately owned.
* test(release): refresh legacy manager before updater restart
Bind the service manager to the candidate registry before the published baseline updater starts its managed service. Preserve restart verification for successful and recoverable outcomes alongside explicit future targets. Exercise stale registry capture, replacement failures, pre-update identity, and attribution without changing timeouts or caps.
* fix(docker): install workspace dependencies for binding smoke
The binding source-test image installed only the root project. With pnpm's
isolated linker, private packages reached through source aliases had no
package-local dependency links, so all three suites failed to import
mdast-util-from-markdown from markdown-core.
Remove the root-only install filter in the owning E2E Dockerfile so pnpm
creates the complete workspace graph. Keep the frozen lockfile, isolated
linker, and disabled lifecycle scripts. Update the existing helper guard.
Proof: the unmodified Docker lane and native Markdown import reproduced
ERR_MODULE_NOT_FOUND. Rebuilding the corrected image passes the import,
workspace/plugin symlink probes, and all three focused binding tests.
pnpm test test/scripts/docker-build-helper.test.ts passes 273 tests with
two existing skips; pnpm check:changed and fresh Codex autoreview pass.
Other sampled release Docker failures have independent plugin/update
causes and are not covered by this image repair.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 1fa94d95b190b30f1b9b4f33235c31b2d8026680)
* fix(e2e): resolve prepared stable plugins during upgrade
Prepared registry merging kept upstream latest tags during candidate upgrade,
so the survivor installed 2026.8.2 plugins despite serving 2026.9.1 artifacts.
The registry helper now distinguishes published baseline tags from candidate
package tags while retaining older dependency versions and fixture identities.
Owner: prepared npm registry harness. Product runtime is unchanged; this
repairs false stable-release upgrade failures for WhatsApp and Matrix.
Proof: stable registry regression failed twice before the repair; all 15
registry helper and 37 plugin selection tests pass. The original 2026.9.1
candidate now passes the published 2026.8.2 survivor in local Docker.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(e2e): preserve the candidate registry across corrupt plugin setup
The nested synthetic registry replaced only one npm environment spelling,
then setup discarded both instead of restoring the parent prepared registry.
This caused a synthetic-package 404 and, once repaired, an unpublished core
dependency ETARGET. Set both spellings and scope fixture setup to a subshell
whose cleanup owns only the temporary server; preserve parent artifact state.
Owner: npm fixture lifecycle and corrupt-plugin scenario. Product runtime is
unchanged; release validation now exercises real corrupt-plugin tolerance.
Proof: real npm regression fails before the repair and passes afterward.
Docker reproduces both failures, then passes the full 2026.8.2 to unchanged
2026.9.1 candidate upgrade while preserving the plugin policy assertions.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* fix(e2e): inspect survivor plugins before restoring legacy config
Companion provenance inspection ran after the harness restored deliberately
invalid legacy Discord configuration, so validation aborted before update.
Keep inspection within the existing parked-config lifetime and restore the
exact authored bytes after success or failure. Existing Doctor migrations
remain responsible for the actual upgrade.
Owner: upgrade-survivor fixture preparation. Product runtime is unchanged;
release validation can reach the migration it is intended to exercise.
Proof: the original candidate reproduces the pre-update Docker failure;
two new lifecycle cases fail before the repair and all three pass afterward,
with the existing registry-order helper case also passing. Full Docker
survivor now passes migration, state survival, and Gateway readiness/RPC
against the same original release candidate.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Closes#134156
## What Problem This Solves
Fixes an issue where a core update could report success and restart the Gateway after a managed plugin refused an unreviewed capability change. The update retained the older plugin payload but started the newer host, which created a mixed host/plugin state.
## Why This Change Was Made
The post-core result owner now treats the existing typed `PLUGIN_CAPABILITY_CONSENT_REQUIRED` outcome as an unresolved convergence error. It keeps other recoverable plugin failures as warnings, preserves the previous plugin, and does not bypass capability review or change inbound dispatch lifecycle checks.
The JSON and terminal paths now return one shared plugin result object.
## User Impact
`openclaw update` now exits non-zero and blocks a requested Gateway restart until the operator reviews the plugin capabilities and runs `openclaw update repair`. The result still names the affected plugin and preserves the exact retry guidance.
## Evidence
- Exact current-main baseline `9ac61cdbab` and release `v2026.8.1` (`ea806575e6`) both accepted the existing consent-deferral fixture while the outer core update stayed successful.
- The new owner-boundary regression failed before the production repair because the outer status was `ok`, not `error`.
- `node scripts/run-vitest.mjs src/cli/update-cli.test.ts`: 286 passed.
- `node scripts/run-vitest.mjs test/scripts/docker-build-helper.test.ts -t 'capability consent|upgrade survivor'`: 14 passed.
- Core Oxlint, script Oxlint, Oxfmt, script syntax, and `git diff --check`: passed.
- Autoreview: no P0 findings, 0.98 confidence.
- Exact built production bytes came from green CI run [33403041210](https://github.com/openclaw/openclaw/actions/runs/33403041210) at `6a89535b5a85cd57504b07af0a2f74692e60cd88`; the next commit changes only the proof fixture.
- The isolated installed-package fixture requested the default restart and passed. The denied update exited 1 with `status: "error"`, `reason: "post-update-plugins"`, and `PLUGIN_CAPABILITY_CONSENT_REQUIRED`; it spawned the fresh post-core child but no `gateway restart` child, and the old plugin payload and record remained at version 1.0.0.
- The same fixture then accepted reviewed consent, updated to version 2.0.0, proved consent did not apply to a later widening, accepted a fresh review for version 3.0.0, and repaired a missing payload only after explicit consent.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Continue scanning readable descendants when an individual procfs read is unavailable, retain proven positive observations, and join unexpected observer errors with command exit. Keep the complete consent scenario and positive fresh-child assertions unchanged.
* fix(update): preserve explicit plugin capability consent
* fix(update): bind plugin consent to staged artifacts
Use the canonical artifact consent adapter for channel migrations and preserve
explicit consent through the update wizard. Keep prior usable payloads on denial
and record the exact accepted surface through the existing install-record owner.
Cover parser boundaries, staged artifact changes, and packaged update/repair
handoffs without treating --yes as consent or granting future permission.
Co-authored-by: Dallin Romney <dallinromney@gmail.com>
* test(update): register consent scenario with probe
Route the packaged consent scenario through the existing plugin-update probe
so Knip discovers the implementation through its normal entry graph. Initialize
scenario state only when the consent command runs, preserving other probe modes.
Co-authored-by: Dallin Romney <dallinromney@gmail.com>
* fix(update): retain consent with compatible finalizers
Inspect the installed update command before forwarding explicit consent so
older and same-version target CLIs keep finalization in the existing parent
path when they lack the option. Preserve the installed compatibility host
through plugin convergence and reuse the update step timeout for inspection.
Use built-in streaming SHA256 for the packaged proof rather than requiring
an undeclared checksum binary.
Co-authored-by: Dallin Romney <dallinromney@gmail.com>
* fix(update): keep convergence code loaded across replacement
Link the mandatory registry repair before the core package swap removes the
old updater's chunks. This keeps current-process finalization runnable when
the installed target cannot receive explicit capability consent, without
retaining old runtime files or changing plugin policy.
Co-authored-by: Dallin Romney <dallinromney@gmail.com>
* test(cli): await MCP Doctor batch readiness
Synchronize the concurrency test at the fourth credential check instead of
polling command startup with a wall-clock deadline. Release blocked checks
and await Doctor in finally, including early command or assertion failures.
Keep the exact concurrency, total-check and sorted-result assertions.
Co-authored-by: Dallin Romney <dallinromney@gmail.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Dallin Romney <dallinromney@gmail.com>