AI coding agents can generate code remarkably quickly.
The problem is that generation speed is now growing faster than our ability to verify what was generated.
That changes the software-development problem.
Can we put an AI agent inside a deterministic engineering system that tells it when it is wrong—and lets it correct itself?
That’s the idea behind Sonar’s Agent Centric Development Cycle (AC/DC): guide the agent with context, verify its output continuously, and solve the problems discovered by verification.
We didn’t want to take the idea on faith. So we built the smallest practical version we could on a real Java codebase.
The experiment
We built a small proof of concept around Spring Petclinic.
Repository: github.com/DevelopersCoffee/acdc-petclinic-poc
Every significant stage is represented by a real, readable commit.
Technical write-up: AC/DC Agentic Verify → Solve POC
Context · Architecture · Constraints
Claude Code implements the feature
Maven · Tests · ArchUnit · SonarQube
Findings go back to the agent
Repeat until the quality gate passes
The important part is that Verify isn’t another prompt. It is a deterministic execution step.
The feature we gave the agent
We asked Claude Code to implement:
GET /api/orders?customerId={id}
- pagination
- input validation
- service layer for business logic
- repository layer for persistence
- tests required
- existing endpoints must not be modified
- no unnecessary dependencies
Guide: Turn engineering expectations into constraints
We put the engineering expectations into CLAUDE.md.
The desired architecture was:
We also specified input validation, safe SQL practices, correct HTTP status codes, tests, scope boundaries and dependency constraints.
A markdown file is guidance. It isn’t enforcement.
Making architecture executable with ArchUnit
We added an ArchUnit rule that enforces the dependency boundary.
classes()
.that().resideInAPackage("..order..")
.and().areAnnotatedWith(RestController.class)
.should().notDependOnClassesThat()
.resideInAPackage("..repository..");
If an architectural rule matters, make it executable.
One complication: legacy architecture
Upstream Spring Petclinic does not consistently use the Controller → Service → Repository structure we wanted for the new feature. Applying the rule repo-wide would fail on existing code.
So we scoped the rule to the new order package.
New order feature: must satisfy the new architecture rule.
This lets teams freeze legacy debt while enforcing a better standard for new code.
Before the loop: What did Claude generate?
We first generated the feature without relying on the verification loop so we could see what the loop had to catch.
1. The controller bypassed the service
Controller
↓
Repository
That violated our architecture rule.
2. It created an unnecessary endpoint
/api/orders/raw-lookup
The endpoint built SQL using string concatenation from request input. More importantly, the endpoint was never requested.
Our preferred fix was deletion, not patching an unnecessary feature.
3. Invalid input returned 200
Missing customerId returned an empty response instead of:
400 Bad Request
4. Test coverage was incomplete
The implementation lacked the controller and service coverage required by the task.
The first Verify run caught something we didn’t plant
We expected ArchUnit to fail. It did eventually.
But the first failure was a compilation error.
Claude generated a plausible-looking Spring Boot import that was incorrect for the version used by the project.
Incorrect import
The second Verify run: architecture fires
After fixing the compilation issue, ArchUnit reported:
OrderController
↓
OrderRepository
Direct repository dependency is not allowed.
The important point: this wasn’t another instruction to Claude. It was a build-enforced constraint.
Solve: fix the root cause, not the symptom
Claude extracted OrderService:
OrderController
↓
OrderService
↓
OrderRepository
We didn’t suppress or weaken the ArchUnit rule. We fixed the underlying design.
The unnecessary endpoint disappeared
The /api/orders/raw-lookup endpoint was deleted.
AI agents can implement things you didn’t ask for. Verification therefore needs to consider scope, not only correctness.
Validation and tests were added
Missing or invalid customerId now produces 400 Bad Request, with service and controller tests covering expected behavior and edge cases.
Then the verification system itself failed
On the third Verify run:
Build: PASS Sonar scan: PASS Quality gate: FAIL
But the quality gate reported zero relevant findings.
We investigated the verification harness instead of immediately changing application code.
Our findings collector was wrong
Our custom findings-collection script queried the SonarQube issues API using a parameter whose behavior had changed in SonarQube 26.x. It was no longer correctly scoping results to new code.
A broken verification loop doesn’t make AI safer. It makes AI confidently optimize against the wrong objective.
Fix the verifier before fixing the application
We stopped the application loop, fixed the findings collector, and ran verification again.
The Verify stage must itself be tested and observable.
A red/green result isn’t enough. We need to know what was checked, which findings belong to the current task, which are pre-existing, and why the gate passed or failed.
The real failure was new-code coverage
Once the harness was fixed, the legitimate remaining problems were new-code coverage below the gate’s 80% threshold plus a couple of code smells.
Claude fixed them and we ran the complete verification sequence again.
- 55/55 tests passing
- 46 baseline tests
- 9 new tests
- 0 new quality violations
- 100% new-code coverage
- 0% new-code duplication
The complete loop
CLAUDE.md · architecture · coding rules
Claude Code
Compile · tests · ArchUnit · SonarQube
Agent fixes root causes
Repeat until green
What surprised us
We expected deterministic verification to catch AI-generated mistakes. It did.
The surprising part was that the verification layer itself became part of the system under test.
| Category | What happened | What caught it |
|---|---|---|
| AI implementation error | Plausible but incorrect Spring import | Maven compilation |
| AI architecture error | Controller bypassed service | ArchUnit |
| AI scope error | Unrequested raw-lookup endpoint | Task constraints / review |
| Verification infrastructure error | Legacy Sonar findings incorrectly included | Harness investigation |
Every layer of the verification system is capable of being wrong.
Why deterministic verification matters
LLMs are probabilistic. A model can produce plausible but incorrect code, violate architecture, or satisfy a prompt while breaking an unstated constraint.
Don’t do X.
If X happens, the build fails.
Those are fundamentally different mechanisms.
Markdown rules are not enough
CLAUDE.md
+
ArchUnit
+
Tests
+
Static analysis
+
Quality gate
The agent receives context and consequences.
The verification loop changes the role of the developer
This doesn’t mean developers disappear. It changes where engineering effort goes.
- architecture
- quality standards
- security constraints
- test requirements
- acceptance criteria
- quality gates
- boundaries around autonomous changes
The developer becomes responsible for designing the system that determines what “done” means.
But this experiment does NOT prove that AI is now safe
There are important limitations.
- one repository
- one feature
- one coding agent
- one controlled experiment
- one verification workflow
We did not run a randomized before/after study or establish a statistically meaningful defect-rate reduction.
We did not prove that every coding task can be safely handled without human review.
We did not prove that a quality gate catches every functional or architectural defect.
A deterministic Verify → Solve loop can catch plausible AI-generated mistakes before they reach a human review stage, while executable architecture rules can turn subjective expectations into enforceable constraints.
The most important lesson: don’t blindly trust the verifier
The most memorable failure wasn’t Claude’s. It was ours.
The verifier returned a result that looked authoritative but was based on incorrectly scoped data.
Automation doesn’t eliminate trust. It moves the trust boundary.
If a human reviewer is replaced by an automated quality gate, the quality gate becomes infrastructure that needs its own tests, monitoring and validation.
The important question becomes:
What exactly did the verifier verify?
Where this gets interesting
The agent doesn’t get to redefine the acceptance criteria while it is working. The acceptance criteria live outside the model.
Try the experiment yourself
Repository:
github.com/DevelopersCoffee/acdc-petclinic-poc
git clone git@github.com:DevelopersCoffee/acdc-petclinic-poc.git cd acdc-petclinic-poc docker compose -f docker-compose.sonar.yml up -d ./verify.sh
The commit history is intentionally part of the experiment. Inspect the initial implementation, compilation failure, architecture violation, fixes, broken findings collector, harness correction and final passing state.
Final takeaway
The interesting story isn’t:
“Claude Code wrote a Spring Boot feature.”
Agents can already do that.
The interesting story is:
“We gave the agent a deterministic definition of correct, let it fail against that definition, fed the findings back into the agent, and repeated until the gate passed.”
Human defines constraints
↓
AI agent
↓
Deterministic verification
↓
Findings
↓
AI solves
↓
Deterministic verification
↓
Repeat
↓
Quality gate
↓
Human review
The goal isn’t to remove engineering judgment. It’s to make the machine do more of the repetitive generate → verify → fix → verify work while keeping the engineering constraints outside the model.
If AI can generate code faster than humans can review it, the bottleneck moves from generation to verification.
References and further reading
- Sonar: Agent Centric Development Cycle
- Sonar: The future is AC/DC
- AC/DC Verify
- AC/DC Solve
- DevelopersCoffee AC/DC Petclinic POC
- Technical POC write-up
This article documents a DevelopersCoffee proof of concept inspired by Sonar’s AC/DC concept. It is not an endorsement or reproduction of Sonar’s proprietary implementation.