# task-2775+2 완료 보고 — PR #255 same-branch +2 micro-fix (B안, ACTIVE=false, no-merge)

> 팀: dev2-team (오딘) | 상태: `TASK2775_PLUS2_ACTIVE_EPOCH_MISSING_LIMITED_MODE_MICROFIX_DONE_ACTIVE_FALSE`
> 작성: 2026-06-26 23:13 KST | 검증 레벨: normal | 결과: **PASS (MERGE_CANDIDATE, 머지 보류)**

## SCQA 요약

**S (Situation)**: PR #255(branch `task/task-2775-dev2`)의 `limited_activation_bound_gate()`는 task-2775+1에서 epoch-scope N 카운트를 보정하고, epoch 부재 fail-closed를 `is_activated_fn` 명시 주입 시에만 발동하도록 정책을 게이트+테스트로 고정했다(기존 14+ 테스트 PASS).

**C (Complication)**: 그러나 production `main()`의 게이트 호출부(line 2136)가 `is_activated_fn`을 주입하지 않아, 실제 limited activation 가동(`p0b_driver_enabled=enabled`) 중 `p0b_activation_epoch`가 없거나 손상되면 **fail-closed 없이 조용히 pass-through → 무기준(N/T 없이) scan 진행** 가능. (ANU 독립검증 `ACTIVE_EPOCH_MISSING_PRODUCTION_GAP_ACTIVE_FALSE`)

**Q (Question)**: legacy scan_once / test-2760 라우팅을 깨지 않으면서, 실제 limited/fire-capable 가동 시에만 epoch 부재/손상 fail-closed를 production 실경로에서 닫을 수 있는가?

**A (Answer)**: **B안 채택**. 기존 `main(*, activation_intended: bool=False)` 신호를 사용해, `activation_intended=True`(실제 limited/fire-capable activation) 경로에서만 게이트에 `is_activated`를 주입한다. `activation_intended=False`(production 기본·legacy·test-2760) → 미주입 → 현행 pass-through 100% 보존. 단일 호출부 1곳 결선 + 회귀 테스트 3개. 임의 확장(새 flag/넓은 activation 정의) 0.

## 구현 (expected_files 2개만)

### 1) `dispatch/anu_pickup_driver.py` (main 호출부 1곳, +14/-1)
```python
_bound = limited_activation_bound_gate(
    CANONICAL_ROOT,
    is_activated_fn=(
        (lambda: is_activated(CANONICAL_ROOT)) if activation_intended else None
    ),
)
```
- `activation_intended=True`일 때만 `is_activated`(호출 시점 모듈 `CANONICAL_ROOT` 명시 읽음)를 주입.
- ★ bare `is_activated`의 default-arg는 정의 시점 root 바인딩이라 root 변경을 못 따름 → lambda로 감싸 line 2214 `is_activated(CANONICAL_ROOT)`와 동일 root 의미로 일관화(이 보정으로 L1 실경로 fail-closed가 실제 발동).
- 게이트는 line 2136(launcher/callback/governor build·scan **이전**) 위치 → 발동 시 fire 0·governor/launcher 미호출로 단락.
- `limited_activation_bound_gate` 본체·`read_activation_epoch`·governor/runner/launcher·test-2760 무수정.

### 2) `tests/regression/test_limited_activation_bounds_2775.py` (+136, 테스트 22~24 추가)
- **22** `test_main_active_intended_epoch_absent_fail_closed`: production main() 실경로, intended=True+active+epoch 부재 → `disabled` 자동전환 + rc=0 + scan_once/scan_live/launcher/governor **미호출**(fire 0).
- **23** `test_main_active_intended_epoch_corrupt_fail_closed`: intended=True+active+epoch 손상(파싱불가) → `disabled` + fire 0.
- **24** `test_main_legacy_active_epoch_absent_not_fail_closed`: intended=False(legacy/test-2760)+active+epoch 부재 → fail-closed **아님**, `enabled` 유지 + scan_once 도달(무손상).
- 기존 테스트 1~21 무수정.

