Jeison Eccel

Can a Local LLM Trace Java Dependencies Reliably?

In the previous test, Ministral did reasonably well at understanding the shape of my Spring Boot project.

It recognized the major packages, feature organization, and shared areas using AGENTS.md and Aider's repository map. But when I asked which files it would inspect to modify Account behavior, it missed important ones such as AccountService and AccountController.

So this time I remove that variable.

Instead of testing whether the model can find the right context, I give it the relevant source and test something narrower:

Once the correct Java files are in front of it, can a small local model accurately understand how they depend on each other?

Start with the Account feature

I start a fresh Aider session with the same stack:

Aider 0.86.2
      ↓
Ollama
      ↓
Ministral 3 8B
      ↓
MyFinancesAPI

I explicitly add the main Account files:

AccountController.java
AccountService.java
AccountRepository.java
Account.java
AccountModel.java

Then I ask Ministral to trace the dependencies using only the source available to it.

This time the result is much stronger.

It correctly identifies the main flow:

AccountController
      ↓ constructor dependency
AccountService
      ↓ constructor dependency
AccountRepository

It also recognizes the other direct dependencies around the service:

AccountService
    ├── AccountRepository
    ├── ServiceUtils
    └── LoggedUser

And it correctly understands the different roles of:

AccountModel
    ↓
API/service model

Account
    ↓
Persistence entity

This is already more useful than the repository-level analysis from the previous post. Ministral is no longer reasoning primarily from filenames and symbols. It can see constructors, method calls, types, and actual Java relationships.

Add the shared abstractions

Some dependencies still point outside the Account feature, so I progressively add the shared source:

AbstractEntity.java
BasicRepository.java
BasicService.java
ServiceUtils.java

Now Ministral can confirm relationships such as:

Account extends AbstractEntity

AccountRepository extends BasicRepository<Account>

AccountService implements BasicService<Account, AccountModel>

It also correctly recognizes ServiceUtils as an injected dependency and can separate much of the Account-specific implementation from shared infrastructure.

The context has grown from roughly 11k to 15k input tokens, but unlike the broader context expansion in the previous post, these files are being added because the dependency trace leads directly to them.

Account feature
      ↓
Referenced shared abstraction
      ↓
Load that source
      ↓
Continue the trace

This is a much more useful reason for context to grow.

The mistakes become more subtle

With the actual source available, Ministral stops making some of the larger repository-level mistakes.

But it doesn't become fully reliable.

For example, it classifies:

findByOwner(User owner)
findByIdAndOwner(String id, User owner)

as methods inherited from BasicRepository.

They're actually declared directly in AccountRepository.

It also describes validateSchema() as inherited while classifying it as a static call. Those two descriptions are inconsistent: an inherited instance method isn't a static call.

These errors are different from inventing a nonexistent file.

The overall dependency graph still looks correct:

Correct class
    ↓
Correct relationship
    ↓
Correct architecture
    ↓
Wrong Java mechanism

And because the explanation sounds technically precise, the mistake can be harder to notice.

Add the tests

The final part is to see whether Ministral can connect the production dependency graph to the tests.

I add:

AccountServiceTest.java
AccountTest.java

The context now reaches approximately 18k input tokens.

Ministral correctly maps:

AccountTest
    ↓
Account

and:

AccountServiceTest
    ↓
AccountService

It also recognizes the shared test abstractions:

AccountTest extends AbstractEntityTest<Account>

and:

AccountServiceTest extends AbstractServiceTest<
    AccountService,
    AccountRepository,
    Account,
    AccountModel
>

The mocked dependencies, including AccountRepository and LoggedUser, are identified correctly too.

This gives Ministral a reasonably complete view of the feature:

HTTP/API
    ↓
Controller
    ↓
Service
    ↓
Repository
    ↓
Persistence Entity

+ API Model
+ Shared Abstractions
+ Utilities
+ Unit Tests

For a small local model, this is a useful result.

Confidence is still a weak point

The remaining problem isn't finding the main architecture.

It's knowing exactly what the source proves.

For example, Ministral sees that AccountServiceTest extends a shared test abstraction. From there, it makes reasonable assumptions about behavior inherited from that abstraction, but sometimes presents those assumptions as confirmed test coverage.

The same pattern appeared earlier with declared versus inherited repository methods.

The distinction I need from a coding agent is:

Visible in source ≠ Reasonable inference ≠ Confirmed behavior

Ministral doesn't always maintain those boundaries.

The answers are often plausible. That's precisely why they still require review.

Targeted context improves the result

Across Task 35, the input grows as I expose more of the actual dependency graph:

StageApprox. input tokensAdded context
Account feature11kController, service, repository, model, entity
Shared abstractions15kBase entity, repository, service, utility
Tests18kAccount production + test relationships

This complements what I saw in the previous post.

There, progressively adding broader project context pushed the conversation from roughly 6.8k to 19k tokens. The model learned more, but I was manually doing much of the context selection.

Here, the context also grows, but for a specific reason: each added file follows a dependency exposed by source already under inspection.

The useful lesson isn't simply:

More context produces better answers.

It's closer to:

Relevant source produces better answers, and context should grow with the dependency being investigated.

So, can a local LLM trace Java dependencies reliably?

Ministral successfully traced the important parts of a real Spring Boot feature:

  • Controller → Service → Repository;
  • constructor injection and direct method calls;
  • API model versus persistence entity;
  • generics, inheritance, and interfaces;
  • shared abstractions and utilities;
  • test inheritance, mocks, and production/test relationships.

That's significantly better than its repository-level context selection.

But reliably is still too strong.

It confused declared and inherited methods, misclassified an instance method as static, and occasionally converted plausible interpretations into confirmed facts.

So my conclusion is narrower:

A small local model can perform useful Java/Spring dependency tracing when the relevant source is explicitly available, but semantic details still require human review.

This is enough to move the experiment forward.

The agent can orient itself in the repository, and with some help selecting context, it can follow the main dependency graph through actual source.

The next question is more consequential.

Understanding the code is useful, but the purpose of this experiment isn't to build an AI code reader.

It's to see whether I can delegate coding work to it.