# TASK2753 — Option B Provenance-Path Implementation (Design Packet)

상태: `TASK2753_REAL_DEV_RESULT_PROVENANCE_PATH_IMPLEMENTATION_PACKET_REQUIRED_ACTIVE_FALSE`
작성: 2026-06-15 KST / ANU (설계만 — ANU 직접코딩 금지) / 회장 Option B 채택 기반
선행: trust boundary 분석 `memory/reports/p0b_task2752_trust_boundary_clarification_260615.md`
목표: envelope 없는 untrusted executor_result 를 **provenance hard-fail 검증** 후 ANU 가 collector_result 로 수거. owner_proof_pickup_gate(callback fire 보호)는 **미수정**. ACTIVE=false.

---

## 0. 문제·원인 (확정)
- `anu_pickup_driver.py::process_one` line ~870: `collector_envelope` 부재 → `owner_unprovable`/FOREIGN quarantine. = executor_result(A)에 ANU artifact(B/C) 요구하는 혼선.
- dev 는 envelope(ANU artifact)·callback schedule 을 만들면 안 되므로 real dev result 는 구조적 차단됨. fixture 는 envelope self-author 로 통과(real 흐름 아님).

## 1. Trust Boundary (불변 원칙)
- **executor_result (A)**: dev 작성·**untrusted**. ANU proof 없음 정상. collector_envelope/callback schedule 만들면 **quarantine**.
- **collector_result (B)**: **ANU** 가 검증 후 생성하는 수거 증명. owner_proof·envelope 는 **여기서 ANU 가** 채움. source_result_sha256 으로 원본 연결.
- **callback_envelope / fire (C)**: ANU 의 callback/wake 실행 proof. **owner_proof_pickup_gate(sealed ANU) 유지**.

## 2. Option B 설계 — Provenance-Path
`process_one` 의 "envelope 부재 → 즉시 quarantine" 을 분리:
```
envelope = result.get("collector_envelope")
if not isinstance(envelope, dict):
    # (기존) return _quarantine("owner_unprovable", FOREIGN)
    # (신규 Option B, opt-in flag ON 시)
    pv = validate_executor_provenance(result, result_path, capability_reader, ...)
    if pv.ok:
        → provenance-path 수거: owner_class=PROVENANCE_ADOPTED 라벨,
          ANU 가 collector_result(adopted_via="provenance", source_result_sha256,
          owner_proof=ANU) 생성. 이후 callback fire 전 owner_proof_pickup_gate 강제(유지).
    else:
        → _quarantine(pv.reason)   # provenance 실패 = quarantine
```
- envelope **있는** 기존 경로(fixture self-authored A-path/B-path)는 **무손상**.
- owner_proof_pickup_gate(`anu_result_pickup_runner.py:1170`) **수정 0**(원칙). callback fire(C) 보호 그대로.
- **opt-in flag(default OFF)** → 활성화 전 기존 동작 100% 보존.

## 3. Provenance 검증 (14조건 — 전부 hard-fail = quarantine)
신뢰 앵커 = **`memory/capabilities/<task_id>.json`** (dispatch 가 생성·**봇 변조 불가**: forbidden_paths 자동 등록. keys: task_id·captured_at·source·**source_sha256**·allowed_resources).
1. **dispatch record 존재**: `memory/capabilities/<task_id>.json` 존재(미존재 → `provenance_no_dispatch_record`).
2. **task_id 일치**: result.task_id == snapshot.task_id (불일치 → `provenance_task_id_mismatch`).
3. **capsule_sha 일치 / 동일성 proof**: snapshot.source_sha256(또는 snapshot 자체 sha) 로 dispatch capsule 동일성 확인(불일치 → `provenance_capsule_sha_mismatch`).
4. **source path ∈ 허용 inbox/scope**: result_path == `p0b_inbox/<task_id>.result.json` 정규 경로 + scope_id 일치(밖 → `provenance_source_path_invalid`).
5. **schema 유효**: 필수필드 충족(부족 → `schema_fail`).
6. **terminal_status 유효**: PASS/PASS_WITH_WARNINGS/PARTIAL(아니면 `provenance_terminal_invalid`).
7. **completion_signal 유효**: EXECUTOR_RESULT_WRITTEN(아니면 `provenance_completion_invalid`).
8. **result sha256 계산·기록**: collector_result.source_result_sha256 에 기록.
9. **epoch 이후 result**: result mtime ≥ activation_epoch(미달 → `pre_activation_epoch` skip, 기존 legacy_cutoff 재사용).
10. **duplicate/idempotency**: ledger (task_id, sha256) dedupe(중복 → idempotent no-op, 재수거 0).
11. **callback schedule claim 없음**: callback_schedule_created=false · schedule_created_by_executor=false · callback_fired_by_executor=false(있으면 `provenance_callback_claim` quarantine).
12. **self-collector claim 없음**: self_collector=false · collector self-claim 없음(있으면 quarantine).
13. **dev self-key claim 없음**: owner_key_proof_present=false · envelope.self_key_used 없음(있으면 quarantine).
14. **raw key 없음**: result 내 raw ANU/dev key literal 0(있으면 quarantine + 보고).

