[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M70FW28X2ZR6MBG23056F43R":3,"skill-same:01M70FW28X2ZR6MBG23056F43R":64},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":34,"linkOnly":35,"markdownContent":36,"markdownBody":37,"frontMatter":38,"refName":43,"commitSha":44,"skillDirectory":45,"forksCount":46,"repositoryHtmlUrl":47,"repositoryHomepageUrl":6,"ownerHtmlUrl":48,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":49,"install":50,"resources":63},"01M70FW28X2ZR6MBG23056F43R","code-reviewer",null,"\u002Frein:codex-review 장애 시 fallback 리뷰어. 변경된 코드에 대해 AGENTS.md rules + 체크리스트 기반으로 리뷰하고 PASS 시 v2 증거를 발급한다.","JayJihyunKim\u002Frein","JayJihyunKim","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F9338574?v=4","01M70FV3CW5XEZGG6GS341V6J6","flyingcat4","01M70FV3DSX4YES0CN14AFJT2T",1,"MIT","https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein\u002Fblob\u002Fmain\u002Fplugins\u002Frein-core\u002Fskills\u002Fcode-reviewer\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33],"code","code reviewer","reviewer","review","codex","ZeRO","Rules","superpowers","fallback","exit","2026-11-10 10:12:30",false,"---\nname: code-reviewer\ndescription: \u002Frein:codex-review 장애 시 fallback 리뷰어. 변경된 코드에 대해 AGENTS.md rules + 체크리스트 기반으로 리뷰하고 PASS 시 v2 증거를 발급한다.\ntriggers:\n  - \u002Fcodex-review 호출 타임아웃\n  - \u002Fcodex-review 호출 에러(exit non-zero)\n  - superpowers:code-reviewer 미설치 + codex 자체 불가 환경\n---\n\n# code-reviewer (rein-native fallback)\n\n## 실행 조건\n\n이 스킬은 `\u002Fcodex-review` 리뷰 게이트를 대체하지 않는다. AGENTS.md §5-1 \u002F `.claude\u002Fskills\u002Fcodex-review\u002FSKILL.md` 의 규정은 \"codex 실패 시에만 fallback\" 이며, 본 스킬은 그 fallback 경로의 rein-native 구현이다. 사용자의 임의 요청만으로는 호출하지 않는다.\n\n1. **codex_timeout** — `\u002Fcodex-review` 호출이 타임아웃\n2. **codex_error** — `\u002Fcodex-review` 가 exit non-zero 로 실패\n3. **no_superpowers_plugin** — `superpowers:code-reviewer` 플러그인이 없고 `\u002Fcodex-review` 경로도 사용 불가\n\n아래 \"리뷰 결과 기록\" 섹션에서 위 slug (codex_timeout \u002F codex_error \u002F no_superpowers_plugin) 중 어느 사유로 호출됐는지를 사람 보고 문구에 그대로 참조한다 (Phase 7 웨이브 3 ③-d 이후 v2 발급은 verdict\u002Fdigest 만 받으므로, 이 slug 는 기록 필드가 아니라 사람 안내용이다).\n\n## v2 evidence subject 스냅샷 캡처 (리뷰 시작 전)\n\n아래 체크리스트 리뷰를 시작하기 **전에**, 리뷰 대상 상태의 digest 와 그 digest 가 실제로 흡수하는 인증된 경로 목록을 **한 번의 호출로 함께** 캡처해 둔다(Phase 7 웨이브 3 ③-a code review round 3 — 이전에는 경로 목록을 리뷰가 끝난 뒤 `files_reviewed` 통계 집계용으로만 별도로 다시 조회했다. 그러면 인증된 경로가 애초에 리뷰 대상 결정에 쓰이지 못하고, 리뷰 시작 시점 캡처와 별개 시점 조회 사이에 트리가 바뀌면 두 값이 서로 다른 상태를 증명할 위험도 있었다). digest 는 리뷰 완료 후 \"v2 evidence 발급 시도\" 절에 그대로 쓰인다(Phase 7 웨이브 3 ③-d 이후 발급 호출이 유일한 기록 경로 — stamp 파일은 더 이상 없다) — 리뷰가 실제로 검토한 상태와 발급 시점 상태가 같은지 v2 가 검증할 수 있게 하기 위함이다.\n\n**NUL-safe consumption (Phase 7 wave 3 ③-a code review round 4, High-1)** — git allows newline-containing filenames, and `--print-subject` returns them RAW. The earlier version of this snippet printed one path per line (`for p in paths: print(p)`) and let bash split on newline — a single path like `dir\u002Fline\\nbreak.py` became TWO entries once bash re-split it, silently corrupting `$REIN_CERTIFIED_PATHS`'s membership. All structural work now happens inside the one python process; only the digest (a scalar, never contains a newline) crosses back via stdout — the path list is written directly to a NUL-delimited temp file, and bash reads it back only with `while IFS= read -r -d ''` (never newline-splitting a path). Each entry then gets its embedded newlines (if any) escaped to a literal `\\n` (two-char backslash-n) before it joins the newline-per-entry `$REIN_CERTIFIED_PATHS` display variable below — that keeps \"one line = one path\" true for the checklist review's reading of it, no matter what the raw filename contains:\n\n~~~bash\nREIN_SUBJECT_JSON=$(\"${CLAUDE_PLUGIN_ROOT:-$PWD\u002Fplugins\u002Frein-core}\u002Fbin\u002Frein\" issue-evidence code_review --print-subject 2>\u002Fdev\u002Fnull || true)\nREIN_PATHS_FILE=$(mktemp \"${TMPDIR:-\u002Ftmp}\u002Frein-cr-subject-paths.XXXXXX\" 2>\u002Fdev\u002Fnull || true)\nREIN_REVIEWED_DIGEST=\"\"\nif [ -n \"$REIN_PATHS_FILE\" ]; then\n  REIN_REVIEWED_DIGEST=$(printf '%s' \"$REIN_SUBJECT_JSON\" \\\n    | REIN_PATHS_OUT=\"$REIN_PATHS_FILE\" python3 -c '\nimport json\nimport os\nimport sys\n\ntry:\n    data = json.load(sys.stdin)\n    subject = data.get(\"subject\", \"\")\n    paths = data.get(\"paths\", [])\n    if not isinstance(paths, list):\n        paths = []\nexcept Exception:\n    sys.exit(1)\n\nout_file = os.environ.get(\"REIN_PATHS_OUT\", \"\")\nif out_file:\n    with open(out_file, \"wb\") as fh:\n        for p in paths:\n            fh.write(str(p).encode(\"utf-8\", \"surrogateescape\"))\n            fh.write(b\"\\0\")\n\nsys.stdout.write(subject)\n' 2>\u002Fdev\u002Fnull || true)\nfi\nREIN_CERTIFIED_PATHS=\"\"\nif [ -n \"$REIN_PATHS_FILE\" ] && [ -s \"$REIN_PATHS_FILE\" ]; then\n  _rein_cert_lines=()\n  while IFS= read -r -d '' _rein_cert_p; do\n    # Injective escape — backslash FIRST, then LF (JSON-string-style\n    # order). Escaping LF before backslash would let a real LF and a\n    # literal `\\n` (backslash-n) in a filename collapse to the same\n    # rendered form, merging two distinct certified paths under a later\n    # dedup. Escaping backslash first means the literal `\\n` case ends up\n    # as `\\\\n` (backslash backslash n) while the real-LF case ends up as\n    # `\\n` (single backslash n) — always distinguishable.\n    _rein_cert_p=\"${_rein_cert_p\u002F\u002F\\\\\u002F\\\\\\\\}\"\n    _rein_cert_lines+=(\"${_rein_cert_p\u002F\u002F$'\\n'\u002F\\\\n}\")\n  done \u003C \"$REIN_PATHS_FILE\"\n  if [ \"${#_rein_cert_lines[@]}\" -gt 0 ]; then\n    REIN_CERTIFIED_PATHS=$(printf '%s\\n' \"${_rein_cert_lines[@]}\")\n  fi\nfi\n[ -n \"$REIN_PATHS_FILE\" ] && rm -f \"$REIN_PATHS_FILE\"\n~~~\n\n**`$REIN_CERTIFIED_PATHS` 를 아래 체크리스트 리뷰의 대상 하한으로 삼는다** — 이 목록의 파일 각각을 리뷰 대상에 반드시 포함해야 한다(단순히 \"무엇이 바뀐 것 같다\"는 추측이 아니라, `--print-subject` 가 실제로 review digest 로 증명하는 정확한 집합이다). 저장소 맥락상 필요한 다른 파일을 더 읽는 것은 자유지만, 이 목록의 항목을 빠뜨리면 발급 시 \"증명한 파일 ≠ 실제로 리뷰한 파일\" 이 된다.\n\n캡처가 실패해도(digest·paths 둘 다 빈 값) 리뷰 자체는 막지 않는다 — 체크리스트 리뷰는 그대로 진행한다. 다만 아래 \"리뷰 결과 기록\" 절의 v2 발급은 이 digest 없이는 시도조차 할 수 없고(발급이 빈 값을 받으면 스스로 스킵한다), legacy stamp 같은 대체 기록 경로는 더 이상 존재하지 않는다(Phase 7 웨이브 3 ③-d — `.codex-reviewed`\u002F`.review-pending`\u002F`.security-reviewed` 3종의 write·read 경로 전체 제거). 즉 **캡처 실패 = 이번 회차에 기록 가능한 통과 증거가 없다**는 뜻이다. 리뷰 결론이 PASS 라도 이 경우엔 \"리뷰는 수행했으나 이번 회차는 기록되지 않았다 — git 상태를 다시 확인한 뒤 재실행이 필요하다\"를 사용자\u002F부모에게 명시적으로 보고한다 (아래 \"사용자 안내\" 절 참조).\n\n## 리뷰 체크리스트\n\n리뷰 시작 전 아래 규칙 파일을 먼저 로드하여 각 그룹의 기준을 확인한다.\n\n### 1. 보안 (`plugins\u002Frein-core\u002Frules\u002Fsecurity.md` 기준)\n\n- [ ] 하드코딩된 credential (API 키, 비밀번호, 토큰) 없음\n- [ ] 모든 외부 입력(사용자 입력, 환경 인수, 파일 경로)에 검증 로직 존재\n- [ ] SQL \u002F 쉘 \u002F HTML 주입 공격 방어 처리 확인\n- [ ] `.env` 파일 또는 `secrets\u002F` 디렉토리 직접 접근·커밋 없음\n\n### 2. 코드 스타일 (`plugins\u002Frein-core\u002Frules\u002Fcode-style.md` 기준)\n\n- [ ] 네이밍: 함수 동사형 camelCase, 상수 UPPER_SNAKE_CASE, Boolean `is\u002Fhas\u002Fcan\u002Fshould` 접두사\n- [ ] 함수 길이 50줄 이내 (초과 시 분리 권고)\n- [ ] 파라미터 3개 이하 (초과 시 객체 묶음 권고)\n- [ ] 중첩 depth 3단계 이하 (early return 또는 함수 분리)\n- [ ] `any` 타입(TypeScript) \u002F `console.log`·`print` 운영 코드 방치 없음\n- [ ] 주석: diff 에서 **추가되거나 수정된(added\u002Fmodified) 주석 줄만** 검사 — 회차 서수·수리 이력 서사·실행 결과 측정 수치가 새로 들어왔으면 삭제 또는 trail 이동을 요구하고, 해당 diff 목적과 무관한 기존 주석 전체의 일괄 청소는 요구하지 않는다\n\n### 3. 테스트 (`plugins\u002Frein-core\u002Frules\u002Ftesting.md` 기준)\n\n- [ ] 변경 범위에 해당하는 테스트가 추가 또는 수정됨\n- [ ] 경계 조건(null\u002Fundefined, 빈 값, 최대\u002F최소값) 커버\n- [ ] 외부 API 직접 호출 단위 테스트 없음 (Mock 사용 확인)\n- [ ] 모킹 과다 여부 — 실제 동작보다 mock 구조 검증에 편중되지 않음\n\n### 4. Rein 고유\n\n- [ ] `trail\u002Fdod\u002Fdod-YYYY-MM-DD-\u003Cslug>.md` 파일이 이 작업 전 생성되어 있음\n- [ ] DoD 또는 plan work unit 에 `covers: [...]` 메타데이터가 존재하고 매트릭스 ID 와 일치\n- [ ] 작업 완료 후 `trail\u002Finbox\u002FYYYY-MM-DD-작업명.md` 기록 대상임을 확인\n\n## 출력 형식\n\n리뷰 결과를 아래 마크다운 템플릿으로 출력한다:\n\n~~~markdown\n## 코드 리뷰 결과 (rein-native, round N)\n\n**리뷰 대상**: [파일 목록]\n**라운드**: N\n\n### High (즉시 수정 필요)\n\n- [파일:줄번호] 이슈 설명 — 권고 조치\n\n### Medium (수정 권고)\n\n- [파일:줄번호] 이슈 설명 — 권고 조치\n\n### Low (선택 개선)\n\n- [파일:줄번호] 이슈 설명\n\n### 통과 항목\n\n- 보안: 하드코딩 credential 없음\n- 스타일: 네이밍 규칙 준수\n- 테스트: 변경 범위 커버됨\n- Rein 고유: DoD 파일 존재 확인\n\n**결론** (아래 중 하나):\n- 통과 — 이슈 없음, 본 스킬이 v2 발급으로 기록\n- 재리뷰 (self-review) — Low 만 또는 Medium ≤3줄, 수정 후 sonnet self-review 로 v2 발급 기록\n- 재리뷰 (same reviewer) — Medium >3줄 또는 High 1건 이상, 수정 후 본 스킬 재실행\n- 에스컬레이션 — 3라운드 후에도 High 잔존, 사람에게 직접 보고 (기록 없음)\n~~~\n\n## 리뷰 에스컬레이션 흐름\n\nAGENTS.md §5-1 \u002F `.claude\u002Fskills\u002Fcodex-review\u002FSKILL.md` 의 표와 일치한다.\n\n| 라운드 결과 | 규모 | 다음 행동 |\n|-----------|------|----------|\n| 이슈 없음 | — | **통과** (본 스킬이 v2 발급으로 기록) |\n| Low 만 | — | 수정 후 **sonnet self-review, v2 발급으로 기록** |\n| Medium 만 | ≤3줄 | 수정 후 **sonnet self-review, v2 발급으로 기록** |\n| Medium 만 | >3줄 | 수정 후 본 스킬 재실행 (round N+1) |\n| High 1건 이상 | — | 수정 후 본 스킬 재실행 (round N+1) |\n| 3라운드 이후 High 잔존 | — | **에스컬레이션** (기록 없음 — 사람에게 직접 보고) |\n\n## 리뷰 결과 기록 (v2 발급 — 유일한 기록 경로)\n\n**Phase 7 웨이브 3 ③-d 갱신.** 이전에는 이 스킬이 legacy stamp (`trail\u002Fdod\u002F.codex-reviewed` 파일 생성 + `trail\u002Fdod\u002F.review-pending` 삭제) 를 먼저 기록하고, 그 위에 v2 발급을 \"병행 기록\"으로 시도했다. ③-d 로 legacy 리뷰 표식 3종(`.review-pending`\u002F`.codex-reviewed`\u002F`.security-reviewed`)의 write·read 경로가 전부 제거되면서, 이제 **v2 발급 호출 자체가 유일한 기록 절차**다 — 별도의 stamp 파일을 먼저 쓰는 단계는 없다. `\u003CREASON>` 은 \"실행 조건\" 섹션의 slug (codex_timeout \u002F codex_error \u002F no_superpowers_plugin) 중 하나이며, 아래 사용자 안내 문구에서 참조용으로만 쓰인다 (기록되는 필드가 아니다 — v2 발급이 받는 인자는 verdict 와 reviewed-digest 뿐이다).\n\n### Spec-review fallback 분기 (CRITICAL, v1.0.0+)\n\n이 스킬이 **`[NON_INTERACTIVE] spec review for plan:` 또는 `design:` prefix 가 붙은 prompt** 로 호출된 경우 (plan-writer 의 codex 실패 fallback 경로), 아래 \"PASS 시 v2 발급\" 절차를 **실행하지 않는다** — code-review 기록 절차 자체가 이 경로에 존재하지 않는다.\n\n근거: code-review v2 발급은 코드리뷰 게이트 증거다. spec review fallback 에서 이 증거를 발급하면 코드 변경 없이도 gate 통과 가능 → rein 규율 오염.\n\nSpec-review fallback 동작:\n1. 리뷰 수행 (AGENTS.md rules + 체크리스트) — 내용 자체는 동일\n   - `for plan:` prefix 이면 계획 문서 전용 **Verification Cost** 관점을 함께 판정한다(래퍼 봉투 슬롯 4 와 같은 계약): 같은 코드 상태(두 검증 Step 사이에 코드·테스트·설정·의존성을 바꾸는 Step 이 없는 상태)에서 전체 검사(전체 테스트 스위트, 전체 포맷·린트·타입검사, 전체 빌드)를 2회 이상 지시하거나 수정 Step 뒤 처음부터 전체 재검증을 지시하는 곳은 rein 플러그인 testing 규칙 \"검증 실행 범위\" 에 근거한 저장소 계약 위반(NEEDS-FIX)이며, 고칠 Step 위치를 함께 적는다. 예외: 그 Step 이 codex-review 스킬 \"전체 테스트 재실행으로 돌아가는 조건\" 중 어느 것에 해당하는지 계획서에 적혀 있으면 — 복귀 조건을 명시한 재실행은 위반이 아니다. 범위·소요 표기 누락은 참고사항이다. 단 소요 수치가 적혀 있으면 이전 실행 기록을 인용하지 않은 모든 소요 수치(단일값·범위·추정)는 NEEDS-FIX 다 — 파일 수·유사 작업 같은 저장소 근거를 붙인 범위 추정도 허용 근거가 아니며, 허용 근거는 이전 실행 기록 인용 하나다(수치 불일치로 NEEDS-FIX). `for design:` prefix 와 코드 리뷰 경로에는 적용하지 않는다.\n2. verdict 만 caller (plan-writer) 에게 반환 — PASS \u002F NEEDS-FIX \u002F REJECT\n3. **code-review v2 발급 없음**. legacy marker 도 이제 존재하지 않으므로 건드릴 대상 자체가 없음\n4. caller 가 PASS 시 `bash \"${CLAUDE_PLUGIN_ROOT:-$PWD\u002Fplugins\u002Frein-core}\u002Fscripts\u002Frein-mark-spec-reviewed.sh\" \u003Cpath> code-reviewer-rein-sonnet-fallback` 호출 — spec-review 축은 이번 웨이브의 존속 예외이므로 그대로 `trail\u002Fdod\u002F.spec-reviews\u002F\u003Chash>.reviewed` 를 생성한다\n\n**Code-review 경로 (일반 fallback, `[NON_INTERACTIVE] spec review` prefix 없음)**: 아래 \"PASS 시 v2 발급\" 절차를 그대로 따른다.\n\n### PASS 시 v2 발급 (최초 통과 \u002F self-review 통과 공통)\n\n체크리스트 리뷰 결과가 PASS (이슈 없음, 또는 Low-only \u002F Medium ≤3줄 수정 후 self-review 통과) 인 회차에서만 앞서 캡처해 둔 `$REIN_REVIEWED_DIGEST` 로 발급을 시도한다. round 이 늘어나는지(최초 통과 vs self-review) 는 위 \"리뷰 에스컬레이션 흐름\" 표의 판단에만 쓰이고, 발급 호출 자체는 두 경로가 동일하다. 아래 \"에스컬레이션\" 경로(3라운드 후에도 High 잔존)는 PASS 가 아니므로 발급을 시도하지 않는다.\n\n~~~bash\nif [ -n \"${REIN_REVIEWED_DIGEST:-}\" ]; then\n  if ISSUE_OUT=$(\"${CLAUDE_PLUGIN_ROOT:-$PWD\u002Fplugins\u002Frein-core}\u002Fbin\u002Frein\" issue-evidence code_review \\\n      --verdict PASS --reviewed-digest \"$REIN_REVIEWED_DIGEST\" 2>\u002Fdev\u002Fnull); then\n    ISSUE_RC=0\n  else\n    ISSUE_RC=$?\n  fi\n  case \"$ISSUE_RC\" in\n    0) echo \"[rein] v2 evidence recorded (code_review, PASS) — this is this cycle's review record.\" ;;\n    2)\n       # High finding (Phase 7 wave 3 ③-a code review round 4, High-2) 계승,\n       # ③-d 로 \"legacy stamp 로 fallback\" 문구만 제거 — 판정 로직 자체는\n       # 그대로다. 응답의 reason 을 긍정적으로 파싱해 \"digest-mismatch\"\n       # 인지 확인한다; 파싱 실패도 digest-mismatch 와 동일하게 fail-\n       # closed 취급한다 (오직 non-mismatch 로 명확히 파싱된 사유만\n       # \"기록 안 됨, 그러나 원인은 트리 변경이 아님\"으로 구분한다).\n       ISSUE_REASON_OK=1\n       ISSUE_REASON=$(printf '%s' \"$ISSUE_OUT\" | python3 -c '\nimport json, sys\ntry:\n    data = json.load(sys.stdin)\n    reason = data.get(\"reason\")\n    if not isinstance(reason, str) or not reason:\n        raise ValueError(\"reason missing or not a non-empty string\")\nexcept Exception:\n    sys.exit(1)\nsys.stdout.write(reason)\n' 2>\u002Fdev\u002Fnull) && ISSUE_REASON_OK=0\n       if [ \"$ISSUE_REASON_OK\" -ne 0 ] || [ \"$ISSUE_REASON\" = \"digest-mismatch\" ]; then\n         # 리뷰 대상 트리가 회차 도중 바뀌었다(또는 그 가능성을 배제할 수\n         # 없다) — 이번 회차는 기록되지 않는다. legacy stamp 가 없으므로\n         # \"표식은 남아있다\" 같은 안전망도 없다: 다음 행동은 명시적으로\n         # digest 재캡처 + 재리뷰뿐이다.\n         if [ \"$ISSUE_REASON_OK\" -ne 0 ]; then\n           echo \"[rein] v2 evidence issuance refused (exit 2) and the response could not be positively parsed to a reason OTHER than digest-mismatch — treating as digest-mismatch (fail-closed). This cycle is NOT recorded. Re-capture the subject digest and re-review before this can count as reviewed.\"\n         else\n           echo \"[rein] v2 evidence issuance refused — reason: digest-mismatch. The reviewed tree changed during this review. This cycle is NOT recorded. Re-capture the subject digest and re-review before this can count as reviewed.\"\n         fi\n       elif [ \"$ISSUE_REASON\" = \"subject-empty\" ]; then\n         # subject-empty 는 실패가 아니다(코드리뷰 Medium 시정, 2026-08-24)\n         # — 리뷰 대상에 non-exempt 코드가 없다는 뜻이라 governance 는\n         # 이 상태를 authority 계층에서 직접 충족으로 판정한다(spec §3.6\n         # 종국 상태표). 기록이 없다고 재리뷰가 필요한 게 아니다.\n         echo \"[rein] no v2 evidence was issued because there is nothing non-exempt to review (digest=empty:no-subject) — this is expected, not a failure; governance treats this changeset as satisfied without an evidence record.\"\n       else\n         echo \"[rein] v2 evidence issuance refused — reason: $ISSUE_REASON. This cycle is NOT recorded (no legacy stamp fallback exists) — the next review cycle must re-capture and retry v2 issuance before governance treats this as reviewed.\"\n       fi\n       ;;\n    *) echo \"[rein] v2 evidence issuance did not complete (exit $ISSUE_RC). This cycle is NOT recorded (no legacy stamp fallback exists) — retry issuance once the infrastructure failure is resolved.\" ;;\n  esac\nelse\n  echo \"[rein] no reviewed-digest was captured at review start (see 'v2 evidence subject 스냅샷 캡처' 절) — v2 issuance was not attempted. This cycle is NOT recorded.\"\nfi\n~~~\n\n`ISSUE_RC` 가 0 이 아닌 경로 중 `subject-empty`(검토할 non-exempt 코드 자체가 없어 governance 가 기록 없이 직접 충족으로 판정하는 정상 상태, 바로 위 PASS 케이스의 `elif` 분기 참조) 를 **제외한** 나머지(digest-mismatch\u002F기타\u002Fdigest 미캡처) 는 \"이번 회차 기록 없음\"으로 동일하게 취급한다 — 더 이상 legacy stamp 로 되돌아갈 안전망이 없으므로, 이 스킬을 호출한 caller(부모 세션)에게 그 사실을 위 echo 문구 그대로 반드시 전달해야 한다 (아래 \"사용자 안내\" 절에도 이 상태를 반영한다).\n\n## 에스컬레이션 (3라운드 이후에도 High 잔존 시)\n\n3라운드 리뷰 후에도 High 가 남아 있으면 작업을 중단하고 사람에게 에스컬레이션한다. 이 경로는 PASS 가 아니므로 v2 발급을 시도하지 않는다 — 남길 기록이 없다(legacy stamp 의 `resolution: escalated_to_human` 같은 별도 마커도 이제 존재하지 않는다). 에스컬레이션 사실과 잔존 이슈는 아래 \"사용자 안내\" 절의 형식으로 사람에게 직접 보고한다.\n\n에스컬레이션 후 작업자는 잔존 이슈를 검토하여 직접 수정하거나 추가 지시를 내린다.\n\n## 사용자 안내\n\n이 SKILL 의 결과를 사용자에게 보고할 때 다음 짧은 형식을 **먼저** 출력한다 (위 `## 코드 리뷰 결과` 템플릿은 그 다음에 그대로 이어 붙인다). 형식은 한 문장 또는 두 문장 — 결과 1줄 + 다음 액션 1줄. 내부 식별자(`.codex-reviewed` 같은 legacy marker 명, `digest`, `evidence` 등)는 평문으로 번역한다 — `plugins\u002Frein-core\u002Frules\u002Fresponse-tone.md` 참조.\n\n**리뷰 PASS + 기록 성공** (`ISSUE_RC=0`):\n> 코드 리뷰 통과. 차단급 결함 없습니다. 통과 증거가 기록됐어요. 다음은 [code-review path 면 보안 리뷰 \u002F spec-review fallback path 면 `bash \"${CLAUDE_PLUGIN_ROOT:-$PWD\u002Fplugins\u002Frein-core}\u002Fscripts\u002Frein-mark-spec-reviewed.sh\"` 로 per-spec stamp 등록].\n\n**리뷰 PASS 이지만 기록 실패** (digest 미캡처 \u002F `ISSUE_RC` 가 0 이 아니고 사유가 검토 대상 없음도 아님) — Phase 7 웨이브 3 ③-d 갱신, legacy stamp 안전망이 없어진 만큼 반드시 별도로 알린다:\n> 코드 리뷰 자체는 통과했지만 이번 회차는 기록되지 않았어요 — [사유: 대상 상태를 확인하지 못함 \u002F 검토 도중 대상이 바뀜 \u002F 기록 시도 실패]. 재리뷰(digest 재캡처부터)가 필요합니다.\n\n**리뷰 PASS + 검토할 대상이 없었음** (`ISSUE_RC=2`, 사유 = 검토할 non-exempt 코드 없음) — 기록이 없는 게 정상이므로 재리뷰를 요구하지 않는다:\n> 코드 리뷰는 통과했고, 이번 회차는 검토할 대상 자체가 없어서(변경이 전부 리뷰 면제) 별도 기록이 필요 없었어요. 재리뷰 없이 다음 단계로 진행하면 됩니다.\n\n**리뷰 NEEDS-FIX (수정 필요)**:\n> 리뷰에서 N건 수정이 필요해요 — [Severity 요약, 예: \"Medium 2건 + Low 1건\"]. [핵심 1-2건과 다음 액션, 예: \"printf 형식 mismatch + symlink 테스트 stderr 미검증. 고치고 재리뷰\"].\n\n**3회차에도 High 잔존 (사람 에스컬레이션)**:\n> 리뷰 3회차에도 High N건이 남아 있어 사람 에스컬레이션이 필요합니다. 잔존 이슈를 확인하고 직접 수정하거나 추가 지시를 내려주세요.\n","# code-reviewer (rein-native fallback)\n\n## 실행 조건\n\n이 스킬은 `\u002Fcodex-review` 리뷰 게이트를 대체하지 않는다. AGENTS.md §5-1 \u002F `.claude\u002Fskills\u002Fcodex-review\u002FSKILL.md` 의 규정은 \"codex 실패 시에만 fallback\" 이며, 본 스킬은 그 fallback 경로의 rein-native 구현이다. 사용자의 임의 요청만으로는 호출하지 않는다.\n\n1. **codex_timeout** — `\u002Fcodex-review` 호출이 타임아웃\n2. **codex_error** — `\u002Fcodex-review` 가 exit non-zero 로 실패\n3. **no_superpowers_plugin** — `superpowers:code-reviewer` 플러그인이 없고 `\u002Fcodex-review` 경로도 사용 불가\n\n아래 \"리뷰 결과 기록\" 섹션에서 위 slug (codex_timeout \u002F codex_error \u002F no_superpowers_plugin) 중 어느 사유로 호출됐는지를 사람 보고 문구에 그대로 참조한다 (Phase 7 웨이브 3 ③-d 이후 v2 발급은 verdict\u002Fdigest 만 받으므로, 이 slug 는 기록 필드가 아니라 사람 안내용이다).\n\n## v2 evidence subject 스냅샷 캡처 (리뷰 시작 전)\n\n아래 체크리스트 리뷰를 시작하기 **전에**, 리뷰 대상 상태의 digest 와 그 digest 가 실제로 흡수하는 인증된 경로 목록을 **한 번의 호출로 함께** 캡처해 둔다(Phase 7 웨이브 3 ③-a code review round 3 — 이전에는 경로 목록을 리뷰가 끝난 뒤 `files_reviewed` 통계 집계용으로만 별도로 다시 조회했다. 그러면 인증된 경로가 애초에 리뷰 대상 결정에 쓰이지 못하고, 리뷰 시작 시점 캡처와 별개 시점 조회 사이에 트리가 바뀌면 두 값이 서로 다른 상태를 증명할 위험도 있었다). digest 는 리뷰 완료 후 \"v2 evidence 발급 시도\" 절에 그대로 쓰인다(Phase 7 웨이브 3 ③-d 이후 발급 호출이 유일한 기록 경로 — stamp 파일은 더 이상 없다) — 리뷰가 실제로 검토한 상태와 발급 시점 상태가 같은지 v2 가 검증할 수 있게 하기 위함이다.\n\n**NUL-safe consumption (Phase 7 wave 3 ③-a code review round 4, High-1)** — git allows newline-containing filenames, and `--print-subject` returns them RAW. The earlier version of this snippet printed one path per line (`for p in paths: print(p)`) and let bash split on newline — a single path like `dir\u002Fline\\nbreak.py` became TWO entries once bash re-split it, silently corrupting `$REIN_CERTIFIED_PATHS`'s membership. All structural work now happens inside the one python process; only the digest (a scalar, never contains a newline) crosses back via stdout — the path list is written directly to a NUL-delimited temp file, and bash reads it back only with `while IFS= read -r -d ''` (never newline-splitting a path). Each entry then gets its embedded newlines (if any) escaped to a literal `\\n` (two-char backslash-n) before it joins the newline-per-entry `$REIN_CERTIFIED_PATHS` display variable below — that keeps \"one line = one path\" true for the checklist review's reading of it, no matter what the raw filename contains:\n\n~~~bash\nREIN_SUBJECT_JSON=$(\"${CLAUDE_PLUGIN_ROOT:-$PWD\u002Fplugins\u002Frein-core}\u002Fbin\u002Frein\" issue-evidence code_review --print-subject 2>\u002Fdev\u002Fnull || true)\nREIN_PATHS_FILE=$(mktemp \"${TMPDIR:-\u002Ftmp}\u002Frein-cr-subject-paths.XXXXXX\" 2>\u002Fdev\u002Fnull || true)\nREIN_REVIEWED_DIGEST=\"\"\nif [ -n \"$REIN_PATHS_FILE\" ]; then\n  REIN_REVIEWED_DIGEST=$(printf '%s' \"$REIN_SUBJECT_JSON\" \\\n    | REIN_PATHS_OUT=\"$REIN_PATHS_FILE\" python3 -c '\nimport json\nimport os\nimport sys\n\ntry:\n    data = json.load(sys.stdin)\n    subject = data.get(\"subject\", \"\")\n    paths = data.get(\"paths\", [])\n    if not isinstance(paths, list):\n        paths = []\nexcept Exception:\n    sys.exit(1)\n\nout_file = os.environ.get(\"REIN_PATHS_OUT\", \"\")\nif out_file:\n    with open(out_file, \"wb\") as fh:\n        for p in paths:\n            fh.write(str(p).encode(\"utf-8\", \"surrogateescape\"))\n            fh.write(b\"\\0\")\n\nsys.stdout.write(subject)\n' 2>\u002Fdev\u002Fnull || true)\nfi\nREIN_CERTIFIED_PATHS=\"\"\nif [ -n \"$REIN_PATHS_FILE\" ] && [ -s \"$REIN_PATHS_FILE\" ]; then\n  _rein_cert_lines=()\n  while IFS= read -r -d '' _rein_cert_p; do\n    # Injective escape — backslash FIRST, then LF (JSON-string-style\n    # order). Escaping LF before backslash would let a real LF and a\n    # literal `\\n` (backslash-n) in a filename collapse to the same\n    # rendered form, merging two distinct certified paths under a later\n    # dedup. Escaping backslash first means the literal `\\n` case ends up\n    # as `\\\\n` (backslash backslash n) while the real-LF case ends up as\n    # `\\n` (single backslash n) — always distinguishable.\n    _rein_cert_p=\"${_rein_cert_p\u002F\u002F\\\\\u002F\\\\\\\\}\"\n    _rein_cert_lines+=(\"${_rein_cert_p\u002F\u002F$'\\n'\u002F\\\\n}\")\n  done \u003C \"$REIN_PATHS_FILE\"\n  if [ \"${#_rein_cert_lines[@]}\" -gt 0 ]; then\n    REIN_CERTIFIED_PATHS=$(printf '%s\\n' \"${_rein_cert_lines[@]}\")\n  fi\nfi\n[ -n \"$REIN_PATHS_FILE\" ] && rm -f \"$REIN_PATHS_FILE\"\n~~~\n\n**`$REIN_CERTIFIED_PATHS` 를 아래 체크리스트 리뷰의 대상 하한으로 삼는다** — 이 목록의 파일 각각을 리뷰 대상에 반드시 포함해야 한다(단순히 \"무엇이 바뀐 것 같다\"는 추측이 아니라, `--print-subject` 가 실제로 review digest 로 증명하는 정확한 집합이다). 저장소 맥락상 필요한 다른 파일을 더 읽는 것은 자유지만, 이 목록의 항목을 빠뜨리면 발급 시 \"증명한 파일 ≠ 실제로 리뷰한 파일\" 이 된다.\n\n캡처가 실패해도(digest·paths 둘 다 빈 값) 리뷰 자체는 막지 않는다 — 체크리스트 리뷰는 그대로 진행한다. 다만 아래 \"리뷰 결과 기록\" 절의 v2 발급은 이 digest 없이는 시도조차 할 수 없고(발급이 빈 값을 받으면 스스로 스킵한다), legacy stamp 같은 대체 기록 경로는 더 이상 존재하지 않는다(Phase 7 웨이브 3 ③-d — `.codex-reviewed`\u002F`.review-pending`\u002F`.security-reviewed` 3종의 write·read 경로 전체 제거). 즉 **캡처 실패 = 이번 회차에 기록 가능한 통과 증거가 없다**는 뜻이다. 리뷰 결론이 PASS 라도 이 경우엔 \"리뷰는 수행했으나 이번 회차는 기록되지 않았다 — git 상태를 다시 확인한 뒤 재실행이 필요하다\"를 사용자\u002F부모에게 명시적으로 보고한다 (아래 \"사용자 안내\" 절 참조).\n\n## 리뷰 체크리스트\n\n리뷰 시작 전 아래 규칙 파일을 먼저 로드하여 각 그룹의 기준을 확인한다.\n\n### 1. 보안 (`plugins\u002Frein-core\u002Frules\u002Fsecurity.md` 기준)\n\n- [ ] 하드코딩된 credential (API 키, 비밀번호, 토큰) 없음\n- [ ] 모든 외부 입력(사용자 입력, 환경 인수, 파일 경로)에 검증 로직 존재\n- [ ] SQL \u002F 쉘 \u002F HTML 주입 공격 방어 처리 확인\n- [ ] `.env` 파일 또는 `secrets\u002F` 디렉토리 직접 접근·커밋 없음\n\n### 2. 코드 스타일 (`plugins\u002Frein-core\u002Frules\u002Fcode-style.md` 기준)\n\n- [ ] 네이밍: 함수 동사형 camelCase, 상수 UPPER_SNAKE_CASE, Boolean `is\u002Fhas\u002Fcan\u002Fshould` 접두사\n- [ ] 함수 길이 50줄 이내 (초과 시 분리 권고)\n- [ ] 파라미터 3개 이하 (초과 시 객체 묶음 권고)\n- [ ] 중첩 depth 3단계 이하 (early return 또는 함수 분리)\n- [ ] `any` 타입(TypeScript) \u002F `console.log`·`print` 운영 코드 방치 없음\n- [ ] 주석: diff 에서 **추가되거나 수정된(added\u002Fmodified) 주석 줄만** 검사 — 회차 서수·수리 이력 서사·실행 결과 측정 수치가 새로 들어왔으면 삭제 또는 trail 이동을 요구하고, 해당 diff 목적과 무관한 기존 주석 전체의 일괄 청소는 요구하지 않는다\n\n### 3. 테스트 (`plugins\u002Frein-core\u002Frules\u002Ftesting.md` 기준)\n\n- [ ] 변경 범위에 해당하는 테스트가 추가 또는 수정됨\n- [ ] 경계 조건(null\u002Fundefined, 빈 값, 최대\u002F최소값) 커버\n- [ ] 외부 API 직접 호출 단위 테스트 없음 (Mock 사용 확인)\n- [ ] 모킹 과다 여부 — 실제 동작보다 mock 구조 검증에 편중되지 않음\n\n### 4. Rein 고유\n\n- [ ] `trail\u002Fdod\u002Fdod-YYYY-MM-DD-\u003Cslug>.md` 파일이 이 작업 전 생성되어 있음\n- [ ] DoD 또는 plan work unit 에 `covers: [...]` 메타데이터가 존재하고 매트릭스 ID 와 일치\n- [ ] 작업 완료 후 `trail\u002Finbox\u002FYYYY-MM-DD-작업명.md` 기록 대상임을 확인\n\n## 출력 형식\n\n리뷰 결과를 아래 마크다운 템플릿으로 출력한다:\n\n~~~markdown\n## 코드 리뷰 결과 (rein-native, round N)\n\n**리뷰 대상**: [파일 목록]\n**라운드**: N\n\n### High (즉시 수정 필요)\n\n- [파일:줄번호] 이슈 설명 — 권고 조치\n\n### Medium (수정 권고)\n\n- [파일:줄번호] 이슈 설명 — 권고 조치\n\n### Low (선택 개선)\n\n- [파일:줄번호] 이슈 설명\n\n### 통과 항목\n\n- 보안: 하드코딩 credential 없음\n- 스타일: 네이밍 규칙 준수\n- 테스트: 변경 범위 커버됨\n- Rein 고유: DoD 파일 존재 확인\n\n**결론** (아래 중 하나):\n- 통과 — 이슈 없음, 본 스킬이 v2 발급으로 기록\n- 재리뷰 (self-review) — Low 만 또는 Medium ≤3줄, 수정 후 sonnet self-review 로 v2 발급 기록\n- 재리뷰 (same reviewer) — Medium >3줄 또는 High 1건 이상, 수정 후 본 스킬 재실행\n- 에스컬레이션 — 3라운드 후에도 High 잔존, 사람에게 직접 보고 (기록 없음)\n~~~\n\n## 리뷰 에스컬레이션 흐름\n\nAGENTS.md §5-1 \u002F `.claude\u002Fskills\u002Fcodex-review\u002FSKILL.md` 의 표와 일치한다.\n\n| 라운드 결과 | 규모 | 다음 행동 |\n|-----------|------|----------|\n| 이슈 없음 | — | **통과** (본 스킬이 v2 발급으로 기록) |\n| Low 만 | — | 수정 후 **sonnet self-review, v2 발급으로 기록** |\n| Medium 만 | ≤3줄 | 수정 후 **sonnet self-review, v2 발급으로 기록** |\n| Medium 만 | >3줄 | 수정 후 본 스킬 재실행 (round N+1) |\n| High 1건 이상 | — | 수정 후 본 스킬 재실행 (round N+1) |\n| 3라운드 이후 High 잔존 | — | **에스컬레이션** (기록 없음 — 사람에게 직접 보고) |\n\n## 리뷰 결과 기록 (v2 발급 — 유일한 기록 경로)\n\n**Phase 7 웨이브 3 ③-d 갱신.** 이전에는 이 스킬이 legacy stamp (`trail\u002Fdod\u002F.codex-reviewed` 파일 생성 + `trail\u002Fdod\u002F.review-pending` 삭제) 를 먼저 기록하고, 그 위에 v2 발급을 \"병행 기록\"으로 시도했다. ③-d 로 legacy 리뷰 표식 3종(`.review-pending`\u002F`.codex-reviewed`\u002F`.security-reviewed`)의 write·read 경로가 전부 제거되면서, 이제 **v2 발급 호출 자체가 유일한 기록 절차**다 — 별도의 stamp 파일을 먼저 쓰는 단계는 없다. `\u003CREASON>` 은 \"실행 조건\" 섹션의 slug (codex_timeout \u002F codex_error \u002F no_superpowers_plugin) 중 하나이며, 아래 사용자 안내 문구에서 참조용으로만 쓰인다 (기록되는 필드가 아니다 — v2 발급이 받는 인자는 verdict 와 reviewed-digest 뿐이다).\n\n### Spec-review fallback 분기 (CRITICAL, v1.0.0+)\n\n이 스킬이 **`[NON_INTERACTIVE] spec review for plan:` 또는 `design:` prefix 가 붙은 prompt** 로 호출된 경우 (plan-writer 의 codex 실패 fallback 경로), 아래 \"PASS 시 v2 발급\" 절차를 **실행하지 않는다** — code-review 기록 절차 자체가 이 경로에 존재하지 않는다.\n\n근거: code-review v2 발급은 코드리뷰 게이트 증거다. spec review fallback 에서 이 증거를 발급하면 코드 변경 없이도 gate 통과 가능 → rein 규율 오염.\n\nSpec-review fallback 동작:\n1. 리뷰 수행 (AGENTS.md rules + 체크리스트) — 내용 자체는 동일\n   - `for plan:` prefix 이면 계획 문서 전용 **Verification Cost** 관점을 함께 판정한다(래퍼 봉투 슬롯 4 와 같은 계약): 같은 코드 상태(두 검증 Step 사이에 코드·테스트·설정·의존성을 바꾸는 Step 이 없는 상태)에서 전체 검사(전체 테스트 스위트, 전체 포맷·린트·타입검사, 전체 빌드)를 2회 이상 지시하거나 수정 Step 뒤 처음부터 전체 재검증을 지시하는 곳은 rein 플러그인 testing 규칙 \"검증 실행 범위\" 에 근거한 저장소 계약 위반(NEEDS-FIX)이며, 고칠 Step 위치를 함께 적는다. 예외: 그 Step 이 codex-review 스킬 \"전체 테스트 재실행으로 돌아가는 조건\" 중 어느 것에 해당하는지 계획서에 적혀 있으면 — 복귀 조건을 명시한 재실행은 위반이 아니다. 범위·소요 표기 누락은 참고사항이다. 단 소요 수치가 적혀 있으면 이전 실행 기록을 인용하지 않은 모든 소요 수치(단일값·범위·추정)는 NEEDS-FIX 다 — 파일 수·유사 작업 같은 저장소 근거를 붙인 범위 추정도 허용 근거가 아니며, 허용 근거는 이전 실행 기록 인용 하나다(수치 불일치로 NEEDS-FIX). `for design:` prefix 와 코드 리뷰 경로에는 적용하지 않는다.\n2. verdict 만 caller (plan-writer) 에게 반환 — PASS \u002F NEEDS-FIX \u002F REJECT\n3. **code-review v2 발급 없음**. legacy marker 도 이제 존재하지 않으므로 건드릴 대상 자체가 없음\n4. caller 가 PASS 시 `bash \"${CLAUDE_PLUGIN_ROOT:-$PWD\u002Fplugins\u002Frein-core}\u002Fscripts\u002Frein-mark-spec-reviewed.sh\" \u003Cpath> code-reviewer-rein-sonnet-fallback` 호출 — spec-review 축은 이번 웨이브의 존속 예외이므로 그대로 `trail\u002Fdod\u002F.spec-reviews\u002F\u003Chash>.reviewed` 를 생성한다\n\n**Code-review 경로 (일반 fallback, `[NON_INTERACTIVE] spec review` prefix 없음)**: 아래 \"PASS 시 v2 발급\" 절차를 그대로 따른다.\n\n### PASS 시 v2 발급 (최초 통과 \u002F self-review 통과 공통)\n\n체크리스트 리뷰 결과가 PASS (이슈 없음, 또는 Low-only \u002F Medium ≤3줄 수정 후 self-review 통과) 인 회차에서만 앞서 캡처해 둔 `$REIN_REVIEWED_DIGEST` 로 발급을 시도한다. round 이 늘어나는지(최초 통과 vs self-review) 는 위 \"리뷰 에스컬레이션 흐름\" 표의 판단에만 쓰이고, 발급 호출 자체는 두 경로가 동일하다. 아래 \"에스컬레이션\" 경로(3라운드 후에도 High 잔존)는 PASS 가 아니므로 발급을 시도하지 않는다.\n\n~~~bash\nif [ -n \"${REIN_REVIEWED_DIGEST:-}\" ]; then\n  if ISSUE_OUT=$(\"${CLAUDE_PLUGIN_ROOT:-$PWD\u002Fplugins\u002Frein-core}\u002Fbin\u002Frein\" issue-evidence code_review \\\n      --verdict PASS --reviewed-digest \"$REIN_REVIEWED_DIGEST\" 2>\u002Fdev\u002Fnull); then\n    ISSUE_RC=0\n  else\n    ISSUE_RC=$?\n  fi\n  case \"$ISSUE_RC\" in\n    0) echo \"[rein] v2 evidence recorded (code_review, PASS) — this is this cycle's review record.\" ;;\n    2)\n       # High finding (Phase 7 wave 3 ③-a code review round 4, High-2) 계승,\n       # ③-d 로 \"legacy stamp 로 fallback\" 문구만 제거 — 판정 로직 자체는\n       # 그대로다. 응답의 reason 을 긍정적으로 파싱해 \"digest-mismatch\"\n       # 인지 확인한다; 파싱 실패도 digest-mismatch 와 동일하게 fail-\n       # closed 취급한다 (오직 non-mismatch 로 명확히 파싱된 사유만\n       # \"기록 안 됨, 그러나 원인은 트리 변경이 아님\"으로 구분한다).\n       ISSUE_REASON_OK=1\n       ISSUE_REASON=$(printf '%s' \"$ISSUE_OUT\" | python3 -c '\nimport json, sys\ntry:\n    data = json.load(sys.stdin)\n    reason = data.get(\"reason\")\n    if not isinstance(reason, str) or not reason:\n        raise ValueError(\"reason missing or not a non-empty string\")\nexcept Exception:\n    sys.exit(1)\nsys.stdout.write(reason)\n' 2>\u002Fdev\u002Fnull) && ISSUE_REASON_OK=0\n       if [ \"$ISSUE_REASON_OK\" -ne 0 ] || [ \"$ISSUE_REASON\" = \"digest-mismatch\" ]; then\n         # 리뷰 대상 트리가 회차 도중 바뀌었다(또는 그 가능성을 배제할 수\n         # 없다) — 이번 회차는 기록되지 않는다. legacy stamp 가 없으므로\n         # \"표식은 남아있다\" 같은 안전망도 없다: 다음 행동은 명시적으로\n         # digest 재캡처 + 재리뷰뿐이다.\n         if [ \"$ISSUE_REASON_OK\" -ne 0 ]; then\n           echo \"[rein] v2 evidence issuance refused (exit 2) and the response could not be positively parsed to a reason OTHER than digest-mismatch — treating as digest-mismatch (fail-closed). This cycle is NOT recorded. Re-capture the subject digest and re-review before this can count as reviewed.\"\n         else\n           echo \"[rein] v2 evidence issuance refused — reason: digest-mismatch. The reviewed tree changed during this review. This cycle is NOT recorded. Re-capture the subject digest and re-review before this can count as reviewed.\"\n         fi\n       elif [ \"$ISSUE_REASON\" = \"subject-empty\" ]; then\n         # subject-empty 는 실패가 아니다(코드리뷰 Medium 시정, 2026-08-24)\n         # — 리뷰 대상에 non-exempt 코드가 없다는 뜻이라 governance 는\n         # 이 상태를 authority 계층에서 직접 충족으로 판정한다(spec §3.6\n         # 종국 상태표). 기록이 없다고 재리뷰가 필요한 게 아니다.\n         echo \"[rein] no v2 evidence was issued because there is nothing non-exempt to review (digest=empty:no-subject) — this is expected, not a failure; governance treats this changeset as satisfied without an evidence record.\"\n       else\n         echo \"[rein] v2 evidence issuance refused — reason: $ISSUE_REASON. This cycle is NOT recorded (no legacy stamp fallback exists) — the next review cycle must re-capture and retry v2 issuance before governance treats this as reviewed.\"\n       fi\n       ;;\n    *) echo \"[rein] v2 evidence issuance did not complete (exit $ISSUE_RC). This cycle is NOT recorded (no legacy stamp fallback exists) — retry issuance once the infrastructure failure is resolved.\" ;;\n  esac\nelse\n  echo \"[rein] no reviewed-digest was captured at review start (see 'v2 evidence subject 스냅샷 캡처' 절) — v2 issuance was not attempted. This cycle is NOT recorded.\"\nfi\n~~~\n\n`ISSUE_RC` 가 0 이 아닌 경로 중 `subject-empty`(검토할 non-exempt 코드 자체가 없어 governance 가 기록 없이 직접 충족으로 판정하는 정상 상태, 바로 위 PASS 케이스의 `elif` 분기 참조) 를 **제외한** 나머지(digest-mismatch\u002F기타\u002Fdigest 미캡처) 는 \"이번 회차 기록 없음\"으로 동일하게 취급한다 — 더 이상 legacy stamp 로 되돌아갈 안전망이 없으므로, 이 스킬을 호출한 caller(부모 세션)에게 그 사실을 위 echo 문구 그대로 반드시 전달해야 한다 (아래 \"사용자 안내\" 절에도 이 상태를 반영한다).\n\n## 에스컬레이션 (3라운드 이후에도 High 잔존 시)\n\n3라운드 리뷰 후에도 High 가 남아 있으면 작업을 중단하고 사람에게 에스컬레이션한다. 이 경로는 PASS 가 아니므로 v2 발급을 시도하지 않는다 — 남길 기록이 없다(legacy stamp 의 `resolution: escalated_to_human` 같은 별도 마커도 이제 존재하지 않는다). 에스컬레이션 사실과 잔존 이슈는 아래 \"사용자 안내\" 절의 형식으로 사람에게 직접 보고한다.\n\n에스컬레이션 후 작업자는 잔존 이슈를 검토하여 직접 수정하거나 추가 지시를 내린다.\n\n## 사용자 안내\n\n이 SKILL 의 결과를 사용자에게 보고할 때 다음 짧은 형식을 **먼저** 출력한다 (위 `## 코드 리뷰 결과` 템플릿은 그 다음에 그대로 이어 붙인다). 형식은 한 문장 또는 두 문장 — 결과 1줄 + 다음 액션 1줄. 내부 식별자(`.codex-reviewed` 같은 legacy marker 명, `digest`, `evidence` 등)는 평문으로 번역한다 — `plugins\u002Frein-core\u002Frules\u002Fresponse-tone.md` 참조.\n\n**리뷰 PASS + 기록 성공** (`ISSUE_RC=0`):\n> 코드 리뷰 통과. 차단급 결함 없습니다. 통과 증거가 기록됐어요. 다음은 [code-review path 면 보안 리뷰 \u002F spec-review fallback path 면 `bash \"${CLAUDE_PLUGIN_ROOT:-$PWD\u002Fplugins\u002Frein-core}\u002Fscripts\u002Frein-mark-spec-reviewed.sh\"` 로 per-spec stamp 등록].\n\n**리뷰 PASS 이지만 기록 실패** (digest 미캡처 \u002F `ISSUE_RC` 가 0 이 아니고 사유가 검토 대상 없음도 아님) — Phase 7 웨이브 3 ③-d 갱신, legacy stamp 안전망이 없어진 만큼 반드시 별도로 알린다:\n> 코드 리뷰 자체는 통과했지만 이번 회차는 기록되지 않았어요 — [사유: 대상 상태를 확인하지 못함 \u002F 검토 도중 대상이 바뀜 \u002F 기록 시도 실패]. 재리뷰(digest 재캡처부터)가 필요합니다.\n\n**리뷰 PASS + 검토할 대상이 없었음** (`ISSUE_RC=2`, 사유 = 검토할 non-exempt 코드 없음) — 기록이 없는 게 정상이므로 재리뷰를 요구하지 않는다:\n> 코드 리뷰는 통과했고, 이번 회차는 검토할 대상 자체가 없어서(변경이 전부 리뷰 면제) 별도 기록이 필요 없었어요. 재리뷰 없이 다음 단계로 진행하면 됩니다.\n\n**리뷰 NEEDS-FIX (수정 필요)**:\n> 리뷰에서 N건 수정이 필요해요 — [Severity 요약, 예: \"Medium 2건 + Low 1건\"]. [핵심 1-2건과 다음 액션, 예: \"printf 형식 mismatch + symlink 테스트 stderr 미검증. 고치고 재리뷰\"].\n\n**3회차에도 High 잔존 (사람 에스컬레이션)**:\n> 리뷰 3회차에도 High N건이 남아 있어 사람 에스컬레이션이 필요합니다. 잔존 이슈를 확인하고 직접 수정하거나 추가 지시를 내려주세요.\n",{"name":5,"triggers":39,"description":7},[40,41,42],"\u002Fcodex-review 호출 타임아웃","\u002Fcodex-review 호출 에러(exit non-zero)","superpowers:code-reviewer 미설치 + codex 자체 불가 환경","main","8e6e9ee16c5c7343c6f0db55f6c8b37d5ef6f1d0","plugins\u002Frein-core\u002Fskills\u002Fcode-reviewer",0,"https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein","https:\u002F\u002Fgithub.com\u002FJayJihyunKim","2026-10-15 08:31:34",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add JayJihyunKim\u002Frein --skill code-reviewer",{"tool":56,"command":57},"bunx","bunx skills add JayJihyunKim\u002Frein --skill code-reviewer",{"tool":59,"command":60},"pnpm","pnpm dlx skills add JayJihyunKim\u002Frein --skill code-reviewer","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein\u002Fblob\u002Fmain\u002Fplugins\u002Frein-core\u002Fskills\u002Fcode-reviewer\u002FSKILL.md",true,[],[65,78,89,100,111,118],{"skillNo":66,"name":67,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":68,"categories":69,"keywords":75,"publishedAt":34},"01M70FX2WFS12FG002RNTCSXC7","sample-skill","https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein\u002Fblob\u002Fmain\u002Ftests\u002Fscripts\u002Ffixtures\u002Frein-template-min\u002F.claude\u002Fskills\u002Fsample-skill\u002FSKILL.md",[70],{"categoryNo":71,"categoryName":72,"taxonomyType":73,"taxonomyTypeDesc":74},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[76,77],"sample","sample skill",{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":34},"01M70FX0BT6WSNZKFF60KTZ5H9","repo-audit","저장소 전체 상태 점검. 오래된 규칙, 누락 테스트, 비활성 에이전트, trail 일관성 확인.","https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein\u002Fblob\u002Fmain\u002Fplugins\u002Frein-core\u002Fskills\u002Frepo-audit\u002FSKILL.md",[],[85,86,87,88],"repo","repo audit","audit","trail",{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":96,"publishedAt":34},"01M70FWXCWRZEJSDQGTNDEKF2G","promote-agent","에이전트 후보를 정식 에이전트로 승격. 사람 승인 이후에만 실행.","https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein\u002Fblob\u002Fmain\u002Fplugins\u002Frein-core\u002Fskills\u002Fpromote-agent\u002FSKILL.md",[95],{"categoryNo":71,"categoryName":72,"taxonomyType":73,"taxonomyTypeDesc":74},[97,98,99],"promote agent","promote","incidents",{"skillNo":101,"name":102,"nameZh":6,"description":103,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":106,"publishedAt":34},"01M70FWTP0QPQN09VJR8DNKWZS","pr-review-fixer","PR 리뷰 코멘트를 읽고 수정 사항을 자동으로 적용한다","https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein\u002Fblob\u002Fmain\u002Fplugins\u002Frein-core\u002Fskills\u002Fpr-review-fixer\u002FSKILL.md",[],[107,27,108,109,110],"pr","pr review","pr review fixer","fixer",{"skillNo":112,"name":113,"nameZh":6,"description":114,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":117,"publishedAt":34},"01M70FWR0TC5NDF12D9E5ETBAW","persona","페르소나 프리셋 선택·해제 + 질문-답변 커스텀 프리셋 생성. \"페르소나 골라줘\u002F만들어줘\u002F바꿔줘\u002F꺼줘\" 류 요청에서 호출.","https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein\u002Fblob\u002Fmain\u002Fplugins\u002Frein-core\u002Fskills\u002Fpersona\u002FSKILL.md",[],[113],{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":34},"01M70FWKFPNVC4M5ECZE1F0WS6","parallel-execute","활성 plan 의 `## 실행 전략`(depends_on\u002Fmode\u002Fscope v2) 을 읽어 의존 위상정렬로 웨이브를 유도하고, 각 웨이브의 독립 edit_only 태스크를 같은 작업 트리에서 서브에이전트로 병렬 실행, mutating·의존 태스크는 순차 실행한다. 부모(메인 세션)가 웨이브 단위로 검증·테스트·커밋. 호스트가 병렬 dispatch 불가 시 순차 fallback 으로 degrade.","https:\u002F\u002Fgithub.com\u002FJayJihyunKim\u002Frein\u002Fblob\u002Fmain\u002Fplugins\u002Frein-core\u002Fskills\u002Fparallel-execute\u002FSKILL.md",[],[125,126,127,128,32,129,130,131,132,133],"parallel","execute","parallel execute","edit","mode","dispatch","scope","plan","only"]