<!-- task=m-iop-agent-cli-runtime/04+01,02,03_task_manager plan=2 tag=REVIEW_REVIEW_API -->

# AgentTaskManager committed event decision·integration identity 보정 계획

## 이 파일을 읽는 구현 에이전트에게

구현과 검증을 모두 마친 뒤 `CODE_REVIEW-cloud-G06.md`의 구현 에이전트 소유 섹션에 실제 변경 내용과 명령별 stdout/stderr를 채운다. active pair는 그대로 두고 리뷰 준비 완료를 보고한다. blocker가 생기면 정확한 원인, 시도한 명령과 출력, 재개 조건만 구현 소유 evidence에 기록한다. 사용자에게 질문하거나 user-input 도구·control-plane stop 파일을 만들거나 다음 상태를 분류하지 않으며, log archive와 `complete.log`는 코드리뷰 에이전트에게 맡긴다.

## 배경

두 번째 리뷰에서 기존 focused/fresh/race suite는 다시 통과했지만 CAS 실패 시도의 auto-resume 판정이 성공 시도에 누출되고, 서로 다른 integration change-set/attempt가 같은 EventID로 합쳐지는 문제가 재현됐다. 이 후속은 committed workflow event decision과 integration logical identity만 보정해 S01/S03의 stable lifecycle/event 계약을 닫는다.

## Archive Evidence Snapshot

- 현재 loop evidence:
  - `agent-task/m-iop-agent-cli-runtime/04+01,02,03_task_manager/plan_cloud_G06_1.log`
  - `agent-task/m-iop-agent-cli-runtime/04+01,02,03_task_manager/code_review_cloud_G06_1.log`
- verdict: `FAIL`
- findings: Required 2, Suggested 0, Nit 0.
  - CAS losing attempt의 auto-resume 판정이 committed explicit start event에 누출된다.
  - integration change-set/attempt discriminator 부재로 서로 다른 logical event가 같은 EventID를 가진다.
- affected files: `packages/go/agenttask/{types,manager,workflow,integration_queue}.go`, 관련 `*_test.go`, `agent-contract/inner/agent-runtime.md`.
- reviewer verification:
  - 계획의 focused/fresh/race/vet/adjacent suite와 predecessor/search/diff gate는 PASS했다.
  - fresh race 재현에서 committed explicit start가 `EventAutoResume`를 발행했고, 서로 다른 change-set/integration attempt의 두 integration result가 같은 EventID를 가져 FAIL했다. 임시 reviewer test는 제거됐다.
- roadmap carryover: `common-runtime`, `task-manager`; SDD S01/S03/S16와 Evidence Map을 그대로 완료 대상으로 유지한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md)
- Task ids:
  - `common-runtime`: AgentTaskManager를 포함한 공통 runtime 단일 구현 완성
  - `task-manager`: 수동 start/auto-resume/dependency-ready isolated dispatch/review/serial integration
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- 규칙/절차: `agent-ops/rules/project/rules.md`, `agent-ops/rules/common/rules-roadmap.md`, `agent-ops/skills/common/router.md`, `agent-ops/skills/common/code-review/SKILL.md`, `agent-ops/skills/common/plan/SKILL.md`, `agent-ops/skills/common/finalize-task-routing/SKILL.md`, `agent-ops/rules/project/domain/platform-common/rules.md`, `agent-ops/rules/project/domain/testing/rules.md`.
- 로드맵/설계: `agent-roadmap/current.md`, `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`, `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`, `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`.
- 계약: `agent-contract/index.md`, `agent-contract/inner/agent-runtime.md`.
- source: `packages/go/agenttask/types.go`, `manager.go`, `state_machine.go`, `intent.go`, `workflow.go`, `reconcile.go`, `dispatch.go`, `review.go`, `integration_queue.go`, `ports.go`, `dependency.go`, `scheduler.go`.
- tests: `packages/go/agenttask/manager_test.go`, `state_machine_test.go`, `integration_queue_test.go`, `test_support_test.go`, `manager_integration_test.go`, `review_test.go`, `dependency_test.go`, `scheduler_test.go`.
- 테스트 규칙: `agent-test/local/rules.md`, `agent-test/local/platform-common-smoke.md`.
- 현재 loop: `agent-task/m-iop-agent-cli-runtime/04+01,02,03_task_manager/plan_cloud_G06_1.log`, `agent-task/m-iop-agent-cli-runtime/04+01,02,03_task_manager/code_review_cloud_G06_1.log`.
- split predecessor: `agent-task/archive/2026/07/m-iop-agent-cli-runtime/01_common_runtime_node_bridge/complete.log`, `agent-task/archive/2026/07/m-iop-agent-cli-runtime/02+01_provider_catalog/complete.log`, `agent-task/archive/2026/07/m-iop-agent-cli-runtime/03+01,02_guardrail_admission/complete.log`.

### SDD 기준

- SDD: `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`, 상태 `[승인됨]`, 잠금 `해제`.
- S01/`common-runtime`: 공통 manager lifecycle/event identity가 replay에서 안정적이어야 한다.
- S03/`task-manager`: manual start와 interrupted auto-resume를 구분하고 committed 상태만 실행·event 근거가 되어야 한다.
- S16/`task-manager`: 기존 dependency-only parallel dispatch/integration trace를 보존한다.
- Evidence Map S01의 common runtime conformance, S03의 manual/default resume trace, S16의 dependency-only/parallel trace를 각각 focused event test와 전체 fresh/race 회귀로 다시 확인한다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 `agent-test/local/platform-common-smoke.md`를 읽었다.
- host Go는 `/config/.local/bin/go` → `/config/opt/go/bin/go`, `go1.26.2 linux/arm64`, `GOROOT=/config/opt/go`다.
- 변경은 `packages/go/agenttask` 내부 durable event와 inner contract에 한정된다. proto/config/Node wire consumer를 바꾸지 않으므로 profile의 proto generation과 Edge-Node full-cycle은 적용하지 않고 fresh/race package·adjacent contract suite를 사용한다.
- cache 결과를 완료 근거로 쓰지 않고 `-count=1`, concurrency 경계는 `-race -count=1`로 실행한다. `go vet`, `gofmt -l`, deterministic `rg --sort path`, `git diff --check`를 보조 oracle로 사용한다.
- 외부 runner, provider, port, secret 또는 field preflight는 필요하지 않다.

### 테스트 커버리지 공백

- `TestWorkflowActivationCASConflictUsesCommittedState`는 active project 목록만 확인해 CAS losing attempt의 event kind/identity 누출을 검출하지 못한다.
- `TestEventIdentityDistinguishesCommandsAndReplays`는 서로 다른 command만 비교하고 같은 tuple replay 안정성을 실제로 assertion하지 않는다.
- integration queue test에는 change-set ID/revision과 integration attempt를 달리한 event identity matrix가 없다.
- 기존 S03/S16 fresh/race 및 adjacent suite는 나머지 progression과 concurrency 회귀를 다룬다.

### 심볼 참조

- rename/remove 예정 심볼은 없다.
- `Event`에 additive discriminator field를 추가하고 `Manager.emit`과 `integrateOne` caller를 함께 갱신한다. 기존 event literal은 zero value 호환을 유지한다.

### 분할 판단

- 단일 plan을 유지한다. CAS committed event decision과 integration EventID는 모두 sink가 논리적 상태 전이를 중복·오분류 없이 식별한다는 하나의 event integrity 불변식이며, 둘 중 하나만 고친 중간 상태는 S01/S03를 PASS하지 못한다.
- predecessor `01`, `02`, `03`은 위 archive `complete.log`로 모두 충족됐다.

### 범위 결정 근거

- explicit stop/resume stage와 project/integration lease claim 반환값은 현재 회귀가 통과하므로 다시 변경하지 않는다.
- provider/integration backend 동작, scheduler/dependency, Node bridge, proto/config, Python dispatcher와 `iop-agent` CLI surface는 이번 두 event defect의 수정 경로가 아니므로 제외한다.
- event sink persistence 재설계나 schema migration을 추가하지 않고 additive field와 committed decision만 보정한다.

### 최종 라우팅

- `evaluation_mode=isolated-reassessment`, finalizer=`finalize-task-policy.sh`, mode=`pair`.
- build/review closures: `scope_closed=true`, `context_closed=true`, `verification_closed=true`, `evidence_trusted=true`, `ownership_closed=true`, `decision_closed=true`.
- build scores: scope=1, state=2, blast=1, evidence=1, verification=1 → `G06`; base=`local-fit`, route=`recovery-boundary`, lane=`cloud`.
- review scores: scope=1, state=2, blast=1, evidence=1, verification=1 → `G06`; route=`official-review`, lane=`cloud`.
- `large_indivisible_context=false`.
- positive loop risks: `temporal_state`, `concurrent_consistency`, `boundary_contract`, `structured_interpretation`; count=4.
- recovery: `review_rework_count=2`, `evidence_integrity_failure=false`; recovery boundary=true.
- capability gap: 없음.
- canonical files: `PLAN-cloud-G06.md`, `CODE_REVIEW-cloud-G06.md`.

## 구현 체크리스트

- [ ] REVIEW_REVIEW_API-1 CAS retry의 workflow activation/auto-resume/command 판정을 structured committed decision으로 반환하고 성공한 시도의 event만 발행한다.
- [ ] REVIEW_REVIEW_API-2 Event와 `event-v1`/integration caller에 change-set ID·revision과 integration attempt를 연결해 variant는 구분하고 exact replay는 같은 ID로 수렴시킨다.
- [ ] REVIEW_REVIEW_API-3 focused logical-event 회귀와 기존 S01/S03/S16 fresh/race/contract 검증을 통과시킨다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 의존 관계 및 구현 순서

1. 위 predecessor `complete.log` 3개를 유지한다.
2. REVIEW_REVIEW_API-1의 committed decision → REVIEW_REVIEW_API-2의 event discriminator → REVIEW_REVIEW_API-3 전체 회귀 순서로 진행한다.

### [REVIEW_REVIEW_API-1] CAS committed workflow event decision

- 문제: `packages/go/agenttask/workflow.go:48-50,142-169`의 `isAutoResumeEvent`와 `commandID`는 CAS change closure 바깥에 있어 실패한 시도의 provisional 값이 다음 성공 시도에 남는다. reviewer 재현에서 first attempt의 interrupted auto-resume 판정 뒤 committed state가 explicit `started`로 바뀌었지만 `EventAutoResume`가 발행됐다.
- 해결 방법: activation, auto-resume 여부, command ID와 workflow revision을 하나의 immutable decision 값으로 만들고 `mutateDecision`의 성공한 CAS attempt가 그 값을 반환하게 한다. `EventObserved`, `EventAutoResume`, active 목록은 반환된 committed decision만 사용한다.

```go
// Before: workflow.go:48-50,142-149
var isAutoResumeEvent bool
var commandID CommandID
activated, err := mutateDecision(m, ctx, func(state *ManagerState) (bool, error) {
    // ...
    isAutoResumeEvent = interrupted && project.Intent.AutoResumeInterrupted
    return true, nil
})

// After
decision, err := mutateDecision(m, ctx, func(state *ManagerState) (workflowDecision, error) {
    // ...
    return workflowDecision{
        Activated: true, AutoResume: interrupted && project.Intent.AutoResumeInterrupted,
        CommandID: project.Intent.CommandID, WorkflowRevision: project.Intent.WorkflowRevision,
    }, nil
})
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/agenttask/workflow.go`: 모든 early return과 active return이 attempt-local structured decision을 반환하게 한다.
  - [ ] `packages/go/agenttask/workflow.go`: observed/auto-resume event와 active append가 committed decision만 소비하게 한다.
  - [ ] `packages/go/agenttask/manager_test.go`: CAS conflict가 interrupted losing attempt에서 explicit-start winner로 바뀌는 deterministic fixture를 검증한다.
- 테스트 작성: `TestWorkflowActivationCASConflictUsesCommittedEventDecision`을 추가해 active project는 하나지만 auto-resume event는 0개이고 committed command/workflow identity만 observed event에 남는지 확인한다. 기존 stopped-winner test도 유지한다.
- 중간 검증:

```bash
/config/.local/bin/go test -race -count=1 ./packages/go/agenttask -run 'Test(WorkflowActivationCASConflictUsesCommitted|InterruptedResumeEmitsStableEvent)'
```

### [REVIEW_REVIEW_API-2] Integration logical event discriminator

- 문제: `packages/go/agenttask/types.go:296-312`의 `Event`, `manager.go:264-278`의 `event-v1` tuple, `integration_queue.go:159-164`의 caller에 change-set ID/revision과 integration attempt가 없다. reviewer 재현에서 이 세 값이 다른 두 integration result가 동일 EventID를 가졌다.
- 해결 방법: `Event`에 additive `ChangeSetID`, `ChangeSetRevision`, `IntegrationAttempt`를 추가하고 length-prefixed `event-v1` tuple에 고정 순서로 포함한다. `integrateOne`은 검증된 result/request identity를 채우며 같은 tuple replay는 같은 ID, change-set 또는 integration attempt가 다르면 다른 ID가 되게 한다.

```go
// Before: manager.go:266-278
event.EventID = durableIdentity("event-v1",
    string(event.Type), string(event.ProjectID), string(event.WorkspaceID),
    string(event.WorkUnitID), string(event.CommandID), string(event.WorkflowRevision),
    string(event.AttemptID), strconv.FormatUint(uint64(event.Ordinal), 10),
    string(event.State), event.Detail)

// After
event.EventID = durableIdentity("event-v1",
    string(event.Type), string(event.ProjectID), string(event.WorkspaceID),
    string(event.WorkUnitID), string(event.CommandID), string(event.WorkflowRevision),
    string(event.AttemptID), strconv.FormatUint(uint64(event.Ordinal), 10),
    string(event.ChangeSetID), event.ChangeSetRevision,
    strconv.FormatUint(uint64(event.IntegrationAttempt), 10),
    string(event.State), event.Detail)
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/agenttask/types.go`: additive integration event discriminator를 정의한다.
  - [ ] `packages/go/agenttask/manager.go`: canonical event tuple에 새 field를 포함한다.
  - [ ] `packages/go/agenttask/integration_queue.go`: integration result event에 검증된 change-set/attempt를 채운다.
  - [ ] `packages/go/agenttask/state_machine_test.go`: command distinction과 exact replay equality를 함께 assertion한다.
  - [ ] `packages/go/agenttask/integration_queue_test.go`: change-set ID/revision/attempt variant와 exact replay event identity를 검증한다.
  - [ ] `agent-contract/inner/agent-runtime.md`: event discriminator와 replay 기준을 구체화한다.
- 테스트 작성: `TestIntegrationEventIdentityDistinguishesChangeSetsAttemptsAndReplays`를 추가한다. change-set ID, revision, integration attempt를 각각 바꾼 event는 모두 distinct이고 같은 logical result replay는 동일 ID인지 확인한다.
- 중간 검증:

```bash
/config/.local/bin/go test -race -count=1 ./packages/go/agenttask -run 'Test(EventIdentityDistinguishesCommandsAndReplays|IntegrationEventIdentityDistinguishes)'
```

### [REVIEW_REVIEW_API-3] S01/S03/S16 회귀와 evidence 재확정

- 문제: 기존 suite가 통과해도 위 두 variant assertion이 없어 event integrity 누락을 검출하지 못했다.
- 해결 방법: 새 focused tests와 기존 stop/claim/manual-auto-resume/S03/S16 tests를 함께 fresh/race로 실행하고 adjacent runtime/guard contract, 단일 manager와 Python fallback 부재를 재확인한다.
- 수정 파일 및 체크리스트:
  - [ ] `packages/go/agenttask/*_test.go`: reviewer 재현을 tracked deterministic regression으로 흡수하고 임시 artifact를 만들지 않는다.
  - [ ] 계획 범위 밖 production 변경과 debug/TODO/format noise가 없는지 확인한다.
  - [ ] contract/source/test가 같은 discriminator와 replay 의미를 사용한다.
- 테스트 작성: REVIEW_REVIEW_API-1/2의 회귀 외 별도 test file은 만들지 않는다. 기존 S01/S03/S16 integration/race suite를 최종 oracle로 재사용한다.
- 중간 검증:

```bash
/config/.local/bin/go test -race -count=1 ./packages/go/agenttask/... -run 'Test(ManagerS03S16|StopProject|Claim|WorkflowActivation|DurableIdentity|EventIdentity|IntegrationEventIdentity|InterruptedResume)'
```

## 수정 파일 요약

| 파일/영역 | 항목 |
|---|---|
| `packages/go/agenttask/workflow.go`, `manager_test.go` | REVIEW_REVIEW_API-1 |
| `packages/go/agenttask/types.go`, `manager.go`, `integration_queue.go` | REVIEW_REVIEW_API-2 |
| `packages/go/agenttask/state_machine_test.go`, `integration_queue_test.go`, 관련 회귀 test | REVIEW_REVIEW_API-2, REVIEW_REVIEW_API-3 |
| `agent-contract/inner/agent-runtime.md` | REVIEW_REVIEW_API-2 |

## 최종 검증

```bash
command -v go
readlink -f "$(command -v go)"
go version
go env GOROOT
test -f agent-task/archive/2026/07/m-iop-agent-cli-runtime/01_common_runtime_node_bridge/complete.log
test -f agent-task/archive/2026/07/m-iop-agent-cli-runtime/02+01_provider_catalog/complete.log
test -f 'agent-task/archive/2026/07/m-iop-agent-cli-runtime/03+01,02_guardrail_admission/complete.log'
/config/.local/bin/go test -count=1 ./packages/go/agenttask/...
/config/.local/bin/go test -race -count=1 ./packages/go/agenttask/...
/config/.local/bin/go test -count=1 ./packages/go/agentruntime/... ./packages/go/agentprovider/... ./packages/go/agentguard/...
/config/.local/bin/go vet ./packages/go/agenttask/...
gofmt -l packages/go/agenttask
rg --sort path -n 'type AgentTaskManager|type Manager struct' packages/go apps cmd || true
rg --sort path -n 'orchestrate-agent-task-loop|dispatch\.py|python(3)?' packages/go/agenttask cmd/iop-agent 2>/dev/null || true
git diff --check
```

기대 결과: predecessor 3개가 존재하고 focused/fresh/race/vet/format/adjacent suite가 PASS한다. CAS winner만 auto-resume 판정을 발행하고 change-set ID/revision/integration attempt variant는 서로 다른 EventID, exact replay는 같은 EventID를 가진다. S01/S03/S16 trace, 단일 manager와 Python fallback 부재가 유지되며 `git diff --check`는 무출력이어야 한다.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.
