Describe the bug
When the AI rule-authoring assistant generates custom.* rules for a framework without built-in support (a Dubbo @DubboService project in this case), the staged proposal passes RuleProposalValidator review (only non-blocking warnings) and is saved — but the generated Groovy scripts can still throw (or misbehave) at evaluation time. Because CustomClassExporter wraps rule evaluation in runCatching { ... }.getOrDefault(false), a throwing custom.method.is.api makes every method evaluate to "not an API": the export is silently empty, with no notification — only WARN lines in idea.log.
Three defects found in one generated rule file (all verified against the script-context API and the IDE's bundled Groovy engine):
-
it.static throws MissingPropertyException on method contexts. MethodContext / ScriptPsiMethodContext expose no isStatic(), while ClassContext and FieldContext both do. Groovy resolves it.static through the boolean is-getter; with no such method it throws. Since custom.method.is.api is evaluated first for each method, this single call skips all endpoints. (For contrast, it.constructor / it.abstract in the same generated line resolve fine via isConstructor() / isAbstract().)
-
it.args throws MissingPropertyException. The accessor is a plain method args() with no getter convention. In custom.http.method the exception is swallowed → null → fallback to method.default.http.method → wrong verb (GET instead of POST for methods with arguments).
-
it.canonicalText() on a param context returns the element path (com.example.Foo#bar.userId), not the parameter's type. The generated scalar-type check therefore returns true for every parameter, so even simple parameters (String, int) are placed in the JSON body. Correct call: it.type().name().
To Reproduce
Steps to reproduce the behavior:
- Open a project using a framework without built-in support (e.g. Dubbo
@DubboService provider classes).
- Ask the AI rule assistant to author custom framework rules (
custom.class.is.api / custom.method.is.api / custom.http.method / custom.path / custom.param.as.json.body).
- Save the staged proposal (review passes with non-blocking warnings only).
- Trigger an API scan/export.
- See: no endpoints exported; no error balloon.
idea.log contains repeated warnings like custom.method.is.api rule threw for <method> with groovy.lang.MissingPropertyException: No such property: static.
Relevant fragments of the generated config:
custom.method.is.api=groovy:```
# ... class-annotation checks ...
if (it.constructor || it.static || it.abstract) return false # it.static throws
# ...
```
custom.http.method=groovy:```
# ... class-annotation checks ...
return (it.args == null || it.args.length == 0) ? 'GET' : 'POST' # it.args throws
```
After replacing the three calls with it.hasModifier('static') / it.args() / it.type().name(), the same rule file works — the correct API surface already exists; the bugs are in validation, API symmetry, and failure surfacing.
Expected behavior
- Dry-run validation:
ProposeRuleContentTool / RuleProposalValidator validates rule keys, filter prefixes and JSON values, but never executes the proposed scripts. Evaluating each Groovy block once against a representative PSI context (e.g. one of the classes the agent already inspected via get_psi_class_info) before staging would have rejected all three defects above.
- Visible failures: an exception in a
custom.* rule during export should surface to the user (e.g. one aggregated notification per run), not silently skip endpoints.
- API symmetry:
isStatic() should exist on method contexts, matching ClassContext / FieldContext — excluding static methods is a legitimate rule need, and its absence is exactly what the model pattern-matched from the neighboring it.constructor / it.abstract.
Screenshots
N/A.
Desktop (please complete the following information):
- OS: Windows 11
- IDE: IntelliJ IDEA 2025.3
- Plugin: v3.0 rewrite, built from current
main
Additional context
Describe the bug
When the AI rule-authoring assistant generates
custom.*rules for a framework without built-in support (a Dubbo@DubboServiceproject in this case), the staged proposal passesRuleProposalValidatorreview (only non-blocking warnings) and is saved — but the generated Groovy scripts can still throw (or misbehave) at evaluation time. BecauseCustomClassExporterwraps rule evaluation inrunCatching { ... }.getOrDefault(false), a throwingcustom.method.is.apimakes every method evaluate to "not an API": the export is silently empty, with no notification — onlyWARNlines inidea.log.Three defects found in one generated rule file (all verified against the script-context API and the IDE's bundled Groovy engine):
it.staticthrowsMissingPropertyExceptionon method contexts.MethodContext/ScriptPsiMethodContextexpose noisStatic(), whileClassContextandFieldContextboth do. Groovy resolvesit.staticthrough the boolean is-getter; with no such method it throws. Sincecustom.method.is.apiis evaluated first for each method, this single call skips all endpoints. (For contrast,it.constructor/it.abstractin the same generated line resolve fine viaisConstructor()/isAbstract().)it.argsthrowsMissingPropertyException. The accessor is a plain methodargs()with no getter convention. Incustom.http.methodthe exception is swallowed →null→ fallback tomethod.default.http.method→ wrong verb (GET instead of POST for methods with arguments).it.canonicalText()on a param context returns the element path (com.example.Foo#bar.userId), not the parameter's type. The generated scalar-type check therefore returnstruefor every parameter, so even simple parameters (String,int) are placed in the JSON body. Correct call:it.type().name().To Reproduce
Steps to reproduce the behavior:
@DubboServiceprovider classes).custom.class.is.api/custom.method.is.api/custom.http.method/custom.path/custom.param.as.json.body).idea.logcontains repeated warnings likecustom.method.is.api rule threw for <method>withgroovy.lang.MissingPropertyException: No such property: static.Relevant fragments of the generated config:
After replacing the three calls with
it.hasModifier('static')/it.args()/it.type().name(), the same rule file works — the correct API surface already exists; the bugs are in validation, API symmetry, and failure surfacing.Expected behavior
ProposeRuleContentTool/RuleProposalValidatorvalidates rule keys, filter prefixes and JSON values, but never executes the proposed scripts. Evaluating each Groovy block once against a representative PSI context (e.g. one of the classes the agent already inspected viaget_psi_class_info) before staging would have rejected all three defects above.custom.*rule during export should surface to the user (e.g. one aggregated notification per run), not silently skip endpoints.isStatic()should exist on method contexts, matchingClassContext/FieldContext— excluding static methods is a legitimate rule need, and its absence is exactly what the model pattern-matched from the neighboringit.constructor/it.abstract.Screenshots
N/A.
Desktop (please complete the following information):
mainAdditional context
respondsTo()discrimination reported in [Feature] Make it.contextType() discoverable to the AI rule agent (avoid respondsTo() in generated rules) #756 — both stem from the model not being able to see method descriptions/semantics throughget_rule_context.args()do not) were verified against stub classes mirroringScriptPsiMethodContext's surface.