Skip to content

fix(state): retire superseded plugin install index#90474

Closed
849261680 wants to merge 1 commit into
openclaw:mainfrom
849261680:fix/90418-plugin-index-conflict
Closed

fix(state): retire superseded plugin install index#90474
849261680 wants to merge 1 commit into
openclaw:mainfrom
849261680:fix/90418-plugin-index-conflict

Conversation

@849261680

@849261680 849261680 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

What problem does this PR solve?

  • Fixes repeated legacy plugin install index conflict warnings after a successful external plugin update leaves newer shared SQLite install metadata for the same npm package.
  • Teaches the legacy install-index migration to treat an older legacy npm record as superseded only when the current SQLite record has the same npm package identity, a managed install path, and a strictly newer parsed version.
  • Keeps true conflicts fail-safe: same-version selector drift, package-name drift, malformed metadata, or newer legacy metadata still leaves the legacy source in place with the existing warning.

Why does this matter now?

Issue #90418 reports macOS upgrades from 2026.5.18 to 2026.6.1 repeatedly warning for codex and discord even though the plugin update completed and runtime health was good.

What is the intended outcome?

After openclaw doctor --fix or the migration path sees newer current SQLite install records for the same npm plugins, the stale legacy plugins/installs.json source is archived so normal doctor/status/restart flows do not keep reporting the same conflict.

What is intentionally out of scope?

  • No plugin API, config surface, or runtime fallback changes.
  • No broad reconciliation for same-version floating selector differences or malformed install metadata.
  • No changes to codex or discord plugin packages.

What does success look like?

A codex/discord state shaped like the reported upgrade archives the stale legacy install index once, preserves the newer SQLite records, and a second doctor run has no repeated plugin install index conflict warning.

What should reviewers focus on?

The safety boundary in legacyNpmInstallRecordSupersededByCurrent: same npm package identity, managed current install path, and strictly newer version are all required before archiving the legacy source.

Linked context

Which issue does this close?

Closes #90418

Which issues, PRs, or discussions are related?

Related #90418

Was this requested by a maintainer or owner?

No direct maintainer request; this follows the open bug report and ClawSweeper source-repro guidance on the issue.

Real behavior proof (required for external PRs)

  • Behavior addressed: repeated legacy plugin install index conflict warnings for codex/discord after current shared SQLite metadata already points at newer npm installs.
  • Real environment tested: local macOS source checkout with isolated HOME, OPENCLAW_CONFIG, and OPENCLAW_STATE_DIR; no user config or credentials used.
  • Exact steps or command run after this patch: seeded an isolated shared SQLite installed_plugin_index with codex/discord records at 2026.6.1, seeded legacy plugins/installs.json with codex/discord records at 2026.5.18, ran pnpm openclaw doctor --non-interactive --fix, then ran pnpm openclaw doctor --non-interactive again against the same isolated state.
  • Evidence after fix:
legacy_json_after_fix=archived
legacy_archive_after_fix=present
second_doctor_conflict_warning=absent

--- doctor --fix excerpt ---
13:│  - Archived plugin install index legacy source →                          │

--- second doctor warning check ---
no repeated plugin install index warning
  • Observed result after fix: the legacy install index source was archived on the fix run, and the follow-up doctor run did not emit conflicting plugin install metadata or Left plugin install index.
  • What was not tested: the full reported supervised update flow with Homebrew/global pnpm package swap and LaunchAgent restart.
  • Proof limitations or environment constraints: the live proof uses a synthetic isolated state matching the reported codex/discord metadata shape instead of a real 2026.5.18 to 2026.6.1 macOS upgrade. The local $autoreview and $agent-transcript skill files advertised to this Codex session were not present on disk, so I could not run those skill-specific workflows.
  • Before evidence (optional but encouraged): current issue evidence and the existing conflict branch show that a legacy plugins/installs.json source remains pending when SQLite has conflicting install metadata, causing repeated detection on later migration/doctor paths.

Tests and validation

Which commands did you run?

node scripts/run-vitest.mjs src/commands/doctor-state-migrations.test.ts
node scripts/run-vitest.mjs src/cli/update-cli/post-core-plugin-convergence.test.ts
./node_modules/.bin/oxfmt --check --threads=1 src/infra/state-migrations.ts src/commands/doctor-state-migrations.test.ts
git diff --check
node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/infra/state-migrations.ts src/commands/doctor-state-migrations.test.ts
pnpm openclaw doctor --non-interactive --fix
pnpm openclaw doctor --non-interactive

What regression coverage was added or updated?

Added focused migration tests for:

  • archiving older codex/discord legacy npm install records when current SQLite records are newer for the same package;
  • preserving the warning/source file when the current SQLite record is older than the legacy metadata.

