Skip to content

fix(plugins): rebuild missing installs on policy refresh#89882

Open
baskduf wants to merge 3 commits into
openclaw:mainfrom
baskduf:codex/fix-plugin-registry-policy-refresh
Open

fix(plugins): rebuild missing installs on policy refresh#89882
baskduf wants to merge 3 commits into
openclaw:mainfrom
baskduf:codex/fix-plugin-registry-policy-refresh

Conversation

@baskduf

@baskduf baskduf commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #89606.

policy-changed registry refresh can take a persisted fast path that only updates enablement. That is safe only when the persisted plugins[] view is complete. If persisted install records still point at recoverable path/npm plugins that are missing from plugins[], the fast path preserves the broken view and keeps those plugins invisible.

This changes the policy refresh guard to fall back to a source rebuild when recoverable install records are missing from the persisted plugin index. The existing registry snapshot recovery check now shares the same helper, so load-time and refresh-time behavior stay aligned.

Verification

  • node scripts/run-vitest.mjs src/plugins/installed-plugin-index-store.test.ts src/plugins/plugin-registry-snapshot.test.ts
  • node scripts/run-vitest.mjs src/plugins/plugin-registry.test.ts src/config/config.plugin-validation.test.ts
  • node scripts/run-vitest.mjs src/plugins/installed-plugin-index-store.test.ts src/plugins/plugin-registry-snapshot.test.ts src/plugins/plugin-registry.test.ts src/config/config.plugin-validation.test.ts
  • corepack pnpm exec oxfmt --check src/plugins/installed-plugin-index-recovery.ts src/plugins/installed-plugin-index-store.ts src/plugins/plugin-registry-snapshot.ts src/plugins/installed-plugin-index-store.test.ts
  • git diff --check
  • .agents/skills/autoreview/scripts/autoreview --mode local

Real behavior proof

Behavior addressed: policy-changed refresh no longer leaves recoverable path/npm install records stranded outside plugins[].

Real environment tested: Local OpenClaw source checkout on macOS with Node 24.8.0 and pnpm 11.2.2 via Corepack, using a temporary OPENCLAW_STATE_DIR and the real SQLite-backed plugin registry store.

Exact steps or command run after this patch: Ran a live corepack pnpm exec tsx command in this PR checkout that created a temporary OpenClaw state directory, wrote an installed registry with path/npm installRecords and an empty plugins[], then invoked refreshPersistedInstalledPluginIndexSync({ reason: "policy-changed" }) through the production registry refresh path.

Evidence after fix: Console output from that live command:

$ OPENCLAW_STATE_DIR=$(mktemp -d) corepack pnpm exec tsx real-policy-refresh-proof.ts
OpenClaw real setup: persisted registry has installRecords but an empty plugins[] view
Before refresh plugins[]: []
Before refresh installRecords: ["local-plugin","whatsapp"]
Command executed: refreshPersistedInstalledPluginIndexSync({ reason: policy-changed })
After refresh plugins[]: ["local-plugin","whatsapp"]
After refresh installRecords: ["local-plugin","whatsapp"]
Observed result: PASS - path and npm plugins were restored to plugins[]

Observed result after fix: The live output shows the broken starting state with plugins[] empty and both local-plugin/whatsapp present only in installRecords; after the policy-changed refresh, both ids are present in plugins[] and the install records remain present.

What was not tested: I did not run the downstream GPU sandbox/NemoClaw image; this proof targets the registry state shape reported in #89606 in a local OpenClaw setup.

@openclaw-barnacle openclaw-barnacle Bot added size: S triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels Jun 3, 2026
@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 30, 2026, 2:48 AM ET / 06:48 UTC.

Summary
The PR adds discovery-backed recoverability checks for missing installed plugin records during policy refresh and snapshot loading, expands registry recovery tests, and adjusts a channel test-helper regex.

PR surface: Source +378, Tests +966. Total +1344 across 7 files.

Reproducibility: yes. Current main and v2026.6.10 can take the policy-changed fast path while only mapping persisted.plugins, which matches the linked issue's state where installRecords contains path/npm plugins missing from plugins[].

Review metrics: 1 noteworthy metric.

  • Persisted refresh guard: 1 policy fast-path guard changed. This guard decides whether existing persisted plugin registry state is reused or rebuilt during policy refreshes, which affects upgrades and existing user state.

Stored data model
Persistent data-model change detected: serialized state: src/plugins/installed-plugin-index-store.ts, serialized state: src/plugins/plugin-registry-snapshot.test.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #89606
Summary: The open issue is the canonical user-facing bug report, and this PR is the active candidate fix; two earlier contributor PRs cover the same root cause but are closed or superseded.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Resolve the dirty/unmergeable base against current main before landing.

Risk before merge

  • [P1] The PR is currently dirty/unmergeable, so maintainers need a rebase or conflict resolution before assessing the actual merge result.
  • [P1] Merging changes when existing persisted registries take the policy-changed enablement-only fast path versus doing a source rebuild, so maintainers should explicitly accept the upgrade behavior for existing user state.
  • [P1] The supplied proof exercises the reported registry state shape in a local OpenClaw setup; it does not rerun the exact downstream GPU sandbox/NemoClaw image from the linked issue.

Maintainer options:

  1. Rebase And Accept Rebuild Semantics (recommended)
    After resolving the dirty base, merge if maintainers accept that recoverable missing install records should force a source rebuild during policy refresh.
  2. Request Exact Sandbox Proof
    Ask for GPU sandbox or NemoClaw-image proof if maintainers want the originally reported environment exercised before accepting the compatibility change.
  3. Choose A Different Contract
    Pause or close if maintainers prefer a validator fallback, doctor migration, or another product contract instead of changing refresh behavior.

Next step before merge

  • [P2] Manual review is needed because the branch is currently dirty/unmergeable and the remaining decision is compatibility acceptance, not a narrow automated code repair.

Security
Cleared: The diff is limited to plugin registry discovery/storage logic, tests, and a test-helper regex cleanup; it adds no dependency, workflow, secret, package-resolution, or code-download changes.

Review details

Best possible solution:

Resolve the dirty base, then land one shared registry-refresh recovery path if maintainers accept the persisted-state rebuild behavior.

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

Yes. Current main and v2026.6.10 can take the policy-changed fast path while only mapping persisted.plugins, which matches the linked issue's state where installRecords contains path/npm plugins missing from plugins[].

Is this the best way to solve the issue?

Yes, with maintainer acceptance. Fixing the persisted registry refresh guard and sharing recovery logic with snapshot loading repairs the canonical registry view more directly than adding a validator-only fallback.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 56c2d637d940.

Label changes

Label justifications:

  • P2: The PR targets a normal-priority plugin registry bug that can hide installed path/npm plugins but has bounded registry blast radius and a manual refresh workaround.
  • merge-risk: 🚨 compatibility: The diff changes persisted plugin registry refresh behavior for existing user state and upgrade paths.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes after-fix live output from a temporary OpenClaw state directory using the production SQLite-backed refresh path and showing missing path/npm records restored into plugins[].
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix live output from a temporary OpenClaw state directory using the production SQLite-backed refresh path and showing missing path/npm records restored into plugins[].
Evidence reviewed

PR surface:

Source +378, Tests +966. Total +1344 across 7 files.

View PR surface stats
Area Files Added Removed Net
Source 5 407 29 +378
Tests 2 966 0 +966
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 7 1373 29 +1344

What I checked:

  • Repository policy applied: Root and scoped plugin/channel AGENTS.md files were read fully; plugin registry persistence and policy-refresh behavior are compatibility-sensitive under the repository guidance. (AGENTS.md:1, 56c2d637d940)
  • Current main fast path is still incomplete: Current main's policy-changed guard checks version, compatibility, migration, install-record hash, and policy target IDs, but not whether durable install records are represented in plugins[]. (src/plugins/installed-plugin-index-store.ts:412, 56c2d637d940)
  • Current main preserves missing plugin rows on fast path: When the fast path is accepted, current main rewrites only persisted.plugins, so records present only in installRecords are not rebuilt into the runtime view. (src/plugins/installed-plugin-index-store.ts:438, 56c2d637d940)
  • Latest release has same missing guard: v2026.6.10 still has the same policy-refresh guard shape without the PR's missing-install-record recovery check. (src/plugins/installed-plugin-index-store.ts:412, aa69b12d0086)
  • PR adds the policy refresh guard: The PR calls hasRecoverableInstallRecordsMissingFromIndex before accepting the policy-only persisted refresh path, forcing a rebuild when recoverable records are missing from plugins[]. (src/plugins/installed-plugin-index-store.ts:455, 0f1532e6fabf)
  • PR shares recovery logic with snapshot loading: The new helper compares persisted plugin ids with install records and delegates discoverability checks to discovery-backed probes rather than leaving snapshot and refresh behavior divergent. (src/plugins/installed-plugin-index-recovery.ts:22, 0f1532e6fabf)

Likely related people:

  • vincentkoc: Commit 579acc3 added the policy-only persisted refresh path, and commit ce611bc recently touched the installed-index store path. (role: introduced policy-refresh fast path and recent area contributor; confidence: high; commits: 579acc3a917c, ce611bc803d1; files: src/plugins/installed-plugin-index-store.ts, src/plugins/plugin-registry-snapshot.ts)
  • steipete: Commit 5443baa moved the installed-plugin index into SQLite and updated the store, snapshot, and install-record reader surfaces central to this PR. (role: recent persisted-index area contributor; confidence: high; commits: 5443baa8527e; files: src/plugins/installed-plugin-index-store.ts, src/plugins/plugin-registry-snapshot.ts, src/plugins/installed-plugin-index-record-reader.ts)
  • IWhatsskill: Commit 22b8e1c changed startup metadata and incomplete-index behavior in the same installed-index and registry snapshot area. (role: recent adjacent contributor; confidence: medium; commits: 22b8e1cf4f5b; files: src/plugins/installed-plugin-index-store.ts, src/plugins/plugin-registry-snapshot.ts, src/plugins/installed-plugin-index.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-06-21T12:21:20.697Z sha 0f1532e :: needs maintainer review before merge. :: none

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: mock-only-proof Candidate: PR proof only shows tests, mocks, snapshots, lint, typecheck, or CI. labels Jun 3, 2026
@baskduf baskduf changed the title [codex] fix plugins policy refresh install recovery fix(plugins): rebuild missing installs on policy refresh Jun 3, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 3, 2026
@baskduf

baskduf commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 3, 2026
@baskduf
baskduf force-pushed the codex/fix-plugin-registry-policy-refresh branch from ff3457c to 0f1532e Compare June 3, 2026 17:54
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 3, 2026
@baskduf

baskduf commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XL stale Marked as stale due to inactivity status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

plugins registry --refresh (refreshReason: policy-changed) drops path/npm-origin plugins from plugins[]

2 participants