<!-- task=m-iop-agent-chronos-extraction-decoupling/04+03_bundle_exporter plan=5 tag=REVIEW_REVIEW_REVIEW_REFACTOR milestone-task=transfer -->

# Bind resumable route decisions to exact manager-owned attempts

## For the Implementing Agent

Filling the implementation-owned sections of `CODE_REVIEW-cloud-G10.md` is mandatory. Implement only this follow-up scope, run every verification command, paste actual notes and stdout/stderr, keep the active pair in place, and report ready for review. If blocked, record the exact blocker, attempted commands/output, and resume condition only in implementation-owned evidence fields. Do not ask the user, call user-input tools, create control-plane stop files, classify the next state, archive logs, or write `complete.log`; finalization belongs to the code-review agent.

## Background

The exporter now strictly decodes every supported integration-record payload and verifies all self-describing key families. Route-decision records remain an exception: any 64-hex suffix is accepted even though the owning key is derived from one exact project, workspace, work unit, and attempt. This can present an integrity-valid but unowned route record as resumable manager state.

## Archive Evidence Snapshot

- `agent-task/m-iop-agent-chronos-extraction-decoupling/04+03_bundle_exporter/plan_cloud_G10_4.log` and `code_review_cloud_G10_4.log` are the predicted archives for the failed plan-4 loop. The review has one Required finding: `taskloop-route` admission checks suffix syntax and decision integrity but does not bind the key to an exact manager-owned attempt; the table currently treats an arbitrary all-`f` suffix as valid and omits the promised invalid enum/state regression.
- Fresh reviewer verification passed the predecessor PASS check, manifest SHA check, pinned commit check, focused validation/quarantine tests, full package test, race test, vet, `gofmt -d`, and `git diff --check`. `evidence_integrity_failure=false`; the recorded implementation commands are accurate, but the oracle encodes the ownership gap as expected behavior.
- All other family-specific strict decoders and exact/disjoint quarantine behavior remain accepted. The `transfer` Milestone contribution remains S02 exporter evidence only; current-input reconciliation, private owner export, isolated staging build, and final bundle closure remain downstream work.

## 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-spec/runtime/iop-agent-cli-runtime.md`
- `agent-contract/inner/iop-agent-cli-runtime.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/04+03_bundle_exporter/CODE_REVIEW-cloud-G10.md`
- `agent-task/m-iop-agent-chronos-extraction-decoupling/04+03_bundle_exporter/plan_cloud_G10_3.log`
- `agent-task/m-iop-agent-chronos-extraction-decoupling/04+03_bundle_exporter/code_review_cloud_G10_3.log`
- `cmd/iop-chronos-transfer/main.go`
- `cmd/iop-chronos-transfer/main_test.go`
- `apps/agent/internal/clientprocess/types.go`
- `apps/agent/internal/clientprocess/store.go`
- `apps/agent/internal/localcontrol/ledger.go`
- `apps/agent/internal/localcontrol/protocol.go`
- `apps/agent/internal/projectlog/record.go`
- `apps/agent/internal/projectlog/store.go`
- `apps/agent/internal/taskloop/module.go`
- `packages/go/agentpolicy/decision.go`
- `packages/go/agentpolicy/quota.go`
- `packages/go/agenttask/types.go`
- `packages/go/agentworkspace/integrator.go`
- `agent-test/local/rules.md`
- `agent-test/local/testing-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-ops/rules/project/domain/agent/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`

### SDD Criteria

- `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-chronos-extraction-decoupling/SDD.md` is `[승인됨]` with its lock released; the first-line scope remains `milestone-task=transfer`.
- This follow-up targets S02. D01, the Interface Contract prohibition on resumable unowned state, and the S02 Evidence Map require full-state provenance, non-resumable quarantine for unauthenticated or unowned residual records, and trustworthy bundle input for later isolated staging.
- The checklist therefore binds each resumable route key to the exact identities retained in the decoded manager checkpoint and preserves unmatched route bytes only in quarantine. Final verification is local exporter evidence and does not claim the downstream real-state export or staging closure.

### Verification Context

- No external handoff was supplied. Repository-native evidence is the active pair, approved SDD, exact prior loop logs, the exporter, the owning route-key derivation, and the durable manager schema.
- Local preflight: `go version` returned `go1.26.2 linux/arm64`; `go env GOMOD` returned `/config/workspace/iop-s1/go.mod`. No provider, credential, daemon, device state, or `iop-agent` execution is required or permitted.
- Fresh reviewer commands all passed: exact predecessor PASS, manifest SHA `7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7`, pinned commit availability with a different HEAD, focused tests, full package test, race test, vet, formatting, and whitespace checks.
- The deterministic defect is direct: `routeDecisionKey` hashes `route`, project, workspace, work-unit, and attempt, but `validateOwnerRouteDecision` accepts any 64-hex suffix and its test constructs an arbitrary all-`f` key. Confidence is high.

### Test Coverage Gaps

- Existing route tests cover malformed suffix syntax, envelope integrity, missing fields, and trailing JSON, but do not prove that the key belongs to any decoded manager work attempt or that an orphaned integrity-valid record reaches byte-preserving quarantine.
- The validation matrix promises invalid enum/state coverage but currently supplies no invalid lifecycle/status enum case. Add a representative case while retaining the existing family matrix.
- Existing exact/disjoint payload binding, invalid-record quarantine, workspace confinement, pinned-tree determinism, receipt, and full package coverage remain applicable.

### Symbol References

- No public or cross-package symbol is renamed. Exporter-internal route ownership helpers and their direct test call sites may change.

### Split Judgment

- Keep one compact follow-up. Deriving manager-owned route keys, applying them during classification, and proving valid/orphan quarantine behavior are one admission invariant and cannot independently PASS if split.
- Encoded predecessor 03 remains satisfied by the unique archived predecessor `complete.log` verified by the final command.

### Scope Rationale

- Modify only the exporter and exporter tests. Do not change the owning task-loop key schema, shared manager state, policy decision envelope, manifest, state fixture/schema, SDD/spec/contract, Chronos repository, or downstream Task 06 artifacts.
- Preserve all accepted family validators, exact opaque bytes, disjoint payload binding, output confinement, fixed-revision Git input, receipt keys, and deterministic archive behavior.

### Final Routing

- `evaluation_mode=isolated-reassessment`; finalizer=`finalize-task-policy.sh`; mode=`pair`.
- Build closures are all true. Scores=`2,2,2,2,2`, grade=`G10`, base/final route=`grade-boundary`, lane=`cloud`.
- Review closures are all true. Scores=`2,2,2,2,2`, route=`official-review`, lane=`cloud`, grade=`G10`.
- `large_indivisible_context=false`; matched loop risks=`boundary_contract,structured_interpretation,variant_product` (3); `review_rework_count=3`; `evidence_integrity_failure=false`; recovery boundary is present but does not replace the grade-boundary basis; no capability gap.
- Canonical files: `PLAN-cloud-G10.md`, `CODE_REVIEW-cloud-G10.md`.

## Implementation Checklist

- [ ] Derive the exact admissible `taskloop-route` keys from the strictly decoded manager checkpoint, require ownership plus strict decision integrity before resumable routing, and preserve every unmatched route record byte-for-byte only in non-resumable quarantine.
- [ ] Add valid-owned and orphan/rebound route regressions plus representative invalid enum/state coverage while preserving all existing family, exact/disjoint payload, and output behavior.
- [ ] Run the focused ownership/quarantine tests and the fresh full package, race, vet, baseline, formatting, and whitespace verification.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_REVIEW_REVIEW_REFACTOR-1] Bind route records to manager-owned attempts

**Problem**

`cmd/iop-chronos-transfer/main.go:1826-1840` accepts every integrity-valid decision whose key merely has a 64-hex suffix. The owning key at `apps/agent/internal/taskloop/module.go:777-784` hashes `route`, project ID, workspace ID, work-unit ID, and attempt ID, but none of those identities is authenticated by the current validator.

```go
// before: cmd/iop-chronos-transfer/main.go:1826
func validateOwnerRouteDecision(key string, payload json.RawMessage) bool {
    if !strings.HasPrefix(key, "taskloop-route/") ||
        !digestPattern.MatchString(strings.TrimPrefix(key, "taskloop-route/")) {
        return false
    }
    // payload integrity only
}
```

**Solution**

After strict manager-state decoding, derive a set of exact route keys from every retained work attempt using the owning length-prefixed digest algorithm. Pass that ownership set into integration-record classification. A route decision is resumable only when its full key is a member and `agentpolicy.DecodeDecision` accepts the exact envelope; otherwise copy its original bytes to `state:broken-residual-records`. Fail closed on incomplete manager identities rather than manufacturing ownership.

```go
// after
ownedRouteKeys, err := ownerManagerRouteKeys(typed)
if err != nil { return ..., err }
id, valid := ownerIntegrationRecordLogicalID(key, record, ownedRouteKeys)

func validateOwnerRouteDecision(key string, payload json.RawMessage, owned map[string]struct{}) bool {
    if _, ok := owned[key]; !ok { return false }
    // existing strict envelope and integrity validation
}
```

**Modified Files and Checklist**

- [ ] `cmd/iop-chronos-transfer/main.go` — retain the typed manager checkpoint long enough to derive exact owner route keys and enforce ownership during route classification.
- [ ] `cmd/iop-chronos-transfer/main_test.go` — replace the arbitrary valid route key with a manager-derived key; add owned success, orphan/rebound quarantine, and invalid enum/state cases.

**Test Strategy**

- Add `TestOwnerRouteDecisionOwnershipBinding` with a manager work attempt and its exact owning key, then an integrity-valid decision under an unrelated 64-hex key. Assert only the owned record is resumable and the unmatched bytes occur only in non-resumable quarantine.
- Update `TestOwnerIntegrationRecordValidationMatrix` so its valid route key is derived from explicit project/workspace/work/attempt identities and add at least one invalid lifecycle/status enum case required by the inherited checklist.
- Preserve `TestInvalidOwnerResidualIsOnlyNonResumableQuarantine`, `TestOwnerStatePayloadsAreExactAndDisjoint`, output confinement tests, and the full suite.

**Verification**

- `go test -count=1 ./cmd/iop-chronos-transfer -run 'TestOwnerRouteDecisionOwnershipBinding|TestOwnerIntegrationRecordValidationMatrix|TestInvalidOwnerResidualIsOnlyNonResumableQuarantine|TestOwnerStatePayloadsAreExactAndDisjoint'` — exact route ownership and byte-preserving quarantine PASS.

## Modified Files Summary

| File | Item |
|------|------|
| `cmd/iop-chronos-transfer/main.go` | REVIEW_REVIEW_REVIEW_REFACTOR-1 |
| `cmd/iop-chronos-transfer/main_test.go` | REVIEW_REVIEW_REVIEW_REFACTOR-1 |
| `agent-task/m-iop-agent-chronos-extraction-decoupling/04+03_bundle_exporter/CODE_REVIEW-cloud-G10.md` | REVIEW_REVIEW_REVIEW_REFACTOR-1 |

## 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; 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}'\'' "${predecessor_logs[0]}"'` — exactly one predecessor completion has exactly one final PASS in Summary.
2. `test "$(sha256sum scripts/fixtures/iop-agent-chronos-ownership-manifest.tsv | awk '{print $1}')" = 7026fedc8b0eb24eab5c4124d3818400f66db5f1d116a71e7781f346fbd256a7` — the current-byte manifest baseline remains unchanged.
3. `git cat-file -e 3155be0e275437a8eedc1aa93497955a7d30465b^{commit} && test "$(git rev-parse HEAD)" != 3155be0e275437a8eedc1aa93497955a7d30465b` — the pinned commit remains available and distinct from HEAD.
4. `go test -count=1 ./cmd/iop-chronos-transfer` — the complete fresh exporter suite PASSes.
5. `go test -count=1 -race ./cmd/iop-chronos-transfer` — the fresh exporter race suite PASSes.
6. `go vet ./cmd/iop-chronos-transfer` — no findings.
7. `gofmt -d cmd/iop-chronos-transfer/main.go cmd/iop-chronos-transfer/main_test.go` — no output.
8. `git diff --check` — no whitespace errors.

All Go tests require fresh output. Run commands from the repository root under Bash; no external provider, credential, device state, daemon, or `iop-agent` execution is used.

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