# task-2561 — Track B baseline noise cleanup (회장 §명시 2026-05-12 2순위, Lv.2)

## 회장 §명시 형식 보고

- **Track**: B (baseline noise cleanup)
- **상태**: 작업 완료 (PR 단계 진행)
- **task_id**: task-2561
- **수정·PR 여부**: 수정 완료, PR 생성 예정
- **expected_files**: 7건 1:1 strict (아래 §expected_files)
- **forbidden**: 0건 (아래 §forbidden_zero_check)
- **Gemini**: PR 생성 후 owner_trigger 자동 / scheduler 자동 사용 (회장 수동 0)
- **CI**: PR 단계에서 11/11 + CLEAN 확인
- **핵심 evidence**: Option A (scope-guard) primary + Option B (정적 fixture) 보조 합성 — Option C (delete) **채택 안 함**
- **회장 결정 필요 여부**: N (회장 §명시 우선순위 그대로 적용)
- **다음 액션**: BOT identity commit → push → BOT PR → Gemini fresh → merge → smoke + reconcile

---

## 본질 (회장 §명시 Track B)

`anu_v2/tests/test_post_merge_smoke_runner_2539.py::test_clean_origin_main_base_assertion` (lines 584-627) 의 hard-coded ALLOWED_PATHS mis-scope 문제를 scope-guard 로 해결.

근거: `memory/events/baseline-noise-diagnosis.20260512T142519Z.json` (Track D 결과).

---

## 필수 구현 4 (회장 §명시) — 완료 확인

| # | 구현 | 상태 | 위치 |
|---|------|------|------|
| 1 | scope guard 추가 (task-2539+1 fixture context만 동작) | DONE | `_is_task_2539plus1_scope()` helper |
| 2 | unrelated branch diff 강제 매칭 X | DONE | out-of-scope → `pytest.skip` |
| 3 | 기존 task-2539+1 보호 의도 유지 | DONE | in-scope 시 원본 ALLOWED_PATHS assert 그대로 |
| 4 | PR #110 task-2550+1 같은 후속 브랜치 false failure 0 | DONE | deterministic skip 회귀 테스트로 박제 |

---

## 권장 방식 — Option A primary + Option B 보조

- **Option A 채택 (primary)**: `_is_task_2539plus1_scope()` scope-guard 추가 — task-2539+1 worktree 외부에서 deterministic skip
- **Option B 보조**: `anu_v2/tests/fixtures/baseline_noise_repro_2561.json` 정적 fixture + 회귀 4건으로 noise mechanism 영구 박제
- **Option C 거부**: test 삭제 — 회장 §명시 "test 삭제 우선 선택 0" 금지

### scope-guard OR 매칭 3조건

1. `os.environ.get("TASK_ID") == "task-2539+1"` — dispatch.py env
2. `git rev-parse --abbrev-ref HEAD` 가 `task/task-2539+1` prefix 매칭
3. `WORKSPACE_ROOT.name` 이 `task-2539+1` 포함 (worktree dir basename)

→ 셋 다 false 면 `pytest.skip(deterministic reason)`, live `git diff` 호출 0.

---

## 필수 테스트 4 (회장 §명시) — 검증 결과

| 테스트 | 검증 내용 | 결과 |
|--------|----------|------|
| task-2539+1 fixture context 기존 검증 유지 | `test_clean_origin_main_runs_under_task_2539plus1_scope_with_clean_diff` (in-scope + clean diff → PASS) | PASS |
| unrelated branch diff deterministic fail 0 | `test_clean_origin_main_skipped_outside_task_2539plus1_scope` (out-of-scope → SKIP, live git 호출 0) | PASS |
| mis-scoped ALLOWED_PATHS noise 재현 fixture PASS | `test_baseline_noise_fixture_2561_present_and_well_formed` (정적 fixture 검증) | PASS |
| post_merge_smoke_runner 기존 회귀 PASS | 12 기존 + 4 신규 = 16 test, anu_v2/tests/ 전체 451 passed + 1 skipped (의도된 scope-guard skip) | PASS |

### 추가 in-scope 보호 의도 회귀

