fix(plugins): preserve contextEngine slot through config normalization#64192
Conversation
Greptile SummaryThis PR fixes a real data-loss bug: The fix is incomplete relative to the stated symptom, however. Confidence Score: 4/5Safe to merge as a data-preservation fix; the incomplete explicit-selection credit should be addressed before the contextEngine slot fully replaces the allow-list for workspace plugins. The normalization fix itself is correct and the tests cover it well. Score is 4 rather than 5 because the PR description claims to fix explicit-selection credit for context-engine plugins, but neither resolveExplicitPluginSelection function is updated to check slots.contextEngine — leaving workspace-origin context-engine plugins still gated behind the allow list. src/plugins/config-state.ts and src/plugins/config-policy.ts — both resolveExplicitPluginSelection functions need a contextEngine slot branch to complete the fix described in the PR. Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/plugins/config-normalization-shared.ts
Line: 146
Comment:
**`resolveExplicitPluginSelection` never grants credit for `contextEngine` slot**
The normalization fix is correct, but `resolveExplicitPluginSelection` in both `src/plugins/config-state.ts` (line 231) and `src/plugins/config-policy.ts` (line 51) only checks `config.slots.memory` for explicit-selection credit — there is no corresponding branch for `config.slots.contextEngine`. Preserving the slot value through normalization is necessary, but insufficient: a workspace-origin context-engine plugin selected via `slots.contextEngine` will still be blocked at the `workspace-disabled-by-default` gate (line 291 in `config-state.ts`) unless the plugin is also listed in `allow`. Likewise, `warnWhenAllowlistIsOpen` is keyed entirely on `allow.length === 0`, so setting only `slots.contextEngine` still triggers the warning described in #64170.
If `contextEngine` slot selection is meant to count as explicit-selection credit (matching the semantics of `memory`), both `resolveExplicitPluginSelection` functions and the allowlist-open warning should be updated to account for it.
```ts
// config-state.ts resolveExplicitPluginSelection — example addition
if (params.config.slots.contextEngine === params.id) {
return { explicitlyEnabled: true, cause: "selected-context-engine-slot" };
}
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(plugins): preserve contextEngine slo..." | Re-trigger Greptile |
| @@ -142,6 +143,7 @@ export function normalizePluginsConfigWithResolver( | |||
| loadPaths: normalizeList(config?.load?.paths, identityNormalizePluginId), | |||
| slots: { | |||
| memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot, | |||
| contextEngine: normalizeSlotValue(config?.slots?.contextEngine), | |||
There was a problem hiding this comment.
resolveExplicitPluginSelection never grants credit for contextEngine slot
The normalization fix is correct, but resolveExplicitPluginSelection in both src/plugins/config-state.ts (line 231) and src/plugins/config-policy.ts (line 51) only checks config.slots.memory for explicit-selection credit — there is no corresponding branch for config.slots.contextEngine. Preserving the slot value through normalization is necessary, but insufficient: a workspace-origin context-engine plugin selected via slots.contextEngine will still be blocked at the workspace-disabled-by-default gate (line 291 in config-state.ts) unless the plugin is also listed in allow. Likewise, warnWhenAllowlistIsOpen is keyed entirely on allow.length === 0, so setting only slots.contextEngine still triggers the warning described in #64170.
If contextEngine slot selection is meant to count as explicit-selection credit (matching the semantics of memory), both resolveExplicitPluginSelection functions and the allowlist-open warning should be updated to account for it.
// config-state.ts resolveExplicitPluginSelection — example addition
if (params.config.slots.contextEngine === params.id) {
return { explicitlyEnabled: true, cause: "selected-context-engine-slot" };
}Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugins/config-normalization-shared.ts
Line: 146
Comment:
**`resolveExplicitPluginSelection` never grants credit for `contextEngine` slot**
The normalization fix is correct, but `resolveExplicitPluginSelection` in both `src/plugins/config-state.ts` (line 231) and `src/plugins/config-policy.ts` (line 51) only checks `config.slots.memory` for explicit-selection credit — there is no corresponding branch for `config.slots.contextEngine`. Preserving the slot value through normalization is necessary, but insufficient: a workspace-origin context-engine plugin selected via `slots.contextEngine` will still be blocked at the `workspace-disabled-by-default` gate (line 291 in `config-state.ts`) unless the plugin is also listed in `allow`. Likewise, `warnWhenAllowlistIsOpen` is keyed entirely on `allow.length === 0`, so setting only `slots.contextEngine` still triggers the warning described in #64170.
If `contextEngine` slot selection is meant to count as explicit-selection credit (matching the semantics of `memory`), both `resolveExplicitPluginSelection` functions and the allowlist-open warning should be updated to account for it.
```ts
// config-state.ts resolveExplicitPluginSelection — example addition
if (params.config.slots.contextEngine === params.id) {
return { explicitlyEnabled: true, cause: "selected-context-engine-slot" };
}
```
How can I resolve this? If you propose a fix, please make it concise.
This comment was marked as low quality.
This comment was marked as low quality.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7c32bea753
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| @@ -231,6 +231,9 @@ function resolveExplicitPluginSelection(params: { | |||
| if (params.config.slots.memory === params.id) { | |||
| return { explicitlyEnabled: true, cause: "selected-memory-slot" }; | |||
| } | |||
| if (params.config.slots.contextEngine === params.id) { | |||
| return { explicitlyEnabled: true, cause: "selected-context-engine-slot" }; | |||
There was a problem hiding this comment.
Add context-engine cause to activation cause tables
The new "selected-context-engine-slot" branch returns a cause string that is not part of PluginExplicitSelectionCause/PluginActivationCause and is also missing from PLUGIN_ACTIVATION_REASON_BY_CAUSE, so selecting a plugin via plugins.slots.contextEngine can produce an activation state with no mapped reason (and will fail in type-checked builds). Please add this cause to the union(s) and reason map so context-engine explicit selection is treated consistently with memory-slot selection.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1ad40f66f
ℹ️ 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".
| if (params.config.slots.contextEngine === params.id) { | ||
| return { explicitlyEnabled: true, cause: "selected-context-engine-slot" }; |
There was a problem hiding this comment.
Hash contextEngine slot in activation cache metadata
This new contextEngine explicit-selection path makes activation depend on activationSource.plugins.slots.contextEngine, but buildActivationMetadataHash in src/plugins/loader.ts still hashes only memorySlot plus allow/deny/entries/channels. In flows that pass different activationSourceConfig and resolved config, changing only plugins.slots.contextEngine can reuse a stale cached registry and leave the wrong plugin activation state. Please include contextEngine in the activation metadata hash (and coverage) so registry cache invalidation matches the new activation input.
Useful? React with 👍 / 👎.
a1ad40f to
1287394
Compare
1287394 to
6457468
Compare
a424454 to
d737c84
Compare
normalizePluginsConfigWithResolver() reconstructed the `slots` object with only the `memory` key, silently dropping `contextEngine`. This caused slot-selected context-engine plugins to lose explicit-selection credit during loader diagnostics, producing false `plugins.allow is empty` warnings even when the on-disk config had a populated allowlist and the context engine was selected via `plugins.slots.contextEngine`. Fix: add `contextEngine: normalizeSlotValue(config?.slots?.contextEngine)` to the returned `slots` object in config-normalization-shared.ts, and add `contextEngine?: string | null` to the NormalizedPluginsConfig type. The normalizeSlotValue helper is already used for the `memory` slot and handles trimming, `"none" → null`, and empty → undefined. Tests added in config-state.test.ts: - contextEngine slot value is preserved through normalization - "none" is normalized to null - whitespace is trimmed - empty/absent returns undefined (no default, unlike memory which defaults to "memory-core") Fixes openclaw#64170
The prior commit preserved `contextEngine` through config normalization, but `resolveExplicitPluginSelection` in both `config-state.ts` and `config-policy.ts` only checked `config.slots.memory` for explicit-selection credit. A context-engine plugin selected via `slots.contextEngine` was still blocked at the `workspace-disabled-by-default` gate and still triggered the `plugins.allow is empty` warning. Fix: add `config.slots.contextEngine === params.id` checks at all 4 selection sites (2 in config-state.ts, 2 in config-policy.ts), mirroring the existing `memory` pattern with `cause: "selected-context-engine-slot"` / `reason: "selected context engine slot"`. Addresses greptile 4/5 review feedback on openclaw#64192.
d737c84 to
ae8bd9f
Compare
|
Merged via squash.
Thanks @hclsys! |
clawmem setup openclaw now auto-creates the symlink at ~/.openclaw/extensions/clawmem instead of only printing manual steps. Handles stale symlinks, existing directories, and file conflicts. --remove actually uninstalls. Fixes #5. Plugin manifest renamed from plugin.json to openclaw.plugin.json so the symlink exposes the correct filename without a copy step that wrote into the package source tree. Adds OpenClaw v2026.4.10+ version warning for the contextEngine slot normalization bug (openclaw/openclaw#64192), troubleshooting entry, and Active Memory coexistence documentation. Codex review: session 019d72d5, turns 25-27, ~4.32M tokens.
openclaw#64192) Merged via squash. Prepared head SHA: ae8bd9f Co-authored-by: hclsys <[email protected]> Co-authored-by: jalehman <[email protected]> Reviewed-by: @jalehman
openclaw#64192) Merged via squash. Prepared head SHA: ae8bd9f Co-authored-by: hclsys <[email protected]> Co-authored-by: jalehman <[email protected]> Reviewed-by: @jalehman
openclaw#64192) Merged via squash. Prepared head SHA: ae8bd9f Co-authored-by: hclsys <[email protected]> Co-authored-by: jalehman <[email protected]> Reviewed-by: @jalehman
openclaw#64192) Merged via squash. Prepared head SHA: ae8bd9f Co-authored-by: hclsys <[email protected]> Co-authored-by: jalehman <[email protected]> Reviewed-by: @jalehman
openclaw#64192) Merged via squash. Prepared head SHA: ae8bd9f Co-authored-by: hclsys <[email protected]> Co-authored-by: jalehman <[email protected]> Reviewed-by: @jalehman
openclaw#64192) Merged via squash. Prepared head SHA: ae8bd9f Co-authored-by: hclsys <[email protected]> Co-authored-by: jalehman <[email protected]> Reviewed-by: @jalehman
Summary
normalizePluginsConfigWithResolver()insrc/plugins/config-normalization-shared.tsreconstructed theslotsobject with only thememorykey, silently droppingcontextEngine. This caused slot-selected context-engine plugins to lose explicit-selection credit during loader diagnostics.Fixes #64170
Symptom
{ "plugins": { "allow": ["cortex", "eva-xt", "lossless-claw"], "slots": { "memory": "cortex", "contextEngine": "lossless-claw" } } }After normalization,
slots.contextEngineisundefined. Loader diagnostics then treat the discovered context-engine plugin as not explicitly selected, andwarnWhenAllowlistIsOpen()emits a false warning:Root cause
The zod schema (
zod-schema.ts:938) acceptscontextEngine: z.string().optional(), and the raw config preserves it, but the normalization function discards it during reconstruction.Fix
Add
contextEngineto the normalizedslotsobject using the samenormalizeSlotValuehelper already used formemory:slots: { memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot, + contextEngine: normalizeSlotValue(config?.slots?.contextEngine), },And add
contextEngine?: string | nullto theNormalizedPluginsConfigtype.Unlike
memory(which defaults to"memory-core"when absent),contextEnginehas no default — it'sundefinedwhen not explicitly configured.Tests
Added 5 parameterized cases in
src/plugins/config-state.test.ts:{}(absent)undefined{ contextEngine: "lossless-claw" }"lossless-claw"{ contextEngine: "none" }null{ contextEngine: " cortex " }"cortex"(trimmed){ contextEngine: "" }undefinedScope
src/plugins/config-normalization-shared.ts(+2),src/plugins/config-state.test.ts(+10)normalizePluginsConfigWithResolveror thecontextEngineslotCredit to @100yenadmin for the precise call-chain RCA in #64170.