{ "assetKey": "analysis-finding-a05-f034", "kind": "terminal", "command": "#!/bin/bash\nset -euo pipefail\ncd /shared/codebase/clean-architecture-backend-template\n. /tmp/lib.sh\nY=src/config/jpa/readiness-cards.yaml\nG=src/gradle/jpa-evidence.gradle\nB=src/build.gradle\nR=src/adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/readiness\nfor f in \"$Y\" \"$G\" \"$B\" \"$R/PostgreSqlAggregateIntegrationTest.java\" \\\n \"$R/PostgreSqlQueryIntegrationTest.java\" \"$R/PostgreSqlLifecycleIntegrationTest.java\"; do test -f \"$f\"; done\n\necho \"# 카드 전체와 selected 카드의 태그 커버리지\"\npython3 - \"$Y\" <<'PY'\nimport json, sys\nfrom collections import Counter\nd = json.load(open(sys.argv[1]))\nc = Counter(v.get('state') for v in d['cards'].values())\nprint(' 카드 %d 개 · %s' % (len(d['cards']), ' · '.join('%s %d' % kv for kv in sorted(c.items()))))\nfor k, v in d['cards'].items():\n if v.get('state') != 'selected':\n continue\n ev = v.get('evidence', {})\n scen, claims = ev.get('scenarios', []), ev.get('task-claims', [])\n tags = v.get('required-evidence', [])\n covered = set()\n for s in scen: covered |= set(s.get('covers', []))\n for c2 in claims: covered |= set(c2.get('covers', []))\n print(' %-26s 태그 %d · 시나리오 %d · task-claim %d · support-task %d · 레지스트리가 덮지 않는 태그 %s'\n % (k, len(tags), len(scen), len(claims), len(v.get('support-tasks') or []),\n sorted(set(tags) - covered) or '없음'))\nPY\n\necho\necho \"# 그 두 태그는 레지스트리가 덮을 수 없다\"\necho \" build.gradle 이 no-skip 을 필수로 요구하면서 클레임에서는 빼는 자리 :\"\nat \"$B\" 1672 1680 build.gradle\necho \" 생성기가 JUnit XML 결과로 채우는 자리 :\"\nat \"$G\" 676 692 jpa-evidence.gradle\n\necho\necho \"# 시나리오가 가리키는 시험이 프로덕션을 지나는가\"\npython3 - \"$Y\" <<'PY'\nimport json, sys\nd = json.load(open(sys.argv[1]))\nfor k in ('jpa-aggregate-store', 'jpa-query-model', 'jpa-observability-lifecycle'):\n v = d['cards'][k]\n print(' ==', k)\n print(' 필수 태그 :', v.get('required-evidence'))\n for s in v.get('evidence', {}).get('scenarios', []):\n print(' 시나리오 :', s['selector'].split('#')[-1])\n print(' 덮는 태그 :', s.get('covers'))\nPY\n\necho\necho \"# 그 세 시험의 본문\"\nat \"$R/PostgreSqlAggregateIntegrationTest.java\" 19 30 PostgreSqlAggregateIntegrationTest.java\nat \"$R/PostgreSqlAggregateIntegrationTest.java\" 36 84 PostgreSqlAggregateIntegrationTest.java\necho\nat \"$R/PostgreSqlQueryIntegrationTest.java\" 22 35 PostgreSqlQueryIntegrationTest.java\nat \"$R/PostgreSqlQueryIntegrationTest.java\" 45 80 PostgreSqlQueryIntegrationTest.java\necho\nat \"$R/PostgreSqlLifecycleIntegrationTest.java\" 51 66 PostgreSqlLifecycleIntegrationTest.java\nat \"$R/PostgreSqlLifecycleIntegrationTest.java\" 107 119 PostgreSqlLifecycleIntegrationTest.java\n\necho\necho \"# 그 시험들이 프로덕션 타입에 닿는가\"\nfor f in PostgreSqlAggregateIntegrationTest PostgreSqlQueryIntegrationTest PostgreSqlLifecycleIntegrationTest; do\n printf ' %-38s dev.caskeleton 를 import 하는 줄 : %s 개\\n' \"$f.java\" \\\n \"$({ grep -cE '^import dev\\.caskeleton' \"$R/$f.java\" || true; })\"\ndone\necho \" [대조] 같은 소스 세트가 훑은 파일 :\"\nprintf ' %s 개\\n' \"$(git ls-files -- \"$R/*.java\" | grep -c .)\"\necho \" import 만이 아니라 이름 단위로 훑어도 :\"\nfor f in PostgreSqlAggregateIntegrationTest PostgreSqlQueryIntegrationTest PostgreSqlLifecycleIntegrationTest; do\n n=0\n while read -r t; do\n git ls-files -- \"src/**/src/main/**/$t.java\" | grep -q . && n=$((n+1)) || true\n done < <(grep -oE '\\b[A-Z][A-Za-z0-9]+\\b' \"$R/$f.java\" | sort -u)\n printf ' %-38s 프로덕션에 정의된 타입 이름 : %s 개\\n' \"$f.java\" \"$n\"\ndone\necho \" [대조] PostgreSqlTransactionIntegrationTest 에 같은 검사를 걸면 :\"\nTT=$(git ls-files -- '**/PostgreSqlTransactionIntegrationTest.java' | head -1)\nn=0\nwhile read -r t; do\n git ls-files -- \"src/**/src/main/**/$t.java\" | grep -q . && n=$((n+1)) || true\ndone < <(grep -oE '\\b[A-Z][A-Za-z0-9]+\\b' \"$TT\" | sort -u)\nprintf ' 프로덕션에 정의된 타입 이름 : %s 개\\n' \"$n\"\necho \" 두 시험이 쓰는 테이블 :\"\n{ grep -hoE 'readiness_[a-z]+' \"$R/PostgreSqlAggregateIntegrationTest.java\" \"$R/PostgreSqlQueryIntegrationTest.java\" || true; } | sort -u | sed 's#^# #'\nprintf ' 그 이름이 프로덕션 소스나 마이그레이션에 나오는가 : %s 개\\n' \"$(count 'readiness_aggregate|readiness_query' 'src/**/src/main/**')\"\nprintf ' [대조] 그 검색이 훑은 main 파일 : %s 개\\n' \"$(git ls-files -- 'src/**/src/main/**' | grep -c .)\"\nprintf ' postgresql-primary 가 프로덕션에 나오는 파일 : %s 개\\n' \"$(count 'postgresql-primary' 'src/**/src/main/**')\"\n\necho\necho \"# 대조 — 시나리오 일곱을 가진 카드\"\npython3 - \"$Y\" <<'PY'\nimport json, sys\nd = json.load(open(sys.argv[1]))\nv = d['cards']['jpa-transaction-runtime']\nprint(' 필수 태그 :', v.get('required-evidence'))\nfor s in v.get('evidence', {}).get('scenarios', []):\n print(' 시나리오 :', s['selector'].split('#')[-1], '->', s.get('covers'))\nPY\nT=$(git ls-files -- '**/PostgreSqlTransactionIntegrationTest.java' '**/PostgreSql*Transaction*IntegrationTest.java' | head -1)\ntest -n \"$T\"\nprintf ' %s 가 dev.caskeleton 를 import 하는 줄 : %s 개\\n' \"$(basename \"$T\")\" \"$({ grep -cE '^import dev\\.caskeleton' \"$T\" || true; })\"\n{ grep -nE '^import dev\\.caskeleton' \"$T\" || true; } | head -8 | sed -E 's#^([0-9]+): *# :\\1 #'\n", "cwd": "/shared/codebase/clean-architecture-backend-template", "exitCode": 0, "executedAt": "2026-09-04T07:07:49+00:00", "sourceRevision": "21234e38cdb9a926cbc92bb97a2aee2e4a7d2916", "raw": "evidence/raw/analysis-finding-a05-f034.txt", "svg": "evidence/rendered/analysis-finding-a05-f034.svg", "rawSha256": "995bbe14932dc87e477244eff9b16a57c26a5bfeed05c4fb066b4cb6819c41b4", "lines": 237, "redaction": "없음" }