Skip to content

[BUG] AI-generated custom rules can throw at export time — all endpoints silently skipped #757

Description

@tangcent

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):

  1. 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().)

  2. 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).

  3. 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:

  1. Open a project using a framework without built-in support (e.g. Dubbo @DubboService provider classes).
  2. 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).
  3. Save the staged proposal (review passes with non-blocking warnings only).
  4. Trigger an API scan/export.
  5. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions