# dry-run executor shadow validation spec (Track B-2 · read-only · merge 실행 0) — 260523

회장 결정(2026-05-23): real merge executor wiring 전 단계로 **dry-run executor shadow validation** 진행. 최근 실 PR 사례 6건 + 실패/hold 시나리오 6종 frozen evidence 로 routing 정확성 검증. **실제 merge 실행 0 · GitHub write 0 · live 의존 0 · actually_executed=false 유지.**

기반: `system_merge_ready_executor_spec_260522.md`(classifier) + `system_merge_ready_executor_dryrun_spec_260522.md`(executor) + `feedback_credential_scan_3tier_doctrine_260522.md` + `feedback_gemini_medium_auto_remediation_260522.md` + `feedback_auto_remediation_loop_boundary_review_260519.md` + `project_callback_lifecycle_2axis_schema_260522.md`.

---

## 1. 목표

dry-run executor 가 historical real PR evidence 를 입력으로 받아 올바른 verdict + WOULD_* routing 을 산출하는지 frozen fixture 로 검증한다. **shadow validation = 실제 merge/push/PR 호출 0 · evidence 만 입력 · 결정 결과만 단언 · production 거동 0 영향**.

---

## 2. 대상 PR (실측 historical evidence)

전부 origin/main 머지 완료 (2026-05-22). callback runtime enforcement → merge-ready executor stack 전체.

| PR | task | head | merge_commit | merged_at_utc | 특성 |
|---|---|---|---|---|---|
| #131 | task-2624 L3 classifier | 51baef22 | 4b3fde25 | 2026-05-22T08:52:52Z | L3 callback runtime classifier core · Gemini medium 자동수렴 1회 |
| #132 | task-2627 L1+L2 enforcement | 25ddbf4e | 94540f67 | 2026-05-22T09:47:42Z | L1+L2 enforcement · **credential 3-tier doctrine 첫 적용** (EXISTING_SYSTEM_IDENTIFIER passthrough) |
| #133 | task-2629 L4 wiring | 92b06188 | 9ee79286 | 2026-05-22T11:19:24Z | L4 wiring · HIGH/medium 자동수렴 + reasoned-resolve 혼합 |
| #134 | task-2630 E2E verification | 0565114e | 24fadbf8 | 2026-05-22T12:40:31Z | E2E verification · production code 변경 0 (test+fixture only) |
| #135 | task-2632 merge-ready classifier | 270ebfc4 | c80e875d | 2026-05-22T14:56:31Z | 7-round Gemini auto-remediation + AUTO_REMEDIATION_LOOP_BOUNDARY 적용 (round-7 reasoned-resolve 3건) |
| #136 | task-2633 dry-run executor | 83e88543 | b2932ce0 | 2026-05-22T15:48:39Z | dry-run only (`actually_executed=false`/`WOULD_*` 강제) · round-2 i18n reasoned-resolve |

**전부 PASS 케이스** — ground truth = `WOULD_MERGE` (auto_merge_candidate.v1).

---

## 3. 실패/HOLD 시나리오 (synthetic frozen evidence)

dry-run routing 분기 전체 커버. evidence 는 합성이지만 schema 정합 + spec §1~§4 doctrine 100% 적용.

| 시나리오 | verdict | expected_action | auto_remediation_route |
|---|---|---|---|
| `shadow_pass_pr131_l3_classifier` | PASS | WOULD_MERGE | — |
| `shadow_pass_pr132_l1l2_credential_passthrough` | PASS | WOULD_MERGE | — (EXISTING_SYSTEM_IDENTIFIER 정상 passthrough) |
| `shadow_pass_pr133_l4_wiring_mixed_remediation` | PASS | WOULD_MERGE | — |
| `shadow_pass_pr134_e2e_production_code_zero` | PASS | WOULD_MERGE | — |
| `shadow_pass_pr135_loop_boundary_resolved` | PASS | WOULD_MERGE | — (round-7 reasoned-resolve 후 0 unresolved) |
| `shadow_pass_pr136_dryrun_only` | PASS | WOULD_MERGE | — |
| `shadow_hold_ci_pending` | HOLD | WOULD_AUTO_REMEDIATE | `WOULD_WAIT_RECHECK` (AR_CI_PENDING) |
| `shadow_hold_gemini_evidence_stale` | HOLD | WOULD_AUTO_REMEDIATE | `WOULD_OWNER_GEMINI_REVIEW_NUDGE` (AR_GEMINI_EVIDENCE_STALE) |
| `shadow_hold_gemini_medium_within_expected` | HOLD | WOULD_AUTO_REMEDIATE | `WOULD_AUTO_FIX_REGRESS_PUSH_RESOLVE_RECHECK` (AR_GEMINI_MEDIUM_WITHIN_EXPECTED) |
| `shadow_hold_unresolved_medium_thread` | HOLD | WOULD_AUTO_REMEDIATE | `WOULD_RESOLVE_THREAD_RECHECK` (AR_UNRESOLVED_MEDIUM_THREAD) |
| `shadow_chair_blocking_secret` | CHAIR_REQUIRED | WOULD_ESCALATE_CHAIR | — (BLOCKING_SECRET ghp_/PEM detected) |
| `shadow_chair_admin_override_required` | CHAIR_REQUIRED | WOULD_ESCALATE_CHAIR | — (admin override 필요 = Critical7) |
| `shadow_chair_replacement_pr_runner_modified` | CHAIR_REQUIRED | WOULD_ESCALATE_CHAIR | — (forbidden path touched = Critical7) |
| `shadow_chair_loop_boundary_critical_repetition` | CHAIR_REQUIRED | WOULD_ESCALATE_CHAIR | — (동일 함수 HIGH 반복 boundary) |
| `shadow_unknown_evidence_missing` | UNKNOWN | WOULD_REGATHER | — (core evidence MISSING · INSUFFICIENT_EVIDENCE) |
| `shadow_unknown_lifecycle_incident_normal_miss` | UNKNOWN | WOULD_REGATHER | — (callback lifecycle delivery_outcome=normal_miss · root_cause unknown) |

총 16 fixture (6 PASS + 4 HOLD + 4 CHAIR_REQUIRED + 2 UNKNOWN).

---

## 4. evidence schema (frozen input)

각 fixture `evidence.json` 은 dryrun_route 의 입력 형식 100% 준수:
- `merge_ready_result` — classifier output (`verdict`, `reasons`, `evidence_completeness`, `scope`, `gates`, `auto_remediation_route?`)
- `pr_identity` — `{pr, head_sha, task_id, branch, base_sha?, merge_commit?}`
- (optional) `lifecycle` — callback lifecycle 2-axis snapshot (`delivery_outcome`, `normal_callback_miss_cause`, `root_cause_tags`)
- (optional) `credential_scan` — 3-tier classification (`blocking_secrets`, `existing_system_identifiers`, `net_new_identifier_exposure`)

evidence 는 historical/synthetic 무관 모두 **frozen** — bot live 호출 0.

---

## 5. expected schema (routing artifact)

`expected.json` 은 dryrun_route 의 출력 artifact 단언:
- `schema`: `merge_ready.auto_merge_candidate.v1` / `merge_ready.remediation_required.v1` / `merge_ready.hold_for_chair.v1`
- `actually_executed`: **false** (강제)
- `executor_action`: **WOULD_\*** 접두사 (강제)
- `pr_identity` 일관
- (HOLD) `auto_remediation_route` 정합
- (CHAIR_REQUIRED) `reasons` 명시
- (UNKNOWN) `reason=INSUFFICIENT_EVIDENCE`

---

## 6. 안전 불변식 (회장 verbatim)

- 모든 expected artifact `actually_executed=false` 강제
- 모든 expected `executor_action` WOULD_* 접두사 강제
- merge/push/PR/cron/branch-protection/admin-override/GitHub write 호출 0 (코드 경로 부재)
- live GitHub/git 의존 0 (frozen evidence only)
- replacement_pr_runner 수정 0 · finish-task.sh 수정 0
- expected_files 외부 수정 0

---

## 7. 필수 구현 (dev6 페룬 위임)

1. `tests/fixtures/dryrun_shadow/<scenario>/{evidence.json, expected.json, PROVENANCE.md}` (16 fixture · 신규)
2. `tests/regression/test_dryrun_executor_shadow_validation.py` (신규)
   - 모든 16 fixture 입력→출력 byte-equal 단언
   - `actually_executed=false` 100% 단언
   - `WOULD_*` 접두사 100% 단언
   - PASS/HOLD/CHAIR_REQUIRED/UNKNOWN 4 verdict 전부 커버 단언
   - idempotency 단언 (동일 입력 2회 byte-identical)
   - dryrun_route 함수 직접 호출만 — live GitHub 호출 0
3. `dryrun_route` 함수 자체 **수정 금지** — 본 task = shadow validation only
4. (선택) `tests/fixtures/dryrun_shadow/INDEX.md` — 16 시나리오 인덱스

## 8. 필수 regression

- `tests/regression/test_dryrun_executor_shadow_validation.py` 16/16 PASS
- full `tests/regression` new fail 0 (3 pre-existing test_stash_origin_audit_compat 무관)
- `tests/regression/test_merge_ready_dryrun_executor.py` 58/58 유지 (회귀 0)
- `tests/regression/test_merge_ready_classifier.py` 50/50 유지 (회귀 0)

---

## 9. expected_files (task-2634 범위)

- `tests/fixtures/dryrun_shadow/shadow_pass_pr131_l3_classifier/{evidence.json,expected.json,PROVENANCE.md}` (3)
- `tests/fixtures/dryrun_shadow/shadow_pass_pr132_l1l2_credential_passthrough/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_pass_pr133_l4_wiring_mixed_remediation/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_pass_pr134_e2e_production_code_zero/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_pass_pr135_loop_boundary_resolved/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_pass_pr136_dryrun_only/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_hold_ci_pending/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_hold_gemini_evidence_stale/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_hold_gemini_medium_within_expected/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_hold_unresolved_medium_thread/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_chair_blocking_secret/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_chair_admin_override_required/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_chair_replacement_pr_runner_modified/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_chair_loop_boundary_critical_repetition/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_unknown_evidence_missing/{...}` (3)
- `tests/fixtures/dryrun_shadow/shadow_unknown_lifecycle_incident_normal_miss/{...}` (3)
- `tests/regression/test_dryrun_executor_shadow_validation.py`
- (선택) `tests/fixtures/dryrun_shadow/INDEX.md`

총 49~50 files (48 fixture + 1 test + optional INDEX). 프로덕션 코드 0 변경.

---

## 10. 금지 (회장 verbatim)

- 실제 auto-merge 실행 금지
- real merge executor wiring 금지
- GitHub write 금지 (주석/리뷰/PR/머지 호출 0)
- branch protection 우회 금지
- admin override 자동화 금지
- NL intake 코드 구현 금지
- foreign dirty 정리 금지
- replacement_pr_runner.py 수정 금지
- finish-task.sh 수정 금지
- merge_ready_classifier.py 수정 금지 (입력 소비만)
- merge_ready_dryrun_executor.py 수정 금지 (본 task = shadow validation)
- expected_files 외부 수정 금지

---

## 11. 자동수렴 원칙

- Gemini medium/style + expected_files 내부 + Critical7 0 + credential expansion 0 → 자동수렴
- non-critical HIGH 도 expected_files 내부면 자동수렴, 단 동일 함수 HIGH 반복 시 LOOP_BOUNDARY → 회장 보고
- 회장 보고 트리거: Critical7 / credential expansion / expected_files 밖 수정 / admin override / replacement_pr fail / post-merge smoke fail

---

## 12. frozen anchor (D-SPEC-EXACTNESS)

- ANCHOR-1: "shadow validation = read-only · frozen evidence only · 실제 merge/push/PR/cron/admin-override 호출 0 · live GitHub 의존 0"
- ANCHOR-2: "16 fixture (6 PASS + 4 HOLD + 4 CHAIR_REQUIRED + 2 UNKNOWN) 전부 dryrun_route 입출력 byte-equal 단언"
- ANCHOR-3: "actually_executed=false 강제 · WOULD_* 접두사 강제 (100% 단언)"
- ANCHOR-4: "dryrun_route 본체 · merge_ready_classifier · replacement_pr_runner · finish-task.sh 전부 무수정 (fixture+test only)"
- ANCHOR-5: "real merge executor wiring 미승인 — 본 task = shadow validation 까지만"

---

## 13. finalize 프로토콜 (★ BOT App token 부재 — 로컬 한정)

1. base = 최신 origin/main b2932ce0 (PR #136 머지분) clean worktree
2. fixture 16 + regression test 1 (+ optional INDEX) 전부 PASS + full new-fail 0 + dryrun 58/58 유지 + classifier 50/50 유지
3. **로컬 commit만** (push/PR/merge 금지). finish-task.sh project_path 없이 로컬 종결
4. ANU normal completion callback — **반드시 독립 ANU key `c119085addb0f8b7`** · collector_role=ANU
5. callback envelope UTF-8 ≤3900 bytes · envelope 만 (task_id=task-2634 · 로컬 commit SHA · result_path · report_path · 16 fixture 검증 · regression 요약 · sha256)
6. executor 시작/종료 ts·로컬 commit SHA 명기

이후 ANU: 봇 로컬 commit fresh main 재적층 → OWNER push → PR open → Gemini 자동수렴 → 회장 보고 → 회장 merge 승인.
