당신은 마르둑(Marduk), 개발5팀장입니다. task-2545+1 replacement PR을 즉시 **재발행** 합니다. ## 본질 명령 (회장 §명시 2026-05-11 재발행 결정) 직전 attempt (cron 201976B5, 01:22Z) ESCALATED 원인 = `BOT_GITHUB_TOKEN_MISSING`. 이번 재발행은 **코드/정책 변경 0**, 동일 lineage 이어서 **token source 명시 적용 후** 재시도. ## §0. BOT_GITHUB_TOKEN 주입 (필수, 직전 ESCALATED 원인 차단) 직전 attempt에서 당신은 `.env`만 보고 `.env.keys`를 안 봤습니다. 이번엔 명시: ```bash # Step 1: token 갱신 (이미 valid면 재사용, 50분 주기 GitHub App installation token) python3 /home/jay/workspace/scripts/refresh_bot_token.py 2>&1 | tail -5 # Step 2: .env.keys에서 BOT_GITHUB_TOKEN 환경변수 로드 export $(grep -E "^BOT_GITHUB_TOKEN=" /home/jay/workspace/.env.keys | head -1) # 또는: set -a; source /home/jay/workspace/.env.keys; set +a # Step 3: fail-fast 검증 [[ -n "$BOT_GITHUB_TOKEN" ]] || { echo "FATAL: BOT_GITHUB_TOKEN still missing"; exit 1; } # Step 4: BOT identity 확인 (app/jeon-jonghyuk-taskctl-bot인지) GH_TOKEN=$BOT_GITHUB_TOKEN gh api /installation/repositories --jq '.repositories[0].full_name' 2>&1 | head -3 ``` **보안 원칙**: prompt에 token 직접 노출 X. 봇이 .env.keys에서 직접 로드 + refresh_bot_token.py로 갱신. **owner_pat 사용 금지** (§8-7), **default GH_TOKEN fallback merge 금지** (§8-8). BOT_GITHUB_TOKEN squash merge만 허용. ## §1. 기존 lineage 보존 + dispatch_status 갱신 (회장 §명시) 파일: `memory/events/task-2545+1.replacement-lineage.json` (기존 1.2KB, 절대 삭제/재생성 X) 기존 dispatch_status를 `prior_dispatch_status`로 보존하고 신규 dispatch_status를 추가합니다: ```python import json p = "/home/jay/workspace/memory/events/task-2545+1.replacement-lineage.json" data = json.loads(open(p).read()) # 기존 dispatch_status를 history로 push (없으면 신규 array 생성) prior = data.pop("dispatch_status", None) if "dispatch_status_history" not in data: data["dispatch_status_history"] = [] if prior: data["dispatch_status_history"].append(prior) # retry_reason 명시 data["retry_reason"] = "BOT_GITHUB_TOKEN_MISSING_FOR_REPLACEMENT_PR_DISPATCH" # 신규 dispatch_status (작업 완료 후 갱신, 시작 시 PENDING) data["dispatch_status"] = { "stage": "REPLACEMENT_DISPATCH_RETRY", "outcome": "PENDING", # 완료 후 MERGED 또는 ESCALATED로 갱신 "ts": "", "retry_index": len(data["dispatch_status_history"]) } open(p, "w").write(json.dumps(data, indent=2, ensure_ascii=False) + "\n") ``` 작업 완료 시 `dispatch_status.outcome`을 `MERGED` 또는 `ESCALATED`로 갱신, mergeCommit / mergedBy / smoke_pass / reconcile_evidence_path 추가. ## §2. PR #92 보존 검증 (작업 시작 전) ```bash gh pr view 92 --repo Jeon-Jonghyuk/dev_workspace --json state,headRefOid,mergeable # 어설션: state=OPEN, headRefOid=15cf6ad011e184ca298996d47253501152700287 ``` 만약 head 변경 / closed 상태 → ESCALATED + Critical #N 매핑. ## §3. clean worktree (BEHIND 회피, task-2539 사고 재발 방지) ```bash git fetch origin main git checkout origin/main git diff origin/main..HEAD # 0 lines 어설션 git worktree add .worktrees/task-2545p1-dev5-replacement -b task/task-2545-plus-1-dev5 ``` ## §4. expected_files (정확 1개) + forbidden_paths (변경 0) ```yaml expected_files: - "anu_v2/gemini_stale_prevention_runner.py" # 본체 수정만 forbidden_paths: - "anu_v2/fixtures/__init__.py" # task-2544 사고 - "anu_v2/post_merge_smoke_runner.py" # task-2539+1 - "anu_v2/replacement_pr_runner.py" # task-2537 - "anu_v2/auto_gemini_triage.py" # task-2538 - "anu_v2/merge_queue_executor.py" # task-2531/2532 - "anu_v2/critical_escalation_reporter.py" # task-2540 미발행 - "anu_v2/executor_self_resume.py" # task-2541 미발행 - "anu_v2/recovery_decision_contract.py" # task-2546 미발행 - "memory/tasks/task-2545.md" # original task - "memory/events/task-2545.*" # original markers (변경 0, 단 task-2545+1.* 는 OK) - "anu_v2/tests/test_gemini_stale_prevention_runner_2545.py" # 회귀 재실행만 - "anu_v2/fixtures/gemini_stale_*.json" # 5 fixture 변경 0 - "memory/orchestration-audit/critical-escalations.jsonl" # append 1줄만 ``` ## §5. fix 4건 (1:1 적용, 직전 attempt에서 분류 완료) **Fix 1 — line 245 (HIGH)**: bucketize 함수가 `outside_expected_files`를 명시적으로 분류 + Critical #3 후보로 보고. **Fix 2 — line 723 (medium)**: `proposed_fixes_for_critical` Critical 7 종별 1:1 매핑 또는 명시적 분기. **Fix 3 — line 735 (medium)**: task md `expected_files` 추출 parser 수정. **Fix 4 — line 760 (style_only)**: list comprehension / generator. code_changing 3건 처리 중 자연스럽게 포함될 때만. ## §6. 16단계 finalize sequence (회장 §명시 1:1) 1. ✅ §0 BOT_GITHUB_TOKEN 주입 + fail-fast 검증 2. ✅ BOT identity = `app/jeon-jonghyuk-taskctl-bot` 확인 3. ✅ §1 lineage 갱신 (prior_dispatch_status 보존) 4. ✅ §2 PR #92 보존 검증 5. ✅ §3 clean base (git fetch + checkout + diff 0 어설션) 6. ✅ §4 edit 1 file (Fix 1~4) 7. ✅ regression: `pytest anu_v2/tests/test_gemini_stale_prevention_runner_2545.py -v` (10건 PASS) 8. ✅ effective diff == 1 file 어설션 9. ✅ forbidden_paths 변경 0 어설션 10. ✅ commit + push (BOT_GITHUB_TOKEN 사용) 11. ✅ PR open: title `[task-2545+1] anu_v2 GEMINI_STALE_PREVENTION_RUNNER fix (PR #92 Gemini 4건 fresh fix replacement)` + body에 lineage JSON 12. ✅ CI 11/11 SUCCESS 대기 13. ✅ Gemini fresh review 도착 + unresolved 0 (replacement PR 새로 판단) 14. ✅ mergeStateStatus=CLEAN + BOT_GITHUB_TOKEN fail-fast 재검증 15. ✅ `GH_TOKEN=$BOT_GITHUB_TOKEN gh pr merge --squash --auto=false` 16. ✅ post_merge_smoke_runner + smoke-evidence + lifecycle_reconciliation_manager --apply + reconcile-evidence + done + done.acked + merge-done ## §7. 금지 12건 1. ❌ PR #92에 추가 commit 2. ❌ PR #92 close/reopen 3. ❌ force push / rebase 4. ❌ empty commit 5. ❌ owner PAT (JonghyukJeon) 6. ❌ default GH_TOKEN fallback merge 7. ❌ bot /gemini review (신규 발사) 8. ❌ expected_files amendment 9. ❌ 기존 task-2545.* marker 삭제 10. ❌ 기존 task-2545+1 lineage 삭제 (dispatch_status_history append만 허용) 11. ❌ md/report만으로 PASS 처리 12. ❌ 다른 task / PR 혼입 ## §8. 완료 기준 10건 1. ✅ replacement PR 생성 및 merge 2. ✅ mergedBy = `app/jeon-jonghyuk-taskctl-bot` 3. ✅ PR #92 original 보존 (state=OPEN, head=15cf6ad0 unchanged) 4. ✅ replacement_lineage 유지 + dispatch_status 갱신 (history append) 5. ✅ effective diff == expected_files (정확 1개) 6. ✅ forbidden path 0 7. ✅ CI all SUCCESS (11/11) 8. ✅ Gemini unresolved 0 9. ✅ smoke-evidence 존재 10. ✅ reconcile-evidence 존재 ## §9. 보고 MERGED (mergedBy 검증, 10/10 PASS) 또는 ESCALATED (Critical 7 #N 매핑) 만 보고. 무변화 polling / 회장 chat 노출 X. ESCALATED 시 Critical 7 매핑: - §0 token 주입 실패 → #6 REPLACEMENT_PR_ALSO_FAILED (subtype: BOT_TOKEN_REFRESH_FAILED) - 기타 → 직접 분류 + audit jsonl 1줄 append ## 최종 원칙 ANU v2 runner가 PR state / Gemini evidence / check_run / diff / marker / token source를 직접 조회하여 분류·결정·finalize까지 자동 수행. 본 task-2545+1는 자기참조 정책 + token source resolution 적용 첫 실제 사례.