Skip to content

feat(review): add the Java backend reviewer agent to /dot-review - #36738

Open
fabrizzio-dotCMS wants to merge 2 commits into
mainfrom
feat/dot-review-java-backend-reviewer
Open

feat(review): add the Java backend reviewer agent to /dot-review#36738
fabrizzio-dotCMS wants to merge 2 commits into
mainfrom
feat/dot-review-java-backend-reviewer

Conversation

@fabrizzio-dotCMS

Copy link
Copy Markdown
Member

What

Adds the dotcms-java-backend-reviewer agent definition and the /dot-review PR review command that dispatches it, so backend Java changes get reviewed against the standards documented in CLAUDE.md and docs/backend/.

Both files are new — neither was ever committed, so the review command and the agent land together. Tooling/config only: no product code, no build, no runtime impact.

File Role
.claude/agents/dotcms-java-backend-reviewer.md The reviewer agent (read-only tools: gh pr view/gh pr diff, Grep, Glob, Read)
.claude/skills/dot-review/SKILL.md The /dot-review command that classifies changed files and dispatches the agent

How the agent behaves

  • Reports only evidence-backed findings with confidence ≥ 75, banded 🔴 Critical (95-100) / 🟡 Important (85-94) / 🔵 Quality (75-84).
  • Every rule carries its own "how to apply without false positives" guidance, and the agent must be able to quote the offending line from the diff.
  • Reviews backend Java / POM / OpenAPI / backend config only — frontend files are explicitly out of its lane.

Rules cover: Config/Logger, Maven versions in bom/application/pom.xml only, REST @Schema correctness and endpoint documentation for OpenAPI/AI-agent consumption, OpenAPI drift, @WrapInTransaction/@CloseDBIfOpened lifecycle, commit listeners, respectFrontendRoles, distributed-FS I/O, Config.getProperty in loops, IT suite registration, input/query/file-name security, cache-returned Contentlet mutation, Page API REST↔GraphQL parity, SecurityLogger audit trail, PostgreSQL-only, third-party library wrapping, Karate/Postman coverage for new endpoints, virtual threads, records reaching VTL, and general quality/progressive-enhancement checks.

Two rules worth highlighting

Both fail silently — the build stays green and Java-level tests pass, so a human reviewer is unlikely to catch them:

Commit listeners. Work that must only run if a preceding persistence operation succeeded belongs in HibernateUtil.addCommitListener, and data that only exists after commit must be read inside the listener body. Verified semantics from HibernateUtil: listeners fire after connection.commit(); on rollback the maps are cleared and they never run; registering with no open transaction runs the listener inline (else { listener.run(); }), silently degrading the post-commit contract; async listeners run on another thread without the transaction's connection or thread-locals. So an index write, cache flush, event notification, external call or file deletion executed inline after a write survives a rollback and leaves the DB and the outside world disagreeing.

Records reaching VTL. dotCMS forks Velocity 1.7 in-tree (dotCMS/src/main/java/org/apache/velocity/), and UberspectImpl.getPropertyGet resolves $obj.foo through getFoo()getfoo()Map.get("foo")get("foo")isFoo()never a record's canonical foo() accessor. With runtime.references.strict = false the unresolved reference renders as the literal text $obj.foo in the page. Reflection itself is fine ($rec.foo() with parens works), but only for public records: ClassMap reflects public classes and public methods only, so a package-private or non-public nested record exposes nothing at all. Net effect: replacing a getter-based type with a record on a Velocity context object breaks shipped templates and customer VTL while everything compiles.

Note this does not contradict the "prefer immutable carriers" rule — records stay recommended for Java-internal DTOs and REST/GraphQL payloads (Jackson handles them natively). The requirement is scoped strictly to the Velocity boundary, and there are currently no records under com.dotcms.rendering, so the rule is preventive rather than describing existing debt.

Agent availability

The skill previously referenced five subagent types that exist in no branch: dotcms-file-classifier, dotcms-typescript-reviewer, dotcms-angular-reviewer, dotcms-test-reviewer, dotcms-scss-html-style-reviewer. Dispatching a non-existent type fails, so the skill now documents which agents are actually committed and instructs the command to fall back to inline review for file classification and the frontend buckets — and to state that in its output rather than claiming a specialized agent ran. When those agents land, that note is what gets removed.

Testing

Documentation/config only; nothing to build or run. Reviewed by exercising /dot-review against backend PRs locally. Every semantic claim in the two highlighted rules was verified against the source rather than from memory:

  • HibernateUtil.addCommitListener / finalizeCommitListeners / addRollbackListener
  • UberspectImpl.getPropertyGet, PropertyExecutor.discover, ClassMap.createMethodCache, SecureUberspector
  • system.properties (runtime.introspector.uberspect) and velocity.properties (runtime.references.strict)

🤖 Generated with Claude Code

Introduces the `dotcms-java-backend-reviewer` agent definition and the
`/dot-review` PR review command that dispatches it, so backend Java
changes get reviewed against the project standards documented in
CLAUDE.md and docs/backend/.

The agent reports only evidence-backed findings with confidence >= 75,
banded Critical/Important/Quality, and each rule carries its own
"how to apply without false positives" guidance.

Two rules in this first revision are worth calling out because both
fail silently in ways Java-level tests do not catch:

- Commit listeners: work that must only run if a preceding persistence
  operation succeeded belongs in HibernateUtil.addCommitListener, and
  data that only exists after commit must be read inside the listener
  body. Registering outside an open transaction runs the listener
  inline, and on rollback it never runs at all.

- Records reaching VTL: dotCMS forks Velocity 1.7 in-tree and its
  introspection resolves $obj.foo through getFoo()/getfoo()/get("foo")/
  isFoo() only, never a record's foo() accessor. With
  runtime.references.strict=false the reference renders as literal
  text, so a record replacing a getter-based type on the Velocity
  context breaks templates while the build stays green.

The skill also documents which subagent types actually exist in the
repo, so the command falls back to inline review instead of dispatching
agents that are not committed yet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

❌ Issue Linking Required

This PR could not be linked to an issue. All PRs must be linked to an issue for tracking purposes.

How to fix this:

Option 1: Add keyword to PR body (Recommended - auto-removes this comment)
Edit this PR description and add one of these lines:

  • Fixes #123 or Closes #123 — same-repo issue
  • Fixes org/repo#123 or Closes org/repo#123 — cross-repo or private issue
  • Closes https://github.com/org/repo/issues/123 — full GitHub URL
  • Other supported keywords: fix, fixed, close, closed, resolve, resolved

Option 2: Link via GitHub UI (Note: won't clear the failed check)

  1. Go to the PR → Development section (right sidebar)

  2. Click "Link issue" and select an existing issue

  3. Push a new commit or re-run the workflow to clear the failed check
    Option 3: Use branch naming
    Create a new branch with one of these patterns:

  • 123-feature-description (number at start)

  • issue-123-feature-description (issue-number at start)

  • feature-issue-123 (issue-number anywhere)

Why is this required?

Issue linking ensures proper tracking, documentation, and helps maintain project history. It connects your code changes to the problem they solve.
---This comment was automatically generated by the issue linking workflow

@claude

claude Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @fabrizzio-dotCMS's task in 19s —— View job


I'll analyze this and get back to you.

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

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant