Direct Answer
Modeling engines should resolve the package (~) visibility of a nested class relative to the outermost package of the top-level containing class, not the immediate nested namespace. For default visibility, set an explicit ~ (package) or - (private) on every new element unless a broader scope is intentionally documented.
Why the Ambiguity Exists
The UML specification (UML 2.5.1, §9.3.2) defines four visibility levels but does not mandate a default. Most tools therefore assume + (public), which causes accidental exposure during code generation. The package modifier is defined as "accessible to elements in the same package," and the package of a nested classifier is the package of its nearest top-level ancestor—not the inner namespace created by nesting.
Cross-Platform Resolution Steps
- Identify the owning package. Walk the containment hierarchy from the nested element upward until you reach a classifier that is directly owned by a package (i.e., not nested inside another classifier). That package is the visibility boundary.
- Apply the same rule in every tool. Configure your modeling tool’s code-generation templates so that
~ on a nested class emits language-specific package-private access (Java: no modifier; C#: internal; C++: friend declarations to the enclosing namespace).
- Validate with a round-trip test. Export a minimal model containing a top-level class
com.example.Outer with a nested class Inner marked ~. Generate code in two different tools (e.g., Enterprise Architect and Visual Paradigm) and confirm both produce package-private access for Inner.
Safe Default Visibility Practice
- Set the project-wide default visibility to
~ (package) or - (private) in the tool preferences.
- Require an explicit visibility keyword on every new attribute, operation, and nested classifier—no implicit public.
- Document any intentional
+ (public) or # (protected) with a tagged value or comment so reviewers can spot over-exposure.
Protected Visibility Mapping
Because # (protected) maps differently across languages (Java: same package + subclasses; C++: derived classes only; C#: derived classes in any assembly), keep the UML model language-agnostic and let the code-generation plugin apply the target-language rule. Do not rely on UML protected to mean the same thing everywhere.
One Diagnostic Detail Needed
Which target language(s) will the generated code compile for? The answer determines whether you must also configure a protected-mapping rule in the generation template.