# task-2777+2 (r2) — PR #257 Gemini MEDIUM micro-fix (epoch dt.timestamp OverflowError/OSError)

상태명: `TASK2777_PR257_GEMINI_MICROFIX2_DONE_ACTIVE_FALSE`
담당: dev2-team · 회장 위임("너가 진행"): 2026-06-28 (bounded +2 micro-fix 1회 · 초소형 · OWNER resolve 금지)
판정: **MERGE_CANDIDATE 보고만** (merge 금지 — ANU 독립검증 → fresh Gemini → CI → merge candidate 재판정)
브랜치: `task/task-2777-dev2` 위 commit 추가 → **PR #257 head 갱신** (새 PR 생성 0)

## 0. 배경
PR #257 +1 micro-fix(acb10894)로 이전 Gemini HIGH(systemctl/DBus) + MED 2(epoch tz, cron helper)는
코드로 해소(outdated). fresh Gemini 재평가가 **새 MEDIUM 1건**을 지적: `_epoch_age_seconds`의
`dt.timestamp()` 호출이 극단 날짜(예: `0001-01-01`, platform `time_t` 범위 밖)에서 `OverflowError`/
`OSError`를 던져 status command 전체 crash 가능. 조종석은 어떤 입력에도 crash 0 이어야 하므로 닫는다.

## 1. expected_files (외 변경 0)
- `scripts/anu_control_status.py` — `_epoch_age_seconds` 안전 처리 보정 (+12/-4)
- `tests/regression/test_anu_control_status_2777.py` — 회귀 3건 추가 (27→30)
- `memory/reports/task-2777-r2.md` — 본 r2 보고서
- `memory/events/task-2777+2.done` — 완료 마커

(`.github/**` · `scripts/finish-task.sh` · `dispatch/anu_pickup_driver.py` · `memory/state/**` ·
inbox/archive/quarantine 등 forbidden_paths 무변경. 작업지시서 `memory/tasks/task-2777+2.md` 미커밋.
effective diff = 2 코드/테스트 파일만 + 보고서/마커.)

## 2. 수정 — Gemini MEDIUM: epoch dt.timestamp() OverflowError/OSError 안전 처리

**결함(이전, anu_control_status.py:327~333):** ISO8601 파싱 후 `dt.tzinfo` 검사와
`dt.timestamp()` 호출이 **try-except 밖**. tz-aware 극단 날짜에서 일부 플랫폼은 `dt.timestamp()`가
`OverflowError`/`OSError`(time_t 범위 밖)를 던질 수 있어 → status command 전체 crash + traceback 노출 가능.

**보정:**
- `dt.tzinfo` 검사 + `dt.timestamp()` 호출을 **try-except 블록 내부**로 이동.
- `except (OverflowError, OSError)` → 안전하게 `EPOCH_WARN_PARSE`(`EPOCH_PARSE_UNAVAILABLE`) 반환.
- crash 0 · traceback 0 · raw 값(원문) 유출 0. naive(`EPOCH_WARN_NAIVE`)/UTC-aware/future(`EPOCH_IN_FUTURE`)
  /numeric/parse-fail 기존 분기 무회귀(naive 는 timestamp 도달 전 조기 반환 유지).
- docstring 에 극단 날짜 OverflowError/OSError → `EPOCH_PARSE_UNAVAILABLE` 동작 명시.

**플랫폼 주의(정직 보고):** 이 빌드(64-bit Linux)에서는 tz-aware 객체의 `datetime.timestamp()`가
순수 Python 산술(`(self-_EPOCH).total_seconds()`)로 계산되어 `0001-01-01`/`9999-12-31` 입력에도
예외 없이 큰 age 를 돌려준다(crash 0 이미 충족). 따라서 except 절은 **time_t 범위가 좁은 플랫폼에
대한 방어적 하드닝**이며, 실제 except 동작은 monkeypatch 로 결정적 검증한다(아래 테스트 3).

## 3. 테스트 (회귀 27→30, 전부 PASS)
- `test_epoch_extreme_date_no_crash` — `0001-01-01`/`9999-12-31` tz-aware 입력 → crash 0,
  (None+`EPOCH_PARSE_UNAVAILABLE`) 또는 (int age, no warn/`EPOCH_IN_FUTURE`) 허용, raw 유출 0.
- `test_epoch_timestamp_overflow_oserror_caught` — monkeypatch 로 `timestamp()`가
  `OverflowError`/`OSError`를 던지도록 강제 → except 절이 잡아 None+`EPOCH_PARSE_UNAVAILABLE` 반환(결정적).
- `test_epoch_extreme_date_surfaces_in_build_no_crash` — state 파일에 극단 날짜 epoch 가 있어도
  `build_status` crash 0 · raw 유출 0 · read-only.
- 기존 numeric/naive/aware/future/parse-fail/build-surface 무회귀.

## 4. 검증 결과
- `python3 -m py_compile scripts/anu_control_status.py` → PASS
- `test_anu_control_status_2777.py` → **30 passed**
- 인접 회귀: `2776`(6) · `2775`(63) · `2760`(36) · `2721`(34) → **139 passed**
- read-only invariant 유지: 테스트는 `tmp_path`만 사용 — 실 파일 생성 0 · 수정 0 · evidence append 0 ·
  flag write 0 · driver execution 0. ACTIVE=false · flags OFF 유지.
- effective diff expected_files 안 · raw key/secret 0 · systemd 조작 0 · cron 신규 0 · real fire 0.

## 5. bounded fix doctrine
이번이 epoch/timestamp axis 관련 **마지막 bounded micro-fix(+2)**. 이후 동일 axis finding 재발 시
미세패치 중단 → 구조 분리 보고(`..._EPOCH_STRUCTURE_REDESIGN_REQUIRED`).

## 6. 판정 / 다음 단계
**MERGE_CANDIDATE (merge 금지).** PR #257 head 갱신만 수행. ANU 독립검증 → fresh Gemini 재평가 →
CI 11/11 → merge candidate 재판정은 ANU/회장 권한. dev2 는 merge/auto-merge/flag ON/driver/real fire 미수행.
