fix: prevent toolDiscovery from overwriting pinned channel registry#87333
fix: prevent toolDiscovery from overwriting pinned channel registry#87333klioen wants to merge 3 commits into
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed June 11, 2026, 4:19 PM ET / 20:19 UTC. Summary PR surface: Source +7, Tests +68. Total +75 across 2 files. Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Review detailsBest possible solution: Retry the Codex review after fixing the execution failure. Do we have a high-confidence way to reproduce the issue? Unclear. The review failed before ClawSweeper could establish a reproduction path. Is this the best way to solve the issue? Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction. AGENTS.md: unclear because the file could not be read completely. Codex review notes: model internal, reasoning high; reviewed against 9827490f5f73. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +7, Tests +68. Total +75 across 2 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
|
|
@DmitryPogodaev Hi, could you help review this PR? It fixes a bug in your code |
|
ClawSweeper PR egg 🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat. Where did the egg go?
|
DmitryPogodaev
left a comment
There was a problem hiding this comment.
Behavior proof: the early-return guard at line 39 prevents installStandaloneRegistry from reaching the surface switch when toolDiscovery=true and registry.channels is empty. Before the fix, the switch would fall through to overwrite the pinned channel registry with an empty one, causing Outbound not configured for channel: feishu errors.
The fix is minimal and correctly scoped — it only short-circuits when both conditions hold (toolDiscovery AND no channels), so normal plugin loading is unaffected.
LGTM.
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
|
🦞👀 Command router queued. I will update this comment with the next step. Re-review progress:
|
a2b0901 to
25aedc0
Compare
When tools.catalog is called from the frontend, it triggers ensureStandalonePluginToolRegistryLoaded with surface=channel and toolDiscovery=true. In toolDiscovery mode, the loaded registry contains no channels, but installStandaloneRegistry still overwrites the pinned channel registry with this empty registry, causing 'Outbound not configured for channel: feishu' errors. Add a guard: if toolDiscovery is enabled and the registry has no channels, return early before the surface switch that would overwrite the channel registry.
25aedc0 to
a3b8244
Compare
|
@frankekn Ready for merge. Please review when possible. Thank you! |
|
@vincentkoc Ready for merge. Please review when possible. Thank you! |
When tools.catalog is called from the frontend, it triggers ensureStandalonePluginToolRegistryLoaded with surface=channel and toolDiscovery=true. In toolDiscovery mode, the loaded registry contains no channels, but installStandaloneRegistry still overwrites the pinned channel registry with this empty registry, causing 'Outbound not configured for channel: feishu' errors.
Add a guard: if toolDiscovery is enabled and the registry has no channels, return early before the surface switch that would overwrite the channel registry.
Summary
What problem does this PR solve?
tools.catalog, which triggersensureStandalonePluginToolRegistryLoaded(surface="channel", toolDiscovery=true). In toolDiscovery mode the loaded registry has zero channels, butinstallStandaloneRegistrystill callspinActivePluginChannelRegistrywith that empty registry, overwriting the pinned channel registry that was correctly set during gateway startup. This causes all outbound channel operations (feishu, discord, slack, etc.) to fail with "Outbound not configured for channel: ".Why does this matter now?
What is the intended outcome?
toolDiscovery=trueand the loaded registry has no channels,installStandaloneRegistryreturns early aftersetActivePluginRegistrybut before theswitch (surface)block that would overwrite the pinned channel registry. The active registry is still updated (preserving tool discovery behavior), but the channel registry pin is left intact.What is intentionally out of scope?
ensureStandalonePluginToolRegistryLoaded's hardcodedsurface: "channel"parameter.getActivePluginChannelRegistryor the outbound delivery path.params.manifestRecord.manifest.idvsparams.manifestRecord.idinconsistency inloader.ts(separate issue).What does success look like?
tools.catalogno longer wipes the channel registry. Outbound channel operations (feishu, etc.) continue to work without requiring a second restart.What should reviewers focus on?
toolDiscovery && registry.channels.length === 0is the correct and complete check, or if there are other scenarios where a channel-less registry should still be allowed to overwrite the pin.setActivePluginRegistrybut before theswitch (surface)block could break any downstream consumers that expect the channel pin to be updated even in toolDiscovery mode.Summary guidance
This PR description is the contributor's durable explanation of the change. Write it for human maintainers first; ClawSweeper and Barnacle use the same text to understand intent, proof, risk, and current review state.
Describe the intent and outcome in 2-5 bullets. Avoid restating the diff; reviewers and bots can read the changed files.
If this PR fixes a plugin beta-release blocker, title it
fix(<plugin-id>): beta blocker - <summary>and link the matchingBeta blocker: <plugin-name> - <summary>issue labeledbeta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.Linked context
Which issue does this close?
Closes #
Which issues, PRs, or discussions are related?
Related #
Was this requested by a maintainer or owner?
No — discovered through live debugging of a production incident.
Linked context guidance
Link the issue, PR, discussion, maintainer request, or owner request that explains why this PR should exist. Maintainer context helps reviewers and automation distinguish intended work from drive-by churn.
Real behavior proof
Behavior or issue addressed:
tools.catalogstandalone tool-discovery loads should not overwrite the startup-pinned channel registry with an empty registry.Real environment tested:
Real OpenClaw gateway setup with a configured
feishuchannel.Exact steps or command run after this patch:
feishuchannel in a real OpenClaw environment.openclaw gateway call channels.status.channels.statusreturns the configured/runningfeishuchannel snapshot.openclaw gateway call tools.catalog.openclaw gateway call channels.statusagain.tools.catalog.Evidence after fix:
The same real environment shows the regression before the fix and stable channel state after the fix.
Real terminal output before/after fix
Observed result after fix:
After the patch,
tools.catalogno longer clears the pinned channel registry.channels.statuscontinues to return the configured/runningfeishuchannel snapshot aftertools.catalogruns.What was not tested:
I did not include a screen recording or multi-host deployment proof in this PR body.
Proof limitations or environment constraints:
This proof is from a real manually configured environment and focuses on the
feishupath that reproduced the bug.Tests and validation
Which commands did you run?
pnpm build— verified the patch compiles without errorsWhat regression coverage was added or updated?
What failed before this fix, if known?
tools.catalogIf no test was added, why not?
standalone-runtime-registry-loaderdoes not cover the interaction betweentoolDiscoverymode andpinActivePluginChannelRegistry. Adding a meaningful unit test would require significant mocking of the plugin loading pipeline, which may not provide reliable regression coverage.Testing guidance
List focused commands, not every incidental check. CI is useful support, but external PRs still need real behavior proof above when behavior changes.
Risk checklist
Did user-visible behavior change? (
Yes/No)No — the fix prevents silent state corruption; no user-facing API or output changes
Did config, environment, or migration behavior change? (
Yes/No)No
Did security, auth, secrets, network, or tool execution behavior change? (
Yes/No)No
What is the highest-risk area?
runtimeChannel=false), so a registry withchannels.length === 0in toolDiscovery mode is expected behavior, not a missing update.How is that risk mitigated?
toolDiscovery=trueANDregistry.channels.length === 0. In full mode (toolDiscovery=false), the channel registry is still updated normally. In toolDiscovery mode with a non-empty channels array (which should not happen but is theoretically possible), the registry would also be updated normally.Risk guidance
Use this for author judgment that is not obvious from the diff. ClawSweeper can see touched files, but it cannot know which behavior you think is risky, why the risk is acceptable, or what mitigation reviewers should verify.
Current review state
What is the next action?
What is still waiting on author, maintainer, CI, or external proof?
Which bot or reviewer comments were addressed?
Review state guidance
Keep this as the durable state for review progress. If useful information appears in comments, fold the current next action or blocker back here so maintainers and ClawSweeper do not need to reconstruct state from comment history.
Real behavior proof (Test output)