# 2중 리뷰 정본 — M12 축 종료 전이의 사용자 검증 대체

- 대상 커밋 : `805375b` (워킹트리 clean 상태에서 심사)
- 리뷰어    : A = codex (`gpt-6-astra`) · B = fable
- 방식      : 독립 병렬. 서로의 출력 접근 금지. 동일 헌장 주입
- 헌장      : CLAUDE.md §3 불변식 INV1~INV6 원문 주입 + 결함 층위 8단 + 재현 명령 필수
- 사유      : 이 저장소에는 사람 몫 판정을 낼 유지보수자가 없다. `check4` 가 스스로 적었다 —
              *"이 검사가 하지 않는 것 — 신원 검증. 저자가 표·레코드·provenance 를 함께 만들면
              결박은 전부 만족된다"*

## 판정 대조

| 심사 | A (codex) | B (fable) | 수렴 |
|---|---|---|---|
| V1 재판정 25건의 참 | FAIL | PASS (`Q46` 1건 과대) | **갈림** |
| V2 사람 몫 축 2건 | FAIL (계수 승인 불가) | PASS | **결론 수렴 · 계수 갈림** |
| V3 이 전이 자체 | FAIL | FAIL | **수렴** |
| V4 모듈 경계 도메인 타당성 | 판정불가 | 판정불가 | **수렴** |

**축 판정 `미성립` 은 양측이 함께 지지한다.** 갈린 것은 성립 계수(13/23 대 12/23)이고
어느 쪽이어도 Target 100% 미달이라 종결 술어는 불변이다.

## 흡수 — 정정 5건 (전건 반사실 검증)

| # | 지적(제기자) | 반사실 실측 | 처분 |
|---|---|---|---|
| 1 | 지정 인과 *"check3·check4·check5 가 함께 붉어진다"* (A·B) | 원장에 `designation` 1행 실제 append 후 측정 — **check3 GREEN · check4 RED · check5 GREEN · check10 RED**. 3중 2 오류 + `check10` 누락 | closure §지정 붉음 을 실측 표로 교체 |
| 2 | backlog RESOLVED 가 인용한 `sha256:df5e5470…` 부재 (B) | `grep -rn df5e5470 .claude/` → backlog 1건뿐. PRD·closure 실측 모두 `e857d95b…` | backlog sha 정정 |
| 3 | *"앵커 대비 무변동"* 거짓 (A·B) | `afa2c91→805375b` 는 3종 신설·1,207행 추가. 무변동은 `2abe3e8→805375b` 에서만 참 | closure 기준선 명시 |
| 4 | 봉인 증거로 든 게이트 셋이 그것을 못 세움 (B) | `check5` 봉인 12종은 m9~m11 뿐 · `check3` 은 verdict 만 · `check9` 는 m12 접두를 **허용** | 증거를 `git diff` 로 교체 |
| 5 | `check7` 토큰 검사가 인용문에 우연 매치 (B) | 정규식이 Status 문장 안 인용문에 매치해 n=12 통과. 실제로 죽는 자리는 12행 셀 하나 | PRD Status 주장 정정 + 사각지대 공시 |

## 이월 — 봉인이라 못 고침 4건

`verdict.jsonl` 은 `check3` 이 앵커 blob 과 바이트 대조한다. M12 가 앞 창 과대평가 5건을
정정으로만 처리한 것과 같은 경로다.

- `id=50m12-q34-verdict-wrong` — `Q34` 성립 판정이 원천과 모순 (A 실측: `THROWN:ANALYSIS_FAILED`)
- `id=50m12-q46-dual-review-split` — **두 리뷰가 정반대로 갈린 유일한 자리**
- `id=50m12-verdict-prose-defects` — 산문 층 결함 6건
- `id=50m12-m9check5-unattributed` — `m9/check5` 붉음 200건이 지정 집합 밖

## 기각 0건

