# task-2612+3 — AUTO_REMEDIATION: _read_json hard-link containment 우회 봉합 (non-Critical 자동 수렴 계속)

> **Lv**: Lv.3. **goal_type**: auto_remediation_planner_hardening. **Executor**: dev4-team 비슈누 (key 7943afbe12c12f7d) 1회 한정 — task-2612 계열 원 executor. **TTL**: 3h. **분류**: **AUTO_REMEDIATION_HOLD 자동 수렴**(non-Critical HIGH×1·CRITICAL 0·critical7 false·회장 확인 대기 0·분류 후 멈춤 금지 — feedback-auto-remediation-hold-vs-chair-hold 강화원칙). 문서-only 금지. **callback: 반드시 독립 ANU key c119085addb0f8b7(executor self key 7943afbe12c12f7d 절대 금지·+49 코드 정본).**
> **판정 정본**: `memory/events/task-2612+2.independent-collector-adjudication.json` (독립 ANU 권위 · Codex CRITICAL 0 · HIGH 1 · critical7 false · H1r 배정 TOCTOU symlink-swap **CLOSED** 확정 · 잔여는 신규 hard-link 우회 HIGH 만 · collector 런타임 probe 독립 재현). **+N=원래 goal completion blocker.**

## 1. 잔여 HIGH×1 (task-2612+2 독립 ANU/Codex 재audit 정본 verbatim · non-Critical · H1r 외 신규)

`anu_v3/auto_remediation_planner.py`:
- **H1h (hard-link bypass)**: `_read_json` 의 containment 가 여전히 **pathname-only**. `CANONICAL_WS_ROOT` 내부 쓰기 권한 보유 공격자가 동일 파일시스템·동일 uid 의 ws-밖 파일에 대한 **hard link** 를 ws 내부에 생성하면: 그 in-root 경로가 `_contained_resolved()` 통과 → `O_NOFOLLOW` 통과(hard link 은 symlink 아님) → `/proc/self/fd` realpath 가 in-root 이므로 fd 재검증 통과(hard link 은 별도 realpath 없음) → `fstat S_ISREG` 통과 → fd 로 **ws-밖 inode 내용 read**. race 없는 out-of-scope read. task-2612+2 의 H1r(validate→open TOCTOU symlink-swap)는 **CLOSED 확정**(O_NOFOLLOW leaf + /proc/self/fd realpath intermediate 재검증 + fstat + fd-only read 실증) — 잔여는 hard-link 동일-inode 벡터만.

CRITICAL 0 · critical7 false · 신규 Critical7 0 · H2 CLOSED · H1r CLOSED → non-Critical AUTO_REMEDIATION (회장 원칙: 분류 후 멈추지 말고 자동 수렴).

## 2. 목표 (자동 remediation — hard-link 동일-inode 우회 봉합)

**용어 명확화**: planner **산출 성격**(plan 골격 생성만·실 dispatch 0·실 코드수정 0) 불변. 본 remediation 은 `_read_json` 입력 read-path 의 **inode-수준 containment 강화**(입력검증 코드 hardening)이며 "plan-only" invariant 와 무모순.

- **H1h 교정**: 열린 fd 의 `os.fstat` 결과로 **link count / 동일-inode 소속**을 fail-closed 검증. 권장 패턴 중 하나:
  - 열린 fd 의 `st_dev`/`st_ino` 를 회수한 뒤, `_contained_resolved()` 가 산출한 정적 경로의 `os.lstat`(symlink 미추종) `st_dev`/`st_ino` 와 **동일성 대조**(불일치 = swap/우회 → `PathContainmentError`), 그리고 `st_nlink > 1` 인 정규파일은 ws-내부 정합 경로임을 추가 확인하거나 fail-closed.
  - 또는 fd 의 inode 가 `CANONICAL_WS_ROOT` 하위에서 **`os.walk`/`os.scandir` 없이** 도달 가능한 inode 인지 `/proc/self/fd` realpath + `os.path.samestat` 로 in-root 경로의 inode 와 일치하는지 재확인.
  - 어떤 이탈도 `PathContainmentError`(fail-closed). 정적 1차 검증(`_contained_resolved`)·H1r 2차 fd 재검증(O_NOFOLLOW+/proc/self/fd+fstat)은 보존, hard-link inode 대조를 3차로 additive(defense-in-depth).
- 단일 진입점 유지: 모든 JSON read 는 여전히 `_read_json` 단일 helper 경유. helper 추가는 최소(필요 시 1개).

## 3. 필수

- 변경 범위: `anu_v3/auto_remediation_planner.py` 의 `_read_json`(+ 필요한 helper 1개) read-path inode-containment hardening **만**. planner 산출 성격 불변(plan 골격 생성만·실 dispatch 0·실 코드수정 0). H1r(O_NOFOLLOW/_fd_realpath/fstat 경로)·H2/`_normalize_expected_rel`/`_expected_files`/skeleton **byte-0**(CLOSED 확정 — 재변경 금지).
- `schemas/auto_remediation_plan.schema.json` byte-0 (sha256 `272a6f415b0ddf00bf0c677c3e97691ce548bd8f5e12458053d58e249bc6f430`)
- regression: `tests/regression/test_auto_remediation_planner.py` 에 (a) ws-내부 hard-link→ws밖 동일-inode 차단 (b) ws-내부 정규 단일-link read 무회귀 (c) H1r symlink-swap 차단 무회귀(기존 케이스 전수) (d) 2604/2605/2609 plan 변환 전수 무회귀 (e) plan-only AST 가드 PASS 케이스 additive. **기존 31 케이스 전수 무회귀**.
- `python -m anu_v3.auto_remediation_planner --self-check` → all_passed=True · plan_only=True · dispatch_performed=False 재현.
- Codex 재audit HIGH/CRITICAL 0 일 때만 durable-success write-back.

