# task-2774+7 완료 보고 — PR#252 remediation round2 (G3 containment HIGH)

> 팀: dev2-team(오딘) | 상태명: `TASK2774_PR252_REMEDIATION_ROUND2_G3_CONTAINMENT_HIGH_GUARD_NATIVE_ACTIVE_FALSE`
> 작성일: 2026-06-25 | base: a41c58e8 (PR #252 head) | 신규 head: 21f94b6f

## SCQA 요약

**S (상황)**: PR #252(activation 전 안전 PR, G2 fail-closed + G3 backlog 보호, ACTIVE=false)가 OPEN 상태이며, +5에서 추가한 root-containment 체크가 동작 중이다.

**C (문제)**: fresh Gemini가 새 HIGH 1건을 지적 — `_norm_under_root`의 containment 체크가 문자열 `startswith(root_real + os.sep)` 기반이라, root=`/`(시스템 루트) 등 엣지에서 `root_real + os.sep == "//"`가 되어 `/foo/bar` 같은 **valid sub-path를 오판(과도 거부)**한다.

**Q (질문)**: containment 체크를 root=`/` 엣지에서도 오판하지 않으면서, root 밖/`..` 탈출 경로는 계속 fail-closed STOP하도록 견고화할 수 있는가?

**A (답변)**: `os.path.commonpath([root_real, np]) == root_real` 기반으로 교체하여 root=`/` valid sub-path 오판 0을 실증했고, root 밖·`..` 탈출·sibling prefix는 계속 STOP을 유지했다. 기존 16종 + 신규 4종 = **pytest 20 PASS**, 핵심 회귀 4종 **66 PASS**, py_compile PASS. 수정은 정확히 2파일(driver 무접촉). **ACTIVE=false 유지, merge 금지(manual)**.

## 수정 내역 (정확히 2파일 = a41c58e8..HEAD delta)

### 1) dispatch/anu_activation_preflight.py (+8/-3)
- **HIGH (`_norm_under_root` containment)**: `if np == root_real or np.startswith(root_real + os.sep)` → `os.path.commonpath([root_real, np]) == root_real` 기반으로 교체. `ValueError`(다른 드라이브/비교 불가)는 `pass` 후 `return None`(fail-closed). realpath/abspath 정규화는 기존 그대로 유지(비교부만 교체).
- **MED (BOM)**: `_default_is_activated`의 flag read 인코딩 `utf-8` → `utf-8-sig`(BOM strip으로 'enabled' 비교 안정화). bounded `readline(100)` 유지. (안전성 보강일 뿐 — BOM 실패 시 기존엔 NOT_ACTIVATED fail-closed였음)

### 2) tests/regression/test_activation_intended_safety_2774p5.py (+76)
신규 containment robustness 테스트 4종 append (기존 16종 무수정 유지):
- `test_norm_under_root_system_root_valid_subpath_not_misjudged` — root=`/` valid sub-path 오판 0 (HIGH 핵심 재현)
- `test_norm_under_root_sibling_prefix_rejected` — `/a/b` vs `/a/bcd` sibling prefix 거부
- `test_preflight_relative_canary_normal_root_ready` — 일반 root + 상대 canary → READY
- `test_preflight_dotdot_escape_canary_stop` — `..` 탈출 canary → CANARY_PATH_INVALID STOP

## L1 스모크테스트 결과 (subprocess/모듈 직접 실행)
- **서버 재시작**: 해당없음 (preflight 게이트 모듈 — 서버/API 무관)
- **API 응답 확인**: 해당없음
- **테스트 결과(L1 실제 실행)**: `pytest tests/regression/test_activation_intended_safety_2774p5.py` → **20 passed**; 핵심 회귀 4종(driver_governor_wiring_2774p3 / anu_pickup_driver_2721 / anu_result_pickup_runner_2720 / spawn_safety_governor_2774) → **66 passed**; `python3 -m py_compile` 두 파일 → PASS.
- **모듈 직접 실행(실동작 실증)**: `python3`로 `_norm_under_root`/`_default_is_activated`를 실제 호출하여 검증 — 통과:
  1. `root="/"` + `/home/jay/x.result.json` → **오판 0** (None 아님, 정규화 경로 반환) ✓ ← 기존 startswith 버그 해소 실증
  2. root 밖 absolute `/etc/passwd` → **None (STOP)** ✓
  3. `..` 탈출 relative → **None (STOP)** ✓
  4. sibling prefix `/a/bcd` (root=`/a/b`) → **None (STOP)** ✓
  5. root 안 sub-path → 정상 정규화 ✓
  6. BOM(`\xef\xbb\xbf`) 섞인 'enabled' flag → `is_activated=True` (BOM strip OK) ✓

## 테스트 결과
- 대상 테스트: `pytest tests/regression/test_activation_intended_safety_2774p5.py` → **20 passed** (기존16+신규4)
- 핵심 회귀: `test_driver_governor_wiring_2774p3` + `test_anu_pickup_driver_2721` + `test_anu_result_pickup_runner_2720` + `test_spawn_safety_governor_2774` → **66 passed**
- `python3 -m py_compile` (두 파일) → PASS

## 의미 보존 (불변 확인)
- CANARY_PATH_INVALID / CANONICAL_BACKLOG_DETECTED / CANARY_PATHS_REQUIRED / INBOX_SCAN_ERROR STOP 의미 유지
- G2 5개 STOP reason 유지 · backlog 삭제/수정/이동/소비 0 · glob 제거(listdir) 유지 · **ACTIVE=false 유지**
- root 밖 path → CANARY_PATH_INVALID STOP, root 안 path → READY 의미 무손상

## evidence-defer (이번 라운드 수정 금지 — 명시)
- driver:1937 (print→logger) MED: 스타일성 + +5 driver scope → **수정 안 함, evidence-defer**
- finish-task scope-guard stacked-PR base 오탐: 별도 인프라 backlog 유지, 이 트랙 무접촉

## 발견 이슈 및 해결
### 자체 해결 (1건)
1. **root=`/` 엣지에서 valid sub-path 과도 거부** — startswith→commonpath 교체로 해결
   - 상세: `dispatch/anu_activation_preflight.py:64-66` → commonpath 기반 try/except 블록

### 범위 외 미해결 (0건)

## Git / PR 상태
- remediation commit sha: **21f94b6f4b28110a2a486f5d790dc89b681f8a3c**
- push: a41c58e8 → 21f94b6f (PR #252 자동 업데이트). pre-commit/pre-push guard PASS. `--no-verify` 미사용.
- PR #252: state=OPEN, mergeable=MERGEABLE, head=21f94b6f
- CI: 1회 확인 시 QUEUED/IN_PROGRESS (CI/Gemini polling 루프 금지 — ANU 독립검증 대상)
- driver/pickup_once/replacement_pr_runner/finish-task/scope-guard 변경 **0건** 확인

## 머지 판단
- **머지 필요**: No (이번 라운드 merge 금지 — manual merge_policy)
- **브랜치**: task/task-2774+5-dev2 (PR #252 위 commit 추가)
- **워크트리 경로**: /home/jay/workspace/.worktrees/task-2774+5-dev2
- **머지 의견**: Gemini HIGH thread는 코드 fix push로 해소(임의 resolve 0). unresolved 0 + final gate 전 merge 금지 원칙 준수. ACTIVE=false 유지. merge는 ANU 독립검증 후 최종 게이트에서 결정.

## 모델 사용 기록
- 팀원: 토르(백엔드) / 작업 내용: commonpath 교체 + BOM MED + 회귀테스트 4종 / 사용 모델: sonnet / 정당성: -
- 팀장(오딘, Opus): 설계/검증/통합/push만 수행 (직접 코딩 0)

## 완료 상태 / 에스컬레이션 (ANU 판단 요청)
- **코드 작업**: 완료 (PR #252에 21f94b6f push, 테스트 20+66 PASS, py_compile PASS)
- **QC**: PASS (overall WARN — l1_smoketest_check PASS, FAIL 0건). `.qc-result`/`.qc-done` 생성됨.
- **finish-task.sh 결과**: scope-guard 단계에서 **stacked-PR base 오탐**으로 차단(exit 1) — `.escalate` 자동 생성.
  - scope-guard가 base를 `merge-base(origin/main, HEAD)=23f1b6db`로 잡아 +3/+5/+7 **stacked 전체 7파일**을 +7 scope로 귀속.
  - 5건 위반 전부 +3/+5 산출물(이번 +7 작업과 무관): `dispatch/anu_pickup_driver.py`, `dispatch/anu_result_pickup_runner.py`, `tests/regression/test_driver_governor_wiring_2774p3.py`, `tests/regression/test_spawn_safety_governor_2774.py`, `utils/spawn_safety_governor.py`.
  - **실제 +7 delta(a41c58e8..HEAD) = 정확히 2파일**(anu_activation_preflight.py + test_activation_intended_safety_2774p5.py), driver 무접촉. → **오탐 확정**.
- **조치**: task 지시("scope-guard 오탐 시 escalate로 멈추고 ANU 판단 요청") 준수. scope-guard 무수정, `.done`/`.scope-guard-done` 수동 생성 안 함, 강제 머지 안 함.
- **ANU-owned callback**: failure-callback-before-exit guard가 ANU key(self_key_used=false)로 등록 완료 — executor self-key 미사용. SELF_COLLECTOR 위반 0.
- **ANU 판단 요청 사항**: stacked-PR base 오탐 reconciliation(실제 delta a41c58e8..HEAD 2파일 기준 재평가) 후 final gate에서 merge 여부 결정.

## 비고
- relay_hints: 없음 (gemini_finding/merge_ready_ambiguous/critical7/consolidated_report 전부 false) → deterministic closeout
- callback_schedule_created: false (executor 직접 cron 등록 안 함 — OS-level pickup runner가 owner-proof 후 결정론 closeout 소유)
- evidence-defer: driver:1937 print→logger MED(미수정), finish-task scope-guard stacked-PR base 오탐(인프라 backlog — 이 트랙 무접촉)
