# [DESIGN DRAFT — HOLD] C. bounded_loop_decider.py 구현 설계

> ★ 설계 **초안**입니다. runtime 구현 금지(회장 승인 전). 코드 변경 0. 이 문서는 decision-as-data → 코드 자동판정 전환 설계만.

## 목적
ANU 가 prompt 해석으로 수행하던 bounded loop 판단(자동수렴 / 예산 / CHAIR_REQUIRED / LOOP_BOUNDARY)을 **결정론적 코드**로 전환. 입력 = 이미 박제 중인 decision-as-data JSON artifacts. 출력 = 다음 행동 enum + 근거.

## 입력 contract (이미 존재 — forward-spec substrate)
1. `memory/events/<task>.bounded-loop-decision.json` (schema `bounded_loop_decision_v1`, 필수 13필드)
2. `memory/events/<task>.finding-attribution.json` (schema `finding_attribution_v1`)
3. `memory/state/automation_capability_matrix.json` (schema `automation_capability_matrix_v1`)

## 출력 (decision verdict)
```
BoundedLoopVerdict {
  verdict: enum[ AUTO_CONTINUE | MERGE_READY_CANDIDATE | CHAIR_REQUIRED
                | LOOP_BOUNDARY | DEFER_EVIDENCE_RESOLVE | BLOCKED_BY_CAPABILITY ]
  reasons: list[str]               # 결정 근거 (감사 가능)
  next_allowed_actions: list[str]  # decision artifact 에서 전파
  forbidden_actions: list[str]
  remediation_round_after: int
  chair_required_reason: str|null
}
```

## 판정 규칙 (deterministic — prompt 해석 대체)
입력 decision + finding-attribution 으로 다음 순서 평가(first-match):
1. **Critical7 매칭** OR **신규 HIGH/CRITICAL(finding severity ∈ {HIGH,CRITICAL} AND reviewed_head==current_head AND dismissed=false)** → `CHAIR_REQUIRED` (자동 fix 0회). chair_required_reason=`NEW_HIGH_OR_CRITICAL` / `CRITICAL7`.
2. **credential/permission 확장 OR expected_files 밖 OR activation/systemd/wake 요구** → `CHAIR_REQUIRED`.
3. **same blocker 반복 ≥2** (동일 finding_id 계열 / 동일 함수·file-boundary 연속) → `LOOP_BOUNDARY` → CHAIR_REQUIRED.
4. **severity=MEDIUM AND remediation_round < max_rounds(2)** → `AUTO_CONTINUE` (code_fix 허용, round+1).
5. **severity=MEDIUM AND remediation_round ≥ max_rounds(2)** → `DEFER_EVIDENCE_RESOLVE` (코드수정 0, backlog/defer).
6. **style/false-positive 분류** → `DEFER_EVIDENCE_RESOLVE` (코드수정 0, evidence resolve).
7. **capability WIRED=false 필요** (자동 push/merge/gemini-trigger 결선 부재) → `BLOCKED_BY_CAPABILITY` (session-bound polling 금지).
8. **모든 gate GREEN + fresh unresolved HIGH/CRITICAL=0 + diff⊆expected_files + forbidden=0 + ANU key=0** → `MERGE_READY_CANDIDATE` (merge 자체는 항상 회장 승인).

## 불변식 (코드 강제)
- merge 실행은 decider 권한 밖 — 항상 회장 승인 게이트.
- activation/install/wire/wake 는 decider 가 절대 true 로 못 바꿈 (read-only on capability matrix).
- ANU key full literal 출력 0.
- decider 는 **판정만**; push/merge/dispatch 부수효과 0 (pure function). 부수효과는 별도 wired executor(회장 승인) 책임.

## 모듈 위치 후보 (회장 확정 필요)
- `dispatch/bounded_loop_decider.py` (신규, pure decision module) + `tests/regression/test_bounded_loop_decider_*.py`
- 결선(누가 호출?) = ci_gemini_watcher_runner / CI_WATCH_HANDOFF watcher — **별도 wiring task** (이번 설계 범위 밖).

## 단계화
- **Phase 1 (설계, 현재)**: schema 확정 + 판정 규칙 표 + 불변식. 코드 0.
- **Phase 2 (구현, 회장 승인 후)**: pure decider + 단위테스트(8 verdict fixture). active=false / wired=false 유지.
- **Phase 3 (결선, 별도 승인)**: watcher 가 decider 호출 → verdict 기반 자동수렴. 이때만 WIRED 승격.

## 현재 capability 상태 (과장 금지)
`bounded_loop_decider`: IMPLEMENTED=false / VERIFIED=false / WIRED=false / ACTIVE=false. BLOCKED_BY_POLICY(runtime 회장 승인 전). decision JSON 은 forward-spec/substrate. ANU 활성 세션이 위 규칙을 **수동** 적용 중 — 코드 자동화 아님.

## consumer contract 구체화 (field → verdict 매핑표)
`bounded_loop_decision_v1` + `finding_attribution_v1` 입력 필드 → verdict 결정(decider 가 읽는 정확한 필드):
- `finding_attribution.findings[].severity ∈ {HIGH,CRITICAL}` AND `.dismissed=false` AND `.reviewed_head_sha == head_sha`(fresh) → `CHAIR_REQUIRED`
- `finding.classification == 'CRITICAL7'` → `CHAIR_REQUIRED`
- `decision.forbidden_actions` 에 해당하는 요구(activation/credential/expected_files 밖) 감지 → `CHAIR_REQUIRED`
- `finding_id` 반복 카운트(같은 id 계열) ≥2 → `LOOP_BOUNDARY`
- `severity==MEDIUM` AND `remediation_round < max_rounds` → `AUTO_CONTINUE`
- `severity==MEDIUM` AND `remediation_round >= max_rounds` → `DEFER_EVIDENCE_RESOLVE`
- `classification ∈ {style, false_positive}` → `DEFER_EVIDENCE_RESOLVE`
- capability `WIRED==false` 가 필요한 자동행위 → `BLOCKED_BY_CAPABILITY`
- 전 gate green(`code_fix_applied` + fresh unresolved HIGH/CRITICAL=0 + diff⊆expected_files + forbidden=0 + ANU key=0) → `MERGE_READY_CANDIDATE`

## test-plan (8 verdict fixtures — Phase 2 구현 시)
1. fresh HIGH → CHAIR_REQUIRED
2. Critical7 → CHAIR_REQUIRED
3. activation/credential 요구 → CHAIR_REQUIRED
4. same finding_id ×2 → LOOP_BOUNDARY
5. medium round1 → AUTO_CONTINUE
6. medium round2(소진) → DEFER_EVIDENCE_RESOLVE
7. false_positive → DEFER_EVIDENCE_RESOLVE
8. all-green → MERGE_READY_CANDIDATE
+ 불변식 fixture: merge 부수효과 0 / activation 절대 미변경 / ANU key 출력 0.

## 상태
DESIGN_DRAFT_HOLD — auto_continue_allowed=false. chair_required_reason: runtime 구현 회장 승인 전. (consumer contract + 8 verdict test-plan 정교화 완료 — Phase 2 구현 spec-ready upon 회장 승인)
