<!-- task=m-workflow-core/02+01_transition_ownership plan=1 tag=REVIEW_WFC-OWNERSHIP -->

# Review Follow-up Plan - REVIEW_WFC-OWNERSHIP

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

이 계획은 `code_review_cloud_G07_0.log`의 Required 이슈만 해결한다. 구현 후 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 실제 내용과 검증 출력으로 채운다. blocker가 사용자 결정이나 외부 환경 준비라면 review stub의 `사용자 리뷰 요청` 섹션을 채우고 멈춘다. 최종 판정과 archive는 code-review 전용이다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/workflow-core/milestones/workflow-core.md`
- Task ids:
  - `transition-ownership`: scheduler와 workflow service의 상태 전이 책임 정리
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/domain/core/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/core-smoke.md`
- `agent-task/m-workflow-core/02+01_transition_ownership/plan_cloud_G07_0.log`
- `agent-task/m-workflow-core/02+01_transition_ownership/code_review_cloud_G07_0.log`
- `services/core/internal/workflow/service.go`
- `services/core/internal/workflow/lifecycle.go`
- `services/core/internal/workflow/service_test.go`
- `services/core/internal/http/handlers.go`
- `services/core/internal/protosocket/tasks.go`

### 리뷰 결과 요약

- `Service.EnqueueTask`는 `s.enqueuer == nil`일 때 이미 `Lifecycle.QueueTask`로 task를 `queued` 상태로 바꾼 뒤 error를 반환한다.
- 실제 queue handoff가 없는데 canonical state가 `queued`로 남을 수 있으므로 nil enqueuer도 enqueue failure path로 처리해야 한다.
- 원 계획의 service enqueue 테스트 요구사항에는 nil enqueuer 케이스가 포함되어 있었지만 현재 `service_test.go`에는 해당 테스트가 없다.

### 범위 결정 근거

- scheduler worker boundary 주석과 `services/core/README.md`의 ownership 문서는 유지한다.
- HTTP/proto-socket route shape은 바꾸지 않는다. `EnqueueTask`가 error를 반환하면 기존 handler mapping을 그대로 탄다.
- 이번 follow-up은 workflow service의 nil enqueuer failure state와 테스트 보강만 다룬다.

### 빌드 등급

- build: `cloud-G07`, review: `cloud-G07`
- 근거: workflow service의 canonical status write와 API-visible enqueue behavior를 보정하는 후속 작업이다.

## 구현 체크리스트

- [ ] [REVIEW_WFC-OWNERSHIP-1] `Service.EnqueueTask`의 nil enqueuer path를 lifecycle failure path로 고정하고 테스트를 추가한다.
- [ ] 중간 및 최종 검증 명령을 실행하고 출력 원문을 review stub에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [REVIEW_WFC-OWNERSHIP-1] Nil Enqueuer Failure Path

### 문제

- [services/core/internal/workflow/service.go](/config/workspace/nomadcode/services/core/internal/workflow/service.go:156)는 nil enqueuer를 확인하기 전에 `QueueTask`를 호출한다.
- 그 결과 `task enqueuer is not configured` error를 반환하면서도 저장소에는 `queued` task가 남는다.
- [services/core/internal/workflow/service_test.go](/config/workspace/nomadcode/services/core/internal/workflow/service_test.go:511)에는 success와 enqueuer failure 테스트만 있고 nil enqueuer 테스트가 없다.

### 해결 방법

`nil` enqueuer도 enqueue failure로 취급한다. `QueueTask` 성공 후 nil enqueuer를 발견하면 기존 enqueuer failure path와 같은 lifecycle failure write를 수행한다.

Before:

```go
if s.enqueuer == nil {
	return queuedTask, errors.New("task enqueuer is not configured")
}
```

After:

```go
if s.enqueuer == nil {
	err := errors.New("task enqueuer is not configured")
	if _, failErr := s.lifecycle.FailTask(ctx, id, err.Error()); failErr != nil && s.logger != nil {
		s.logger.Error("failed to mark task enqueue error", "task_id", id, "error", failErr)
	}
	return queuedTask, err
}
```

중복이 거슬리면 private helper로 묶어도 된다. 단, helper 추가는 `Service.EnqueueTask`의 두 enqueue failure branch에만 한정한다.

### 수정 파일 및 체크리스트

- [ ] `services/core/internal/workflow/service.go`: nil enqueuer branch를 lifecycle failure path로 연결한다.
- [ ] `services/core/internal/workflow/service_test.go`: nil enqueuer test를 추가한다.

### 테스트 작성

- Required:
  - `TestServiceEnqueueTaskWithoutEnqueuerMarksTaskFailedThroughLifecycle`

테스트 기대값:

- `Service.EnqueueTask`는 `task enqueuer is not configured` error를 반환한다.
- 저장된 task status는 `failed`다.
- 저장된 task error와 metadata `agent_run_state`, `status_reason`은 nil enqueuer error를 반영한다.
- enqueuer call은 발생하지 않는다.

### 중간 검증

```bash
cd services/core && go test -count=1 ./internal/workflow
```

Expected: workflow package tests pass, including the new nil enqueuer test.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/core/internal/workflow/service.go` | REVIEW_WFC-OWNERSHIP-1 |
| `services/core/internal/workflow/service_test.go` | REVIEW_WFC-OWNERSHIP-1 |

## 최종 검증

```bash
cd services/core && go test -count=1 ./internal/workflow ./internal/scheduler ./internal/http ./internal/protosocket
cd services/core && go test ./...
```

Expected: focused and full core tests pass. Fresh `-count=1` is required for focused packages; final full run may use cache.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