What failed before this fix, if known?

Before this fix, the same current-vs-legacy codex/discord shape would be treated as conflicting metadata and leave plugins/installs.json in place, making future migration/doctor paths repeat the warning.

If no test was added, why not?

Tests were added.

Risk checklist

Did user-visible behavior change? (Yes/No)

Yes. A stale legacy install-index warning is suppressed only after the migration archives an older superseded legacy npm record.

Did config, environment, or migration behavior change? (Yes/No)

Yes. Legacy state migration behavior changes for superseded npm plugin install records.

Did security, auth, secrets, network, or tool execution behavior change? (Yes/No)

No.

What is the highest-risk area?

Incorrectly archiving a legacy install index that still contains meaningful install metadata.

How is that risk mitigated?

The new branch requires same npm package identity, a current managed install path, and a strictly newer current version. Existing richer-match behavior and same-version conflict tests remain intact, and a new negative test covers the newer-legacy case.

Current review state

What is the next action?

Maintainer review and CI.

What is still waiting on author, maintainer, CI, or external proof?

No author-side code work is pending. Full supervised upgrade proof was not run locally; CI and maintainer judgment can decide whether that broader proof is needed.

Which bot or reviewer comments were addressed?

Addresses the ClawSweeper source-repro guidance on issue #90418 by targeting the legacy state/plugin install index migration layer and adding the requested regression coverage.

@openclaw-barnacle openclaw-barnacle Bot added commands Command implementations size: S proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 4, 2026
@clawsweeper

clawsweeper Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed June 15, 2026, 8:24 AM ET / 12:24 UTC.

Summary
The PR adds a legacy install-index migration rule that archives older legacy npm records when newer current SQLite install metadata appears to supersede the same package.

PR surface: Source +84, Tests +77. Total +161 across 2 files.

Reproducibility: yes. Source inspection shows current main returns before archiving when legacy/current install records conflict, so the legacy file can be read again on later doctor or migration paths.

Review metrics: 1 noteworthy metric.

  • Legacy Migration Decision: 1 supersession branch added. The new branch decides whether an existing legacy install-index file is archived or kept active during upgrade migration.

Stored data model
Persistent data-model change detected: migration/backfill/repair: src/commands/doctor-state-migrations.test.ts, serialized state: src/infra/state-migrations.ts, unknown-data-model-change: src/commands/doctor-state-migrations.test.ts, unknown-data-model-change: src/infra/state-migrations.ts, vector/embedding metadata: src/commands/doctor-state-migrations.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🐚 platinum hermit
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

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

Rank-up moves:

  • Tighten package/version identity extraction so inconsistent legacy npm fields keep the warning path.
  • [P2] Add negative migration tests for older legacy records whose resolved fields match but spec or resolvedSpec names another package or version.

Risk before merge

Maintainer options:

  1. Tighten Supersession Identity (recommended)
    Require all present npm package and version identity fields to agree before archiving, then add negative migration tests for mismatched older legacy records.
  2. Accept Current Compatibility Risk
    Maintainers may intentionally accept the current first-field heuristic if they decide the observed upgrade states cannot contain contradictory npm identity metadata.
  3. Consolidate Conflict Policy
    Pause this PR and land one coordinated migration-policy PR if maintainers want older-version and same-version conflict handling reviewed together.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Update the supersession guard to collect all present npm package/version candidates from resolvedName, resolvedSpec, spec, resolvedVersion, and version, return false unless every usable candidate agrees, and add doctor-state migration tests where older legacy records with mismatched spec/resolvedSpec or version fields keep the conflict warning and source file.

Next step before merge

  • [P2] A narrow automated repair can tighten the identity guard and add focused migration tests; maintainer review should still decide the broader compatibility policy before merge.

Security
Cleared: No concrete security or supply-chain issue found; the diff changes internal migration logic and tests without new dependencies, scripts, permissions, or secret handling.

Review findings

  • [P1] Require all npm identity fields to agree — src/infra/state-migrations.ts:411-423
Review details

Best possible solution:

Keep the migration in core, but only retire an older legacy npm record when every present package and version identity field agrees and focused negative tests prove mismatched legacy metadata keeps the warning path.

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

Yes. Source inspection shows current main returns before archiving when legacy/current install records conflict, so the legacy file can be read again on later doctor or migration paths.

Is this the best way to solve the issue?

No, not yet. The state-migration layer is the right place, but the proposed guard needs stricter identity agreement before it is the safest fix.

