Skip to content

Config: centralize known plugin ID resolution for validation#56705

Open
yejiming wants to merge 8 commits intoopenclaw:mainfrom
yejiming:jimmy/2026-03-29-01-48-29
Open

Config: centralize known plugin ID resolution for validation#56705
yejiming wants to merge 8 commits intoopenclaw:mainfrom
yejiming:jimmy/2026-03-29-01-48-29

Conversation

@yejiming
Copy link
Copy Markdown

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: Known plugin-id validation logic was assembled inline in src/config/validation.ts, which made future extension/error-prone drift likely.
  • Why it matters: During cold-start or missing-plugin-directory scenarios, manifest discovery can be incomplete; relying only on discovered manifest IDs can incorrectly classify valid bundled IDs as missing.
  • What changed: Added resolveKnownPluginIds(...) to centralize known-ID resolution from manifest registry IDs + bundled alias metadata + auto-enable provider IDs; updated ensureKnownIds to use this helper; added parameterized tests covering warning/issue severity across plugins.allow, plugins.entries.*, and plugins.slots.memory.
  • What did NOT change (scope boundary): No changes to plugin loading behavior, enable/disable decision logic, or manifest discovery mechanics; this PR only adjusts validation known-ID resolution and related tests.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Root Cause / Regression History (if applicable)

  • Root cause: Known plugin IDs were composed locally/inlined instead of via a single helper, and the set was too dependent on runtime manifest discovery state.
  • Missing detection / guardrail: No focused parameterized tests asserting severity consistency for known vs unknown plugin IDs across allow/entries/slot surfaces.
  • Prior context (git blame, prior PR, issue, or refactor if known): Validation had evolved incrementally with separate known-ID additions in-place.
  • Why this regressed now: Plugin surfaces and alias sources expanded, increasing the chance of incomplete known-ID assembly in one-off call sites.
  • If unknown, what was ruled out: N/A

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/config/config.plugin-validation.test.ts
  • Scenario the test should lock in: plugins.allow, plugins.entries.*, and plugins.slots.memory must classify known bundled IDs as valid and unknown IDs with stable warning/issue severity per surface.
  • Why this is the smallest reliable guardrail: It directly exercises config validation decisions without adding external integration dependencies.
  • Existing test that already covers this (if any): Existing plugin validation tests cover related cases; this PR adds explicit matrix-style severity assertions.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • Config validation is more resilient when bundled manifests are temporarily unavailable; valid bundled alias/auto-enable IDs are less likely to be misclassified as missing.
  • No CLI flag or config schema changes.

Diagram (if applicable)

Before:
[config plugin ID] -> [known IDs built inline + manifest-dependent] -> [possible false missing-plugin warning/issue]

After:
[config plugin ID] -> [resolveKnownPluginIds(manifest IDs + bundled aliases + auto-enable IDs)] -> [stable classification]

@openclaw-barnacle openclaw-barnacle Bot added channel: slack Channel integration: slack size: M labels Mar 29, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a145356ebf

ℹ️ 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".

Comment thread src/tts/directives.ts Outdated

const blockRegex = /\[\[tts:text\]\]([\s\S]*?)\[\[\/tts:text\]\]/gi;
const blockRegex =
/(?:^|\n)[ \t]*\[\[tts:text\]\][ \t]*(?:\n|$)([\s\S]*?)(?:\n|^)[ \t]*\[\[\/tts:text\]\][ \t]*(?=\n|$)/gi;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve inline [[tts:text]] blocks in directive parser

The new blockRegex only matches [[tts:text]] when the opening and closing tags are on their own lines, so compact tagged payloads like [[tts:text]]Hello world[[/tts:text]] are no longer recognized as directives. That regresses tagged-mode auto-TTS behavior (these payloads are treated as plain text, hasDirective stays false, and synthesis is skipped), even though this inline form is already used in existing tests and runtime message flows.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 29, 2026

Greptile Summary

This PR centralizes known plugin-ID resolution in src/config/validation.ts by extracting a resolveKnownPluginIds helper that merges manifest registry IDs with bundled alias maps and auto-enable provider IDs. The PR also bundles two unrelated fixes: adding ignoreSelf: false to the Slack Bolt socket-mode App config, and tightening TTS directive parsing to require directives on their own lines.

Key observations:

  • The config validation refactoring (resolveKnownPluginIds) is correct, well-commented, and backed by solid parameterized tests covering plugins.allow, plugins.entries.*, and plugins.slots.memory surfaces.
  • The Slack ignoreSelf: false fix is a clear and correct bug fix, accompanied by a targeted assertion test.
  • The TTS directive regex change (src/tts/directives.ts) is the most notable concern: both blockRegex and directiveRegex now require directives to appear on their own dedicated lines. Any [[tts:...]] directive embedded inline within a sentence is silently ignored without any warning. This is a user-visible behavior change that is neither described in the PR summary nor in the scope section. Existing integrations relying on inline directives will silently stop working.
  • The PR packages three logically independent fixes together; the title and description accurately describe only one of them.

Confidence Score: 4/5

Safe to merge pending clarification of the intentional TTS inline-directive behavior change, which silently drops previously-functional overrides.

The config-validation core and the Slack fix are correct and well-tested. Score is 4 rather than 5 because the TTS regex change represents a present, undocumented behavioral regression: directives that previously activated TTS overrides when placed inline in text are now silently ignored. If this is intentional, documenting the change and adding a user-visible warning would resolve the concern and bring the score to 5.

src/tts/directives.ts — the regex tightening changes parsing behavior in a way that is silent and undocumented.

Important Files Changed

Filename Overview
src/tts/directives.ts Both TTS directive regexes changed to require on-own-line placement; inline directives are now silently ignored — a behavioral change out of the stated PR scope.
src/config/validation.ts Extracts resolveKnownPluginIds helper that merges manifest registry IDs with bundled alias keys+values and auto-enable IDs, making cold-start validation resilient. Logic is correct.
src/config/config.plugin-validation.test.ts Adds parameterized severity-consistency tests and a missing-bundled-dir test; coverage is solid.
extensions/slack/src/monitor/provider.ts Adds ignoreSelf: false to socket-mode Bolt App config so reaction events on bot-authored messages are not suppressed. Correct fix, well-commented.
extensions/slack/src/monitor.test-helpers.ts Adds lastAppOptions capture to the mock Bolt App constructor and exposes getLastSlackAppOptions() for test assertions.
extensions/slack/src/monitor.tool-result.test.ts Adds test asserting socket mode is started with ignoreSelf: false. Well-targeted guard for the provider.ts fix.
src/plugins/contracts/tts.contract.test.ts Test inputs updated to place directives on their own lines matching the new regex requirement; one new inline-literal test added to assert the changed behavior.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/tts/directives.ts
Line: 55-65

Comment:
**Silent breaking change: inline directives no longer parsed**

Both `blockRegex` and `directiveRegex` now require `[[tts:...]]` markers to appear on their own dedicated lines (preceded by `^` or `\n`, followed by `\n` or `$`). Previously any inline occurrence — e.g. `Please use [[tts:provider=edge]] for this` — was parsed and applied.

After this change, that same directive is silently left in the text and **ignored**; no warning is emitted, no error is raised. Existing users or integrations that embed TTS directives inline in a sentence will have their overrides quietly dropped without any feedback.

This is also out of the stated scope in the PR description:

> *"What did NOT change (scope boundary): … this PR only adjusts validation known-ID resolution and related tests."*

If the intent is to deliberately require directives to be on their own lines (to avoid false positives in prose), that design decision should be explicitly documented, a migration note / deprecation warning should be added, and the PR description should be updated to reflect this behavioral change.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/tts/directives.ts
Line: 55-56

Comment:
**`^` in closing-tag alternation is dead code**

In the `blockRegex`, the closing-tag prefix is `(?:\n|^)`. Without the `m` (multiline) flag, `^` only matches the very start of the entire input string. A `[[/tts:text]]` closing tag can never appear at position 0 (the opening tag and its content always precede it), so the `^` branch can never fire in practice. The regex works correctly, but the `^` is misleading. Replacing it with just `\n` would be clearer:

