# task-2712+2 — PR #161 Gemini 4 unresolved same-PR micro-fix (dev4 Vishnu)

- **팀**: dev4-team (비슈누 / Vishnu) — task-2712 원작자
- **레벨**: Lv.2 (micro-fix, expected_files 내부)
- **PR**: #161 (https://github.com/Jeon-Jonghyuk/dev_workspace/pull/161)
- **base head**: `58a15618` (task/task-2712-dev4) — **이 head 기준 clean worktree 에서 작업**
- **chair_authorization**: 회장 verbatim 2026-05-30 — same-PR micro-fix 인가
- **same-PR push 예외 마커**: `EXCEPTIONAL_OWNER_TRIGGER_AFTER_SAFE_SAME_PR_GEMINI_FIX` / scope=`THIS_PR_AND_THIS_HEAD_ONLY` (PR #161, 58a15618→new head)

## 배경
PR #161 = CI_PASS_BUT_GEMINI_HIGH_BLOCKED. Gemini unresolved 4건(HIGH×2, MEDIUM×2). merge-ready 아님. 4건 해결 전 merge 금지.

## 수정 4건 (Gemini 코멘트 verbatim 근거)

### 1. dispatch.py:43 — HIGH (`_REPO_ROOT` undefined)
Gemini: "`_REPO_ROOT` is used ... never defined ... broad `except Exception:` raises NameError silently caught, causing `_fcb_write_handoff` and `_verify_bot_spawn` to always be None. This silently disables the entire failure callback mechanism."
- **fix**: 모듈 레벨에 `_REPO_ROOT = Path(__file__).resolve().parent` 추가 (`from pathlib import Path` 필요 시 기존 import 확인 후 최소 추가)
- broad except 에 삼켜져 failure callback 이 silent disable 되지 않도록 **최소 보강** (예: 해당 import-guard except 가 NameError 를 가리지 않게 하거나, _REPO_ROOT 정의로 NameError 자체 제거)
- **기존 dispatch behavior 변경 금지** — _REPO_ROOT 정의로 import 성공만 보장

### 2. scripts/finish-task.sh:41-42 — HIGH (INT/TERM trap exit 누락)
Gemini: "trapping INT or TERM without calling exit ... script resumes after handler ... append `exit 130` (INT) and `exit 143` (TERM)."
- **fix**: INT trap 끝에 `exit 130`, TERM trap 끝에 `exit 143` 추가
- **EXIT trap(line 40)과 충돌 금지** — EXIT trap 의 `_emit_failure_envelope ... ; cleanup_timer` 동작 보존. INT/TERM 에서 exit 호출 시 EXIT trap 이 한 번 더 fire 되더라도 marker idempotent(exactly-one) 로 안전한지 확인
- **success path .done 동작 변경 금지**

### 3. scripts/harness/v36/before_exit_guard_hook.sh:~44 — MEDIUM (events dir mkdir)
Gemini: "events dir 부재 시 redirect `2>>$_FCB2712_EVENTS_DIR/...stderr-emit.log` 실패 → python 미실행. `mkdir -p` 필요."
- **fix**: `[ -z "$task_id" ] && return 0` 직후, 어떤 file 연산/redirect 전에 `mkdir -p "$_FCB2712_EVENTS_DIR"` 수행
- **기존 marker schema 변경 금지**

### 4. scripts/harness/v36/failure_callback_dispatcher.py:~238 — MEDIUM (file handle with)
Gemini: "`json.load(open(path))` leaks fd ... use `with`."
- **fix**: `with open(path, encoding="utf-8") as f: envelope = json.load(f)` 로 변경 (기존 except 보존)
- **로직 변경 없이 resource handling 만 개선**

## 필수 검증 (전부 PASS 후에만 완료)
1. `python3 -m pytest tests/test_failure_callback_before_exit_guard_2712.py -v` → **23/23 PASS**
2. L1 hook smoke 재실행: SCOPE_GUARD_FAIL / QC_FAIL / CRASH / SUCCESS no-op / exactly-one marker (5종 전부)
3. dispatch.py import/smoke: `python3 -c "import dispatch"` 또는 동등 → PASS (NameError 0)
4. `bash -n scripts/finish-task.sh` → syntax PASS
5. Gemini 4건 fix evidence md 작성: 각 finding → 변경 라인 → 검증 결과
6. `git diff --name-only origin/main...HEAD` = expected_files 만 (외부 변경 0, forbidden path 0)

## expected_files (이 밖 수정 금지)
dispatch.py · scripts/finish-task.sh · scripts/harness/v36/before_exit_guard_hook.sh · scripts/harness/v36/failure_callback_dispatcher.py (+ 검증로그/evidence md)

## 금지 (verbatim)
- force push 금지 · rebase 금지 · admin merge 금지 · merge 금지
- task-2713 혼입 금지 · task-2710/task-2711/task-2706~2709 evidence 변경 금지
- caveat 3건 삭제 금지 · expected_files 밖 수정 금지 · unrelated refactor 금지

## push 정책 (★중요 — dev bot App token 부재)
- **dev bot 은 push 하지 않는다** (ghs_ App token 부재로 push 불가).
- 로컬 commit 까지만 수행(branch task/task-2712-dev4, head 58a15618 위 1 commit). **finish-task 는 project_path 없이(머지/푸시 스킵) 로컬 완료**.
- 완료 후 ANU callback(ANU key c119085addb0f8b7)으로 **new local commit sha + worktree path + fix evidence path** 보고.
- **push 는 ANU 가 OWNER PAT 로 fast-forward normal push 만 수행**(auth path marker 남김). dev bot 임의 push 금지.

## 완료 시 ANU callback envelope 필수 필드
task_id · new_commit_sha · worktree_path · fix_evidence_path · pytest_result(23/23) · l1_smoke_result · dispatch_import_result · bash_syntax_result · expected_files_only(true/false) · collector_role=ANU · self_key_used=false
