{ "assetKey": "an-order-contract-with-no-implementation", "kind": "terminal", "command": "#!/bin/bash\nset -euo pipefail\nshopt -s inherit_errexit\ncd /shared/codebase/clean-architecture-backend-template\n\nnamed() { # 이름이 저장소에 아예 없으면 오타이므로 죽는다\n local out rc\n git grep -qE \"$1\" || { echo \"NAME NOT FOUND: $1\" >&2; exit 3; }\n out=$(git grep -nE \"$1\" -- \"$2\") && rc=0 || rc=$?\n [ \"$rc\" -le 1 ] || { echo \"SEARCH FAILED rc=$rc : $1\" >&2; exit 2; }\n [ \"$rc\" -eq 0 ] && printf '%s\\n' \"$out\" || true\n}\nmod() { sed -E 's#^src/(.*)/src/(main|test)/java/.*/([A-Za-z]+\\.java):([0-9]+):# \\1 · \\2 · \\3:\\4 #'; }\n\nL=src/messaging/messaging-transport-spi/src/main/java/dev/caskeleton/messaging/transport/MessagingLifecycle.java\nT=src/messaging/messaging-transport-spi/src/test/java/dev/caskeleton/messaging/transport/MessagingLifecycleTest.java\ntest -f \"$L\" && test -f \"$T\"\n\necho \"# MessagingLifecycle 전문 ($(wc -l < \"$L\") 줄)\"\nawk '{printf \" MessagingLifecycle.java:%d %s\\n\", NR, $0}' \"$L\"\necho \" ShutdownPhase 상수 개수 : $(sed -n '/enum ShutdownPhase/,/^ }$/p' \"$L\" | grep -cE '^ [A-Z_]+' || true) 개\"\necho \" 인터페이스가 요구하는 메서드 :\"\ngrep -nE '^ [A-Za-z].*\\(.*\\);' \"$L\" | sed -E 's#^([0-9]+): *# :\\1 #'\n\necho\necho \"# MessagingLifecycleTest 전문 ($(wc -l < \"$T\") 줄)\"\nawk '{printf \" MessagingLifecycleTest.java:%d %s\\n\", NR, $0}' \"$T\"\n\necho\necho \"# 그 두 이름을 저장소 어디서 쓰는가\"\necho \" pathspec 없이 이름이 나오는 파일 전부 :\"\ngit grep -l 'MessagingLifecycle\\|ShutdownPhase' | sed 's#^# #'\ncount() { # 세 갈래를 구분해 출력한다. git 오류면 죽는다.\n local out rc\n out=$(git grep -lE \"$1\" -- 'src/**/*.java') && rc=0 || rc=$?\n [ \"$rc\" -le 1 ] || { echo \"SEARCH FAILED rc=$rc : $1\" >&2; exit 2; }\n [ \"$rc\" -eq 0 ] && printf '%s\\n' \"$out\" | grep -c . || echo 0\n}\nIMPL='implements[[:space:]]+([A-Za-z0-9_.]+,[[:space:]]*)*'\necho \" implements MessagingLifecycle 를 가진 파일 : $(count \"${IMPL}MessagingLifecycle\") 개\"\necho \" [자기시험] implements MessagingLifecycleZZZ 를 가진 파일 : $(count \"${IMPL}MessagingLifecycleZZZ\") 개 (0 이어야 정상)\"\necho \" [대조] implements MessagingTransport 를 가진 파일 : $(count \"${IMPL}MessagingTransport\") 개 (0 이면 검색식이 깨진 것)\"\nnamed \"${IMPL}MessagingTransport\" 'src/**/*.java' | mod\n\necho\necho \"# DEFAULT_DRAIN_DEADLINE 이라는 이름을 가진 선언과 그 사용처\"\nnamed 'DEFAULT_DRAIN_DEADLINE' 'src/**/*.java' | mod\n\necho\necho \"# 프로퍼티로 들어오는 드레인 마감과 그것을 받는 자리\"\nnamed 'drainDeadline = Duration\\.ofSeconds|getShutdown\\(\\)\\.getDrainDeadline\\(\\)' 'src/**/*.java' | mod\n\necho\necho \"# 오늘 종료를 담당하는 구현\"\nnamed 'class MessagingShutdownLifecycle|class MessagingOutboxRelayLifecycle' 'src/**/*.java' | mod\n\necho\necho \"# 열거형 상수 순서를 바꾸면 무엇이 깨지는가 (레포 사본을 /tmp 에서 컴파일)\"\nG=/root/.gradle/caches/modules-2/files-2.1\nCP=$(find $G -name 'junit-jupiter-api-*.jar' -o -name 'assertj-core-*.jar' \\\n -o -name 'apiguardian-api-*.jar' -o -name 'opentest4j-*.jar' | sort | tr '\\n' ':')\nD=/tmp/reorder/src/dev/caskeleton/messaging/transport\nrm -rf /tmp/reorder && mkdir -p \"$D\"\ncp \"$L\" \"$T\" \"$D/\"\ncat > \"$D/RunPhaseTests.java\" <<'JAVA'\npackage dev.caskeleton.messaging.transport;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\npublic final class RunPhaseTests {\n public static void main(String[] args) throws Exception {\n MessagingLifecycleTest t = new MessagingLifecycleTest();\n List names = new ArrayList<>();\n for (Method m : MessagingLifecycleTest.class.getDeclaredMethods()) {\n if (m.getParameterCount() == 0 && !m.getName().contains(\"$\")) names.add(m.getName());\n }\n Collections.sort(names);\n List failed = new ArrayList<>();\n int pass = 0;\n for (String n : names) {\n Method m = MessagingLifecycleTest.class.getDeclaredMethod(n);\n m.setAccessible(true);\n try {\n m.invoke(t);\n pass++;\n } catch (Exception e) {\n failed.add(n);\n }\n }\n System.out.printf(\" 통과 %d · 실패 %d%n\", pass, failed.size());\n for (String n : failed) {\n System.out.println(\" 깨진 시험 : \" + n);\n }\n }\n}\nJAVA\nrun() {\n rm -rf /tmp/reorder/out && mkdir -p /tmp/reorder/out\n javac -nowarn -cp \"$CP\" -d /tmp/reorder/out \"$D\"/*.java 2>/dev/null\n java -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 \\\n -cp \"$CP:/tmp/reorder/out\" dev.caskeleton.messaging.transport.RunPhaseTests\n}\necho \" 사본을 그대로 컴파일했을 때\"\nrun\npython3 - \"$D/MessagingLifecycle.java\" <<'PY'\nimport sys\np = sys.argv[1]\nlines = open(p).read().split('\\n')\ni = [n for n, l in enumerate(lines) if l.strip().startswith('CLOSE_CONNECTIONS')][0]\nlines[i] = 'XX_DROP'\nj = [n for n, l in enumerate(lines) if l.strip().startswith('STOP_PUBLISH_ADMISSION')][0]\nlines[j] = ' CLOSE_CONNECTIONS,\\n STOP_PUBLISH_ADMISSION,'\ntxt = '\\n'.join(l for l in lines if l != 'XX_DROP')\nopen(p, 'w').write(txt.replace('RELEASE_OUTBOX_LEASES,', 'RELEASE_OUTBOX_LEASES'))\nPY\necho \" CLOSE_CONNECTIONS 를 첫 상수로 옮겼을 때\"\nrun\necho \" 레포가 수정되지 않았는지 : $(git status --porcelain | grep -c . || true) 건 변경\"\n", "cwd": "/shared/codebase/clean-architecture-backend-template", "exitCode": 0, "executedAt": "2026-09-04T04:30:09+00:00", "sourceRevision": "21234e38cdb9a926cbc92bb97a2aee2e4a7d2916", "raw": "evidence/raw/an-order-contract-with-no-implementation.txt", "svg": "evidence/rendered/an-order-contract-with-no-implementation.svg", "rawSha256": "2454fdc0ee237dcdd973c473a19433deec8b62cc9d9a14f375bb13ad82d66f92", "lines": 181, "redaction": "비밀값 없음" }