```suggestion
  const blockRegex =
    /(?:^|\n)[ \t]*\[\[tts:text\]\][ \t]*(?:\n|$)([\s\S]*?)\n[ \t]*\[\[\/tts:text\]\][ \t]*(?=\n|$)/gi;
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Config: centralize known plugin id resol..." | Re-trigger Greptile

Comment thread src/tts/directives.ts
Comment on lines 55 to +65
@@ -61,7 +62,7 @@ export function parseTtsDirectives(
return "";
});

const directiveRegex = /\[\[tts:([^\]]+)\]\]/gi;
const directiveRegex = /(?:^|\n)[ \t]*\[\[tts:([^\]]+)\]\][ \t]*(?=\n|$)/gi;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Silent breaking change: inline directives no longer parsed

Both blockRegex and directiveRegex now require [[tts:...]] markers to appear on their own dedicated lines (preceded by ^ or \n, followed by \n or $). Previously any inline occurrence — e.g. Please use [[tts:provider=edge]] for this — was parsed and applied.

After this change, that same directive is silently left in the text and ignored; no warning is emitted, no error is raised. Existing users or integrations that embed TTS directives inline in a sentence will have their overrides quietly dropped without any feedback.

This is also out of the stated scope in the PR description:

"What did NOT change (scope boundary): … this PR only adjusts validation known-ID resolution and related tests."

If the intent is to deliberately require directives to be on their own lines (to avoid false positives in prose), that design decision should be explicitly documented, a migration note / deprecation warning should be added, and the PR description should be updated to reflect this behavioral change.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/tts/directives.ts
Line: 55-65

Comment:
**Silent breaking change: inline directives no longer parsed**

Both `blockRegex` and `directiveRegex` now require `[[tts:...]]` markers to appear on their own dedicated lines (preceded by `^` or `\n`, followed by `\n` or `$`). Previously any inline occurrence — e.g. `Please use [[tts:provider=edge]] for this` — was parsed and applied.

After this change, that same directive is silently left in the text and **ignored**; no warning is emitted, no error is raised. Existing users or integrations that embed TTS directives inline in a sentence will have their overrides quietly dropped without any feedback.

This is also out of the stated scope in the PR description:

> *"What did NOT change (scope boundary): … this PR only adjusts validation known-ID resolution and related tests."*

If the intent is to deliberately require directives to be on their own lines (to avoid false positives in prose), that design decision should be explicitly documented, a migration note / deprecation warning should be added, and the PR description should be updated to reflect this behavioral change.

How can I resolve this? If you propose a fix, please make it concise.

Comment thread src/tts/directives.ts Outdated
yejiming and others added 3 commits March 29, 2026 09:56
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3de196e13

ℹ️ 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".

Comment thread src/tts/directives.ts
Comment on lines +55 to +56
const blockRegex =
/(?:^|\n)[ \t]*\[\[tts:text\]\][ \t]*(?:\n|$)([\s\S]*?)\n[ \t]*\[\[\/tts:text\]\][ \t]*(?=\n|$)/gi;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Accept compact [[tts:text]] blocks in directive parser

The updated blockRegex now requires [[tts:text]] and [[/tts:text]] to be on separate lines, so compact payloads like [[tts:text]]Hello world[[/tts:text]] are no longer recognized as directives. In tagged auto-TTS mode this leaves hasDirective false and skips synthesis, which regresses existing tagged payload behavior (the contract suite still includes a tagged case using this compact form).

Useful? React with 👍 / 👎.

@yejiming yejiming changed the title Config: centralize known plugin ID resolution for validationJimmy/2026 03 29 01 48 29 Config: centralize known plugin ID resolution for validation Mar 29, 2026
@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 Apr 30, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 30, 2026

Codex review: needs changes before merge.

Summary
The PR centralizes config validation known-plugin-ID collection, adds plugin-validation tests, adds Slack Bolt ignoreSelf: false coverage, and changes TTS directive parsing/tests around standalone directive lines.

Reproducibility: yes. A source-level reproduction is parseTtsDirectives("Hello [[tts:provider=edge]] world", policyWithAllowProvider): current main parses the provider override, while this PR's newline-bounded directive regex would ignore it.

Next step before merge
A narrow replacement can salvage the config-validation fix while dropping the unrelated TTS and already-shipped Slack hunks.

Security
Cleared: The PR diff does not add dependencies, lifecycle hooks, workflow permissions, downloaded artifacts, secret access, or other concrete supply-chain-sensitive behavior.

Review findings

  • [P1] Preserve inline TTS directives — src/tts/directives.ts:75
  • [P2] Rebase known-id helper onto current metadata exports — src/config/validation.ts:4-10
Review details

Best possible solution:

Ship a focused config-validation patch on current main that centralizes known plugin-id resolution through current manifest/metadata contracts, preserves inline TTS parsing, and leaves the already-shipped Slack behavior alone.

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

Yes. A source-level reproduction is parseTtsDirectives("Hello [[tts:provider=edge]] world", policyWithAllowProvider): current main parses the provider override, while this PR's newline-bounded directive regex would ignore it.

Is this the best way to solve the issue?

No. Centralizing known plugin-id validation is a reasonable narrow fix, but this branch is not the best vehicle because it mixes unrelated behavior changes and is stale against the current bundled metadata boundary.

Full review comments:

  • [P1] Preserve inline TTS directives — src/tts/directives.ts:75
    The new directiveRegex only matches [[tts:...]] markers on standalone lines. Current main, tests, and docs support inline directives such as Hello [[tts:provider=edge]] world; with this patch those overrides are left in the reply and ignored, so tagged TTS can silently use the wrong provider or voice. Keep inline parsing unless this ships as an explicit, documented migration.
    Confidence: 0.9
  • [P2] Rebase known-id helper onto current metadata exports — src/config/validation.ts:4-10
    The added config helper imports ../plugins/bundled-capability-metadata.js and BUNDLED_PROVIDER_PLUGIN_ID_ALIASES, but current main has no top-level module or provider-alias export there. Rebase this onto the current manifest/metadata snapshot boundary before merging, otherwise the focused config fix cannot build cleanly on main.
    Confidence: 0.82

Overall correctness: patch is incorrect
Overall confidence: 0.88

Acceptance criteria:

  • pnpm test src/config/config.plugin-validation.test.ts
  • pnpm test src/plugins/contracts/tts.contract.test.ts
  • pnpm exec oxfmt --check --threads=1 src/config/validation.ts src/config/config.plugin-validation.test.ts
  • pnpm check:changed

What I checked:

  • Current config validation still builds known IDs from discovered manifests only: ensureKnownIds on current main memoizes new Set(info.registry.plugins.map((record) => record.id)); the proposed resolveKnownPluginIds helper is not present on main. (src/config/validation.ts:875, 0fbf4636f52c)
  • Current TTS parser accepts inline directives: Current main uses an unanchored directiveRegex, so inline markers such as Hello [[tts:provider=edge]] world are parsed outside markdown code blocks. (src/tts/directives.ts:243, 0fbf4636f52c)
  • Contract tests lock inline TTS behavior: The TTS contract suite asserts inline provider overrides and compact [[tts:text]]...[[/tts:text]] tagged auto-TTS payloads. (src/plugins/contracts/tts-contract-suites.ts:596, 0fbf4636f52c)
  • Docs describe model-driven TTS directives without a standalone-only migration: The TTS docs show [[tts:...]] directives and compact [[tts:text]]...[[/tts:text]] text blocks as model-driven directive surfaces. Public docs: docs/tools/tts.md. (docs/tools/tts.md:591, 0fbf4636f52c)
  • PR head changes directive parsing to newline-bounded matching: The provided PR diff changes directiveRegex in src/tts/directives.ts to /(?:^|\n)...(?=\n|$)/, which leaves inline provider/voice directives in visible text and ignores their overrides. (src/tts/directives.ts:75, fee7a5700811)
  • Slack change is already on current main: Current main creates Slack Bolt apps with ignoreSelf: false and has interop tests asserting that option for socket and HTTP modes. (extensions/slack/src/monitor/provider-support.ts:202, 0fbf4636f52c)

Likely related people:

  • Vincent Koc: Recent current-main history touches the config validation path and direct blame attributes the current TTS parser plus Slack Bolt factory lines to fix(plugins): remove unsupported bundle metadata; this is routing evidence, not fault attribution. (role: recent maintainer / adjacent owner; confidence: medium; commits: 0841bcdc012a, 76c327c0964a, 46d4238425ca; files: src/config/validation.ts, src/tts/directives.ts, extensions/slack/src/monitor/provider-support.ts)

Remaining risk / open question:

  • The config-validation false positive should be reproved against current main before rewriting the helper, because plugin metadata snapshot behavior and bundled metadata boundaries have changed since the PR branch was created.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 0fbf4636f52c.

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

Labels

channel: slack Channel integration: slack size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants