Status: Draft

Author: Viquar Khan (Vaquar.khan@gmail.com)

Discussion thread: TBD

Jira:


Motivation The open-source community is seeing a sharp increase in automated pull requests. While code generation tools can help developers, they frequently produce pull requests that look correct on the surface but contain empty boilerplate, unnecessary comments, and hallucinated logic. This puts a heavy burden on maintainers who spend limited review time on code with no real substance.

Other major Apache projects are already dealing with this. Apache Airflow changed their contribution policies after automated bots started taking over open issues. Apache Iceberg wrote strict new contribution guidelines to protect their reviewers.

Why AGENTS.md is not enough: Adding an AGENTS.md or CLAUDE.md file is a "soft control." AI models use probabilistic reasoning; if their context window fills up or a user overrides the prompt, the agent will silently ignore markdown instructions and submit bad code anyway. We need a deterministic "hard control" that catches these failures before they reach a human reviewer.

I propose adding two focused validation tasks to Kafka's Gradle build that catch the two most damaging categories of low-quality contributions: scaffolding-heavy PRs with no real logic, and code that violates Kafka's specific architectural rules.

Public Interfaces This KIP introduces no changes to the Kafka protocol, public APIs, client behaviors, or broker metrics. It modifies only the project's internal build tools and CI workflow.

Proposed Changes I propose adding two new Gradle tasks to Kafka's buildSrc directory. These are native Java classes that live inside the Kafka repository — no external dependencies beyond JavaParser (build-time only, same pattern as checkstyle/spotbugs). Developers run them locally with ./gradlew checkContributionQuality, and CI runs them automatically as part of ./gradlew check.

Important: These tasks complement, not duplicate, Kafka's existing checks. Kafka already enforces FinalLocalVariable, CyclomaticComplexity (max 16), MethodLength (max 170), and NPathComplexity (max 500) via checkstyle/checkstyle.xml. The proposed tasks target problems that Checkstyle structurally cannot detect.

Task 1: Logic Density Validation (LDR) The problem Checkstyle cannot solve: Checkstyle measures the complexity of individual methods. It cannot answer the question: "Did this PR add real logic, or is it 300 lines of scaffolding wrapping 2 lines of actual work?" AI tools are notorious for generating massive PRs with very little executable logic—empty class hierarchies, verbose documentation for trivial getters, and copy-pasted boilerplate. These PRs pass all existing checks because each individual method is simple.

How it works: The task uses JavaParser to build an Abstract Syntax Tree (AST) of each changed Java file in the PR diff and counts two categories of nodes:

  1. Logic nodes (weighted): if, for, while, switch (weight 5); method calls, binary expressions (weight 2).

  2. Structure nodes (weighted): class declarations, method declarations (weight 1). Formula: Logic Density Ratio (LDR) = logicNodes / (logicNodes + structureNodes)

Default Thresholds & Exceptions:

Task 2: Design Compliance (Kafka Architecture Linter) The problem Checkstyle cannot solve: Checkstyle's Regexp module can block individual patterns globally (e.g., System.exit). But it cannot express conditional rules like "if a file uses KafkaConsumer, then it must NOT use ExecutorService." It also cannot express required patterns like "if a file creates a KafkaProducer, it should call close()."

How it works: Rules are defined in a simple YAML file (.validation/design-rules.yaml) at the repository root. This allows committers to add new rules without writing Java code.

Kafka-Specific Rules to Ship With:

  1. consumer-thread-safety:

  2. producer-close:

  3. no-deprecated-metrics:

Implementation Details

Where the code lives: buildSrc/ is Gradle's standard convention for custom build logic. This directory does not currently exist in the Kafka repo, but introducing it is the idiomatic Gradle approach to prevent polluting the root 

buildSrc/
├── build.gradle
└── src/
    ├── main/java/org/apache/kafka/gradle/integrity/
    │   ├── DensityAnalyzer.java          # LDR + entropy calculation
    │   ├── DesignComplianceChecker.java  # YAML rule enforcement
    │   ├── ContributionQualityTask.java  # Gradle task entry point
    │   └── DiffParser.java              # Git diff extraction
    └── test/java/org/apache/kafka/gradle/integrity/
        ├── DensityAnalyzerTest.java
        └── DesignComplianceCheckerTest.java

Build-Time Dependencies:

Human Overrides:

Compatibility, Deprecation, and Migration Plan This proposal does not change the Kafka protocol or public APIs. It adds only internal build logic. Migration: None. Existing code passes both checks (validated against trunk). The tasks only evaluate changed files in a PR diff, not the entire codebase.

Test Plan

To guarantee zero disruption to developer velocity, this KIP relies on strict unit testing and a phased CI rollout.

1. Unit Tests (JUnit 5 in buildSrc/src/test/):

2. Shadow Mode (30-Day Rollout): Upon merge, the GitHub Action will run with continue-on-error: true. It will log results (Pass/Fail, LDR score, AST violations) to the GitHub Actions step summary for 30 days without blocking PRs. Once the PMC validates that the false-positive rate is practically zero, we will remove the continue-on-error flag to make it a mandatory, blocking check.


FAQ:

Q: Won't failing a CI check generate massive email spam to the dev@kafka mailing list? A: No. To ensure zero spam, the check does not post comments or fail loudly in a way that emails the list. If a PR falls below the density threshold, a GitHub Action silently executes gh pr ready --undo to convert the PR into a Draft and applies a needs-substance label. This removes it from the review queue silently.

Q: Checkstyle already handles our code quality. Why do we need a new AST Design Gate? A: Checkstyle is fantastic for formatting and simple regex (like blocking System.exit), but it struggles with complex, conditional architectural logic. For instance, Checkstyle cannot easily enforce "If KafkaConsumer is used, ensure it is not wrapped in java.util.concurrent." This custom task handles the architectural patterns that Checkstyle structurally cannot.

Q: What if the script has a bug and blocks legitimate human contributors? A: The system prioritizes developer velocity. Any developer can bypass the gate immediately by adding /skip-validation to their commit message or PR description. Additionally, the initial 30-day "Shadow Mode" runs non-blocking, allowing the PMC to review its accuracy before it ever gains the power to block a merge.

Q: Will this block my emergency hotfix?

A: No. Any committer can bypass all gates by adding /aiv skip to the commit message.

Q.Does LDR penalize good documentation?

A: No. The Logic Density Ratio is designed to ignore comments and javadocs, focusing strictly on executable AST (Abstract Syntax Tree) nodes.

Q: How does the gate handle refactoring?

A: AIV includes a "Refactor Exception"—if a PR removes more lines than it adds (net-negative lines), the density check is automatically bypassed.

Q: Is my code being sent to an external AI?

A: No. The AIV Gate is designed for 100% local execution and does not require external API keys or cloud processing.


Rejected Alternatives