<!-- task=m-iop-agent-chronos-extraction-decoupling/05+03_state_fixture plan=0 tag=REFACTOR milestone-task=transfer -->

# Legacy state schema와 sanitized fixture 고정

## For the Implementing Agent

`CODE_REVIEW-cloud-G05.md`의 implementation-owned 섹션 작성은 필수다. encoded predecessor의 exact PASS를 확인하고 이 child 범위만 구현·검증한다. active pair를 유지해 review 준비 완료를 보고하며 finalization은 code-review agent만 수행한다. 차단되면 질문하거나 상태를 분류하지 말고 blocker, 실제 명령/출력, 재개 조건만 evidence 필드에 기록한다.

## Background

실제 private state를 추적하지 않고도 original manifest의 10개 logical state와 D04 addendum가 보완할 cache/temp 2개, 전체 category와 broken residual 정책을 검증할 수 있는 versioned schema와 sanitized fixture를 만든다.

## 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_0.log`
- `configs/iop-agent.local.example.yaml`

### SDD Criteria

- SDD `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-chronos-extraction-decoupling/SDD.md`는 `[승인됨]`, 잠금 `해제` 상태이고 사용자 결정 D01을 포함한다.
- 첫 줄 `milestone-task=transfer`의 target은 Acceptance Scenario `S02`와 Milestone Task `transfer`이며, Evidence Map row는 전체 상태 이전 fixture, provenance, digest 및 staging evidence를 요구한다.
- 이 child는 그 row의 tracked-safe 입력 계약을 schema, original 10 logical IDs와 supplemental 2 IDs, 전체 category fixture, non-resumable quarantine와 semantic 검증으로 구체화한다.

### Verification Context

- Handoff는 없다. Milestone, 승인 SDD, 보존된 parent plan과 current state category 설정을 읽었고 predecessor `03+02_inventory_closure`의 exact archived `complete.log`에서 PASS를 확인했다.
- gap은 schema와 sanitized fixture가 아직 없다는 점이다. 실제 state/path/credential은 tracked artifact에 기록하지 않고 synthetic values만 사용한다.
- Confidence는 high다. JSON parse뿐 아니라 original manifest state set equality, supplemental addendum provenance, category, digest, quarantine invariant와 sensitive scan을 이 child에서 독립 검증한다.

### Test Coverage Gaps

- 실제 state는 포함하지 않는다. JSON 유효성과 sensitive pattern 부재를 검증한다.

### Symbol References

- runtime symbol 변경 없음.

### Split Judgment

- 안정 계약은 exporter와 외부 runner가 공유할 sanitized state-v1 입력 형식이다.
- Predecessor `03`의 exact archived PASS를 확인했다. 이 child의 추가 PASS evidence는 schema/fixture parse, category/provenance/quarantine invariant와 sensitive scan이다.

### Scope Rationale

- exporter code와 실제 state export는 다른 children이 소유한다.

### Final Routing

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

## Dependencies and Execution Order

1. `03+02_inventory_closure`의 exact archived `complete.log` PASS를 유지 확인한다.
2. 그 predecessor evidence 뒤 이 child 범위만 구현·검증한다.

## Implementation Checklist

- [ ] Refuse to start until predecessor 03+02_inventory_closure has an exact PASS complete.log.
- [ ] Define the complete versioned state schema and sanitized fixture for all 10 original logical state IDs plus the two D04 cache/temp addendum IDs, including malformed residual quarantine.
- [ ] Validate JSON structure, exact manifest/addendum ID provenance, required state categories/quarantine invariants, and absence of host paths, credentials, and secrets.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REFACTOR-2] State schema와 sanitized full-category fixture

**Problem**

실제 state를 tracked fixture로 복사할 수 없고, config/state/client/log/overlay/cache/temp 및 broken residual을 모두 포함한다는 검증 가능한 schema가 없다. Broad category만 나열하면 original manifest의 10개 `state:` row가 실제로 모두 이전 입력에 대응하는지도 증명할 수 없다.

```yaml
# configs/iop-agent.local.example.yaml:5-10
device:
  state_root: ...
  overlay_root: ...
  log_root: ...
  temp_root: ...
  cache_root: ...
```

**Solution**

schema는 logical_id, repository-neutral bundle_path, source_manifest, category, source_revision, digest, size, mode, resumable, quarantine_reason을 정의하고 실제 host path와 credentials를 금지한다. Synthetic fixture는 original manifest의 10개 `state:` logical ID를 정확히 한 번씩 포함하고, 그 밖의 cache/temp root는 `d04-addendum` provenance의 `state:cache-root`, `state:temp-root`로 분리한다. 깨진 residual은 non-resumable quarantine다.

```json
// after: scripts/fixtures/iop-agent-chronos-transfer-state-v1.json
{"version":1,"records":[{"logical_id":"state:manager-checkpoint","source_manifest":"original","resumable":true},{"logical_id":"state:cache-root","source_manifest":"d04-addendum","resumable":true},{"logical_id":"state:broken-residual-records","source_manifest":"original","resumable":false}]}
```

**Modified Files and Checklist**

- [ ] `scripts/fixtures/iop-agent-chronos-transfer-state-v1.schema.json` — state/provenance schema와 sensitive-field 금지.
- [ ] `scripts/fixtures/iop-agent-chronos-transfer-state-v1.json` — sanitized full-category fixture.

**Test Strategy**

- 이 child는 exporter Go code보다 먼저 독립 실행될 수 있어야 하므로 `jq`가 schema-required fields, 12개 unique logical/bundle IDs, all categories와 broken quarantine를 검증한다. `awk`/`cmp`는 fixture의 10개 `original` ID가 immutable manifest의 state row set과 정확히 같은지 확인하고 supplemental set이 cache/temp 두 개뿐인지 확인한다. `rg`는 path/secret redaction을 fail closed로 검증한다.

**Verification**

- `jq -e . scripts/fixtures/iop-agent-chronos-transfer-state-v1.schema.json scripts/fixtures/iop-agent-chronos-transfer-state-v1.json >/dev/null && printf 'VERIFICATION_2_PASS\n'` — valid JSON.
- `jq -e '.version == 1 and (.records | type == "array" and length == 12) and ([.records[].logical_id] | unique | length == 12) and ([.records[].bundle_path] | unique | length == 12) and ((["config","state","client","log","overlay","cache","temp"] - [.records[].category]) | length == 0) and all(.records[]; (.source_manifest == "original" or .source_manifest == "d04-addendum") and .source_revision == "3155be0e275437a8eedc1aa93497955a7d30465b" and (.logical_id | test("^state:[a-z0-9-]+$")) and (.bundle_path | test("^legacy-state/[a-z0-9-]+$")) and (.digest | test("^[0-9a-f]{64}$")) and (.size | type == "number") and (.mode | type == "string") and (.resumable | type == "boolean")) and any(.records[]; .logical_id == "state:broken-residual-records" and .category == "quarantine" and .resumable == false and ((.quarantine_reason // "") | length > 0))' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json >/dev/null && printf 'VERIFICATION_3_PASS\n'` — 12 unique records, required categories/provenance/digest와 quarantine invariant PASS.
- `bash -lc 'set -euo pipefail; manifest_ids=$(mktemp); fixture_ids=$(mktemp); trap '\''rm -f -- "$manifest_ids" "$fixture_ids"'\'' EXIT; awk -F "\t" '\''NR>1 && $2=="state" {print $1}'\'' scripts/fixtures/iop-agent-chronos-ownership-manifest.tsv | LC_ALL=C sort >"$manifest_ids"; jq -r '\''.records[] | select(.source_manifest=="original") | .logical_id'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json | LC_ALL=C sort >"$fixture_ids"; test "$(wc -l <"$manifest_ids")" -eq 10; cmp "$manifest_ids" "$fixture_ids"; test "$(jq -r '\''[.records[] | select(.source_manifest=="d04-addendum") | .logical_id] | sort | join(",")'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json)" = "state:cache-root,state:temp-root"; printf "VERIFICATION_4_PASS\n"'` — original 10-ID exact equality와 supplemental 2-ID contract PASS.
- `bash -lc 'set -euo pipefail; set +e; rg -n '\''/home/|/Users/|token|credential|secret|private_key'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json; scan_rc=$?; set -e; case "$scan_rc" in 0) exit 1;; 1) :;; *) exit "$scan_rc";; esac; printf "VERIFICATION_5_PASS\n"'` — sensitive 값이 없고 scan I/O 오류도 성공으로 처리하지 않음.

## Modified Files Summary

| File | Item |
|------|------|
| `scripts/fixtures/iop-agent-chronos-transfer-state-v1.schema.json` | REFACTOR-2 |
| `scripts/fixtures/iop-agent-chronos-transfer-state-v1.json` | REFACTOR-2 |
| `agent-task/m-iop-agent-chronos-extraction-decoupling/05+03_state_fixture/CODE_REVIEW-cloud-G05.md` | REFACTOR-2 |

## Final Verification

1. `bash -lc 'set -euo pipefail; mapfile -t predecessor_logs < <({ test ! -f agent-task/m-iop-agent-chronos-extraction-decoupling/03+02_inventory_closure/complete.log || printf "%s\n" agent-task/m-iop-agent-chronos-extraction-decoupling/03+02_inventory_closure/complete.log; find agent-task/archive -path "*/m-iop-agent-chronos-extraction-decoupling/03+02_inventory_closure/complete.log" -type f -print 2>/dev/null; } | sort -u); test "${#predecessor_logs[@]}" -eq 1; awk "BEGIN {in_summary=0; found=0} /^## Summary$/ {in_summary=1; next} in_summary && /^## / {in_summary=0} in_summary && /final verdict: PASS/ {found++} END {exit found==1?0:1}" "${predecessor_logs[0]}"; printf "%s\n" "${predecessor_logs[0]}"'`
2. `jq -e . scripts/fixtures/iop-agent-chronos-transfer-state-v1.schema.json scripts/fixtures/iop-agent-chronos-transfer-state-v1.json >/dev/null && printf 'VERIFICATION_2_PASS\n'` — valid JSON.
3. `jq -e '.version == 1 and (.records | type == "array" and length == 12) and ([.records[].logical_id] | unique | length == 12) and ([.records[].bundle_path] | unique | length == 12) and ((["config","state","client","log","overlay","cache","temp"] - [.records[].category]) | length == 0) and all(.records[]; (.source_manifest == "original" or .source_manifest == "d04-addendum") and .source_revision == "3155be0e275437a8eedc1aa93497955a7d30465b" and (.logical_id | test("^state:[a-z0-9-]+$")) and (.bundle_path | test("^legacy-state/[a-z0-9-]+$")) and (.digest | test("^[0-9a-f]{64}$")) and (.size | type == "number") and (.mode | type == "string") and (.resumable | type == "boolean")) and any(.records[]; .logical_id == "state:broken-residual-records" and .category == "quarantine" and .resumable == false and ((.quarantine_reason // "") | length > 0))' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json >/dev/null && printf 'VERIFICATION_3_PASS\n'` — 12 unique records, required categories/provenance/digest와 quarantine invariant PASS.
4. `bash -lc 'set -euo pipefail; manifest_ids=$(mktemp); fixture_ids=$(mktemp); trap '\''rm -f -- "$manifest_ids" "$fixture_ids"'\'' EXIT; awk -F "\t" '\''NR>1 && $2=="state" {print $1}'\'' scripts/fixtures/iop-agent-chronos-ownership-manifest.tsv | LC_ALL=C sort >"$manifest_ids"; jq -r '\''.records[] | select(.source_manifest=="original") | .logical_id'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json | LC_ALL=C sort >"$fixture_ids"; test "$(wc -l <"$manifest_ids")" -eq 10; cmp "$manifest_ids" "$fixture_ids"; test "$(jq -r '\''[.records[] | select(.source_manifest=="d04-addendum") | .logical_id] | sort | join(",")'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json)" = "state:cache-root,state:temp-root"; printf "VERIFICATION_4_PASS\n"'` — original 10-ID exact equality와 supplemental 2-ID contract PASS.
5. `bash -lc 'set -euo pipefail; set +e; rg -n '\''/home/|/Users/|token|credential|secret|private_key'\'' scripts/fixtures/iop-agent-chronos-transfer-state-v1.json; scan_rc=$?; set -e; case "$scan_rc" in 0) exit 1;; 1) :;; *) exit "$scan_rc";; esac; printf "VERIFICATION_5_PASS\n"'` — sensitive 값이 없고 scan I/O 오류도 성공으로 처리하지 않음.

Commands containing `go test -count=1` require fresh output; all other checks are rerun against the current checkout.

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