양측 모두 전제 부정형 지적을 스스로 `out_of_scope_observations` 로 분리했다 —
*"`check7` 을 고쳐 초록으로 만들라"* · *"12행을 되돌리라"* · *"봉인된 verdict 를 직접 고치라"*
전건이 그 칸에 들어갔다. **헌장 §3 불변식 원문 주입이 작동했다는 실측이다** (CLAUDE.md §3 이
예고한 효과 — 무한 반복되던 항목이 한 라운드에서 out-of-scope 로 닫힌다).

## 리뷰 인프라 결함 — 기록

`codex:codex-rescue` 플러그인 경로는 이 환경에서 **작동하지 않았다**. bwrap 샌드박스가
`read-only` 모드에서도 못 뜬다 — `bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted`.
첫 시도는 헌장 파일 `cat` 조차 실패해 판정 0건으로 끝났다. **codex 가 그것을 저장소 결함이
아니라 실행 환경 장애로 스스로 구분해 보고했고**, 그 구분이 없었다면 빈 리뷰를 통과로 오독할
수 있었다. `codex exec --dangerously-bypass-approvals-and-sandbox` 로 우회해 재실행했다.

---

# A (codex) — 원문

## VERDICT

V1: FAIL — Q34·Q46의 성립 근거가 동결 소스와 모순된다. Q21·Q35·Q50·Q54·Q36의 미성립 근거는 확인했다.  
V2: FAIL — 두 축의 **미성립 결론에는 동의**하지만, 잘못된 Q34·Q46 판정을 포함한 13/23은 승인할 수 없다. 회차 1의 48건과 회차 2의 누락 12종은 재유도했다.  
V3: FAIL — 지정 붉음 2건과 provenance 해시 9건은 일치하지만, 원장 추가 시 check3·check4·check5가 함께 실패한다는 근거는 거짓이다.  
V4: 판정불가 — 동결 모듈 45개와 배정 원장의 집합 일치는 확인했다. 각론 배정 39개·총론 배정 6개의 도메인 경계 전체를 승인할 근거는 확보하지 못했다.

## BLOCKING FINDINGS

| # | 층위 | 파일:행 | 지적 | 재현 명령 | 왜 blocker 인가 |
|---|---|---|---|---|---|
| B1 | 1·6 | `.claude/plans/insuniverse-docs-50-domain-m12.verdict.jsonl:9`; `docs/10-server/02-treat.md:186` | **Q34의 실패 처리 설명이 틀렸다.** 판정은 모든 단계가 실패를 흡수하고 뒤 단계를 계속 실행한다고 승인했다. 실제 `createAnalyze` 실패 경로는 실패 상태 기록·실패 알림·예약 환불 후 **454행에서 예외를 던진다**. 458행 사용량 반영과 464행 성공 알림, 472행 완료 상태 갱신은 실행되지 않는다. 동결 코드 조각에 실패를 주입한 메모리 실행에서도 `THROWN:ANALYSIS_FAILED`, `success-tail-ran false`였다. | `git --git-dir=/home/madsc/work/insuniverse-temp/.git/modules/insuniverse-server show 4d798f55:apps/api/src/modules/treat/treat.event-handler.ts \| sed -n '415,476p'` | 사람 몫 재판정이 원천과 다른 답을 성립으로 인정했다. 온보딩 성립 계수와 잔여 목록의 근거가 무너진다. |
| B2 | 1·6 | `.claude/plans/insuniverse-docs-50-domain-m12.verdict.jsonl:17`; `docs/30-admin/05-treat-monitoring.md:187` | **Q46의 “사용자 통지 없음”은 직접 호출만 본 잘못된 추론이다.** `treat.event-handler.ts:100`이 호출하는 `treatService.compare()`는 `treat.service.ts:895`에서 회원 대상 알림을 만든다. 실패 경로에도 867행 회원 알림이 있다. 두 메서드를 모의 의존성과 함께 메모리에서 실행하자 **회원 알림 → 관리자 알림**이 생성됐다. “이 핸들러 안에 호출이 없다”는 사실로 사용자 통지 부재를 결론낼 수 없다. | `git --git-dir=/home/madsc/work/insuniverse-temp/.git/modules/insuniverse-server show 4d798f55:apps/api/src/modules/treat/treat.service.ts \| sed -n '827,907p'` | 갈린 판정을 성립으로 유지한 핵심 반증이 거짓이다. 허용 문서의 미확인을 부정의 확답으로 바꾼 것이므로 Q46 및 이를 포함한 13/23을 승인할 수 없다. |
| B3 | 1·7 | `.claude/milestone-closures/12-axis-close-transition.md:55`; 같은 파일 `:63` | **closure의 지정·봉인 인과가 검사 구현과 다르다.** designation 한 행을 실제 추가했을 때 **check3=0, check4=1, check5=0**이었다. check4만 `ledger_digest` 불일치로 실패했다. check3은 verdict를 비교하고, check5의 봉인 대상은 **M9~M11** 12종이다. M12 원장의 앵커 바이트 동일성을 검사하는 구성이 아니다. 원장은 즉시 복원했고 `git status --porcelain` 출력이 비었음을 확인했다. | `git show 805375b:.claude/plans/insuniverse-docs-50-domain-m12.gates.mjs \| sed -n '479,490p;533,558p;568,610p'` | 원장 대신 closure가 지정을 받는 선택의 명시적 근거가 실측과 모순된다. 선택 자체는 유지할 수 있지만, 기계적 불가능성과 봉인의 증명을 사실대로 정정해야 한다. |