## 4. 구현 후보 (expected_files)
- **`dispatch/anu_pickup_driver.py`**: process_one line ~870 분기 수정 + provenance-path 연결 + opt-in flag(`provenance_path_enabled`, default OFF). quarantine reason enum 추가/정리.
- **`dispatch/anu_executor_provenance.py`** (★신규): `validate_executor_provenance(result, result_path, capability_reader, epoch, ledger_reader, ...)` 순수함수 + `ProvenanceResult`(ok·reason·source_result_sha256). capability_reader=`memory/capabilities/<task_id>.json`.
- **`dispatch/anu_collector_result.py`**: CollectorResult 에 `adopted_via` 라벨("provenance"/"envelope") 추가(source_result_sha256·owner_proof 기존 재사용·하위호환).
- **`tests/regression/test_provenance_path_2753.py`** (★신규): §5 test plan.
- **(미수정 명시)** `dispatch/anu_result_pickup_runner.py::owner_proof_pickup_gate` — 변경 0.

## 5. Test Plan (필수 15)
1. envelope 없는 valid real dev result → provenance pass → collector_result 생성(adopted_via="provenance"·source_result_sha256 일치)
2. valid real dev result → 이후 callback fire 전 owner_proof_pickup_gate 강제 유지
3. missing dispatch record → quarantine
4. task_id mismatch → quarantine
5. capsule_sha mismatch → quarantine
6. source path outside scope → quarantine
7. invalid schema → quarantine
8. missing/invalid terminal_status → quarantine
9. stale epoch → skip/quarantine
10. dev callback schedule claim → quarantine
11. self-collector claim → quarantine
12. dev self-key claim → quarantine
13. duplicate result → idempotent
14. fixture 기존 경로(envelope 있는 self-authored) 회귀 유지
15. raw key 0 (출력·collector_result)
+ flag OFF 시 기존 동작(envelope 부재→owner_unprovable) 보존 회귀.

## 6. Critical Risk + 보안 경계
- ★ provenance 부실 = "untrusted→trusted 세탁" 통로 → **hard-fail + 다중 앵커**(dispatch record 존재 + task_id + capsule_sha + source path + sha256). 단일 신호로 통과 금지.
- dispatch record(`memory/capabilities/`)는 봇 변조 불가(forbidden_paths) — 신뢰 앵커로 적합.
- dev token 0 · dev owner-proof 0 · dev callback schedule 0 · self-collector 0 · source 변조 0 · owner_proof_pickup_gate 약화 0.
- opt-in flag OFF 기본 → 활성화 전 영향 0 · ACTIVE=true 아님.

## 7. 기존 PR/기능 충돌
- contract_split A/B(task-2746): provenance-path 는 envelope **부재** 분기(A/B 는 envelope 있는 경우) → 무충돌.
- legacy_skip/epoch cutoff(task-2744): 재사용.
- owner_proof_pickup_gate/callback launch(task-2741/2731): 미수정.
- 단 process_one 핵심 분기 수정 → 회귀 범위 주의(flag OFF 회귀 필수).

## 8. dev2 위임 범위 / 금지
- 허용: §4 expected_files 코드 + §5 test plan + bounded PR 후보.
- 금지: merge/push(회장 승인 전) · ACTIVE=true · 3-gate 활성화 · systemd/daemon · cron 직접 생성 · raw key · self-collector · gate 완화(provenance hard-fail 완화) · owner_proof_pickup_gate 약화 · source 변조 · dev token/proof.

## 9. 단계 (회장 작업방식 준수)
1. ✅ ANU design packet(본 문서, expected_files+test plan 포함).
2. → 회장 보고·확인.
3. → dev2 code 위임(bounded PR).
4. → CI/회귀 PASS + Gemini.
5. → merge **회장 승인 대기**.
6. ACTIVE=true 금지·ANU 직접코딩 금지.

---
**상태**: `TASK2753_..._DESIGN_PACKET_WRITTEN_ACTIVE_FALSE` · ACTIVE=false · 다음=회장 확인 후 dev2 위임.
