{ "assetKey": "a05-f019-ssot", "kind": "terminal", "command": "L=adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/JpaModuleBoundaryTest.java\nR=app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.java\n\necho '# 리프가 선언하는 export 목록'\ngrep -n -A14 'EXPORTED_PACKAGES =' \"$L\"\n\necho\necho '# 컴포지션 루트의 소비자 규칙이 같은 목록을 다시 적는다'\nsed -n '1112,1120p' \"$R\"\nsed -n '1129,1148p' \"$R\"\n\necho\necho '# 두 집합의 차이'\npython3 - <<'PYX'\nimport re\ndef pkgs(path, marker, span):\n text = open(path, encoding='utf-8').read().splitlines()\n start = next(i for i, l in enumerate(text) if marker in l)\n body = '\\n'.join(text[start:start + span])\n return {p for p in re.findall(r'\"([a-z][a-z0-9.]*)\"', body) if not p.endswith('.')}\nleaf = pkgs('adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/JpaModuleBoundaryTest.java', 'EXPORTED_PACKAGES =', 16)\nroot = pkgs('app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.java', 'java.util.Set EXPORTED =', 22)\nprint(f'# 리프 {len(leaf)}개 / 루트 {len(root)}개')\nprint(f'# 루트에만 있는 것: {sorted(root - leaf)}')\nprint(f'# 리프에만 있는 것: {sorted(leaf - root)}')\nPYX\n\necho\necho '# 사본은 정본을 이름으로 적는다'\ngrep -n 'owns the definition' \"$R\"\necho -n '# app-bootstrap 에서 그 정본 클래스를 언급하는 줄: '\ngrep -rn 'JpaModuleBoundaryTest' --include=*.java --exclude-dir=build app-bootstrap | wc -l\necho -n '# 선언 파일 밖에서 EXPORTED_PACKAGES 를 참조하는 자바 코드: '\ngrep -rn 'EXPORTED_PACKAGES' --include=*.java --exclude-dir=build . | grep -vc 'JpaModuleBoundaryTest.java'\n\necho\necho '# 리프의 export 목록을 쓰는 두 시험이 무엇을 보는가'\ngrep -n -A2 '@DisplayName(\"the export list names only packages that exist\")' \"$L\"\ngrep -n -A2 '@DisplayName(\"every exported package is one the catalog governs\")' \"$L\"", "cwd": "/shared/codebase/clean-architecture-backend-template/src", "exitCode": 0, "executedAt": "2026-09-02T04:24:12+00:00", "sourceRevision": "21234e38cdb9a926cbc92bb97a2aee2e4a7d2916", "raw": "evidence/raw/a05-f019-ssot.txt", "svg": "evidence/rendered/a05-f019-ssot.svg", "rawSha256": "0866dc172440fe0164347bfbc64c60481f27e90a5b3ceb1b6555f361b3f90f29", "lines": 65, "redaction": "none — 코드베이스 정적 검색" }