## NON-BLOCKING FINDINGS

| # | 층위 | 파일:행 | 지적 |
|---|---|---|---|
| N1 | 1·6 | `.claude/plans/insuniverse-docs-50-domain-m12.verdict.jsonl:2` | **Q20은 소재와 계산 방법을 혼동한다.** 질문 원문은 모듈과 순서를 묻는다(`onboarding-questions.yaml:250`). 문서 `02-treat.md:246`은 분석 자료 생성의 위치를 `treat.event-handler.ts:424`로 명시한다. 계산 방법 미서술만으로 “소재 모듈이 없다”고 결론내리는 사유는 부정확하다. 다만 B1 때문에 전체 흐름 설명의 성립까지 승인하지는 않는다. |
| N2 | 6 | `.claude/plans/insuniverse-docs-50-domain-m12.verdict.jsonl:13` | **Q41의 푸시 분기 해석은 보류한다.** 채택한 `05-content-board.md:176`·`:236`과 실제 `Alarm.tsx:264`는 헤더 알림 항목의 외부 URL 열기 분기다. 이것이 질문의 푸시 분기를 충분히 답한다는 연결 근거는 확인하지 못했다. |
| N3 | 1·7 | `.claude/plans/insuniverse-docs-50-domain-m12.verdict.jsonl:10` | Q35는 `refuters_backing_blind:2`지만 두 번째 반증 산문은 절 분해가 과도하며 그 렌즈에서는 1차 판정을 무너뜨릴 수 있다고 적는다. **“2/2 합의”의 의미가 산문과 맞지 않는다.** 잔여 한도·영수증 설명 부족에 따른 미성립 결론은 별도로 지지된다. |
| N4 | 1 | `.claude/plans/insuniverse-docs-50-domain-m12.verdict.jsonl:29` | “지적 건수 감소 없음(48→12)”은 산술적으로 틀렸다. 감소는 있지만 연속 0건은 아니다. 미성립 결론에는 영향이 없다. |
| N5 | 7 | `.claude/milestone-closures/12-axis-close-transition.md:61` | **봉인 비교 기준을 구별해야 한다.** `2abe3e8→805375b`에서는 M12 산출물 6종 모두 무변동이다. 반면 `afa2c91→805375b`에는 하네스·원장·notes **3종 신설, 1,207행 추가**가 있다. 최종 전이의 무변동 주장은 참이며, 앵커 대비 무변동으로 설명하면 참이 아니다. |

## out_of_scope_observations

- `check7`·`check11`의 지정 붉음 자체는 결함으로 세지 않았다. 11종 개별 실행에서 두 검사만 rc 1, 나머지 9종은 rc 0이었다. `--selfprobe`는 12종 통과했고 `check-all`은 명시된 대로 check7에서 중단했다.
- PRD 12행을 `in-progress`로 되돌리거나 check7을 수정하라는 요구는 하지 않는다. **산출 인도 + 잔여 이월**이라는 종료 정의도 부정하지 않는다.
- 신규 의존 설치, 서브모듈 초기화·포인터 변경, 봉인된 앞 창 산출물 수정은 수행하지 않았다.