Full review comments:

  • [P1] Require all npm identity fields to agree — src/infra/state-migrations.ts:411-423
    readNpmInstallRecordPackageName returns resolvedName before checking spec or resolvedSpec, and the version helper below follows the same first-field pattern. A record with matching resolved fields but a different package or version in another present field would now be archived instead of staying on the conflict-warning path. Collect all present package/version candidates and reject supersession when any disagree.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: This is a bounded upgrade-state bug with confusing repeated warnings but no reported runtime outage.
  • merge-risk: 🚨 compatibility: The PR changes persisted legacy plugin install-index migration behavior that can affect upgrade cleanup for existing users.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🐚 platinum hermit and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (terminal): The PR body includes after-fix terminal output from an isolated state run showing the legacy JSON archived and a second doctor run without the repeated warning, though it does not prove the full supervised macOS upgrade flow.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal output from an isolated state run showing the legacy JSON archived and a second doctor run without the repeated warning, though it does not prove the full supervised macOS upgrade flow.
Evidence reviewed

PR surface:

Source +84, Tests +77. Total +161 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 84 0 +84
Tests 1 77 0 +77
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 161 0 +161

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs src/commands/doctor-state-migrations.test.ts.
  • [P1] node scripts/run-vitest.mjs src/cli/update-cli/post-core-plugin-convergence.test.ts.
  • [P1] ./node_modules/.bin/oxfmt --check --threads=1 src/infra/state-migrations.ts src/commands/doctor-state-migrations.test.ts.
  • [P1] node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/infra/state-migrations.ts src/commands/doctor-state-migrations.test.ts.
  • [P1] git diff --check.

What I checked:

  • Repository policy applied: Root AGENTS.md was read fully and applied; persisted plugin install metadata and state migrations are compatibility-sensitive review surfaces. (AGENTS.md:29, d1b33a6040a4)
  • Current conflict path repeats the warning: Current main returns a warning before archiving when legacy/current install records conflict, leaving the legacy source in place for later doctor or migration runs. (src/infra/state-migrations.ts:1556, d1b33a6040a4)
  • Doctor and auto-migration entry points use this migration: The install-index migration is called from auto-migration and doctor legacy-state flows, so the preserved legacy file can surface on normal health and startup paths. (src/flows/doctor-health-contributions.ts:379, d1b33a6040a4)
  • PR guard trusts first package field: On the PR head, readNpmInstallRecordPackageName returns resolvedName before checking spec or resolvedSpec, so disagreeing present identity fields do not force the conflict path. (src/infra/state-migrations.ts:411, eb31b1f2255f)
  • PR guard adds supersession before legacy field comparison: The new legacyNpmInstallRecordSupersededByCurrent path returns true before the existing field-by-field legacy comparison, so any false positive archives the legacy source instead of warning. (src/infra/state-migrations.ts:463, eb31b1f2255f)
  • Existing tests only cover same-version identity drift: Current negative fixtures keep conflicting same-version npm records, but the PR's older-version supersession tests do not cover mismatched present spec/resolvedSpec or version fields. (src/commands/doctor-state-migrations.test.ts:1693, d1b33a6040a4)

Likely related people:

  • steipete: Authored and merged the SQLite plugin install-index migration and multiple adjacent install-index commits that own this state boundary. (role: feature-history owner; confidence: high; commits: 5443baa8527e; files: src/infra/state-migrations.ts, src/commands/doctor-state-migrations.test.ts, src/plugins/installed-plugin-index-store.ts)
  • RomneyDa: Authored the repeat-doctor state migration repair that added the current richer install-record conflict coverage and keep-in-place behavior this PR refines. (role: introduced current conflict behavior; confidence: high; commits: 30b9e123b871; files: src/infra/state-migrations.ts, src/commands/doctor-state-migrations.test.ts)
  • zhuisDEV: Authored official npm install-record pinning work whose package/version metadata is part of the supersession guard used here. (role: adjacent install-record contributor; confidence: medium; commits: 7b5f75eb98f4; files: src/plugins/installs.ts)
  • gumadeiras: Earlier history shows work on suppressing repeated legacy state migration warnings in the same migration/test area. (role: adjacent migration contributor; confidence: medium; commits: b75d6180809d; files: src/infra/state-migrations.ts, src/commands/doctor-state-migrations.test.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.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. 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. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 4, 2026
@849261680
849261680 force-pushed the fix/90418-plugin-index-conflict branch from 12a4595 to eb31b1f Compare June 5, 2026 07:02
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 5, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 5, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed 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. labels Jun 15, 2026
@849261680 849261680 closed this Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands Command implementations 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: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Upgrade leaves repeated shared SQLite plugin install metadata conflict warnings for codex/discord

1 participant