# task-2775+8 — PR #255 same-branch: ledger newest-first reverse scan (진짜 chunk reverse iterator) micro-fix (ACTIVE=false)

상태명: `TASK2775_PLUS8_REVERSE_LEDGER_SCAN_MICROFIX_APPROVED_FOR_DEV2_ACTIVE_FALSE`
담당: dev2-team (PR #255 / branch `task/task-2775-dev2` 소유)
회장 승인: 2026-06-26 — **+8 micro-fix 1회 (=+7 미완성 reverse scan 보정).**
★ HIGH 재발 아니므로 구조 재설계 자동 전환 조건은 엄밀히 미발동. 단 efficiency 축 반복이므로 **+8은 "+7
미완성 보정"으로 딱 1회만** 허용. **+8 이후 efficiency/O(N)/ledger scan finding이 HIGH든 MEDIUM이든 다시
나오면 → micro-fix 중단, 즉시 `LEDGER_COUNT_STRUCTURE_REDESIGN_REQUIRED_ACTIVE_FALSE` 보고.**
★ 이 승인은 **merge / activation / real fire / systemd enable·start / flag 생성 승인이 아님.** ACTIVE=false.

## 배경 (fresh-head 210ff3ce Gemini MEDIUM driver:538)
+7에서 `count >= max_count` early-stop·epoch 이전 break 없음·under-count 0·117 passed는 확보됐으나, 실제
스캔 방향은 **여전히 순방향(oldest-first)**이라 active window(파일 끝)에 도달하기 전 historical entry를 전부
스캔하는 구조가 남음. Gemini MEDIUM: *"O(N) Ledger Scan from the Beginning — even with max_count early-break,
must still scan past all historical entries before reaching the active window."* → reverse 읽기로 O(1).

## 수정 목표
Gemini MEDIUM driver:538 — `_count_active_window_pickups`가 ledger를 **oldest-first로 읽어 active window 도달
전 historical entry를 전부 스캔하는 문제를 닫는다**.

## 핵심 구현 원칙
- `_count_active_window_pickups`는 ledger를 **newest-first로 읽어야 한다.**
- stop 조건은 계속 **`count >= max_count` 하나만** 사용.
- ★ **`processed_at < activation_epoch`를 만났다는 이유로 break 금지**(단조성 가정 금지).
- **correctness > efficiency.** N 미만이면 **under-count 없이 정확**해야 함.
- `processed_at` 부재 / 파싱 실패 / naive timestamp 제외 정책 **무회귀**.

## ★ 중요 금지 (회장 verbatim — "가짜 reverse" 금지)
- `reversed(path.read_text().splitlines())` **금지**.
- `list(file)` 후 reversed **금지**.
- `readlines()`로 전체 파일을 메모리에 올린 뒤 reversed **금지**.
- 전체 ledger를 먼저 다 읽은 뒤 뒤집는 방식 **금지**.
- 이유: 이런 방식은 파일 I/O·메모리 측면에서 **여전히 O(N)**이라 Gemini 지적을 못 닫는다(닫은 척만 됨).

## 허용 방향 (진짜 reverse)
- **파일 끝에서부터 chunk 단위로 읽는 reverse line iterator**를 추가.
- 이 iterator는 **필요한 line만 뒤에서부터 yield**.
- `max_count=3`에 도달하면 **더 이상 과거 chunk를 읽지 않아야** 함.
- ★ 구현이 과도하게 커지거나 driver/test **2파일 범위를 넘어가면 STOP 보고**.
- ★ dev2가 **안전한 bounded reverse iterator를 2파일 안에서 닫을 수 없다고 판단하면** →
  `LEDGER_COUNT_STRUCTURE_REDESIGN_REQUIRED_ACTIVE_FALSE`로 보고(억지 구현 금지).

## 범위 (엄수)
- **PR #255 같은 브랜치(`task/task-2775-dev2`) 위 commit 추가**. **새 PR 생성 금지**(불가 시 STOP).
- expected_files **2개만**: `dispatch/anu_pickup_driver.py` · `tests/regression/test_limited_activation_bounds_2775.py`.
- **수정 금지**: preflight(`anu_activation_preflight.py`) / **test-2760** / governor / runner / launcher /
  owner-proof / entrypoint shell·systemd / `.github/**` / `scripts/finish-task.sh` / production flag 파일.
- **금지**: merge / activation / real fire / `systemctl enable·start` / activation flag 생성 / canary /
  recurring / backlog consumption / **Gemini thread 임의 resolve**.

## 필수 테스트 (test_limited_activation_bounds_2775.py)
- ledger **앞쪽 historical entry 대량 + 끝쪽 active window 3건**인 경우 parse/read가 **active window 근처에서
  멈추는지** 확인.
- **단순 readlines() 전체 read 방식이 아님**을 테스트 또는 코드 근거로 확인.
- `max_count=3` 도달 시 **과거 historical entry를 읽지 않음**.
- N 미만일 때는 **끝까지 읽어 정확한 count 반환**(under-count 0).
- epoch 이전/이후 mixed ledger에서 **epoch-scope 의미 무회귀**.
- `processed_at` 부재 / 파싱 실패 / naive 제외 정책 **무회귀**.
- **+7 thread5 fail-closed 테스트 무회귀** · **+7 thread4 0644 테스트 무회귀**.
- **2775 bounds 전체 PASS** · **test-2760 전체 PASS** · **2721 driver 인접 회귀 PASS** · `py_compile` PASS ·
  expected_files 밖 수정 **0**.

## ★ 메타 가드
+8은 **+7에서 빠뜨린 reverse scan 완성으로만** 허용. **+8 fresh-head Gemini 재리뷰에서 efficiency/O(N)/ledger
scan 계열 finding이 HIGH 또는 MEDIUM으로 다시 나오면** → +9 micro-fix 승인 금지, 즉시
`LEDGER_COUNT_STRUCTURE_REDESIGN_REQUIRED_ACTIVE_FALSE` 보고. 그 경우 다음 방향 = ledger 재계산이 아닌
**별도 상태화**(activation epoch baseline offset / active-window counter marker / consumed schedule id set /
crash-safe update / stale·corrupt marker fail-closed).

## 결과 보고 (필수)
- PR #255 head · base/head SHA · **diff 파일 수**.
- **reverse scan 구현 방식** · **전체 read 후 reversed가 아님을 입증하는 근거**.
- **max_count 도달 후 과거 ledger를 읽지 않는다는 테스트 결과**.
- correctness 무회귀 · 2775/2760/2721 테스트 결과.
- ACTIVE=false / real fire 0 증거 · **fresh-head Gemini 재리뷰 필요 여부**.

## 완료 처리 + ANU callback (필수)
- 완료 시 `memory/events/task-2775+8.done` + `memory/reports/task-2775+8.md`.
- 봇 idle 전 **ANU callback 필수**. collector=ANU, owner_key=`c119085addb0f8b7`, self-key 금지. callback prompt
  UTF-8 **≤3900 bytes**, envelope 만(task_id·PR#255·new head sha·result_path·report_path·one-line). **merge 금지.**
- PASS 나와도 **머지 금지** — ANU 독립검증 → fresh-head Gemini 재리뷰 → CI 확인 → MERGE_CANDIDATE로만 보고.

## 진행
dev2는 chunk 기반 reverse line iterator로 newest-first scan 구현·테스트(real fire 0)·로컬검증 후 branch push로
**PR #255 갱신**, 보고서 + .done + ANU callback으로 마감. ANU가 이후 독립검증/Gemini 재리뷰/CI 확인.

## allowed_resources (본 task의 capability)

```yaml
allowed_resources:
  paths:
    - "dispatch/anu_pickup_driver.py"
    - "tests/regression/test_limited_activation_bounds_2775.py"
    - "memory/reports/task-2775+8.md"
    - "memory/events/task-2775+8.done"
  forbidden_paths:
    - ".github/**"
    - "memory/events/*.cron-*"
    - "scripts/finish-task.sh"
    - "dispatch/anu_activation_preflight.py"
    - "tests/regression/test_*2760*.py"
    - "utils/spawn_safety_governor.py"
    - "dispatch/anu_result_pickup_runner.py"
    - "dispatch/anu_callback_launch_audit.py"
    - "dispatch/anu_owned_callback_enforcement.py"
    - "memory/state/p0b_driver_enabled"
    - "memory/state/p0b_callback_launch_enabled"
  commands:
    - "pytest"
    - "python3 -m py_compile"
    - "git"
    - "gh"
  merge_policy: "manual"
  ttl_hours: 24
```