- `test_clean_origin_main_in_scope_detects_forbidden_path` — in-scope + forbidden path → AssertionError 정상 발생 (task-2539+1 보호 의도 유지 검증) → PASS

---

## expected_files (7건, 1:1 strict)

1. `anu_v2/tests/test_post_merge_smoke_runner_2539.py` — 수정 (+170 lines, scope-guard + 4 회귀)
2. `anu_v2/tests/fixtures/baseline_noise_repro_2561.json` — 신규
3. `memory/reports/task-2561.md` — 이 파일
4. `memory/events/task-2561.dispatch-decision.json` — 신규
5. `memory/plans/tasks/task-2561/plan.md` — 신규
6. `memory/plans/tasks/task-2561/context-notes.md` — 신규
7. `memory/plans/tasks/task-2561/checklist.md` — 신규

---

## forbidden_zero_check (회장 §명시)

| 항목 | 검증 |
|------|------|
| `anu_v2/post_merge_smoke_runner.py` 본체 변경 | 0 ✓ |
| PR #98~#111 branch 변경 | 0 ✓ |
| task-2558 expected_files 재수정 | 0 ✓ |
| task-2560 (FUC-4) 영역 PR 섞기 | 0 ✓ |
| task-2562 (G4) 영역 PR 섞기 | 0 ✓ |
| 다른 anu_v2 modules 변경 | 0 ✓ |
| dashboard/ 변경 | 0 ✓ |
| 회장 수동 `/gemini review` | 0 ✓ |

---

## 14단계 standard 진행

| # | 단계 | 상태 |
|---|------|------|
| 1 | cokacdir current time | DONE |
| 2 | worktree `task-2561-dev2` 생성 | DONE |
| 3 | plan/context/checklist 작성 | DONE |
| 4 | test 수정 + fixture 신설 | DONE |
| 5 | pytest 회귀 검증 (451 passed + 1 skipped) | DONE |
| 6 | BOT identity commit | IN-PROGRESS |
| 7 | push to origin | PENDING |
| 8 | BOT PR 생성 (admin override 0) | PENDING |
| 9 | Gemini fresh (owner_trigger 또는 scheduler 자동) | PENDING |
| 10 | unresolved 0 확인 | PENDING |
| 11 | CI 11/11 통과 | PENDING |
| 12 | CLEAN 상태 확인 | PENDING |
| 13 | BOT squash merge (admin override 0) | PENDING |
| 14 | post-merge smoke + reconcile + 보고서 + .done | PENDING |

---

## 완료 5조건 (회장 §명시) — 진행도

- [x] baseline-noise-diagnosis.json 근거 반영 (Track D 결과)
- [x] regression PASS (anu_v2/tests/ 451 passed, 1 skipped — scope-guard 의도)
- [x] expected_files strict (7건 1:1)
- [x] forbidden path 0
- [ ] BOT merge — PR 단계 진행

---

## 핵심 코드 변경 요약

```python
# anu_v2/tests/test_post_merge_smoke_runner_2539.py:

# (1) os import 추가
import os

# (2) scope-guard 헬퍼 신설
def _is_task_2539plus1_scope() -> bool:
    """task-2539+1 worktree/dispatch 컨텍스트 여부 (OR 매칭)."""
    if os.environ.get("TASK_ID") == _TASK_2539PLUS1_ID:
        return True
    # git branch + worktree basename fallback ...
    return False

# (3) test_clean_origin_main_base_assertion 진입부에 가드
def test_clean_origin_main_base_assertion() -> None:
    if not _is_task_2539plus1_scope():
        pytest.skip("out-of-scope: ... (task-2561 scope-guard, deterministic)")
    # 기존 ALLOWED_PATHS assertion 그대로 유지 ...

# (4) 회귀 테스트 4 추가
def test_baseline_noise_fixture_2561_present_and_well_formed(): ...
def test_clean_origin_main_skipped_outside_task_2539plus1_scope(monkeypatch): ...
def test_clean_origin_main_runs_under_task_2539plus1_scope_with_clean_diff(monkeypatch): ...
def test_clean_origin_main_in_scope_detects_forbidden_path(monkeypatch): ...
```
