Back to Portfolio HomePortfolioAI Coverage

Java · CI/CD · Regulated Enterprise · 2025

Ship tests, not risk. AI coverage that can't touch production code.

How a regulated Java shop raised SonarQube line coverage to 91% using Claude Opus 4 and GitHub Copilot — with three enforcement layers that make "AI touched src/main" architecturally impossible.

91%
Coverage target
3
Enforcement layers
0
Main-source edits possible
7
Config files to deploy

Context

A hard SonarQube quality gate blocks the pipeline below 91% line coverage. The ticket prohibits changes to pom.xml or any src/main file — the build config and production source are frozen. Only new test code is in scope.

The default answer — hand-write tests class by class — doesn't scale to a multi-module Spring Boot codebase with dozens of undertested service and utility classes. A regulated bank also can't hand an AI agent unconstrained write access to a codebase and wave it through.

The approach: Generate tests with AI in the developer's IDE; enforce the "tests only" contract with three independent guardrail layers so no single point of failure can cause production code to be modified. Both tools — GitHub Copilot and Claude Code — share a single policy expressed in seven config files.

Three layers of enforcement

Prompt instructions are advisory. Real governance needs enforcement that survives a model hallucination, a bypass-mode flag, and a stray manual edit. Each layer covers a different failure mode.

01

CLAUDE.md + copilot-instructions.md — Steering

Project memory files read at session start. Tell both tools the mission, conventions, and constraints. Steers the model toward the right behavior before any code is written.

Advisory only · first line

02

.claude/settings.json — Deny Rules

Declarative deny array. Blocks Edit and Write tool calls that target src/main/** or pom.xml. Deny rules evaluate before allow rules and cannot be overridden at the project level.

Hard block · survives session restart

03

PreToolUse hook — OS-level enforcement

A shell script that intercepts every Edit/Write call before it executes. Exits 2 (hard block) if the target path is src/main or pom.xml. Fires even in bypassPermissions mode — the one layer that cannot be disabled by any flag.

Fires in bypass mode · the real backstop

04

CI diff gate (.gitlab-ci.yml) — MR enforcement

A dedicated GitLab pipeline job diffs the branch against default and fails if any changed file falls outside src/test/**. Catches manual edits and any gap in local guardrails. The governance anchor.

Audit trail · blocks merge · governance anchor

Developer workflow

Claude Code adds an autonomous /increase-coverage command that reads the JaCoCo XML report, ranks classes by uncovered lines, writes tests, validates with Maven, and loops — stopping at 91% or after five classes. The developer reviews, commits, and pushes. Nothing merges without human eyes and a green CI gate.

# one command. no arguments. runs the full autonomous loop.
claude $ /increase-coverage

Reading target/site/jacoco/jacoco.xml …

Ranked by uncovered lines:
  1. com.bank.eqd.PriceService        42 lines missed  (61%)
  2. com.bank.eqd.OrderValidator       31 lines missed  (55%)
  3. com.bank.eqd.TradeAggregator      28 lines missed  (68%)

→ Writing PriceServiceTest.java …
 mvn test passed  (module: eqd-core)  coverage: 61% → 84%

→ Writing OrderValidatorTest.java …
 mvn test passed  (module: eqd-core)  coverage: 84% → 91%

✓ Target 91% reached. Stopping.

# nothing committed. review the tests, then commit manually.

Seven files, drop and go

The entire setup is seven config files committed to the repo root. No new dependencies, no pipeline infrastructure, no API keys in CI.

CLAUDE.mdProject memory — guardrails + test conventions
.claude/settings.jsonDeny rules, model pin (Opus 4), hook wiring
.claude/hooks/guard-paths.shPreToolUse hard block — fires even in bypass mode
.claude/commands/increase-coverage.mdAutonomous slash command — reads JaCoCo, writes tests, loops
.github/copilot-instructions.mdCopilot repo rules — auto-applied, same policy
.github/prompts/cover.prompt.mdCopilot reusable prompt — single-class coverage mode
.gitlab-ci.ymlDiff gate + Sonar gate + optional PIT mutation job

The thesis

The pattern isn't "AI writes tests and a human rubber-stamps them." The developer triggers the run, reviews every generated test method for meaningful assertions, commits from their own hands, and the pipeline blocks anything that doesn't conform. The AI does the legwork of parsing coverage reports, mapping uncovered branches, and writing the scaffolding — the human owns the judgment call on whether it actually tests behavior or just touches lines.

On coverage theater: A test that executes a line without asserting an outcome inflates the SonarQube number without adding regression value. Mutation testing (PIT) runs optionally in the pipeline and kills tests with no real assertions before they merge. The guardrails prevent AI from touching production code; this prevents AI from gaming the metric.

Brian Uckert · Be Digital Biz Inc. · Start a conversation →

Want this kind of work for your team?

AI-assisted test coverage with guardrails your security team will sign off on — scoped to your compliance framework.

See GenAI & AppSec advisory