{
  "schema": "replacement_pr_v3_adapter_proposal.v1",
  "track": "Track F — replacement PR v3 gap closure plan",
  "ts_kst": "2026-05-21 05:03 KST",
  "mode": "proposal-only · 실 코드 생성 0 · 회장 승인 시 별도 task 발행",
  "purpose": "utils/replacement_pr_runner.py (0 lines stub) 를 thin re-export shim 으로 결선 (anu_v2 sole source of truth)",
  "proposal_overview": {
    "approach": "Option A — thin re-export shim",
    "rationale": "v2 442 lines 가 본질 4축 완비 · v3 era 변경 0 · namespace 호환만 보장",
    "loc_estimate": "≤ 15 LOC + docstring + __all__",
    "risk_class": "LOW",
    "blast_radius": "LOW · 본 task closure 후에도 import 경로 외 동작 변경 0"
  },
  "adapter_design_sketch": {
    "file": "utils/replacement_pr_runner.py",
    "skeleton_lines_pseudo": [
      "\"\"\"utils.replacement_pr_runner — v3 thin re-export shim (sole source: anu_v2).\"\"\"",
      "from __future__ import annotations",
      "from anu_v2.replacement_pr_runner import (",
      "    ContaminationReport,",
      "    PreservationRecord,",
      "    ReplacementResult,",
      "    ReplacementFailure,",
      "    ReplacementPRRunner,",
      "    REPLACEMENT_PR_CREATED,",
      "    REPLACEMENT_PR_FAILED,",
      "    ORIGINAL_PR_PRESERVED,",
      "    CRITICAL_REPLACEMENT_FAILED,",
      "    CRITICAL_DIFF_REPLACEMENT_FAILED,",
      ")",
      "__all__ = [",
      "    \"ContaminationReport\", \"PreservationRecord\", \"ReplacementResult\",",
      "    \"ReplacementFailure\", \"ReplacementPRRunner\",",
      "    \"REPLACEMENT_PR_CREATED\", \"REPLACEMENT_PR_FAILED\",",
      "    \"ORIGINAL_PR_PRESERVED\", \"CRITICAL_REPLACEMENT_FAILED\",",
      "    \"CRITICAL_DIFF_REPLACEMENT_FAILED\",",
      "]"
    ],
    "verification_smoke_test": "tests/test_utils_replacement_pr_runner_shim.py — import + class equivalence assertion + __all__ length"
  },
  "non_goals": [
    "v3 namespace 에서 v2 와 다른 동작 도입 (drift 위험 — 금지)",
    "BOT identity / token / gh / git 호출 동작 변경 (변경 0)",
    "executor contract dict 키 추가 (회장 §명시 2개만)",
    "anu_v2 코드 수정 (sole source 유지)"
  ],
  "alternative_evaluated": {
    "Option_B_v3_full_module_clone": {
      "scope_loc": "~450 LOC",
      "risk_class": "MEDIUM (v2 ↔ v3 drift)",
      "extra_cost": "v2 ↔ v3 sync test + dual maintenance",
      "rejected_reason": "v3 era 의 변경 사항이 callback contract chaining 만이고, 이는 dispatch/__init__.py task-2621 wiring 으로 이미 결선. replacement PR runner 본체 변경 불필요."
    }
  },
  "expected_files_if_implemented": [
    "utils/replacement_pr_runner.py (변경: 0 → ~15 LOC re-export)",
    "tests/test_utils_replacement_pr_runner_shim.py (신규 ~30 LOC import + equivalence)"
  ],
  "forbidden_paths": [
    "anu_v2/replacement_pr_runner.py (변경 금지 — sole source)",
    "dispatch/__init__.py (변경 금지 — task-2621 wiring intact 유지)",
    ".github/workflows/* (변경 0)"
  ],
  "preconditions_for_chair_authorization": [
    "(a) 본 proposal ACCEPT",
    "(b) task ID 발행 (예: task-NNNN)",
    "(c) expected_files anchor 정확 명시",
    "(d) dispatch prompt 에 v2 sole source / drift 금지 / live PR open 0 명문 포함",
    "(e) callback contract 9 fields enforcement"
  ],
  "follow_up_tasks_chained": [
    "(i) live PR-open pilot preconditions 검토 (별도 chair-authorized — limited_live_pr_open_pilot_preconditions.json)",
    "(ii) replacement PR 실패 regression test 구현 (test_replacement_pr_failure_critical7.py · mock-based)"
  ],
  "chair_approval_required": true,
  "auto_progress": false,
  "scope_invariants_preserved": [
    "proposal-only", "실 코드 생성 0", "실 PR open 0", "merge 0",
    "GitHub write 0", "credential raw exposure 0",
    "Track C 미접촉", "zombie cron 미접촉"
  ]
}
