<!-- task=m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification plan=1 tag=REFACTOR milestone-task=transfer -->

# Fixed-revision bundle과 실제 owner state 이전 검증

## For the Implementing Agent

`CODE_REVIEW-cloud-G10.md`의 implementation-owned 섹션 작성은 필수다. exact predecessor PASS와 D04 manifest byte baseline/source fixture invariant를 먼저 확인한 뒤 이 child 범위만 실행·검증한다. active pair를 유지해 review 준비 완료만 보고하고 finalization은 code-review agent만 수행한다. 실제 owner input이 없거나 안전 조건을 만족하지 못하면 synthetic 결과로 대체하지 말고 exact blocker, 시도한 명령·출력, 재개 조건만 evidence 필드에 기록한다.

## Background

04는 historical inventory revision의 Git object를 읽는 deterministic exporter를 만들고, 05는 private state 대신 사용할 sanitized schema/fixture를 고정한다. 이 child는 두 producer를 결합해 synthetic acceptance bundle을 격리 검증하고, 별도의 owner-approved config/state root로 실제 bundle을 만든다. source/state payload나 로컬 경로를 tracked evidence에 남기지 않고 digest와 count만 남겨 S02/`transfer`를 닫는다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-chronos-extraction-decoupling.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-chronos-extraction-decoupling.md)
- Task ids:
  - `transfer`: 전체 source/contract/behavior/state의 versioned Chronos acceptance bundle 전달
- Completion mode: `milestone-task` evidence aggregation; this PASS alone does not check the Roadmap Task.

## Archive Evidence Snapshot

- `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/plan_cloud_G10_0.log`와 `code_review_cloud_G10_0.log`는 미착수 pair다. implementation item, actual verification output, verdict가 없고 당시 HEAD를 source provenance처럼 사용했으며 fixed `/tmp` 삭제, prose-only predecessor/owner command, stable downstream receipt 부재 문제가 있었다.
- 승계하는 범위는 04/05 결과를 결합한 synthetic 격리 검증과 실제 owner-state export, S02/`transfer` closure뿐이다.

## Analysis

### Files Read

- `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-chronos-extraction-decoupling.md`
- `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-chronos-extraction-decoupling/SDD.md`
- `agent-task/m-iop-agent-chronos-extraction-decoupling/04+03_bundle_exporter/PLAN-cloud-G10.md`
- `agent-task/m-iop-agent-chronos-extraction-decoupling/05+03_state_fixture/PLAN-local-G05.md`
- `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/plan_cloud_G10_0.log`
- `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/code_review_cloud_G10_0.log`
- `scripts/fixtures/iop-agent-chronos-ownership-manifest.tsv`
- `scripts/fixtures/iop-agent-chronos-transfer-state-v1.schema.json`
- `scripts/fixtures/iop-agent-chronos-transfer-state-v1.json`
- `configs/iop-agent.local.example.yaml`
- `agent-test/local/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`

### SDD Criteria

- SDD는 `[승인됨]`, 잠금 `해제`다. 첫 줄 `milestone-task=transfer`에 따라 이 child가 S02 Evidence Map의 pinned source provenance, isolated behavior verification, 전체 state category, deterministic digest와 owner-only archive mode를 실제 aggregation evidence로 닫는다.
- Source payload는 inventory source revision `3155be0e275437a8eedc1aa93497955a7d30465b`의 Git object만 사용한다. 최신/dirty worktree content는 receipt의 source로 취급하지 않는다.
- Real state는 D01에 따라 실행 시점 owner root의 읽기 전용 입력이다. broken residual은 삭제하거나 재개하지 않고 `resumable=false` quarantine count/digest에 포함한다.
- Tracked receipt는 다음 child가 archive 이동과 무관하게 소비할 수 있는 stable fixture path에 둔다. raw payload, hostname, 사용자명, absolute path, credential은 기록하지 않는다.

### Verification Context

- 별도 handoff는 없다. 현재 branch는 `feature/iop-agent-chronos-extraction-decoupling`, HEAD는 `7ae4be6ceba80c3298d7c2e0968db7d9e8767223`이고 roadmap/UI/task 변경으로 dirty다. Historical inventory source revision은 의도적으로 이전 commit이다.
- 04/05는 아직 active review 상태이므로 이 child는 각 task의 active/archived 후보에서 exact PASS `complete.log`가 한 건씩 확인되기 전에는 실행하지 않는다.
- Synthetic run은 `mktemp -d` 아래에서만 source fixture를 사용하고 cleanup trap을 설치한다. fixed `/tmp` path를 지우지 않는다.
- Real run은 `IOP_CHRONOS_LOCAL_CONFIG`, `IOP_CHRONOS_STATE_ROOT`, `IOP_CHRONOS_OUTPUT_ROOT` 세 환경변수를 필수로 요구한다. input readability/current-user ownership, output parent ownership, repository 밖 output, non-existing output target을 모두 fail closed로 확인한다.
- Go `go1.26.2 linux/arm64`, module `iop`; provider/network/long-running IOP Agent process는 실행하지 않는다. Owner paths/권한이 없으면 external-execution blocker이며 synthetic success는 대체 evidence가 아니다. Confidence는 medium이다.

### Test Coverage Gaps

- 실제 owner state는 planning checkout에서 검증할 수 없다. 실행자가 세 owner 환경변수와 읽기 권한을 제공해야 한다.
- Real state가 실행 중 변경되면 exporter의 quiesced-state guard가 실패해야 하며 재실행 전에 owner가 writer를 정지해야 한다.

### Symbol References

- 새 runtime symbol은 없다. 04가 제공하는 `cmd/iop-chronos-transfer` CLI/output contract만 소비한다.

### Split Judgment

- Synthetic fixed-revision verification, real owner export와 redacted durable receipt는 동일 bundle digest/provenance invariant를 공유하므로 한 closure child로 유지한다.
- 이 child만 `transfer` Roadmap Task를 닫는다. Chronos repository import/write와 D04 disposition/addendum 작성은 13 이후 child가 소유한다.

### Scope Rationale

- Exporter code/schema 변경은 각각 04/05 범위다. 검증 중 producer defect가 발견되면 이 child에서 우회하지 않고 predecessor rework로 돌린다.
- `scripts/fixtures/iop-agent-chronos-transfer-bundle-receipt-v1.json`은 non-secret digest/count contract이며 task 13이 pre-deletion evidence에 복사할 때까지 유지한다.

### Final Routing

- `evaluation_mode=isolated-reassessment`, finalizer=`finalize-task-policy.sh`, mode=`pair`.
- Build closures 모두 true. Scores=`2,2,2,2,2`, grade=`G10`, base/route=`grade-boundary`, lane=`cloud`.
- Review closures 모두 true. Scores=`2,2,2,2,2`, route=`official-review`, lane=`cloud`, grade=`G10`.
- `large_indivisible_context=false`; positive loop risks=`temporal_state, concurrent_consistency, boundary_contract, structured_interpretation` (4); `review_rework_count=0`; `evidence_integrity_failure=false`; capability gap 없음.
- Canonical files: `PLAN-cloud-G10.md`, `CODE_REVIEW-cloud-G10.md`.

## Dependencies and Execution Order

1. 04/05 exact predecessor PASS와 manifest/source fixture invariant를 확인한다.
2. Synthetic bundle을 임시 owner-only roots에 export/extract하고 bundled behavior, forbidden dependency와 receipt digest를 fresh 검증한다.
3. Owner-provided real inputs를 동일 exporter로 export하고 private output의 mode/digest와 state counts를 검증한다.
4. Stable redacted receipt와 task-local audit logs를 기록하고 민감정보 부재/상호 digest 일치를 확인한다.

## Implementation Checklist

- [ ] Resolve exactly one PASS completion log for each of 04+03_bundle_exporter and 05+03_state_fixture, then verify the D04 manifest byte baseline/source fixture invariants.
- [ ] Run the synthetic fixed-revision export/extract/behavior/dependency command entirely under a fresh `mktemp -d` root and capture its digest-only result.
- [ ] Run the env-driven owner export with fail-closed input ownership/readability, external non-existing output and mode checks; do not substitute synthetic evidence for a missing owner run.
- [ ] Write the stable redacted bundle receipt and task-local manifest/verification logs, then prove schema, digest, 12-ID canonical set, count and sensitive-data invariants.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REFACTOR-3] Synthetic/real acceptance bundle closure receipt

**Problem**

