Skip to content

fix(update): mandatory post-core plugin convergence before gateway restart#79143

Merged
steipete merged 12 commits into
openclaw:mainfrom
BKF-Gitty:fix/post-core-plugin-convergence
May 12, 2026
Merged

fix(update): mandatory post-core plugin convergence before gateway restart#79143
steipete merged 12 commits into
openclaw:mainfrom
BKF-Gitty:fix/post-core-plugin-convergence

Conversation

@BKF-Gitty

@BKF-Gitty BKF-Gitty commented May 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Distinguish "package files actively being swapped" (OPENCLAW_UPDATE_IN_PROGRESS=1) from "post-core convergence" (OPENCLAW_UPDATE_POST_CORE_CONVERGENCE=1); plugin repair no longer defers in the latter.
  • After the core swap completes and before gateway restart, run a mandatory convergence pass that repairs missing configured plugin payloads, validates install records on disk, and runs a static plugin payload smoke check (no plugin code is executed).
  • Convergence failures escalate postUpdate.plugins.status to "error", which the existing pre-restart gate maps to exit 1 with precise repair guidance.
  • Invalid config also returns status: "error" (was "skipped") so the gateway is not restarted with an unverifiable plugin set.

Motivation

A live OpenClaw instance had Brave/Discord plugins configured with install records present in the persisted index but their payload directories / package.json missing on disk. openclaw update ran the in-update doctor pass with OPENCLAW_UPDATE_IN_PROGRESS=1, which deferred configured plugin repair, and then restarted the gateway with broken plugins. This PR makes that scenario an explicit pre-restart failure with actionable guidance instead of a silently broken gateway.

What changed

  • src/commands/doctor/shared/update-phase.ts — new module exporting isUpdatePackageSwapInProgress / isPostCoreConvergencePass (post-core wins).
  • src/commands/doctor/shared/missing-configured-plugin-install.ts — switched to phase helpers; deferral path no longer fires when post-core convergence is set. repairMissingConfiguredPluginInstalls now accepts an optional baselineRecords (so callers can pass in-memory state from earlier post-core steps) and returns the post-mutation records map.
  • src/commands/doctor/repair-sequencing.ts, src/commands/doctor/shared/release-configured-plugin-installs.ts — switched to the same phase helpers.
  • src/cli/update-cli/plugin-payload-validation.ts — new static payload check (validates package dir, parses package.json, only fails on missing-main-entry when main is explicitly declared and absent — OpenClaw plugins with exports/openclaw.extensions and no main are accepted).
  • src/cli/update-cli/post-core-plugin-convergence.ts — orchestrator that sets the env signal, calls repairMissingConfiguredPluginInstalls with the in-memory baseline, runs the payload check on the post-repair record map, and folds warnings into outcomes.
  • src/cli/update-cli/update-command.ts — wired the convergence call into updatePluginsAfterCoreUpdate after the existing npm-update pass; passes the in-memory pluginConfig.plugins.installs as the baseline and reseeds pluginConfig from convergence.installRecords unconditionally before the commit block (so sync/npm in-memory mutations and convergence repairs are both preserved). Convergence failures and invalid configs flip status to "error". Per-warning guidance[] lines are surfaced under the warning message in non-JSON mode.
  • Drive-by: removed dead __testing export from missing-configured-plugin-install.ts (zero consumers).

Real behavior proof

Behavior or issue addressed: An OpenClaw instance had configured plugins (Brave, Discord) whose persisted install records pointed at payload directories that no longer existed on disk. Running openclaw update deferred configured plugin repair while OPENCLAW_UPDATE_IN_PROGRESS=1 was set, and then restarted the gateway with broken plugins instead of failing the update with actionable guidance. The fix introduces a mandatory post-core convergence pass that repairs / validates configured plugin payloads after the package swap and before the gateway restart, escalating any unrepairable failure to status: "error" so the existing pre-restart gate exits the update with non-zero status and clear repair instructions.

Real environment tested: macOS Darwin arm64, Node 22.21.1, branch fix/post-core-plugin-convergence at commit 77e70802d0, baseline compared against upstream/main@97d2d40fb7 (fix: allow safe exec secret passEnv inheritance). The same synthetic driver script (a small TypeScript program that constructs an OpenClawConfig mirroring the production failure shape and invokes updatePluginsAfterCoreUpdate directly) was executed against both code states. Only the function-under-test code differs between the two runs.

