Find accidental boundary leaks
The problem
You set up a module with a clean public API package. The internal implementation packages were supposed to stay internal. Three months later, you discover that six external packages are importing the internal helpers directly. Nobody made a deliberate choice to expose them. One developer found the shortcut, and others followed. The module boundary exists in the original design, but not in the actual code.
Why it matters
Leaks like this start small. One internal class imported by one external caller is a fixable problem. Twenty external callers importing twelve internal classes is a refactoring project that will take multiple sprints and require coordination across teams. The longer a leak stays unchecked, the more callers build on the internal package, and the harder it becomes to change the internals without breaking something external. Catching leaks early is the difference between a one-commit fix and a migration.
Where to start
Begin with the Package Matrix.
Step by step
- Open the module boundary.
Right-click the relevant module root or package boundary and choose Pin subject · Matrix. This keeps the intended boundary as the subject while preserving the outside callers and dependencies you need for a leak check. Do not use Set as Root here: it would hide those outside callers.
- Read the boundary overview first.
Start with the subject collapsed. Its row and column aggregate the incoming and outgoing traffic across the whole boundary, so you can see which outside neighbours cross it before opening the package tree.
- Expand the subject for package-level attribution.
Expand the subject when you need to see which child package owns a crossing. The child packages appear as nested rows and matching columns. The column labels are visually flat, but they represent the same packages as the row tree.
- Look for crossings that need explanation.
Scan for cells where a row outside the intended boundary depends on a package inside it. In the module-internals case, start with outside callers reaching implementation packages. These crossings are candidates to inspect, not automatic boundary violations. The number in the cell is the reference count for that package pair.
- Surface the smallest crossings.
Set Max refs to 2 when you want to isolate low-weight crossings that are more likely to be opportunistic shortcuts. Clear it again when you want the complete boundary picture.
- Click into each candidate cell.
Click the cell to inspect the concrete references behind the crossing. Compare that evidence with the boundary you intended before deciding whether the dependency is accidental, an accepted public seam, or a sign that the boundary itself needs to change.
- Remove unrelated noise precisely.
If one unrelated package subtree crowds the boundary read, right-click it and choose Hide this package from view. AtlasArc hides that module-aware subtree without changing its metric or cycle contribution.
- Use reach as a triage aid.
Caller and reference counts help estimate how widely a crossing has spread, but they do not decide whether it is a leak. A small, clearly accidental shortcut may be the cheapest first repair; a widely used internal seam may need a coordinated migration or a deliberate public contract.
Interpreting results
The key question is whether the concrete crossing agrees with the boundary you intended. Reference and caller counts describe reach, not intent: a single crossing can violate an important boundary, while a heavily used dependency may be a deliberate contract. When the evidence confirms a leak, the options include restricting access, moving the needed functionality to the public API, or extracting a shared library when several areas legitimately need the type.
Export & share
Use Export → Data as TSV when a sortable boundary record helps the review. Filtering that file to the internal package columns can rank the external callers, but it is a follow-up artifact rather than a required part of finding the leak.