# 인프라 결함 대응 설계 (설계 전용) — A축 정밀감시 실행안 / B축 최소수정안

상태명: `INFRA_DEFECT_REMEDIATION_DESIGN_READY_ACTIVE_FALSE`
작성: ANU 직접 (2026-07-02 KST). **설계 전용 — 코드수정/파일수정/PR/dispatch/실행 0.** 근거: 회장 GPT 판정(A축 원인 미확정·정밀감시 먼저·B축 최소수정 설계·코드수정 아직 X). 선행: [[infra_defect_two_axis_260702]].
★ A축 truncate 원인은 **미확정**. merge-executor 체인/import-time은 **1순위 후보로만** 기록(syscall/pid/comm/라인 증거 없음).

## 환경 가용성 실측 (설계 전제)
- auditctl/ausearch: **미설치**. inotifywait/py-inotify: **미설치**. fanotify: 무권한.
- bpftrace: 설치됨(/usr/bin/bpftrace)이나 **root 필요**(tracefs 무권한).
- **passwordless sudo 불가**(암호 요구). auditd **inactive**. chattr: 바이너리 존재(+i는 root 필요 추정).
→ 결론: 최고정밀(auditctl/bpftrace)은 **회장의 sudo 승인 또는 패키지 설치 없이는 불가**. 무권한 실행 가능한 것은 stdlib inotify(ctypes)·`/proc` 스냅샷·python audit hook(파일추가 승인)·chmod 트립와이어(속성변경 승인).

---
# PART A — truncate 정밀 캡처 실행안 (4안, 권한/장점/리스크/명령/중단복구)

목표: **어떤 pid·comm·exe가 어떤 syscall(openat O_TRUNC / ftruncate)로 어떤 path를 truncate 했는지** timestamp와 함께 확정. 다음 finish-task 직전 arm(지금 실행 X).

### A안. auditctl 파일 워치 (최고정밀·현재 BLOCKED)
- 권한: **root 필요 + auditd 설치 필요**(현재 둘 다 없음).
- 장점: pid·comm·exe·syscall·cwd·target path·ts 완전 확보. 가장 확실.
- 리스크: 설치/권한이 회장 개입 필요. 시스템 전역 audit 부하.
- 명령 후보: `sudo apt-get install auditd` → `sudo auditctl -w /home/jay/workspace/utils/replacement_pr_runner.py -p wa -k truncwatch` (test 파일도 동일) → 재현 후 `sudo ausearch -k truncwatch`.
- 중단/복구: `sudo auditctl -W <file> -p wa -k truncwatch`(rule 삭제) 또는 `sudo auditctl -D`(전체 삭제). 설치물 유지/제거는 회장 결정.

### B안. bpftrace syscall 트레이스 (고정밀·root 필요)
- 권한: bpftrace 있음, 단 **root/CAP_BPF 필요**(현재 불가).
- 장점: `tracepoint:syscalls:sys_enter_ftruncate`·`sys_enter_openat`(flags & O_TRUNC) 필터 → pid·comm·ustack(파이썬이면 코드 프레임). 라인 근접.
- 리스크: root 필요. ustack 심볼화 제약.
- 명령 후보: `sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat /str(args->filename)=="...replacement_pr_runner.py"/ { printf("%d %s O_TRUNC=%d\n", pid, comm, args->flags & 512); }'`
- 중단/복구: Ctrl-C(프로세스 종료)만, 시스템 변경 0.

### C안. stdlib inotify 정밀 워치 (무권한·즉시가능·1순위 실효안)
- 권한: **불필요**(사용자 소유 파일). 패키지 불필요(ctypes로 inotify_init1/inotify_add_watch 직접 호출).
- 장점: `IN_MODIFY|IN_CLOSE_WRITE|IN_OPEN|IN_ATTRIB` 이벤트를 **즉시(폴링 지연 0)** 포착. 이벤트 순간 즉시 `ps --forest`(finish-task 트리 상시 존재)+`/proc/*/fd` 스캔으로 파일 연 pid 후보 특정. 30초 폴링의 "핸들 이미 해제" 문제 완화.
- 리스크: inotify는 **pid를 직접 안 줌** → 순간 truncate면 `/proc/fd` 스캔도 놓칠 수 있음(그러나 부모 finish-task 트리는 잡힘 → 서브프로세스 후보 범위 축소). ustack/라인 불가.
- 명령 후보: ANU 작성 stdlib 워치(전 watch와 동일 형식, 폴링→inotify blocking read 교체) + 이벤트 콜백에서 `ps -eLf --forest`, `ls -l /proc/*/fd 2>/dev/null | grep replacement_pr_runner` 캡처.
- 중단/복구: 프로세스 종료만. 파일/시스템 변경 0. **바로 arm 가능(승인 시)**.

### D안. python audit hook (무권한·파일추가 승인 필요·라인 특정 최강)
- 권한: 무권한. 단 **감시용 sitecustomize.py를 PYTHONPATH에 추가**해야 함(파일 추가 = 승인 대상).
- 장점: `sys.addaudithook`로 `open`(O_TRUNC) 이벤트를 잡아 **파이썬 truncate 호출의 정확한 traceback(파일:라인)** 기록. 범인이 파이썬 서브프로세스면 코드 라인 직격.
- 리스크: 범인이 파이썬이 아니면(쉘 `>`/git) 안 잡힘. sitecustomize 추가는 감시창 한정·종료 후 제거 필요(코드베이스 오염 방지).
- 중단/복구: 감시창 후 sitecustomize.py 제거 + PYTHONPATH 원복.

### E안. chmod/chattr 트립와이어 (강력·파일속성 변경·승인 전용, 실행 아직 X)
- 권한: chmod 0444는 무권한(소유자)·chattr +i는 root. 
- 장점: truncate 시도가 **EACCES로 실패** → finish-task 로그에 정확한 명령/라인/traceback 노출.
- 리스크: **파일 정상 쓰기를 막아 finish-task 흐름 교란 가능**. 파일속성 변경이라 GPT 지침상 **별도 승인 필수**. 실행 금지(설계로만 제시).
- 중단/복구: `chmod 644`/`chattr -i` 원복.

### A축 권장 (환경 반영)
- **즉시 실효(승인 시 바로): C안(stdlib inotify)** — 무권한·무변경·다음 finish-task arm.
- **라인 특정 최강: D안(audit hook)** — 파일추가 승인 시 병행.
- **최고정밀: A안/B안** — 회장 sudo/설치 승인 시 최우선.
- **E안(트립와이어)**: 승인 전용, 지금 실행 X.
- 조합 제안: **C+D 동시 arm**(무권한 이벤트 + 파이썬 라인) → 그래도 미상이면 A/B(sudo) 승격.

---
# PART B — callback/finalize 최소 수정안 (설계만, 코드수정 아직 X)

### 원칙 (GPT verbatim)
성공/실패/차단/에스컬레이션 **4종 종단 모두 ANU terminal status가 남는다.** escalation은 정상완료가 아니라 **terminal callback 대상**. dispatched marker 부재 시 fail-open 조용한 종료 **금지** → fail-closed marker 또는 fallback context. escalation 종단도 **최소 result.json 반드시 생성**.

### 수정 파일 후보 (expected_files)
- `scripts/finish-task.sh` — state_file_missing/ESCALATED/BLOCKED 분기(≈878~929)에서 (a)최소 result.json 생성 (b)terminal callback emit 호출 추가.
- `scripts/harness/v36/terminal_state_callback.py` — dispatched marker 부재 시 **fail-closed**(‥failed.json marker 또는 fallback context) — silent exit 0 제거.
- `tests/regression/test_finish_task_terminal_termination_<id>.py` (신규).
- (검토) `scripts/escalation_marker.py` — result.json envelope 동시 발행 여부.

### 종단 상태 enum
- terminal_state: `SUCCESS` / `FAILED` / `BLOCKED` / `ESCALATED` — **각각 필수 산출 3종**: terminal marker · result.json · ANU terminal callback(등록 또는 fail-closed marker).
- callback 분류(검증용): `CALLBACK_DELIVERED` / `CALLBACK_NOT_DELIVERED` / `CALLBACK_REGISTERED_BUT_NOT_PICKED_UP` / `CALLBACK_FALSE_CLAIM`.
- context 폴백: `DISPATCHED_MARKER_MISSING_FALLBACK_SCHEDULE_ID` / `CALLBACK_CONTEXT_UNRESOLVED_FAIL_CLOSED`.

### result.json 보장 방식
- 모든 종단에서 최소 envelope 생성: `{task_id, terminal_state, result_path(self-ref 허용), callback_schedule_created:bool, reason, report_path, ts}`. escalation 분기가 `.done.escalated` 발행 직후 result.json(최소본)도 원자적 write. 부재 시 finalize를 fail-closed 처리.

### terminal callback 보장 방식
- escalation/BLOCKED 분기에서 terminal_state_callback emit **호출 추가**(현재 SUCCESS .done 경로만 커버).
- terminal_state_callback: dispatched marker 있으면 그 schedule_id, 없으면 **dispatch 시점 산출물(예: capabilities/task-*.json, cron_response schedule_id)로 fallback**. 그래도 불가 시 **fail-closed marker(.terminal-callback-failed.json)** 남기고 non-zero 신호(비차단이되 침묵 금지).

### 테스트 케이스 (신규 회귀)
1. state_file_missing escalation → result.json 생성 + terminal callback marker/registration 존재.
2. dispatched marker 부재 → **fail-closed marker 또는 fallback context 기록**(silent exit 0 금지) assert.
3. BLOCKED 종단 → result.json + terminal callback 존재.
4. SUCCESS(.done) → 기존 동작 회귀 0(마커·콜백·result.json 정상).
5. 4종 종단 각각 ANU terminal status 마커 존재 전수 assert.
6. escalation result.json에 `callback_schedule_created` 필드 존재.
7. terminal callback 등록 실패 주입 시 fail-closed marker 존재(침묵 금지).

### B축 근본원인 재확인 (미확정 1건)
state 파일 미생성이 escalation 트리거였으나 2778/2779도 state 부재로 머지됨 → dispatch incomplete(`progress_watcher_registered:false`) 상관 가설은 **미확정**. 최소수정은 "state 유무와 무관하게 4종 종단에 terminal status 보장"으로 잡아 근본원인 확정 전에도 콜백 누락을 막는다.

---
## 진행 순서 (A/B 설계 이후·각 단계 별도 승인)
1. (승인) A축 C안(+D안) arm → 다음 finish-task 재현 시 pid/comm/라인 캡처. 미상 시 A/B(sudo 승격).
2. (승인) B축 최소수정을 **bounded task로 분리**(4종 종단 terminal callback 결선 + result.json 보장). dispatch는 그때 승인.
3. task-2781 PR은 위 2건 처리 후. 브랜치 task/task-2781-dev2 + worktree 보존.

## 금지 (현 단계)
코드수정·파일수정/추가·PR·CI/ruleset 변경·Merge Queue 활성화·추가 dev dispatch·감시 즉시실행·chattr/chmod·sudo 실행 — 전부 미실행. 설계까지만.