Exact steps or command run after this patch:

  1. Created a temp HOME and OPENCLAW_STATE_DIR so the persisted installed-plugin index lives in an isolated sandbox.
  2. Constructed an OpenClawConfig with three failure shapes mirroring the live incident: (a) configured plugin entry + persisted install record + missing payload directory; (b) configured plugin entry + persisted install record + payload directory present but with an unparseable package.json; (c) configSnapshot.valid = false to exercise the invalid-config gate.
  3. Imported updatePluginsAfterCoreUpdate from src/cli/update-cli/update-command.ts and invoked it with opts: { json: false } so the human-readable terminal output is captured.
  4. Captured stdout/stderr to a log file via tee, plus the returned { status, reason, warnings } object.
  5. Repeated the same three runs against upstream/main@97d2d40fb7 (after temporarily exporting the otherwise-private function) to capture the before-fix terminal output for comparison.

Driver invocations (recorded with tee so the captured output below is verbatim stdout):

node --import tsx .claude/repro/post-core-convergence-repro-invalid-config.mts
node --import tsx .claude/repro/post-core-convergence-repro-unrepairable.mts
node --import tsx .claude/repro/post-core-convergence-repro.mts

Evidence after fix:

Live terminal output captured from the after-fix run on branch HEAD 77e70802d0 against the invalid-config shape:

=== running updatePluginsAfterCoreUpdate against an invalid configSnapshot ===

Plugin post-update convergence skipped because the config is invalid; refusing to restart the gateway with an unverified plugin set.
  Run `openclaw doctor` to inspect the config validation errors.
  Once the config parses, rerun `openclaw update`.

returned status: error
returned reason: invalid-config

structured warnings:
- Plugin post-update convergence skipped because the config is invalid; refusing to restart the gateway with an unverified plugin set.
    Run `openclaw doctor` to inspect the config validation errors.
    Once the config parses, rerun `openclaw update`.

pre-restart gate would fire (status === "error"): true

Live terminal output captured from the after-fix run on branch HEAD 77e70802d0 against the corrupt-payload shape (configured made-up-plugin whose payload directory exists but contains package.json = "this-is-not-json", and whose plugin id does not exist on npm so the existing repair path cannot fix it):

=== running updatePluginsAfterCoreUpdate against a corrupt plugin payload ===

Updating plugins...
Disabled "made-up-plugin" after plugin update failure; OpenClaw will continue without it. Failed to update made-up-plugin: npm package not found for @openclaw/made-up-plugin.
Plugin "made-up-plugin" failed post-core payload smoke check (invalid-package-json): Could not parse package.json: Unexpected token 'h', "this-is-not-json" is not valid JSON
  Run `openclaw doctor --fix` to retry plugin repair.
  Run `openclaw plugins inspect made-up-plugin --runtime --json` for details.

For comparison, the same invalid-config invocation against upstream/main@97d2d40fb7 (before fix) — stdout captured verbatim — returned the silently-passing path:

=== running updatePluginsAfterCoreUpdate against an invalid configSnapshot ===

Skipping plugin updates: config is invalid.

returned status: skipped
returned reason: invalid-config

structured warnings:

pre-restart gate would fire (status === "error"): false

And the corrupt-payload invocation against upstream/main@97d2d40fb7 (before fix) silently auto-disabled the plugin without any payload validation:

=== running updatePluginsAfterCoreUpdate against a corrupt plugin payload ===

Updating plugins...
Disabled "made-up-plugin" after plugin update failure; OpenClaw will continue without it. Failed to update made-up-plugin: npm package not found for @openclaw/made-up-plugin.

Observed result after fix: updatePluginsAfterCoreUpdate now returns status: "error" and a structured warnings[].guidance payload for both the invalid-config shape and the unrepairable-payload shape. The exact same situations on upstream/main@97d2d40fb7 returned status: "skipped" (invalid config) or silently auto-disabled the plugin (corrupt payload) and would have allowed the gateway to restart in a broken state. The new payload smoke check surfaces the actual JSON-parse error in the corrupt-payload case (Unexpected token 'h', "this-is-not-json" is not valid JSON) and the human-readable guidance lines (Run \openclaw doctor --fix`, Run `openclaw plugins inspect made-up-plugin --runtime --json`) are emitted to stderr under each warning. The pre-restart gate in updateCommand (if (postCorePluginUpdate?.status === "error") { exit(1) }`) maps this to a non-zero exit, blocking the gateway restart that previously masked the broken state.