Exporter unit tests만으로는 source revision과 실제 state가 동일 acceptance-v1 contract로 전달됐는지, live checkout 없이 bundled behavior가 실행되는지, 다음 disposition child가 어떤 digest를 승계해야 하는지 증명하지 못한다.

```text
# before risk
synthetic PASS only
real owner export = prose
downstream digest/path = task archive location에 암묵 의존
```

**Solution**

Synthetic run은 fresh temp root에서 export/extract하고 `acceptance-v1/behavior`의 fresh test와 fail-closed dependency scan을 실행한다. Real run은 세 필수 환경변수로만 입력/출력을 받아 안전 preflight 뒤 non-existing output path를 exporter에 전달한다. 두 run 모두 exporter가 mode `0700` output root와 mode `0600` archive/receipt를 생성했는지 확인하고, gzip tar의 unsafe/duplicate/link entry를 거부한 뒤 exact regular member `acceptance-v1/state/state-export-v1.json`을 `tar -xOzf`로 임시 파일에 추출한다. Exporter receipt는 exact 12-key schema여야 하며 `state_export_sha`와 모든 state count/digest를 추출한 member에서 다시 계산해 대조한다. 그 후 stable tracked receipt에 version, inventory source revision, manifest/synthetic/real/state digests, record/category/quarantine counts, archive mode와 source mode만 기록한다.

```json
{
  "version": 1,
  "inventory_source_revision": "3155be0e275437a8eedc1aa93497955a7d30465b",
  "manifest_sha": "7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7",
  "synthetic_bundle_sha": "<sha256>",
  "real_bundle_sha": "<sha256>",
  "real_state_export_sha": "<sha256>",
  "state_record_count": 12,
  "state_category_count": 8,
  "quarantine_record_count": 1,
  "state_logical_id_count": 12,
  "state_logical_ids_sha": "9bce499e286514baeb7ad9bc7c59119a3b5725f69763706dfeba06569d7404b9",
  "archive_mode": "0600",
  "source_mode": "pinned-git-tree"
}
```

Real payload record counts may exceed the logical-set size, but the canonical logical-ID contract is exact: the 10 original-manifest state IDs plus the two D04 cache/temp addendum IDs yield `state_logical_id_count=12` and `state_logical_ids_sha=9bce499e286514baeb7ad9bc7c59119a3b5725f69763706dfeba06569d7404b9`. `state_record_count` must be at least 12, all 8 categories including quarantine must be represented, and quarantine count is non-negative. The receipt contains no filesystem path or raw ID list.

Stable receipt는 위 JSON의 exact 13-key object이고 extra key를 허용하지 않는다. `real_state_export_sha`는 real archive의 canonical `acceptance-v1/state/state-export-v1.json` member bytes에 대해 검증한 exporter `state_export_sha`를 그대로 승계한다.

**Modified Files and Checklist**

- [ ] `scripts/fixtures/iop-agent-chronos-transfer-bundle-receipt-v1.json` — task 13이 소비할 stable non-secret digest/count receipt.
- [ ] `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/transfer-bundle-manifest.log` — source/manifest/synthetic/real/state digest와 count의 canonical key-value summary.
- [ ] `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/transfer-verification.log` — exact command marker, exit/result marker, safety/digest/build/dependency marker만 포함하는 redacted audit log.
- [ ] `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/CODE_REVIEW-cloud-G10.md` — actual implementation/review evidence.

**Test Strategy**

- Synthetic command는 temp root cleanup, exporter-created root/archive/receipt mode, safe archive/member extraction, member-derived receipt, isolated bundled test와 fail-closed forbidden-import scan을 한 process에서 검증한다.
- Real command는 owner env 누락, unreadable/unowned input, repository-inside/existing output을 모두 거부하고 exporter stdout/stderr, exact-key receipt와 canonical state index의 sensitive pattern도 검사한다.
- Stable receipt validator는 fixture에서 canonical logical-ID count/SHA를 다시 계산하고 exporter/stable receipt 및 task-local logs의 모든 필드를 상호 대조한다.

**Verification**

