Symptom

Module A reaches into module B's private fields or undocumented behavior; the agent reasoning about A must also load B's internals to make any change.

Goal

Cooperation flows through a narrow named interface the agent can read once; A's reasoning context excludes B's implementation details.

Smellier version

class A { _data; }
class B {
read(a) {
return a._data.value;
}
}

Fresher version

class A { value() { return this._data.value; } }
class B { read(a) { return a.value(); } }
Example source: Illustrative example written for this site, not a quotation from any source.
Pressure

Refactoring one module silently breaks the other in ways the type system doesn't catch; the agent must trace cross-module assumptions on every edit.

Tradeoff

Defining a real public interface adds a contract the agent must respect at both ends; until the interface stabilizes, every change forces synchronized edits across both modules.

Relief

Each module's public surface is the only contract callers depend on; the agent reads one module to predict behavior instead of loading both modules together to verify the unwritten coupling still holds.

Trap

Erecting elaborate public APIs between modules that genuinely belong together creates a fake boundary the agent must navigate at every interaction with no isolation gain.