## 4. expected_files allowlist (자기 deliverable 한정)

`anu_v3/auto_remediation_planner.py`(read-path inode-containment hardening 만) · `tests/regression/test_auto_remediation_planner.py`(hard-link 재현 additive·기존 31 무회귀) · `memory/events/task-2612+3.{decision,result}.json` · `memory/reports/task-2612+3.md`. 이 외 write 0. **schema·H1r 경로·H2 영역·Track A/B/C·task-2610/2611+2/2613·task-2553/2604 multitrack byte-0**. git HEAD `20456b5f83fc039f2fd6f50f4b94095c29b41bfb`·branch `task/task-2553p1-f1-clean-replacement` 전후 EQUAL(ANU Layer-A no-git·커밋 0).

## 5. 금지

planner 산출 성격 변경 · schema 변경 · H1r(O_NOFOLLOW/_fd_realpath/fstat)·H2/`_normalize_expected_rel`/`_expected_files` 재변경(CLOSED 확정) · H1h 외 임의 리팩터링 · 2604/2605/2609 plan 변환 동작 변경 · executor self-callback/self-collector/self-adjudication/self-dispatch · PR/branch/main write·merge·credential · premature write-back(독립 ANU Codex HIGH/CRITICAL 0 확정 전) · 타 track/기존 산출물 변조 · 문서-only 완료.

## 6. HOLD_FOR_CHAIR

신규 Critical7 또는 shared invariant 파손 시에만 CHAIR_HOLD. 그 외 잔여 non-Critical 은 AUTO_REMEDIATION 자동 수렴 계속(회장 확인 대기 0·멈춤 금지). 본 라운드 독립 ANU Codex 재audit HIGH/CRITICAL 0 달성 시 +53 durable-success write-back 으로 수렴 종료 + 본 task ANU fallback cron cancel-on-success 제거(노이즈 0). authoritative 판정원은 독립 ANU only.

★ **LOOP-BOUNDARY (회장 directive 2026-05-19 명문)**: task-2612+3 은 `_read_json` read-path 보안 hardening 의 회장-인가 마지막 자동 수렴 라운드다. **+3 이후에도 동일 함수(`_read_json`)/동일 file-boundary 계열 non-Critical HIGH 가 또 적출되면 단순 task-2612+4 무한 +N 으로 진행 금지** — 독립 ANU collector 는 **AUTO_REMEDIATION_LOOP_BOUNDARY_REVIEW** 로 분류하고 batch-level 재판정(①Critical7 여부 ②동일 root-cause family 여부 ③새 공격면 확장 여부 ④동일 함수 3회 이상 반복 여부 ⑤자동 remediation scope 가 원래 task-2612 goal 내인지) 후 **회장 요약 보고 → 다음 수렴 여부 회장 결정 대기**. Critical7/credential/permission/forbidden-path/out-of-scope read-write 위험 확대 시 즉시 CHAIR_HOLD. 본 라운드 자체는 자동 수렴 계속(분류 후 멈춤 금지)이며 loop-boundary review 는 +3 collector 결과에 대한 사후 게이트다.

## 7. callback (a) — 독립 ANU key 강제 + fallback 노이즈 0

완료 직후 normal completion callback **ANU key c119085addb0f8b7로만 발사** → 독립 ANU collector 회수·Codex 재audit·adjudication. collector 는 adjudication 완료 **즉시 본 task ANU fallback cron cancel-on-success 제거**(노이즈 0). Codex 재audit HIGH/CRITICAL 0 일 때만 +53 durable-success write-back(독립 ANU 수행·executor 금지). **잔여 non-Critical HIGH 시: §6 LOOP-BOUNDARY 규칙 적용**(단순 +4 금지·AUTO_REMEDIATION_LOOP_BOUNDARY_REVIEW 분류·회장 요약 보고). executor self key 7943afbe12c12f7d 절대 금지(callback/collector/adjudication/dispatch·+49 코드 정본). ANU fallback=ANU key·안전망 한정·진행 트리거 아님(고정시각/dead-man 진행 트리거 금지)·정상수렴 시 self-cancel. authoritative 판정원=독립 ANU only.

## 8. 9-R (확정 — 본 절 본문 우선 · PRE-DISPATCH SPEC)

본 task md 는 dispatch 전 작업 명세(spec). 산출물 부재·baseline 일치 정상. lint 기준=spec 정합성(구현 검증 아님·feedback-spec-lint-not-implementation-check). 1차 ANU-Codex lint NEEDS_9R(§7 callback 전용 섹션 부재 — collector 가 callback 계약을 헤더·§6 에 분산시켜 section-stable 하지 않음) → **9-R 정정**: 부모 task-2612+1/+2 와 동형의 전용 §7 callback 섹션 복원 + 회장 loop-boundary directive 를 §6/§7 에 명문화(§8 신설). H1h 한정·H1r(O_NOFOLLOW/_fd_realpath/fstat) byte-0·H2/_normalize_expected_rel/skeleton byte-0·schema byte-0·기존 31 regression 무회귀·plan-only AST 불변·premature write-back gate(독립 ANU Codex HIGH/CRITICAL 0 후에만)·fallback cancel-on-success·LOOP-BOUNDARY 사후 게이트·자기 deliverable 한정·self-* 금지·ANU-key callback 정합. **ANU-Codex re-lint GO_READY 확정 후 dev4 비슈누 1회 위임**(회장 보고 없이 자동 수렴 진행 — non-Critical·Critical7 false).