- Verification 1의 exact resolver로 predecessor PASS와 immutable inputs를 확인한다.
- Verification 2의 single Bash command로 synthetic export/extract/build/scan을 실행하고 `transfer-bundle-manifest.log`에 synthetic digest만 남긴다.
- Verification 3의 env-driven command로 real export를 실행하고 세 redacted evidence 파일을 완성한다.
- Verification 4/5로 receipt/log consistency와 fixture-derived logical-ID set을 확인하고, Verification 6으로 sensitive-data 부재를 fail closed 검증한다.

## Modified Files Summary

| File | Item |
|------|------|
| `scripts/fixtures/iop-agent-chronos-transfer-bundle-receipt-v1.json` | REFACTOR-3 |
| `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/transfer-bundle-manifest.log` | REFACTOR-3 |
| `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/transfer-verification.log` | REFACTOR-3 |
| `agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/CODE_REVIEW-cloud-G10.md` | REFACTOR-3 |

## Final Verification

1. `bash -lc 'set -euo pipefail; for child in 04+03_bundle_exporter 05+03_state_fixture; do mapfile -t logs < <({ test ! -f "agent-task/m-iop-agent-chronos-extraction-decoupling/${child}/complete.log" || printf "%s\n" "agent-task/m-iop-agent-chronos-extraction-decoupling/${child}/complete.log"; find agent-task/archive -path "*/m-iop-agent-chronos-extraction-decoupling/${child}/complete.log" -type f -print 2>/dev/null; } | sort -u); test "${#logs[@]}" -eq 1; awk '\''BEGIN {in_summary=0; count=0} /^## Summary$/ {in_summary=1; next} in_summary && /^## / {in_summary=0} in_summary {line=$0; while (match(line, /final verdict: PASS/)) {count++; line=substr(line, RSTART+RLENGTH)}} END {exit count==1 ? 0 : 1}'\'' "${logs[0]}"; done; test "$(sha256sum scripts/fixtures/iop-agent-chronos-ownership-manifest.tsv | cut -d " " -f1)" = 7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7; git cat-file -e 3155be0e275437a8eedc1aa93497955a7d30465b^{commit}; jq -e '\''.version == 1 and (.records | length == 12) and ([.records[].logical_id] | unique | length == 12) and ([.records[].bundle_path] | unique | length == 12) and all(.records[]; .source_revision == "3155be0e275437a8eedc1aa93497955a7d30465b")'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json >/dev/null'`
2. `bash -lc 'set -euo pipefail; task_dir=agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification; temp_root=$(mktemp -d); trap '\''chmod -R u+w "$temp_root" 2>/dev/null || true; rm -rf -- "$temp_root"'\'' EXIT; synthetic_out="$temp_root/output"; staging="$temp_root/staging"; archive_list="$temp_root/archive.list"; archive_verbose="$temp_root/archive.verbose"; state_index="$temp_root/state-export-v1.json"; install -d -m 0700 "$staging"; test ! -e "$synthetic_out"; go run ./cmd/iop-chronos-transfer export --manifest scripts/fixtures/iop-agent-chronos-ownership-manifest.tsv --source-revision 3155be0e275437a8eedc1aa93497955a7d30465b --repo-root . --state-fixture scripts/fixtures/iop-agent-chronos-transfer-state-v1.json --output "$synthetic_out"; test -d "$synthetic_out"; test "$(stat -c %a "$synthetic_out")" = 700; test "$(stat -c %u "$synthetic_out")" = "$(id -u)"; archive="$synthetic_out/chronos-acceptance-v1.tar.gz"; receipt="$synthetic_out/receipt.json"; test "$(stat -c %a "$archive")" = 600; test "$(stat -c %a "$receipt")" = 600; synthetic_sha=$(sha256sum "$archive" | cut -d " " -f1); tar -tzf "$archive" >"$archive_list"; test -s "$archive_list"; awk '\''BEGIN {bad=0} /^\// {bad=1} {n=split($0, parts, "/"); for (i=1; i<=n; i++) if (parts[i]=="..") bad=1} END {exit bad ? 1 : 0}'\'' "$archive_list"; test -z "$(LC_ALL=C sort "$archive_list" | uniq -d)"; tar -tvzf "$archive" >"$archive_verbose"; awk '\''substr($1,1,1)!="-" && substr($1,1,1)!="d" {bad=1} END {exit bad ? 1 : 0}'\'' "$archive_verbose"; state_member=acceptance-v1/state/state-export-v1.json; test "$(awk -v member="$state_member" '\''$0==member {count++} END {print count+0}'\'' "$archive_list")" = 1; tar -xOzf "$archive" "$state_member" >"$state_index"; jq -e '\''.version == 1 and (.records | type == "array") and all(.records[]; (.logical_id | type == "string") and (.category | type == "string"))'\'' "$state_index" >/dev/null; state_sha=$(sha256sum "$state_index" | cut -d " " -f1); state_record_count=$(jq -r '\''.records | length'\'' "$state_index"); state_category_count=$(jq -r '\''[.records[].category] | unique | length'\'' "$state_index"); quarantine_record_count=$(jq -r '\''[.records[] | select(.category=="quarantine")] | length'\'' "$state_index"); state_logical_id_count=$(jq -r '\''[.records[].logical_id] | unique | length'\'' "$state_index"); state_logical_ids_sha=$(jq -r '\''.records[].logical_id'\'' "$state_index" | LC_ALL=C sort -u | sha256sum | cut -d " " -f1); expected_record_count=$(jq -r '\''.records | length'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json); expected_category_count=$(jq -r '\''[.records[].category] | unique | length'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json); expected_quarantine_count=$(jq -r '\''[.records[] | select(.category=="quarantine")] | length'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json); expected_logical_id_count=$(jq -r '\''[.records[].logical_id] | unique | length'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json); expected_logical_ids_sha=$(jq -r '\''.records[].logical_id'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json | LC_ALL=C sort -u | sha256sum | cut -d " " -f1); test "$expected_logical_id_count" = 12; test "$state_record_count" = "$expected_record_count"; test "$state_category_count" = "$expected_category_count"; test "$quarantine_record_count" = "$expected_quarantine_count"; test "$state_logical_id_count" = "$expected_logical_id_count"; test "$state_logical_ids_sha" = "$expected_logical_ids_sha"; jq --arg bundle_sha "$synthetic_sha" --arg state_sha "$state_sha" --argjson state_record_count "$state_record_count" --argjson state_category_count "$state_category_count" --argjson quarantine_record_count "$quarantine_record_count" --argjson state_logical_id_count "$state_logical_id_count" --arg state_logical_ids_sha "$state_logical_ids_sha" -e '\''keys == ["archive_mode","bundle_sha","manifest_sha","quarantine_record_count","source_mode","source_revision","state_category_count","state_export_sha","state_logical_id_count","state_logical_ids_sha","state_record_count","version"] and .version == 1 and .source_revision == "3155be0e275437a8eedc1aa93497955a7d30465b" and .manifest_sha == "7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7" and .bundle_sha == $bundle_sha and .state_export_sha == $state_sha and .state_record_count == $state_record_count and .state_category_count == $state_category_count and .quarantine_record_count == $quarantine_record_count and .state_logical_id_count == $state_logical_id_count and .state_logical_ids_sha == $state_logical_ids_sha and .archive_mode == "0600" and .source_mode == "pinned-git-tree"'\'' "$receipt" >/dev/null; set +e; rg -n '\''/home/|/Users/|/config/|token|credential|secret|private_key'\'' "$receipt" "$state_index" >/dev/null; receipt_sensitive_rc=$?; set -e; case "$receipt_sensitive_rc" in 0) exit 1;; 1) :;; *) exit "$receipt_sensitive_rc";; esac; tar -xzf "$archive" -C "$staging"; (cd "$staging/acceptance-v1/behavior" && go test -count=1 ./...); scan_log="$temp_root/forbidden-scan.log"; set +e; rg --sort path -n '\''/config/workspace/iop|replace[[:space:]].*iop|\.\./.*iop'\'' "$staging/acceptance-v1/behavior" >"$scan_log" 2>&1; scan_rc=$?; set -e; case "$scan_rc" in 0) cat "$scan_log" >&2; exit 1;; 1) :;; *) cat "$scan_log" >&2; exit "$scan_rc";; esac; { printf "version=1\n"; printf "inventory_source_revision=3155be0e275437a8eedc1aa93497955a7d30465b\n"; printf "manifest_sha=7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7\n"; printf "synthetic_bundle_sha=%s\n" "$synthetic_sha"; } >"$task_dir/transfer-bundle-manifest.log"'`
3. `bash -lc 'set -euo pipefail; : "${IOP_CHRONOS_LOCAL_CONFIG:?set owner-approved readable config}"; : "${IOP_CHRONOS_STATE_ROOT:?set owner-approved readable state root}"; : "${IOP_CHRONOS_OUTPUT_ROOT:?set fresh external output root}"; repo_root=$(git rev-parse --show-toplevel); task_dir="$repo_root/agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification"; stable_receipt="$repo_root/scripts/fixtures/iop-agent-chronos-transfer-bundle-receipt-v1.json"; test -f "$IOP_CHRONOS_LOCAL_CONFIG" && test -r "$IOP_CHRONOS_LOCAL_CONFIG"; test -d "$IOP_CHRONOS_STATE_ROOT" && test -r "$IOP_CHRONOS_STATE_ROOT" && test -x "$IOP_CHRONOS_STATE_ROOT"; test "$(stat -c %u "$IOP_CHRONOS_LOCAL_CONFIG")" = "$(id -u)"; test "$(stat -c %u "$IOP_CHRONOS_STATE_ROOT")" = "$(id -u)"; output_parent=$(dirname "$IOP_CHRONOS_OUTPUT_ROOT"); test -d "$output_parent" && test "$(stat -c %u "$output_parent")" = "$(id -u)"; case "$(realpath -m "$IOP_CHRONOS_OUTPUT_ROOT")/" in "$repo_root"/*) exit 1;; esac; test ! -e "$IOP_CHRONOS_OUTPUT_ROOT"; audit_root=$(mktemp -d); raw_log="$audit_root/export.log"; generated="$audit_root/stable.json"; archive_list="$audit_root/archive.list"; archive_verbose="$audit_root/archive.verbose"; state_index="$audit_root/state-export-v1.json"; trap '\''chmod -R u+w "$audit_root" 2>/dev/null || true; rm -rf -- "$audit_root"'\'' EXIT; go run ./cmd/iop-chronos-transfer export --manifest scripts/fixtures/iop-agent-chronos-ownership-manifest.tsv --source-revision 3155be0e275437a8eedc1aa93497955a7d30465b --repo-root . --local-config "$IOP_CHRONOS_LOCAL_CONFIG" --state-root "$IOP_CHRONOS_STATE_ROOT" --output "$IOP_CHRONOS_OUTPUT_ROOT" >"$raw_log" 2>&1; test -d "$IOP_CHRONOS_OUTPUT_ROOT"; test "$(stat -c %a "$IOP_CHRONOS_OUTPUT_ROOT")" = 700; test "$(stat -c %u "$IOP_CHRONOS_OUTPUT_ROOT")" = "$(id -u)"; archive="$IOP_CHRONOS_OUTPUT_ROOT/chronos-acceptance-v1.tar.gz"; exporter_receipt="$IOP_CHRONOS_OUTPUT_ROOT/receipt.json"; test "$(stat -c %a "$archive")" = 600; test "$(stat -c %a "$exporter_receipt")" = 600; real_sha=$(sha256sum "$archive" | cut -d " " -f1); tar -tzf "$archive" >"$archive_list"; test -s "$archive_list"; awk '\''BEGIN {bad=0} /^\// {bad=1} {n=split($0, parts, "/"); for (i=1; i<=n; i++) if (parts[i]=="..") bad=1} END {exit bad ? 1 : 0}'\'' "$archive_list"; test -z "$(LC_ALL=C sort "$archive_list" | uniq -d)"; tar -tvzf "$archive" >"$archive_verbose"; awk '\''substr($1,1,1)!="-" && substr($1,1,1)!="d" {bad=1} END {exit bad ? 1 : 0}'\'' "$archive_verbose"; state_member=acceptance-v1/state/state-export-v1.json; test "$(awk -v member="$state_member" '\''$0==member {count++} END {print count+0}'\'' "$archive_list")" = 1; tar -xOzf "$archive" "$state_member" >"$state_index"; jq -e '\''.version == 1 and (.records | type == "array") and all(.records[]; (.logical_id | type == "string") and (.category | type == "string"))'\'' "$state_index" >/dev/null; state_sha=$(sha256sum "$state_index" | cut -d " " -f1); record_count=$(jq -r '\''.records | length'\'' "$state_index"); category_count=$(jq -r '\''[.records[].category] | unique | length'\'' "$state_index"); quarantine_count=$(jq -r '\''[.records[] | select(.category=="quarantine")] | length'\'' "$state_index"); logical_id_count=$(jq -r '\''[.records[].logical_id] | unique | length'\'' "$state_index"); logical_ids_sha=$(jq -r '\''.records[].logical_id'\'' "$state_index" | LC_ALL=C sort -u | sha256sum | cut -d " " -f1); expected_logical_id_count=$(jq -r '\''[.records[].logical_id] | unique | length'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json); expected_logical_ids_sha=$(jq -r '\''.records[].logical_id'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json | LC_ALL=C sort -u | sha256sum | cut -d " " -f1); test "$expected_logical_id_count" = 12; test "$record_count" -ge "$logical_id_count"; test "$category_count" = 8; test "$quarantine_count" -ge 0; test "$logical_id_count" = "$expected_logical_id_count"; test "$logical_ids_sha" = "$expected_logical_ids_sha"; jq --arg bundle_sha "$real_sha" --arg state_sha "$state_sha" --argjson record_count "$record_count" --argjson category_count "$category_count" --argjson quarantine_count "$quarantine_count" --argjson logical_id_count "$logical_id_count" --arg logical_ids_sha "$logical_ids_sha" -e '\''keys == ["archive_mode","bundle_sha","manifest_sha","quarantine_record_count","source_mode","source_revision","state_category_count","state_export_sha","state_logical_id_count","state_logical_ids_sha","state_record_count","version"] and .version == 1 and .source_revision == "3155be0e275437a8eedc1aa93497955a7d30465b" and .manifest_sha == "7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7" and .bundle_sha == $bundle_sha and .state_export_sha == $state_sha and .state_record_count == $record_count and .state_category_count == $category_count and .quarantine_record_count == $quarantine_count and .state_logical_id_count == $logical_id_count and .state_logical_ids_sha == $logical_ids_sha and .archive_mode == "0600" and .source_mode == "pinned-git-tree"'\'' "$exporter_receipt" >/dev/null; set +e; rg -n '\''/home/|/Users/|/config/|token|credential|secret|private_key'\'' "$raw_log" "$exporter_receipt" "$state_index" >/dev/null; sensitive_rc=$?; set -e; case "$sensitive_rc" in 0) exit 1;; 1) :;; *) exit "$sensitive_rc";; esac; synthetic_sha=$(awk -F= '\''$1 == "synthetic_bundle_sha" {print $2}'\'' "$task_dir/transfer-bundle-manifest.log"); [[ "$synthetic_sha" =~ ^[0-9a-f]{64}$ ]]; jq -n --arg source 3155be0e275437a8eedc1aa93497955a7d30465b --arg manifest 7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7 --arg synthetic "$synthetic_sha" --arg real "$real_sha" --arg state "$state_sha" --argjson records "$record_count" --argjson categories "$category_count" --argjson quarantine "$quarantine_count" --argjson logical_id_count "$logical_id_count" --arg logical_ids_sha "$logical_ids_sha" '\''{version:1,inventory_source_revision:$source,manifest_sha:$manifest,synthetic_bundle_sha:$synthetic,real_bundle_sha:$real,real_state_export_sha:$state,state_record_count:$records,state_category_count:$categories,quarantine_record_count:$quarantine,state_logical_id_count:$logical_id_count,state_logical_ids_sha:$logical_ids_sha,archive_mode:"0600",source_mode:"pinned-git-tree"}'\'' >"$generated"; jq -e '\''keys == ["archive_mode","inventory_source_revision","manifest_sha","quarantine_record_count","real_bundle_sha","real_state_export_sha","source_mode","state_category_count","state_logical_id_count","state_logical_ids_sha","state_record_count","synthetic_bundle_sha","version"] and .state_record_count >= .state_logical_id_count and .state_category_count == 8 and .quarantine_record_count >= 0 and .state_logical_id_count == 12 and .state_logical_ids_sha == "9bce499e286514baeb7ad9bc7c59119a3b5725f69763706dfeba06569d7404b9"'\'' "$generated" >/dev/null; install -m 0644 "$generated" "$stable_receipt"; { jq -r '\''to_entries[] | "\(.key)=\(.value)"'\'' "$stable_receipt"; } >"$task_dir/transfer-bundle-manifest.log"; { printf "predecessors=PASS\nsynthetic_export=PASS\nsynthetic_build=PASS\nforbidden_dependency_scan=PASS\nowner_preflight=PASS\nreal_export=PASS\nreceipt_consistency=PASS\nlogical_id_set=PASS\nsensitive_scan=PASS\n"; } >"$task_dir/transfer-verification.log"'`
4. `jq -e 'keys == ["archive_mode","inventory_source_revision","manifest_sha","quarantine_record_count","real_bundle_sha","real_state_export_sha","source_mode","state_category_count","state_logical_id_count","state_logical_ids_sha","state_record_count","synthetic_bundle_sha","version"] and .version == 1 and .inventory_source_revision == "3155be0e275437a8eedc1aa93497955a7d30465b" and .manifest_sha == "7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7" and (.synthetic_bundle_sha | test("^[0-9a-f]{64}$")) and (.real_bundle_sha | test("^[0-9a-f]{64}$")) and (.real_state_export_sha | test("^[0-9a-f]{64}$")) and .state_record_count > 0 and .state_category_count > 0 and .quarantine_record_count >= 0 and .state_logical_id_count == 12 and .state_logical_ids_sha == "9bce499e286514baeb7ad9bc7c59119a3b5725f69763706dfeba06569d7404b9" and .state_record_count >= .state_logical_id_count and .state_category_count == 8 and .archive_mode == "0600" and .source_mode == "pinned-git-tree"' scripts/fixtures/iop-agent-chronos-transfer-bundle-receipt-v1.json >/dev/null && bash -lc 'set -euo pipefail; task_dir=agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification; for field in version inventory_source_revision manifest_sha synthetic_bundle_sha real_bundle_sha real_state_export_sha state_record_count state_category_count quarantine_record_count state_logical_id_count state_logical_ids_sha archive_mode source_mode; do expected=$(jq -r ".${field}" scripts/fixtures/iop-agent-chronos-transfer-bundle-receipt-v1.json); actual=$(awk -F= -v field="$field" '\''$1 == field {print substr($0, index($0, "=") + 1)}'\'' "$task_dir/transfer-bundle-manifest.log"); test "$actual" = "$expected"; done; for marker in predecessors=PASS synthetic_export=PASS synthetic_build=PASS forbidden_dependency_scan=PASS owner_preflight=PASS real_export=PASS receipt_consistency=PASS logical_id_set=PASS sensitive_scan=PASS; do rg -Fx "$marker" "$task_dir/transfer-verification.log" >/dev/null; done'`
5. `bash -lc 'set -euo pipefail; expected_count=$(jq -r '\''[.records[].logical_id] | unique | length'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json); expected_sha=$(jq -r '\''.records[].logical_id'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json | LC_ALL=C sort | sha256sum | cut -d " " -f1); test "$expected_count" = 12; jq --arg expected_sha "$expected_sha" -e '\''.state_logical_id_count == 12 and .state_logical_ids_sha == $expected_sha and .state_record_count >= .state_logical_id_count and .state_category_count == 8 and .quarantine_record_count >= 0'\'' scripts/fixtures/iop-agent-chronos-transfer-bundle-receipt-v1.json >/dev/null'`
6. `bash -lc 'set -euo pipefail; set +e; rg -n '\''/home/|/Users/|/config/|token|credential|secret|private_key|IOP_CHRONOS_(LOCAL_CONFIG|STATE_ROOT|OUTPUT_ROOT)='\'' scripts/fixtures/iop-agent-chronos-transfer-bundle-receipt-v1.json agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/transfer-bundle-manifest.log agent-task/m-iop-agent-chronos-extraction-decoupling/06+04,05_bundle_verification/transfer-verification.log; scan_rc=$?; set -e; case "$scan_rc" in 0) exit 1;; 1) :;; *) exit "$scan_rc";; esac'`

`go test -count=1`은 fresh output이 필요하다. Verification 3은 output target이 존재하면 overwrite하지 않고 실패하므로 implementation/review 재실행마다 owner가 새 external path를 제공해야 한다. Owner input/권한 부재는 external-execution blocker이며 synthetic evidence로 대체할 수 없다.

After completing all changes and evidence capture, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.