## 테스트 결과 (전부 PASS)
- **2775 bounds**: 24 passed (기존 21 + 신규 3), 0.20s.
- **test-2760 무손상**: `test_p0b_event_strategy_2760` + `_wiring_2760` = **36 passed**.
- **driver 회귀**: `test_anu_pickup_driver_2721`(main entry) + `_2744` + `_2746` = **61 passed**.
- `py_compile` PASS (driver + test). expected_files 밖 수정 **0**.

## L1 스모크테스트 결과 (실프로세스, ALL_L1_PASS)
- 서버 재시작: 해당없음(subprocess 정제형 entrypoint).
- API 응답 확인: 해당없음. 대신 production `main()` 실프로세스 직접 실행:
  - `[active+epoch부재]` intended=True → rc=0, flag `enabled`→`disabled`, stderr `NOOP_ACTIVE_EPOCH_MISSING_AUTO_DISABLED` → **PASS**
  - `[active+epoch손상]` intended=True → rc=0, flag `disabled`, fire 0 → **PASS**
  - `[legacy무손상]` intended=False → rc=0, flag `enabled` 유지, scan_once 도달 → **PASS**
- 스크린샷: 해당없음(CLI 백엔드).

## PR / SHA 증거
- PR **#255 유지**(새 PR 생성 0). state=OPEN, mergeable=MERGEABLE, base=main.
- base(main): `e8925d91`
- +2 parent(이전 head): `29ec5819`
- **new head**: `20875ef6` (push 완료: `29ec5819..20875ef6 task/task-2775-dev2`)
- files_changed = 정확히 2개(`dispatch/anu_pickup_driver.py`, `tests/regression/test_limited_activation_bounds_2775.py`).

## ACTIVE=false / 금지사항 준수 증거
- canonical `memory/state/p0b_driver_enabled` == `disabled`(OFF), `p0b_activation_epoch` 부재, `p0b_callback_launch_enabled` 부재(OFF) → **ACTIVE=false 유지**.
- real fire 0 / canary 0 / recurring 0 / backlog consumption 0 / systemd enable·start 0 / activation flag 생성 0 / merge 0 / 새 PR 0.
- 모든 fail-closed write는 **테스트 tmp_path 격리** 내에서만 발생(canonical state 무변경).

## 모델 사용 기록
- 토르(백엔드, driver 결선): general-purpose(sonnet). driver 호출부 1곳.
- 헤임달(테스터, 테스트 22~24): general-purpose(sonnet).
- 오딘(팀장, Opus): 설계·통합·L1 실경로 보정(is_activated lambda root 바인딩, default-arg 결함 1건 직접 수정 — Sonnet 산출물의 환경 결함을 통합 단계에서 닫음).
- haiku 미사용.

## 발견 이슈 및 해결
- **이슈**: 초기 결선(`is_activated` bare 주입)에서 test 22/23 FAIL — 게이트 무인자 호출 시 default-arg root가 monkeypatch된 root를 못 읽어 active=False로 오판 → preflight `CANARY_PATHS_REQUIRED` STOP, fail-closed 미발동.
- **해결**: `lambda: is_activated(CANONICAL_ROOT)`로 호출 시점 모듈 글로벌 root 읽기. 재실행 24 passed + L1 ALL_PASS. (프로덕션에선 root 동일이라 무영향이나, 의미상으로도 line 2214와 일관되게 정정.)

## MERGE_CANDIDATE 판단
- **MERGE_CANDIDATE 가능: Yes (단, 머지 보류).** 회장 명시 승인 전까지 PR #255 OPEN 유지.
- 후속: ANU 독립검증 → fresh-head Gemini 리뷰 → CI 확인 → MERGE_CANDIDATE 최종 판정(회장 머지 판단). 본 보고는 **머지 미수행**.

### 머지 판단
- 머지 필요: **No (보류 — manual merge_policy, 회장 승인 대기)**
- 브랜치: `task/task-2775-dev2` (PR #255)
- 워크트리 경로: `/home/jay/workspace/.worktrees/task-2775-dev2`
- 머지 의견: 24+36+61 회귀 PASS·L1 실경로 ALL_PASS·expected_files 2개 한정·ACTIVE=false 유지로 코드 품질/안전 충족. 단 본 task는 no-merge 한정승인이므로 ANU 독립검증/Gemini/CI 후 회장 판단 필요.
