당신은 페룬(Perun), 개발6팀장입니다. task-2547 / PR #95 finalize 재개를 즉시 진행합니다. ## 본질 명령 (회장 §명시 2026-05-11 serial order, PR #96 머지 후) 회장이 PR #95에 OWNER 계정 `/gemini review` 댓글 1회 트리거 완료. 직전 ESCALATED 원인(GEMINI_AUTO_REVIEW_NOT_TRIGGERED_FOR_BOT_OPENED_PR_HUMAN_LOOP_REQUIRED) RESOLVED. **선행 머지 확정**: PR #96 (task-2545+3) merged at 2026-05-11 05:54:13 KST, merge commit `2bae7b7bd8f9fb816c6dcf2fef35d452529ce8fc`. origin/main 새 sha 진입. **serial order finalize 시작**: PR #95 stale base revalidation + finalize 14단계. ## §0. BOT_GITHUB_TOKEN_RUNTIME_RESOLUTION_STEP0 (4-step) ```bash python3 /home/jay/workspace/scripts/refresh_bot_token.py 2>&1 | tail -3 export $(grep -E "^BOT_GITHUB_TOKEN=" /home/jay/workspace/.env.keys | head -1) [[ -n "$BOT_GITHUB_TOKEN" ]] || { echo "FATAL: BOT_GITHUB_TOKEN missing"; exit 1; } GH_TOKEN=$BOT_GITHUB_TOKEN gh api /installation/repositories --jq '.repositories[0].full_name' 2>&1 | head -1 ``` ## §1. origin/main fetch + 새 sha 확인 (stale base revalidation) ```bash cd /home/jay/workspace git fetch origin main NEW_MAIN=$(git rev-parse origin/main) echo "new origin/main = $NEW_MAIN" # 어설션: NEW_MAIN starts with 2bae7b7bd8f9 (PR #96 머지 후) ``` ## §2. PR #95 effective diff 재계산 (stale base 대응) ```bash PR_HEAD=$(gh pr view 95 --repo Jeon-Jonghyuk/dev_workspace --json headRefOid --jq '.headRefOid') # 어설션: PR_HEAD == 90cadf5fd3eda572ab28fe53ea4321285f5af2e8 (추가 push 0) # 새 main 기준 effective diff 재계산 gh pr view 95 --repo Jeon-Jonghyuk/dev_workspace --json files --jq '.files[].path' | sort > /tmp/pr95_files_new.txt wc -l /tmp/pr95_files_new.txt # 어설션: 18 lines ``` ## §3. expected_files 18개 1:1 재확인 `memory/events/task-2547.effective-diff.json` 기준 18 files: - dashboard/helpers.py - dispatch/__init__.py - report_parser.py - scripts/auto_merge.py - scripts/done-watcher.py - scripts/notify-completion.py - scripts/pattern-detector.py - scripts/report_utils.py - scripts/start_task_guard.py - scripts/token-tracker.py - teams/shared/verifiers/browser_verify.py - tests/regression/test_dashboard_report_hardening_2487.py - tests/regression/test_dispatch_hardening_2487.py - tests/regression/test_dotphase_compat_2487.py - tests/regression/test_legacy_compat_2487.py - tests/regression/test_scripts_hardening_2487.py - tests/regression/test_task_id_parser_v3.py - utils/task_id_parser.py → `/tmp/pr95_files_new.txt`와 1:1 일치 어설션. ## §4. forbidden path 0 재확인 PR #96 머지로 main에 추가된 7 files와 PR #95 18 files = **anu_v2 overlap 0** (이미 effective-diff.json `anu_v2_overlap_count=0` 박제). → 충돌 위험 0. 그러나 직접 재검증: ```bash # PR #95 18 files 중 anu_v2/ 영역 0건 어설션 grep -c "^anu_v2/" /tmp/pr95_files_new.txt # 어설션: 0 ``` - PR #92/#93/#94/#96 branch 변경 0 - PR #49/#50/#51/#52 branch 변경 0 - task-2487.* / task-2487+1.* / task-2545*.* markers 변경 0 - POC 영역 변경 0 - .github/workflows/ 변경 0 ## §5. regression 재실행 (PR #96 머지 후 호환 검증) ```bash cd /home/jay/workspace git worktree add .worktrees/task-2547-dev6-revalidate origin/main 2>/dev/null || true cd .worktrees/task-2547-dev6-revalidate git fetch origin task/task-2547-dev6-clean git checkout FETCH_HEAD python -m pytest tests/regression/test_task_id_parser_v3.py tests/regression/test_dispatch_hardening_2487.py tests/regression/test_dashboard_report_hardening_2487.py tests/regression/test_dotphase_compat_2487.py tests/regression/test_legacy_compat_2487.py tests/regression/test_scripts_hardening_2487.py -v # 어설션: 모두 PASS (PR #96 머지 후에도 충돌 없음) ``` regression FAIL 발견 시 → ESCALATED (rebase/force push 금지, 새 task 필요) ## §6. Gemini fresh review 도착 확인 (OWNER 트리거 후) ```bash GH_TOKEN=$BOT_GITHUB_TOKEN gh api repos/Jeon-Jonghyuk/dev_workspace/pulls/95/reviews \ --jq '.[] | select(.user.login | test("gemini|google-labs"; "i")) | {id, state, submitted_at, commit_id}' ``` 어설션: - OWNER 트리거 후 신규 review 1건 이상 - commit_id == PR #95 current head 90cadf5fd3ed (FRESH) ## §7. unresolved thread triage ```bash GH_TOKEN=$BOT_GITHUB_TOKEN gh api graphql -f query=' { repository(owner: "Jeon-Jonghyuk", name: "dev_workspace") { pullRequest(number: 95) { reviewThreads(first: 50) { nodes { id, isResolved, comments(first:1) { nodes { body, author { login } } } } } } } }' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)' ``` - unresolved 0 → §8 - unresolved 있으면 triage: - false_positive / style_only / no_code_change → reply + resolve (same-PR push 0) - code_changing_fix → ESCALATED (CHAIN_LIMIT_HIT, OWNER_DECISION_REQUIRED, 자동 task-2547+1 발행 X) ## §8. CI 11/11 SUCCESS ```bash GH_TOKEN=$BOT_GITHUB_TOKEN gh pr view 95 --repo Jeon-Jonghyuk/dev_workspace \ --json statusCheckRollup \ --jq '.statusCheckRollup[] | select(.conclusion != "SUCCESS") | {name, conclusion}' ``` 어설션: 미PASS 0건. ## §9. mergeStateStatus CLEAN ```bash GH_TOKEN=$BOT_GITHUB_TOKEN gh pr view 95 --repo Jeon-Jonghyuk/dev_workspace --json mergeStateStatus,mergeable ``` 어설션: mergeStateStatus=CLEAN, mergeable=MERGEABLE. **BEHIND 상태일 경우**: PR #95 squash merge는 base의 새 sha에 squash commit 추가하는 방식이므로 anu_v2 overlap=0인 본 케이스에서는 BEHIND여도 squash merge 가능. 시도 진행. CONFLICT 발견 시 ESCALATED. ## §10. BOT_GITHUB_TOKEN identity 재확인 ```bash GH_TOKEN=$BOT_GITHUB_TOKEN gh api /installation/repositories --jq '.repositories[0].full_name' 2>&1 ``` 어설션: BOT identity = installation token (app/jeon-jonghyuk-taskctl-bot). ## §11. BOT squash merge ```bash GH_TOKEN=$BOT_GITHUB_TOKEN gh pr merge 95 \ --repo Jeon-Jonghyuk/dev_workspace \ --squash --auto=false --delete-branch=false ``` mergedBy 직접 검증: ```bash GH_TOKEN=$BOT_GITHUB_TOKEN gh pr view 95 --repo Jeon-Jonghyuk/dev_workspace --json mergedBy --jq '.mergedBy.login' ``` 어설션: `app/jeon-jonghyuk-taskctl-bot`. ## §12. post_merge_smoke_runner 실행 ```bash cd /home/jay/workspace git fetch origin main python3 -c " from anu_v2.post_merge_smoke_runner import PostMergeSmokeRunner runner = PostMergeSmokeRunner() result = runner.run_post_merge_smoke(task_id='task-2547', merge_commit='') print(result) " ``` 어설션: smoke PASS, marker `memory/events/task-2547.smoke-evidence` 생성. ## §13. reconcile evidence 생성 ```bash python3 /home/jay/workspace/utils/lifecycle_reconciliation_manager.py \ --reconcile --task-id "task-2547" --apply --json ``` 어설션: state=FINALIZED, marker `memory/events/task-2547.reconcile-evidence` 생성. ## §14. done.acked / merge-done 정리 - `memory/events/task-2547.done` 보존 (또는 신규 생성) - `memory/events/task-2547.done.acked` 생성 - `memory/events/task-2547.merge-done` 생성 ## §15. replacement_lineage 갱신 `memory/events/task-2547.replacement-lineage.json`: ```python import json p = "/home/jay/workspace/memory/events/task-2547.replacement-lineage.json" data = json.loads(open(p).read()) 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) data["dispatch_status"] = { "stage": "REPLACEMENT_PR_FINALIZED_AFTER_OWNER_GEMINI_TRIGGER_SERIAL_ORDER", "outcome": "MERGED", "ts": "", "retry_index": len(data["dispatch_status_history"]), "merge_commit": "", "merged_by": "app/jeon-jonghyuk-taskctl-bot", "smoke_pass": True, "reconcile_evidence_path": "memory/events/task-2547.reconcile-evidence", "owner_gemini_trigger_required": True, "owner_gemini_trigger_completed_at": "", "serial_order_predecessor_pr": 96, "serial_order_predecessor_merge_commit": "2bae7b7bd8f9fb816c6dcf2fef35d452529ce8fc", "stale_base_revalidation_pass": True, "anu_v2_overlap_count_post_pr96_merge": 0 } open(p, "w").write(json.dumps(data, indent=2, ensure_ascii=False) + "\n") ``` ## §16. PR #49/#50/#51/#52 + PR #92/#93/#94/#96 head 보존 audit (read-only) ```bash for n in 49 50 51 52 92 93 94 96; do GH_TOKEN=$BOT_GITHUB_TOKEN gh pr view $n --repo Jeon-Jonghyuk/dev_workspace --json state,headRefOid \ --jq "{pr:$n, state:.state, head:.headRefOid[0:12]}" done ``` 어설션: - PR #49 head=`da9a8e1265fb` unchanged + OPEN - PR #50 head=`464114bfbcf9` unchanged + OPEN - PR #51 head=`0d388b989111` unchanged + OPEN - PR #52 head=`b341e8747eb7` unchanged + OPEN - PR #92 head=`15cf6ad011e1` unchanged + OPEN - PR #93 head=`5ad46d999988` unchanged + OPEN - PR #94 head=`2996be2565ec` unchanged + OPEN - PR #96 state=MERGED + head=`429569cdb1e5` → close 액션 0. ## 금지 12건 (회장 §명시 1:1) 1. ❌ 추가 `/gemini review` 요청 (OWNER 1회로 충분) 2. ❌ bot `/gemini review` 3. ❌ empty commit 4. ❌ close/reopen (PR #49/#50/#51/#52/#92/#93/#94/#95/#96 모두) 5. ❌ force push / rebase 6. ❌ expected_files amendment 7. ❌ owner PAT 8. ❌ default GH_TOKEN fallback 9. ❌ PR #92/#93/#94/#96 변경 10. ❌ PR #49/#50/#51/#52 변경 11. ❌ md/report만으로 PASS 처리 12. ❌ long polling / self-register 반복 ## 보고 MERGED (mergedBy=app/jeon-jonghyuk-taskctl-bot, 16/16 PASS, PR #49/#50/#51/#52/#92/#93/#94/#96 head unchanged) 또는 ESCALATED (Critical 7 #N 매핑) 만 보고. 무변화 polling / 회장 chat 노출 X. ESCALATED 매핑 가이드: - §1 origin/main 새 sha 불일치 → #6 STALE_BASE_REVALIDATION_FAILED - §2/§3 effective diff 변동 → #2 EFFECTIVE_DIFF_FAIL - §4 forbidden path 발견 → #1 FORBIDDEN_PATH - §5 regression FAIL → #2 EFFECTIVE_DIFF_FAIL (PR #96 머지 후 호환 실패) - §6 Gemini fresh evidence 미도착 → #6 GEMINI_AUTO_REVIEW_DELAYED - §7 unresolved code_changing → #6 SELF_POLICY_REPLACEMENT_CHAIN_LIMIT_HIT (OWNER_DECISION_REQUIRED) - §9 mergeStateStatus CONFLICT → #6 STALE_BASE_MERGE_CONFLICT (OWNER_DECISION_REQUIRED, 새 replacement task 필요) - §11 mergedBy 불일치 → BOT_IDENTITY_DIVERGENCE ## 최종 원칙 task-2487 series clean replacement의 serial order finalize. PR #96 (task-2545+3 ANU v2 self-reference chain terminal) 머지 후 PR #95 (task-2547 task-2487 series replacement) 진입. anu_v2 overlap=0이므로 stale base 충돌 0 가정. 그러나 §5 regression / §9 mergeStateStatus로 직접 재검증 후만 finalize.