## 내가 확인하지 못한 것

- **23건 전체의 독립 확정 성립률.** 질문 모집단 23건과 기록상 13/10은 재계수했지만, B1·B2 및 Q20·Q41의 해석 문제 때문에 대체 확정 비율을 제시하지 않는다.
- **회차 계수의 비교 가능성.** 48건은 M4의 38건과 M6의 10건에서 유도된다. M10은 동결 라우터 112개 중 화면 97개와 문서 85개를 대조해 누락 12개·문서에만 있는 경로 0개를 재현했다. 두 수는 동일 모집단의 반복 측정이 아니므로 감소를 수렴 증거로 해석하지 않았다.
- **실제 운영 실행·알림 도달.** B1·B2 실행은 동결 코드 조각과 모의 의존성을 사용했다. DB·벤더·기기까지 포함한 통합 실행은 하지 않았다.
- **전이 직전 완주 기록의 당시 실행 사실과 판정자 신원.** 이력과 기록은 대조했지만 당시 실행을 관측한 것은 아니다.
- **V4의 도메인 경계 전수 심사.** 모듈 집합 결박 확인을 의미적 타당성 승인으로 대체하지 않았다.
- Reviewer B의 출력은 찾거나 읽지 않았다. 최종 작업 트리는 깨끗하다.

---

# B (fable) — 원문

## VERDICT

