{ "assetKey": "a19-f020-messaging-admin-api", "kind": "terminal", "command": "#!/bin/bash\ncd /shared/codebase/clean-architecture-backend-template\n# leaf 이름을 남긴다. 긴 문자열 리터럴은 값이 새지 않도록 가린다.\nstrip() { sed -E 's#^src/messaging/([^/]+)/src/(main|test)/java/dev/caskeleton/[^:]*/([^:/]+):([0-9]+):# \\2 · \\1 · \\3:\\4 #' \\\n | sed -E 's#\"[^\"]{16,}\"#\"<가림>\"#g'; }\n\necho \"# 계약 leaf 와 그 소비자 leaf 의 소스 규모\"\nfor m in messaging-admin-api messaging-admin-runtime; do\n echo \" $m 의 소스 세트 : $(ls src/messaging/$m/src/ | tr '\\n' ' ')\"\n for ss in main test; do\n n=$(find src/messaging/$m/src/$ss -name '*.java' 2>/dev/null | wc -l)\n l=$(find src/messaging/$m/src/$ss -name '*.java' -exec cat {} + 2>/dev/null | wc -l)\n printf \" %-4s %2s 파일 · %4s 줄\\n\" \"$ss\" \"$n\" \"$l\"\n done\ndone\n\necho\necho \"# 계약 leaf 의 유일한 시험 파일이 담은 것\"\nT=src/messaging/messaging-admin-api/src/test/java/dev/caskeleton/messaging/admin/DestructiveOperationGuardTest.java\necho \" 파일 : $(basename $T) · @Test $(grep -c '@Test' $T) 개\"\ngrep -n 'void .*(' $T | sed -E 's#^([0-9]+): *# :\\1 #'\n\necho \" 그 시험들이 승인 객체를 어떻게 얻는가 :\"\nawk 'NR>=27 && NR<=33 {printf \" DestructiveOperationGuardTest.java:%d %s\\n\", NR, $0}' $T\nawk 'NR>=45 && NR<=48 {printf \" DestructiveOperationGuardTest.java:%d %s\\n\", NR, $0}' $T\necho \" 그 셋의 단언이 무엇에 떨어지는가 :\"\ngrep -n 'Optional.empty()\\|Optional.of(\\|hasMessageContaining\\|doesNotThrowAnyException' $T \\\n | sed -E 's#^([0-9]+): *# DestructiveOperationGuardTest.java:\\1 #' | sed -E 's#\"[^\"]{16,}\"#\"<가림>\"#g'\necho \" 가드가 그 메시지를 내는 자리 :\"\nG=$(find src -name DestructiveOperationGuard.java -path '*/main/*')\ngrep -n 'APPROVAL_REQUIRED\\|APPROVAL_EXPIRED\\|isValidAt' $G | sed -E 's#^([0-9]+): *# DestructiveOperationGuard.java:\\1 #'\n\necho\necho \"# 소비자 leaf 의 시험 여섯\"\nfor f in $(find src/messaging/messaging-admin-runtime/src/test -name '*.java' | sort); do\n printf \" %-34s @Test %s 개\\n\" \"$(basename $f)\" \"$(grep -c '@Test' $f)\"\ndone\necho \" 그중 승인 위조 시험이 단언하는 것 :\"\ngrep -n 'void .*(' src/messaging/messaging-admin-runtime/src/test/java/dev/caskeleton/messaging/admin/runtime/ApprovalForgeryTest.java \\\n | sed -E 's#^([0-9]+): *# ApprovalForgeryTest.java:\\1 #'\n\necho\necho \"# 계약 leaf 가 담은 main 타입 스물다섯\"\nfind src/messaging/messaging-admin-api/src/main -name '*.java' | sed 's#.*/##;s#\\.java$##' | sort | tr '\\n' ' ' | fold -w 92 -s | sed 's#^# #'\necho\n\necho \"# 승인 검증자는 어디서 만들어지는가\"\necho \" main 구현 :\"\ngit grep -n 'implements ApprovalVerifier' -- 'src/**/*.java' | strip\necho \" 생성 지점 :\"\ngit grep -n 'new HmacApprovalVerifier' -- 'src/**/*.java' | strip\necho \" 생성 지점 $(git grep -c 'new HmacApprovalVerifier' -- 'src/**/*.java' | awk -F: '{s+=$2} END{print s}') 곳 · 파일 $(git grep -l 'new HmacApprovalVerifier' -- 'src/**/*.java' | wc -l) 개\"\n\necho\necho \"# main 에 검증자를 두지 않는 것이 공백인가 경계인가\"\necho \" 자기 자바독이 적은 이유 :\"\nH=$(find src -name HmacApprovalVerifier.java -path '*/main/*')\nawk 'NR>=50 && NR<=53 {printf \" HmacApprovalVerifier.java:%d %s\\n\", NR, $0}' $H\necho \" 같은 사슬의 가드는 main 빈으로 있다 :\"\nA=$(find src -name MessagingAdminAutoConfiguration.java -path '*/main/*')\nawk 'NR>=35 && NR<=41 {printf \" MessagingAdminAutoConfiguration.java:%d %s\\n\", NR, $0}' $A\n\necho\necho \"# 계약 타입의 경계 조건이 따로 고정돼 있는가\"\nfor t in PlanDigest ApprovalGrant VerifiedApproval ApprovedRedrivePlan ApprovedReplayPlan TopologyManifest; do\n m=$(git grep -lw \"$t\" -- 'src/**/*.java' | grep '/main/' | grep -v \"/$t.java\" | wc -l)\n s=$(git grep -lw \"$t\" -- 'src/**/*.java' | grep '/test/' | wc -l)\n n=$(find src \\( -name \"*${t}*Test.java\" -o -name \"*${t}*Tests.java\" -o -name \"*${t}*IT.java\" \\) | wc -l)\n printf \" %-22s main %s 파일 · test %s 파일 · 그 이름을 건 시험 파일 %s 개\\n\" \"$t\" \"$m\" \"$s\" \"$n\"\ndone\necho \" 만료를 직접 고정하는 자리 :\"\ngit grep -n 'anExpiredGrantDoesNotVerify\\|anExpiredApprovalDoesNotAuthorise' -- 'src/**/*.java' | strip\necho \" PlanDigest 가 test 에서 어떻게 쓰이는가 :\"\ngit grep -n 'PlanDigest' -- 'src/**/*.java' | grep '/test/' | strip\n", "cwd": "/shared/codebase/clean-architecture-backend-template", "exitCode": 0, "executedAt": "2026-09-04T02:14:47+00:00", "sourceRevision": "21234e38cdb9a926cbc92bb97a2aee2e4a7d2916", "raw": "evidence/raw/a19-f020-messaging-admin-api.txt", "svg": "evidence/rendered/a19-f020-messaging-admin-api.svg", "rawSha256": "3d4c0ce0b30a6f4b58a89ca9f07e3e7c3908f38328742dde04f6081727a32506", "lines": 123, "redaction": "시험 키 리터럴 가림" }