# 리프가 선언하는 export 목록
135:  private static final Set<String> EXPORTED_PACKAGES =
136-      Set.of(
137-          // The contracts other leaves are meant to speak.
138-          "api",
139-          // Capability configuration facades, each assembling its own capability's internals.
140-          "notification.configuration",
141-          // Cross-cutting seams a composition root legitimately wires.
142-          "transaction",
143-          "security",
144-          "observation",
145-          "migration",
146-          "hibernate",
147-          "fileserver",
148-          "failure",
149-          "config");

# 컴포지션 루트의 소비자 규칙이 같은 목록을 다시 적는다
   * implementation types by name — every store, every repository, the record mapper — which made
   * each of them a cross-leaf source contract: moving one to another package, or reducing its
   * visibility, broke this module's compile. The notification wiring is a facade the leaf owns now,
   * and this keeps the surface from re-growing one convenient import at a time.
   *
   * <p>The list is the leaf's export allowlist, mirrored here because this is the consumer side of
   * the same boundary. {@code JpaModuleBoundaryTest} owns the definition.
   */
  @ArchTest
                private static final java.util.Set<String> EXPORTED =
                    java.util.Set.of(
                        "api",
                        "notification.configuration",
                        "transaction",
                        "security",
                        "observation",
                        "migration",
                        "hibernate",
                        "fileserver",
                        "failure",
                        "config",
                        // The two vendor entry points. A vendor configuration imports the core JPA
                        // config rather than the reverse, so there is no single internal entry the
                        // composition root could gate instead — inverting the import to make one
                        // produced a package cycle. Admitting exactly these two, and no other
                        // vendor
                        // internals, is the narrower price.
                        "postgresql",
                        "h2");

# 두 집합의 차이
#   리프 10개 / 루트 12개
#   루트에만 있는 것: ['h2', 'postgresql']
#   리프에만 있는 것: []

# 사본은 정본을 이름으로 적는다
1118:   * the same boundary. {@code JpaModuleBoundaryTest} owns the definition.
#   app-bootstrap 에서 그 정본 클래스를 언급하는 줄: 1
#   선언 파일 밖에서 EXPORTED_PACKAGES 를 참조하는 자바 코드: 0

# 리프의 export 목록을 쓰는 두 시험이 무엇을 보는가
380:  @DisplayName("the export list names only packages that exist")
381-  void theExportListNamesOnlyPackagesThatExist() {
382-    java.nio.file.Path root = sourceRoot().resolve(ROOT.replace('.', '/'));
396:  @DisplayName("every exported package is one the catalog governs")
397-  void everyExportedPackageIsGoverned() {
398-    Set<String> ungoverned = new TreeSet<>();
