# PR242_HOLD_LEDGER_AXIS_SPLIT_REQUIRED packet (설계 보고 전용, 260617)

상태: `PR242_HOLD_LEDGER_AXIS_SPLIT_REQUIRED_PACKET_READY_ACTIVE_FALSE` · ACTIVE=false · ★설계 보고만 — 구현/PR/push/close/merge 0

## 0. 판정 고정 (회장)
PR #242 HOLD·merge-ready 아님. HIGH 1 + 같은 ledger robustness 축 반복 = whack-a-mole 재발(task-2760→2760+1→#242 "방어 추가→새 엣지"). 추가 bounded fix 금지. ledger compaction/self-healing/robustness는 event strategy PR 범위에서 분리. event strategy = "ledger 완벽 수정 PR"이 아니라 "move-first 불변식 보존 PR"로 재정의.

대상 = task/task-2760+1 head **0eebecbd**, `dispatch/anu_pickup_driver.py`(라인은 해당 branch 기준).

## 1. PR #242에서 제거해야 할 ledger compaction/robustness 범위
| 항목 | 위치(0eebecbd) | 분류 |
|---|---|---|
| `LIVE_LEDGER_MAX_ENTRIES = 10000` 상수 | L105-106 | compaction |
| `_rewrite_ledger()` 함수 전체(atomic 재기록) | L1647-1666 | compaction |
| `_load_processed_ledger()`의 **compaction trim 블록**(order/last_entry/kept/trim + `_rewrite_ledger` 호출) | L1682-1711 | compaction·무한증가 |
| corrupt entry skip / 손상 라인 방어 | `_load_processed_ledger` 파싱부(L1685~) | corrupt tuple |
| non-string `task_id`/`source_result_sha256` 방어(incomplete tuple `(None,None)`) | `_load_processed_ledger` | non-string |
| `os.path.dirname(ledger)` 빈 문자열 → `os.makedirs("")` 처리 | `_rewrite_ledger` L1652 / ledger dir 생성부 | empty dirname |
| rewrite failure consistency(메모리 seen vs 디스크 불일치) | compaction trim 직후 | rewrite consistency |

→ 위 7항목 = **HIGH 1(`_load_processed_ledger` non-string) + MEDIUM 4(compaction rewrite·empty dirname·truncate)의 발생원**. 전부 **제거/분리 대상**.

## 2. 유지해야 할 move-first 최소 diff (event strategy 핵심 불변식)
| 항목 | 위치 | 유지 |
|---|---|---|
| VERDICT enum: LIVE_PROCESSED / SKIP_DEDUPE / PENDING_BUSY / PENDING_OWNER / **PENDING_MOVE** | L98-104, __all__ L315-319 | ✅ |
| `scan_live_inbox_once` move-first 흐름: owner gate → **move 성공 후에만** 완료 ledger append(L284,297) → **move 실패 시 VERDICT_LIVE_PENDING_MOVE**(L272), inbox 잔존·재시도 | scan 본문 | ✅ |
| dedupe: `(task_id, source_result_sha256)` 완료 ledger 존재 시 SKIP_DEDUPE(재처리 0) | L205 | ✅ |
| busy → PENDING_BUSY(누락 아닌 지연, inbox 잔존) | L217 | ✅ |
| owner_proof 미통과 → PENDING_OWNER(fire 0) | L235 | ✅ |
| `_move_processed`(기존 함수, base 존재) | L598 | ✅(기존) |
| **단순 append-only ledger 읽기**(seen set) — ★compaction 없는 최소 버전으로 축소 | `_load_processed_ledger` 대체 | ✅(축소) |

핵심 불변식 = **"move 성공 = 완료 ledger 기록 / move 실패 = 완료 미기록 + PENDING_MOVE + inbox 잔존"**. 이진 결정론. stuck-complete dedupe-skip 0.

## 3. expected_files 후보
- **유지**(move-first 최소 diff): `dispatch/anu_pickup_driver.py` · `tests/regression/test_p0b_event_strategy_2760.py`
- **제거/되돌릴**: 위 §1 7항목(compaction/robustness 코드 + 그 robustness 테스트). 단순 ledger 읽기로 대체.
- **expected_files 밖 수정 불필요** — 2파일 내부에서 compaction/robustness 들어냄 + move-first 보존으로 닫힘. (밖 필요 시 STOP_REPORT 대상이나, 현 분석상 불필요)

## 4. DESIGN_BACKLOG 이동 항목
→ `P0B_LEDGER_ROBUSTNESS_DESIGN_BACKLOG` 신설(또는 기존 `P0B_V213_INPUT_CONTRACT_COERCE_DESIGN_BACKLOG`와 통합):
- ledger compaction(_rewrite_ledger·LIVE_LEDGER_MAX_ENTRIES)
- ledger 무한증가/매 cycle 전체읽기
- corrupt/incomplete tuple 처리
- non-string task_id/sha 처리
- empty dirname 처리
- rewrite failure consistency(메모리 seen ↔ 디스크)
- **통합 가능성**: 이들은 전부 "입력/파일시스템 상태 정형화 robustness"로 _coerce(입력 계약 정형화)와 **동일 성질** → 통합 설계 1축으로 묶어 별도 goal_id에서 design-first로 다룸이 적절.

## 5. 왜 이 방향이 같은 축 반복을 끊는지
- compaction/self-healing은 **입력 표면이 넓다**: 파일시스템 실패 모드(rename/makedirs/dirname)·타입(list/dict/None task_id)·손상 JSON·메모리-디스크 일관성 → 방어 추가마다 새 엣지(whack-a-mole, matching 4회차와 동형).
- move-first 불변식은 **이진 결정론**(move 성공/실패 2상태)이라 입력 표면이 좁고 닫힌다.
- ★ compaction을 PR에서 **들어내면(고치는 게 아니라 제거)** 그 넓은 표면 자체가 PR에서 사라져 축이 종료된다. "기능을 더 넣어 안정화"가 아니라 "범위를 줄여 안정화".

## 6. 안전 상태
PR #242 OPEN/**HOLD** · merge 0 · canary 0 · systemd enable 0 · admin override 0 · canonical f641cd58 변경 0 · **ACTIVE=false**. 본 packet 작성 중 코드 수정 0(read-only 분석만) · expected_files 밖 0 · HIGH/activation/canary/systemd/admin scope 터치 0.

## 7. 다음 (회장 승인 대기 — 이 packet은 설계 보고까지만)
이 방향 수용 시에만 → 별도 승인된 좁은 replacement PR(compaction/robustness 제거 + move-first 보존, expected_files 2파일) → CI/Gemini. ledger robustness는 DESIGN_BACKLOG 별도 goal_id. **PR 생성/push/close/merge는 별도 승인 전까지 0.**