V1: PASS — 정정 5건(`Q20` `Q21` `Q35` `Q50` `Q54`)과 유지 `Q36`·`Q41` 은 원천(문서 자기 선언 행 실재 · `영수증` grep 0건 · 03↔04 상호 위임)이 지지한다. 단 `Q46` 성립 유지는 `Q50`·`Q54` 에 적용한 기준(문서가 스스로 "답하지 않는다" 고 적으면 미성립)으로는 미성립이라 계수 13/23 은 1건 과대 — 축 판정(미성립)은 불변이라 비차단.
V2: PASS — 온보딩 13/23(내 판정 12/23) 어느 쪽도 Target 100% 미달. 회차 1 = 48 은 m9 원장 `import` 행의 `mark_round1∈{사실과다름,빠짐}` 을 src 별로 세면 m4 38 + m6 10 으로 재유도되고(m8 3건은 m9 notes:146 이 이름으로 배제), 회차 2 = 12 는 m10 원장 `round2-source` `covered=false` 12행으로 재유도된다. 12≠0 만으로 "2라운드 연속 0" 미성립 확정. provenance 경로 실재, 원장 `maintainer-verdict` 2행과 판정 산출물 `axis-verdict` 2행이 verdict·evidence·target_gap·residuals 4필드 전건 동일.
V3: FAIL — 실측 붉음 2건(`check7` 직접·`check11` 연쇄, 나머지 9종+selfprobe 초록) · provenance 9행 sha256 전건 일치 · M12 산출물 6종 무변동 · 닫기 전 바이트(2abe3e8) `checkall ok 11/11`·`selfprobe ok 12종` 은 전부 참이다. 그러나 closure 가 지정 귀속의 **근거**로 적은 인과("원장에 행을 더하면 `check3`·`check4`·`check5` 가 함께 붉어진다")가 반사실에서 거짓이고(`check3`·`check5` 초록 유지, 붉어지는 것은 `check4`·`check10`), backlog RESOLVED 행이 인용한 provenance sha(`df5e5470…`)가 실재하지 않는다.
V4: 판정불가 — 동결 서브모듈 객체(`4d798f55`)가 이 워크트리에 없어(`git cat-file` 실패, `git submodule status` 전건 `-`) 모듈 실체 대조가 불가하다. 원장 근거만으로는 45행 = 배정 39 + 총론 6 으로 PRD 문면과 정합하나, 3건은 도메인 적합이 아니라 소거로 놓였다(NON-BLOCKING #9).

## BLOCKING FINDINGS

**#1** (층위 1) `12-axis-close-transition.md:55-57` — 지정 인과가 실측 거짓. 원장은 앵커 `afa2c91` 에 존재하지 않아 앵커 바이트 대조 대상이 아니다. 실제 결박은 `check4` 의 `ledger_digest`(`gates.mjs:260-266`), `check3` 은 verdict.jsonl 만, `check5` 는 m9~m11 봉인 12종만 본다(`gates.mjs:53-66`, `:572-573`). 더해 적히지 않은 `check10` 이 붉어진다(`gates.mjs:799` — m12 창은 `PRIOR` 대상이 아니라 "붉지 않은데 지정된 항목"). 재현: designation 1행 append 후 check3 → `#3 ok` rc0 · check4 → `#4 FAIL: maintainer-verdict 2건` rc1 · check5 → `#5 ok` rc0 · check10 → `#10 FAIL: 붉지 않은데 지정된 항목 1건 — m12/check7` rc1. 복원 후 `git status --porcelain` 빈 출력 및 `cmp` 동일 확인.

**#2** (층위 1) `codex-findings-backlog.md:553` — RESOLVED 가 인용한 `sha256:df5e5470…` 가 저장소 어디에도 없다. PRD `:277` 값과 closure 실측 모두 `e857d95b…`. 이월 해소 행의 유일한 검증 포인터가 대조에 실패한다.

## NON-BLOCKING FINDINGS (요약)

- **#3** (층위 1) `Q46` 은 `05-treat-monitoring.md:184-187` 이 스스로 "답하지 않는다" 고 적어 `Q50`·`Q54` 와 같은 구조 → 대체 판정자로서 **미성립**, 성립 12/23(52.2%)
- **#4** (층위 6) closure `:59-64` 봉인 주장은 참이나 인용한 게이트가 그것을 못 세운다. 증거는 git 이지 그 셋이 아니다
- **#5** (층위 8) `gates.mjs:186` 정규식이 새 `*Status: complete —` 토큰 안의 인용 문면(col 479)에 매치해 n=12 를 낸다 — 토큰 검사는 **우연히 통과**한다. 다음 하네스가 같은 사각지대를 물려받는다
- **#6** (층위 1) `verdict.jsonl` 내부 불일치 6건 (렌즈 계수·좌표 실재·자기모순·집계 불일치)
- **#7** (층위 8) `m9.gates.mjs check5` 가 현재 바이트에서 `#5 FAIL: 200건` rc1 인데 `check10` 지정 대상 4건 밖이라 어느 원장에도 귀속되지 않는다
- **#8** (층위 1) 봉인 열거가 PRD 5종 · closure 6종으로 어긋난다
- **#9** (층위 1) V4 부차 — `allow-ip`·`authority`·`courses`·`disease`/`search` 배정이 도메인 적합이 아니라 소거로 놓였다

## out_of_scope_observations

- `check7` 수정 · 12행 되돌리기 · 봉인 verdict 직접 수정 처방은 내지 않는다 — 확립된 규약
- 서브모듈 초기화는 INV2 인접 환경 작업이라 처방 밖
- 재판정의 독립성·신원 검증은 `check4` 가 이미 `(미검증)` 으로 이름을 냈고 INV6 상 최대치

## 내가 확인하지 못한 것

- 동결 서브모듈 트리 부재로 소스 층 주장 전건은 문서·원장 문면으로만 대조
- 일치 15건은 개별 재판정하지 않음. 갈린 8건 전건과 미달 4건의 질문 원문만 읽음
- `df5e5470` 의 출처(초안 해시인지 오타인지) 미확인
- `m9/check5` 붉음 200건의 원인 미확정
- fable 워크플로 43 에이전트의 실제 실행·블라인드 조건은 산출물 밖이라 검증 불가
- 닫기 전 바이트 완주 확인은 스크래치패드에 임시 `git worktree`(2abe3e8 detached)를 만들어 돌린 뒤 제거했다. 대상 워크트리 파일은 건드리지 않았고 `git status --porcelain` 빈 출력이나 `.git/worktrees/` 메타데이터를 일시 생성했음을 밝힌다
