Persist plugin install index in SQLite#88794
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed May 31, 2026, 8:48 PM ET / 00:48 UTC. Summary PR surface: Source +466, Tests +490, Docs 0, Other +181. Total +1137 across 56 files. Reproducibility: yes. The blocking PR findings are source-reproducible from the live head: Review metrics: 2 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Keep the SQLite migration, preserve install-ledger reads when only persisted snapshots are bypassed, rebuild or mark stale records-only legacy rows, rethrow state DB compatibility errors, and require redacted real migration proof before merge. Do we have a high-confidence way to reproduce the issue? Yes. The blocking PR findings are source-reproducible from the live head: Is this the best way to solve the issue? No. Moving the index to SQLite matches repository direction, but the current patch is not the best merge shape until it preserves existing registry semantics, handles legacy rows safely, and proves a real upgrade path. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 82d24b26ea93. Label changesLabel justifications:
Evidence reviewedPR surface: Source +466, Tests +490, Docs 0, Other +181. Total +1137 across 56 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
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
|
180e020 to
354e907
Compare
354e907 to
abda602
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abda602ca1
ℹ️ 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".
| const disabledByEnv = hasEnvFlag(env, DISABLE_PERSISTED_PLUGIN_REGISTRY_ENV); | ||
| const persistedReadsEnabled = !disabledByCaller && !disabledByEnv; | ||
| const persistedInstallRecordReadsEnabled = !disabledByEnv; | ||
| const persistedInstallRecordReadsEnabled = persistedReadsEnabled; |
There was a problem hiding this comment.
Keep install records when bypassing persisted registry
When callers set preferPersisted: false (for example provider-scoped discovery and provider env-var metadata), this line now also disables reading the install ledger, so the derived path below passes installRecords: {} instead of allowing loadInstalledPluginIndexWithDiscovery to load the SQLite install records. Installed external plugins that are only reachable through the ledger are therefore omitted from provider/model/auth metadata whenever the caller only wanted to bypass the persisted snapshot; before this change persisted metadata was skipped but install records were still read unless the env break-glass disabled them.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: da9b029a61
ℹ️ 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".
| return parseInstalledPluginIndex({ | ||
| version: INSTALLED_PLUGIN_INDEX_VERSION, | ||
| hostContractVersion: "legacy", | ||
| compatRegistryVersion: "legacy", | ||
| migrationVersion: INSTALLED_PLUGIN_INDEX_MIGRATION_VERSION, | ||
| policyHash: "legacy", | ||
| generatedAtMs: 0, | ||
| installRecords, | ||
| plugins: [], | ||
| diagnostics: [], |
There was a problem hiding this comment.
Rebuild records-only legacy indexes before persisting
When plugins/installs.json is a legacy records-only shape and there is no current SQLite row, this synthetic index is written to installed_plugin_index with hostContractVersion: "legacy" and an empty plugins array. loadPluginRegistrySnapshotWithMetadata({ stateDir }) only checks the policy hash when a config is supplied, so no-config registry callers can accept this row as source: "persisted" and see zero plugin records even though the migrated install records are present. Please persist a freshly derived index from the migrated records, or make these legacy envelopes unambiguously stale so the registry is rebuilt before being used.
Useful? React with 👍 / 👎.
9a523ba to
40c0efb
Compare
bb210b9 to
2697ae3
Compare
fb55ee9 to
5666478
Compare
b7c3b96 to
8d5c340
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f55198acf
ℹ️ 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".
| } catch { | ||
| return null; |
There was a problem hiding this comment.
Do not hide unsupported state DB errors
When the canonical SQLite state DB exists but cannot be opened with this build (for example after a downgrade, openOpenClawStateDatabase throws on a newer PRAGMA user_version in src/state/openclaw-state-db.ts), this broad catch turns that hard compatibility error into null. Registry callers then treat the install index as missing and can run with installed external plugins silently absent instead of stopping with the existing unsupported-schema error, so only malformed/missing index rows should be downgraded to null here.
Useful? React with 👍 / 👎.
8f55198 to
66bcc17
Compare
# Conflicts: # src/commands/agent-command.test-mocks.ts
8e64f19 to
a672738
Compare
Dependency GuardThis PR changes dependency-related files. Maintainers should confirm these changes are intentional. Changed files:
Maintainer follow-up:
|
Dependency graph change authorizedThis PR includes dependency graph changes. A member of
A later push changes the PR head SHA and requires a fresh security approval. |
|
/allow-dependencies-change remove unused ui three dependency after dependency-check failure |
* refactor: persist plugin install index in sqlite * fix: merge legacy plugin index records into sqlite * test: update plugin index sqlite fixtures * fix: migrate custom plugin install indexes * test: update plugin index sentinel * fix: exclude migrated plugin index archives * fix: read post-upgrade plugin index from sqlite * fix: migrate legacy plugin index before agent runs * fix: respect disabled persisted plugin registry reads * test: type plugin install record fixtures * fix: simplify plugin index record reader type * test: fix sqlite plugin index CI fallout * test: mock provider normalization in agent command tests # Conflicts: # src/commands/agent-command.test-mocks.ts * build: remove unused ui three dependency
* refactor: persist plugin install index in sqlite * fix: merge legacy plugin index records into sqlite * test: update plugin index sqlite fixtures * fix: migrate custom plugin install indexes * test: update plugin index sentinel * fix: exclude migrated plugin index archives * fix: read post-upgrade plugin index from sqlite * fix: migrate legacy plugin index before agent runs * fix: respect disabled persisted plugin registry reads * test: type plugin install record fixtures * fix: simplify plugin index record reader type * test: fix sqlite plugin index CI fallout * test: mock provider normalization in agent command tests # Conflicts: # src/commands/agent-command.test-mocks.ts * build: remove unused ui three dependency
Summary
plugins/installs.jsonthrough doctor/preflight state migrations, including record-only legacy shapes, embedded plugin records, custom state dirs, and merge-with-existing SQLite rows.agentpost-upgrade startup from missing legacy installed plugins, and honor disabled persisted-registry reads without touching SQLite.Verification
pnpm test src/commands/doctor/shared/plugin-registry-migration.test.ts src/cli/argv.test.ts src/cli/program/config-guard.test.ts src/infra/state-migrations.state-dir.test.ts src/plugins/installed-plugin-index.test.ts src/plugins/installed-plugin-index-store.test.ts src/plugins/installed-plugin-index-records.test.ts src/plugins/plugin-registry.test.ts src/plugins/plugin-metadata-snapshot.memo.test.ts src/config/io.write-config.test.ts src/commands/doctor-state-migrations.test.ts test/scripts/live-docker-stage.test.ts test/scripts/docker-build-helper.test.ts src/plugins/manifest-registry-installed.test.ts src/plugins/manifest-metadata-scan.test.ts src/plugins/plugin-metadata-snapshot.memo.test.ts src/plugins/manifest-model-id-normalization.test.tspnpm test src/plugins/plugin-metadata-snapshot.memo.test.tspnpm tsgo:corepnpm check:test-typespnpm check:architecturegit diff --check origin/main...HEAD/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/mainclean after fixing two accepted findings