What was not tested: An end-to-end run on the original affected production instance after deploying this branch is not yet captured — that needs to land before the PR moves out of draft, and will be appended to this section as additional terminal-capture evidence (openclaw update, openclaw gateway status --deep, and the gateway/restart.log excerpt). The synthetic driver also stops short of the post-restart gateway health probe because the harness fakes the config-file hash; the convergence behavior asserted above all happens before that point and is independent of the post-convergence commit step.

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes commands Command implementations size: L triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 8, 2026
@BKF-Gitty
BKF-Gitty marked this pull request as draft May 8, 2026 00:16
@clawsweeper

clawsweeper Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Summary
The PR adds a post-core plugin convergence phase to openclaw update, static plugin payload validation, update-phase helpers, docs/changelog entries, and focused tests.

Reproducibility: yes. Current-main source shows the invalid-config path returns skipped, and the PR body provides before/after terminal output for that path; the blocking review finding is source-reproducible from the PR head’s path.join extension validation versus the existing package-entry boundary/runtime resolver.

Real behavior proof
Sufficient (terminal): The PR body includes relevant after-fix terminal output from a real macOS/Node setup showing the changed update result versus current main; the remaining blocker is a code correctness finding, not absent proof.

Next step before merge
There is a narrow, mechanical blocker in the PR branch: align the new smoke check with existing package-entry validation semantics and add focused regression tests.

Security
Cleared: No new dependencies, workflow permissions, secret handling, downloaded executable artifacts, or plugin code execution were introduced; the package-boundary mismatch is tracked as a functional gate bug.

Review findings

  • [P2] Use package entry validation for extension smoke checks — src/cli/update-cli/plugin-payload-validation.ts:105-106
Review details

Best possible solution:

Land the convergence design after the smoke check shares the existing package-entry boundary and runtime-resolution contract, then refresh targeted tests and proof if the observable update output changes.

Do we have a high-confidence way to reproduce the issue?

Yes. Current-main source shows the invalid-config path returns skipped, and the PR body provides before/after terminal output for that path; the blocking review finding is source-reproducible from the PR head’s path.join extension validation versus the existing package-entry boundary/runtime resolver.

Is this the best way to solve the issue?

Not yet. The post-core convergence direction is the right narrow fix, but the static payload smoke check should reuse or mirror package-entry-resolution semantics before merge.

Full review comments:

  • [P2] Use package entry validation for extension smoke checks — src/cli/update-cli/plugin-payload-validation.ts:105-106
    The smoke check builds openclaw.extensions candidates with path.join() and only stats the resulting file. That can pass an entry like ../dist/index.js when a sibling file exists even though runtime rejects package-escaping entries, and it can also fail valid installed packages that load a declared openclaw.runtimeExtensions built entry while the source extension path is absent. Please reuse the existing package-entry boundary/runtime validation rules here so convergence cannot report success for a plugin the gateway will reject or block a valid runtime-extension package.
    Confidence: 0.93

Overall correctness: patch is incorrect
Overall confidence: 0.9

Acceptance criteria:

  • pnpm test src/cli/update-cli/plugin-payload-validation.test.ts src/cli/update-cli/post-core-plugin-convergence.test.ts src/cli/update-cli/update-command.test.ts
  • pnpm check:changed

What I checked:

  • Current main invalid-config behavior: On current main, updatePluginsAfterCoreUpdate returns status: "skipped" for invalid config snapshots, so the existing status === "error" restart gate would not fire for that shape. (src/cli/update-cli/update-command.ts:1114, 00d0d4bd1916)
  • PR convergence wiring: The PR head calls runPostCorePluginConvergence after npm/plugin sync, passes the in-memory install-record baseline, folds convergence warnings into outcomes, and maps convergence errors to status: "error". (src/cli/update-cli/update-command.ts:1341, 2afa84dffe62)
  • Blocking PR smoke-check bug: The PR head validates openclaw.extensions entries with path.join(installPath, extensionRel) and fs.stat, rather than the existing package-entry boundary/runtime resolver; this misses escaping entries and does not honor runtime-extension fallback semantics. (src/cli/update-cli/plugin-payload-validation.ts:105, 2afa84dffe62)
  • Existing package-entry contract: Current main resolves package entries through boundary checks that reject entries escaping the plugin package directory, and docs state openclaw.extensions must stay inside the package directory. (src/plugins/package-entry-resolution.ts:391, 00d0d4bd1916)
  • Install-time runtime-extension contract: Current install validation reads openclaw.extensions, then validates extension entries with requireExisting: false and runtime entries with requireExisting: true, so valid installed packages may rely on built runtime entries rather than shipping the source extension path. (src/plugins/package-entry-resolution.ts:154, 00d0d4bd1916)
  • PR proof evidence: The PR body includes after-fix terminal output from a macOS Node 22 run showing invalid config and corrupt payload paths returning status: "error", compared with current-main behavior returning skipped or silently continuing. (2afa84dffe62)

Likely related people:

  • steipete: Recent current-main work touched package entry repair and filesystem safety primitives, and the PR branch also has late commits from this account in the same update/plugin safety area. (role: recent area contributor and merger; confidence: high; commits: b3e2f3b2610b, 538605ff44d2, 6e9b7f964556; files: src/plugins/package-entry-resolution.ts, src/plugins/install.ts, src/cli/update-cli/plugin-payload-validation.ts)
  • vincentkoc: Recent current-main commits changed update plugin warning context and plugin package runtime validation near the same install/update contract. (role: recent plugin/update contributor; confidence: high; commits: 64ab50e42bad, 89a15fddaf84, 88b21427f8ad; files: src/cli/update-cli/update-command.ts, src/plugins/package-entry-resolution.ts, src/commands/doctor/shared/missing-configured-plugin-install.ts)
  • Patrick-Erichsen: Authored the current-main corrupt-plugin update tolerance work that the PR extends with stricter pre-restart convergence behavior. (role: introduced adjacent behavior; confidence: high; commits: 8aa7b7a4ca17; files: src/cli/update-cli/update-command.ts, src/commands/doctor/shared/missing-configured-plugin-install.ts, docs/cli/update.md)
  • Kaspre: Recently changed plugin package entry loading behavior in the same package-entry resolution surface used by this PR's smoke check. (role: recent adjacent contributor; confidence: medium; commits: 537528197423; files: src/plugins/package-entry-resolution.ts)

Remaining risk / open question:

  • No local tests were run because this review was required to keep the checkout read-only; the verdict is based on source inspection, PR-head raw files, current-main code, and the supplied terminal proof.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 00d0d4bd1916.

@BKF-Gitty

BKF-Gitty commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

Addressed independent code review (Codex). New commit 223689d4b2.

#1 (blocker) — convergence-then-commit stale record overwrite. runPostCorePluginConvergence now returns installRecords (the disk state after repairMissingConfiguredPluginInstalls may have written new ones). updatePluginsAfterCoreUpdate re-seeds pluginConfig from those records (and forces pluginsChanged = true) before the commitPluginInstallRecordsWithConfig block, so the commit can no longer overwrite fresh repairs with the pre-convergence in-memory snapshot. New regression test verifies the returned installRecords reflect the post-repair state.

#2 (should-fix) — smoke check too strict for OpenClaw extensions. runPluginPayloadSmokeCheck no longer falls back to index.js when main is absent. We now only fail missing-main-entry when main is explicitly declared and missing/non-file. OpenClaw plugins that ship exports (e.g. extensions/qa-channel) or openclaw.extensions (e.g. extensions/brave, extensions/discord) now pass. New tests cover: exports-only, openclaw.extensions-only, main pointing to a directory, and main as a broken symlink.

#3 (should-fix) — guidance not surfaced in non-JSON output. Both the per-warning loop and the new invalid-config error path now log each guidance[] line as muted text under the warning/error message.

#4 (should-fix) — invalid config silently bypassed convergence. updatePluginsAfterCoreUpdate now returns status: "error" (with structured guidance) when params.configSnapshot.valid === false, so the existing pre-restart gate fires exit 1 instead of restarting the gateway with an unverified plugin set.

#5 (nit) — phase-helper comment overstates safety. Expanded the isUpdatePackageSwapInProgress doc to explicitly list the four direct-readers that were intentionally NOT migrated and explain why their OPENCLAW_UPDATE_IN_PROGRESS-only semantics are still correct.

pnpm check:changed exits 0; 257 tests pass across the affected packages.

Re-review progress:

@BKF-Gitty

Copy link
Copy Markdown
Contributor Author

Round 2 of Codex review addressed in commit 9eaa66f4f3.

New blocker from R1 (sync/npm in-memory mutations clobbered by convergence reseed). Fixed by plumbing the baseline through:

  • repairMissingConfiguredPluginInstalls now takes optional baselineRecords and returns the post-mutation records map (RepairMissingPluginInstallsResult). When a baseline is provided, it is used in place of the disk-loaded snapshot and is persisted before return so the disk and the returned map agree.
  • runPostCorePluginConvergence now takes optional baselineInstallRecords and forwards it; the result's installRecords is the merged map (baseline ∪ repair mutations).
  • updatePluginsAfterCoreUpdate passes pluginConfig.plugins?.installs ?? {} as the baseline and now reseeds pluginConfig from convergence.installRecords unconditionally, so the subsequent commitPluginInstallRecordsWithConfig block can no longer overwrite either sync/npm changes or fresh repairs with a stale snapshot.
  • Removed the now-unnecessary second loadInstalledPluginIndexInstallRecords call inside convergence — repair already returns the post-write records.
  • New convergence test asserts baselineInstallRecords is forwarded; existing convergence tests now assert against repair.records directly.

#4 incomplete (no test for invalid-config error). Extracted buildInvalidConfigPostCoreUpdateResult() (exported pure helper) so the early-return branch is testable without mocking the full orchestrator. Two new tests in update-command.test.ts assert status: "error", reason: "invalid-config", and that guidance references both openclaw doctor and openclaw update.

pnpm check:changed exits 0; full surface (cli/update-cli + commands/doctor/shared + repair-sequencing) is 257 tests across 22 files, all passing.

@BKF-Gitty

Copy link
Copy Markdown
Contributor Author

Round 3 of Codex review addressed in commit 77e70802d0.

#4 mock omission. Added records: {} to the repair-warning mock at post-core-plugin-convergence.test.ts so every repairMissingConfiguredPluginInstalls mock now matches the consumer contract (convergence dereferences repair.records).

#2 invalid-config end-to-end test. Exported updatePluginsAfterCoreUpdate and added a real end-to-end test that calls it with configSnapshot.valid: false and asserts result.status === "error" + reason === "invalid-config" + structured guidance. Since the pre-restart gate in updateCommand is literally if (postCorePluginUpdate?.status === "error") { exit(1) }, asserting the function returns status: "error" proves the gate fires; testing the gate's exit(1) separately would require driving the entire updateCommand orchestrator, which is out of scope for this PR.

pnpm check:changed exits 0; full pnpm tsgo:all clean; 25 tests in update-command.test.ts and 9 in post-core-plugin-convergence.test.ts all pass.

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 8, 2026
@BKF-Gitty
BKF-Gitty marked this pull request as ready for review May 8, 2026 01:39
@BKF-Gitty

Copy link
Copy Markdown
Contributor Author

@greptile @codex please review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 06a490c8e2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli/update-cli/plugin-payload-validation.ts
@openclaw-barnacle openclaw-barnacle Bot added the docs Improvements or additions to documentation label May 8, 2026
@BKF-Gitty

BKF-Gitty commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

Codex / clawsweeper review addressed in commit a8cff07fc8 (rebased on latest fix/post-core-plugin-convergence).

[P2] Scope convergence smoke check to active records. Added filterRecordsToActive in src/cli/update-cli/post-core-plugin-convergence.ts that mirrors the existing collectMissingPluginInstallPayloads({ skipDisabledPlugins: true, syncOfficialPluginInstalls: true }) policy at update-command.ts:~218: drops disabled / denied entries, retains records whose resolveTrustedSourceLinkedOfficial{Npm,ClawHub}Spec is set (so e.g. a disabled-but-trusted Codex install is still validated). runPostCorePluginConvergence now passes filterRecordsToActive({ cfg, records: repair.records }) into runPluginPayloadSmokeCheck. Four new tests cover: enabled record retained, explicitly-disabled record dropped, plugins.deny-listed record dropped, disabled-but-trusted-official record retained.

[P3] Update docs/cli/update.md for the new failure mode. Added a paragraph to the <Note> block immediately after the existing scoped-plugin-warning note describing: when post-core convergence runs, what it validates (active records only), the failure modes (invalid config, payload smoke check failures), the new top-level update status: "error" semantics, and where the structured postUpdate.plugins.warnings[].guidance lines surface.

[P3] CHANGELOG entry. Added under ## Unreleased### Fixes describing the user-facing convergence behavior, the new error escalation, and the active-record scope policy.

pnpm check:changed exits 0; pnpm tsgo:all clean; convergence test file is now 13 tests, all passing.

Real-behavior-proof gate is still green from the prior captured-output update; the active-record filter doesn't change the captured before/after terminal output for the in-scope failure shapes, but I'm happy to recapture if the maintainers want additional coverage of a stale-disabled-record-no-longer-blocking-update scenario.

Re-review progress:

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@BKF-Gitty
BKF-Gitty force-pushed the fix/post-core-plugin-convergence branch from a8cff07 to 0ef654b Compare May 8, 2026 02:31
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@BKF-Gitty

BKF-Gitty commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper, @openclaw-barnacle now mergeable

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@BKF-Gitty
BKF-Gitty force-pushed the fix/post-core-plugin-convergence branch from 0ef654b to 7f4e1b2 Compare May 8, 2026 10:51
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@BKF-Gitty
BKF-Gitty force-pushed the fix/post-core-plugin-convergence branch from 7f4e1b2 to c1ad01f Compare May 8, 2026 11:38
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@BKF-Gitty

Copy link
Copy Markdown
Contributor Author

Rebased onto current upstream/main (15b39313cc fix: separate Current time from Reference UTC) to pick up the package-acceptance workflow/test alignment. The previous red checks-node-core / checks-node-core-support-boundary were from the PR merge ref combining the newer release-checks workflow scenario list with the older test/scripts/package-acceptance-workflow.test.ts expectation; that test passes locally on the refreshed branch. CI should rerun on the refreshed merge ref.

@BKF-Gitty

Copy link
Copy Markdown
Contributor Author

@clawsweeper proof should be sufficient again. Just needed to rebase

@BKF-Gitty

Copy link
Copy Markdown
Contributor Author

Codex review: needs real behavior proof before merge.

Summary Review failed before ClawSweeper could summarize the requested change.

Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path.

Real behavior proof Not applicable: Real behavior proof was not assessed because the Codex review failed.

Next step before merge Review did not complete, so no work-lane recommendation was made.

Review details

@BKF-Gitty BKF-Gitty closed this May 8, 2026
@BKF-Gitty BKF-Gitty reopened this May 8, 2026
@BKF-Gitty
BKF-Gitty force-pushed the fix/post-core-plugin-convergence branch from 6db984a to 23493da Compare May 8, 2026 17:16
@BKF-Gitty

Copy link
Copy Markdown
Contributor Author

@clawsweeper for your review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 87e899c19f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +105 to +107
const extensionPath = path.join(installPath, extensionRel);
const extensionStat = await safeStat(extensionPath);
if (!extensionStat?.isFile()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate extension paths stay inside install directory

The smoke check currently builds each extension candidate with path.join(installPath, extensionRel) and only verifies file existence, so a manifest entry like ../dist/index.js can pass if that sibling file exists even though plugin runtime resolution rejects entries that escape the package root (see resolveSafePackageEntry in src/plugins/package-entry-resolution.ts). In that case post-core convergence reports success, the gateway restarts, and the plugin still fails to load—the exact failure mode this convergence gate is meant to prevent.

Useful? React with 👍 / 👎.

@steipete
steipete force-pushed the fix/post-core-plugin-convergence branch from 87e899c to 2afa84d Compare May 12, 2026 06:54
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 12, 2026
@steipete
steipete merged commit 109493b into openclaw:main May 12, 2026
113 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Landed via squash merge: 109493b

Thanks @BKF-Gitty.

Verification before merge:

  • CI=true pnpm test src/cli/update-cli/plugin-payload-validation.test.ts src/cli/update-cli/post-core-plugin-convergence.test.ts src/cli/update-cli.test.ts src/commands/doctor/shared/missing-configured-plugin-install.test.ts src/commands/doctor/shared/update-phase.test.ts
  • CI=true pnpm check:changed
  • PR checks green for 2afa84dffe628562a6504cb337415b10fa7d1dd7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes commands Command implementations docs Improvements or additions to documentation proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants