# ✅ Peer Review Report: M2 PTY _exit Syscall Symbol Correction (Commit f0e2bd2)

**Job**: `cc09bae5` · **Reviewer**: Reviewer B (Cline, `canary-projects-multi-agent-mux-reviewer-cline`)
**Review Target**: Commit `f0e2bd2` — "fix(ui): correct libc symbol lookup for direct _exit syscall to achieve async-signal-safety"
**Prior Reviews**:
- Job `66ec158f` (b7901bc) → 3 BLOCKING 결함 지적
- Job `fcf4c9d0` (f52f6eb) → DEFECT 1/2 해결, DEFECT 3 미해결
- Job `7448cb2f` (7781e79) → async-signal-safety/waitpid 해결, DEFECT 3 미해결 (3회차)
- Job `ef0b32ff` (7f1a7e5) → **DEFECT 3 해결 (4회차) + 모든 결함 PASS** — 본 커밋은 ef0b32ff 리뷰의 NON-BLOCKING 관찰 #1 정밀 수정
**Plan Reference**: `.agents/reports/canary-projects-multi-agent-mux-planner-reviewer-claude/report-final.md` (Rev.3, §6.7 PTY 메커니즘 / §10 DoD)
**Review Scope**: 브리프가 명시한 `cExit` lookup 심볼 오타 수정 (`'exit'` → `'_exit'`) 검증 + 회귀 확인
**Method**: 라인 단위 diff 분석 + `dart analyze`/`flutter analyze`/`dart test` + **`_exit` 심볼 glibc resolve实证** + TMUX env 격리 회귀实证

---

## 1. 커밋 개요

커밋 `f0e2bd2`는 이전 리뷰(ef0b32ff)의 NON-BLOCKING 관찰 #1을 정밀 수정. 1개 파일, +1/-1행 (단일 라인 변경).

**변경 내용** (`pty_session.dart:111`):
```diff
-    final cExit = libc.lookupFunction<_exit_c, _exit_dart>('exit');
+    final cExit = libc.lookupFunction<_exit_c, _exit_dart>('_exit');
```

---

## 2. 수정 항목 교차 검증

### 2.1 이전 리뷰 관찰 (ef0b32ff, NON-BLOCKING #1)

> **`cExit` lookup 이름 (정확성)**: 라인 111 `lookup('exit')`는 C `exit()`를 바인딩 (async-signal-unsafe, atexit handlers 실행). 브리프가 "libc exit syscall"이라고 서술했으나, 진정한 async-signal-safe는 `lookup('_exit')` 또는 `lookup('_Exit')`. 단, 자식이 fork 직후이므로 Dart 런타임 atexit handlers가 미등록 상태이며, 기능적으로 자식 종료를 달성하므로 실질적 영향 없음. 향후 정확성을 위해 `_exit` 권장.

### 2.2 수정 검증

**diff 분석**: 라인 111에서 `lookup('exit')` → `lookup('_exit')`로 정확히 1행 수정. 다른 라인 무변경 ✅.

**C `exit()` vs `_exit()` 구분**:
- `exit(int status)` (stdlib.h): async-signal-**unsafe** — `atexit()` 등록 핸들러 실행, `stdio` 버퍼 flush, `_exit()` 최종 호출
- `_exit(int status)` (unistd.h): async-signal-**safe** — 커널 syscall 직접 호출, 버퍼 flush/handlers 미실행

POSIX async-signal-safety 규칙에 따르면, fork 후 exec 실패 시 자식에서 호출할 수 있는 함수는 async-signal-safe 목록에 있는 함수만. `_exit()`는 이 목록에 포함되나, `exit()`는 포함되지 않음. 본 수정으로 자식 분기의 예외 퇴장 경로(`cExit(-1)` at 라인 192, `cExit(-2)` at 라인 211)가 진정한 async-signal-safe `_exit` syscall을 사용하게 됨.

**FFI 시그니처 일관성**: typedef `_exit_c = ffi.Void Function(ffi.Int32 status)` / `_exit_dart = void Function(int status)`는 C `_exit(int)` 시그니처와 정확히 일치 ✅. 변경 전에도 시그니처는 `_exit` 기준이었으나 lookup 이름만 `exit`였던 불일치가 해결됨.

---

## 3. `_exit` 심볼 glibc resolve实证

**검증 방법**: `nm -D /lib/x86_64-linux-gnu/libc.so.6`로 glibc에서 `_exit` 심볼 존재 확인 + Dart FFI `lookupFunction<_exit_c, _exit_dart>('_exit')` 실행实证.

**결과 1 — glibc 심볼 확인**:
```
$ nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep -w '_exit'
00000000000f7480 T _exit@@GLIBC_2.2.5
```
`T` (Text segment, exported symbol) — `_exit`가 glibc에 존재하며 export됨 ✅.

**결과 2 — Dart FFI lookup实证**:
```
SUCCESS: _exit symbol resolved from libc.so.6 - async-signal-safe exit syscall available
(lookupFunction throws if symbol not found, so reaching here means _exit is bound)
```
`lookupFunction<_exit_c, _exit_dart>('_exit')`가 예외 없이 성공 — 런타임에 `_exit` 심볼이 올바르게 바인딩됨을实证 ✅. `lookupFunction`은 심볼을 찾지 못하면 `ArgumentError`를 throw하므로, 정상 실행 자체가 resolve 성공의 증거.

**평가**: ✅ `lookup('_exit')`가 glibc의 `_exit@@GLIBC_2.2.5` 심볼을 올바르게 바인딩. 런타임에 자식 분기의 `cExit(-1)`/`cExit(-2)` 호출이 진정한 async-signal-safe `_exit` syscall을 기동함.

---

## 4. 정적 분석 및 회귀 검증

| 항목 | 검증 방법 | 결과 |
|------|----------|------|
| `dart analyze` (mam_pty) | 실행 | ✅ No issues found! |
| `flutter analyze` (mam_desktop) | 실행 | ✅ No issues found! |
| M1 회귀 (`dart test` mam_core) | 실행 | ✅ 3/3 All tests passed |
| 런타임 PTY 동작 (`dart test` echo) | 실행 | ✅ echo `hello-pty-ok` 출력 정상 |
| DEFECT 3 TMUX env 격리 (회귀) | 런타임实证 (TMUX 설정 + printenv) | ✅ PASS — 자식 printenv 빈 출력 (회귀 없음) |
| `_exit` 심볼 glibc resolve | `nm -D` + Dart FFI lookup实证 | ✅ `_exit@@GLIBC_2.2.5` 바인딩 성공 |
| 기존 스크립트 회귀 | git diff --stat | ✅ status.sh 외 기존 스크립트 무변경 |

**전체 테스트 실행 결과** (부모에 `TMUX=fake-server,12345,0 TMUX_PANE=%5` 설정):
```
00:00 +0: test/pty_runtime_test.dart: PtySession runtime execution resolves process output
PTY Runtime stdout verified: hello-pty-ok
00:00 +1: test/pty_runtime_test.dart: PtySession strips TMUX/TMUX_PANE from child environment
printenv TMUX TMUX_PANE output: []
00:00 +2: All tests passed!
```

이전 리뷰(ef0b32ff)에서 PASS 판정된 모든 기능이 회귀 없이 유지됨:
- DEFECT 1 (/proc/self/fd 경로): ✅ 유지
- DEFECT 2 (자식 stdio PTY 연결): ✅ 유지
- DEFECT 3 (TMUX env 격리, unsetenv): ✅ 유지 (회귀 없음)
- async-signal-safety: ✅ 유지 + `_exit` 정확성 향상
- waitpid zombie reaping (blocking): ✅ 유지
- non-blocking master fd (fcntl): ✅ 유지

---

## 5. AGENTS.md 원칙 검증

- **Surgical Changes (§3)**: 단일 라인 수정 (`'exit'` → `'_exit'`) — 이전 리뷰 관찰에 정확히 대응하는 최소 변경 ✅. 다른 코드/포맷/주석 무변경. "Every changed line should trace directly to the user's request" — 본 수정은 1행이며 리뷰 관찰 #1에 직접 추적됨.
- **Simplicity First (§2)**: 단일 라인 정밀 수정 — 더 단순할 수 없는 최소 변경 ✅.
- **Goal-Driven Execution (§4)**: 본 수정의 성공 기준은 "async-signal-safe `_exit` syscall 바인딩" → `nm -D` + Dart FFI lookup实证으로 검증 완료 ✅.
- **Think Before Coding (§1)**: 이전 리뷰(ef0b32ff)에서 `exit()` vs `_exit()`의 async-signal-safety 차이를 명확히 지적했으며, 주 개발자가 이를 정확히 이해하고 수정 — §1 원칙 이행.

---

## 6. 종합 평가

커밋 `f0e2bd2`는 이전 리뷰(ef0b32ff)의 NON-BLOCKING 관찰 #1을 **정확히 단일 라인으로 해결**:

### 수정 항목 — 해결
1. ✅ **`cExit` lookup 심볼 정확성**: `lookup('exit')` → `lookup('_exit')`로 수정. C `exit()` (async-signal-unsafe, atexit handlers 실행) 대신 C `_exit()` (async-signal-safe, 커널 syscall 직접 호출)를 바인딩. 자식 분기의 예외 퇴장 경로(`cExit(-1)` slave open 실패, `cExit(-2)` execvp 실패)가 진정한 async-signal-safe `_exit` syscall을 사용.

### 검증 결과
- `dart analyze`: No issues found ✅
- `flutter analyze`: No issues found ✅
- M1 회귀: 3/3 All tests passed ✅
- 런타임 PTY echo: 정상 동작 ✅
- 런타임 TMUX env 격리: ✅ PASS (회귀 없음)
- **`_exit` 심볼 glibc resolve实证**: ✅ `_exit@@GLIBC_2.2.5` 바인딩 성공 (nm -D + Dart FFI lookup)
- 기존 스크립트 회귀: 없음 ✅

### 전체 리뷰 이력 (5회차 누적)

| 회차 | 커밋 | 판정 | 핵심 |
|------|------|------|------|
| 1 (66ec158f) | b7901bc | NOT PASS | 3 BLOCKING 결함 지적 |
| 2 (fcf4c9d0) | f52f6eb | NOT PASS | DEFECT 1/2 해결, DEFECT 3 미해결 |
| 3 (7448cb2f) | 7781e79 | NOT PASS | async-signal-safety/waitpid 해결, DEFECT 3 미해결 |
| 4 (ef0b32ff) | 7f1a7e5 | **PASS** | DEFECT 3 해결 (unsetenv), 모든 결함 해결 |
| 5 (본 리뷰) | f0e2bd2 | **PASS** | NON-BLOCKING 관찰 #1 정밀 수정 (_exit 심볼) |

ef0b32ff에서 PASS 판정된 모든 기능이 회귀 없이 유지되며, 추가로 `_exit` syscall 바인딩 정확성이 향상됨. M2 마일스톤(Desktop PTY 연동 + attach terminal tab)의 모든 핵심 계약(§6.7 PTY 메커니즘, §10 DoD)이 런타임实证으로 검증됨. 정적 분석과 런타임实证 테스트가 모두 통과.

[VERDICT: PASS]