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

# Code Review Reference - WFC-OWNERSHIP

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`.
> Finalization is review-agent-only.

## 개요

date=2026-06-01
task=m-workflow-core/02+01_transition_ownership, plan=0, tag=WFC-OWNERSHIP

## Roadmap Targets

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

## 이 파일을 읽는 리뷰 에이전트에게

> **[REVIEW AGENT ONLY]** 종결 절차는 코드리뷰 에이전트 전용이다.

각 항목의 구현을 실제 소스 파일과 대조하고 검증 출력이 코드와 일치하는지 확인하세요.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [WFC-OWNERSHIP-1] lifecycle-owned queue transition | [x] |
| [WFC-OWNERSHIP-2] scheduler execution boundary | [x] |

## 구현 체크리스트

- [x] [WFC-OWNERSHIP-1] `Lifecycle.QueueTask`를 추가하고 `Service.EnqueueTask`가 lifecycle을 통해 queued/failure 상태를 기록하게 한다.
- [x] [WFC-OWNERSHIP-2] scheduler worker는 running 이후 execution terminal transition만 소유한다는 문서와 tests를 추가한다.
- [x] 중간 및 최종 검증 명령을 실행하고 출력 원문을 review stub에 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 코드리뷰 전용 체크리스트

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] active review/plan을 `.log`로 아카이브한다.
- [ ] PASS이면 `complete.log`를 작성하고 active task 디렉터리를 archive로 이동한다.
- [ ] PASS이고 task group이 `m-workflow-core`이면 완료 이벤트 메타데이터를 보고한다.
- [x] roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.

## 계획 대비 변경 사항

- **status transition 제약 완화**: `StatusQueued` task가 큐 등록 실패 시 `StatusFailed`로 전이되거나 대기열에서 수동으로 `StatusCanceled` 상태로 전이되는 것을 허용하기 위해 `lifecycle.go` 내 `canTransition` 함수를 업데이트하여 `StatusQueued -> StatusFailed`, `StatusQueued -> StatusCanceled` 경로를 추가로 허용하였습니다. 이 변경을 통해 대기열 전송 실패 시 적절하게 에러를 기록하고 fail 시킬 수 있습니다.

## 주요 설계 결정

- **`Service`와 `Lifecycle` 간 분리 및 주입**: `Service` 생성자의 서명을 보존하기 위해 `NewService` 내부에서 `lifecycle` 헬퍼 필드를 초기화하며, 테스트 용이성을 위해 같은 `workflow` 패키지 테스트 스위트 내에서 mock lifecycle 주입이 가능하도록 설계했습니다.
- **`canTransition` 확장**: canonical 라이프사이클에 맞춰 `StatusQueued` 상태의 작업을 큐 대기 상태나 대기열 등록 에러 상황에서 안전하게 실패(failed) 또는 취소(canceled) 처리할 수 있도록 상태 전이 정책을 유연하게 보완하였습니다.

## 사용자 리뷰 요청

- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음

## 리뷰어를 위한 체크포인트

- `Service.EnqueueTask`가 status writes를 직접 우회하지 않는지 확인한다.
- enqueue failure가 lifecycle failure path를 통해 metadata-compatible하게 남는지 확인한다.
- README ownership 설명이 Milestone 범위를 넘지 않는지 확인한다.

## 검증 결과

### WFC-OWNERSHIP-1 중간 검증
```text
$ cd services/core && go test -count=1 ./internal/workflow
ok      github.com/nomadcode/nomadcode-core/internal/workflow   0.003s
```

### WFC-OWNERSHIP-2 중간 검증
```text
$ cd services/core && go test -count=1 ./internal/scheduler ./internal/workflow
ok      github.com/nomadcode/nomadcode-core/internal/scheduler  1.507s
ok      github.com/nomadcode/nomadcode-core/internal/workflow   0.003s
```

### 최종 검증
```text
$ cd services/core && go test -count=1 ./internal/workflow ./internal/scheduler ./internal/http ./internal/protosocket
ok      github.com/nomadcode/nomadcode-core/internal/workflow   0.003s
ok      github.com/nomadcode/nomadcode-core/internal/scheduler  1.507s
ok      github.com/nomadcode/nomadcode-core/internal/http       0.003s
ok      github.com/nomadcode/nomadcode-core/internal/protosocket        0.010s

$ cd services/core && go test ./...
ok      github.com/nomadcode/nomadcode-core/cmd/plane-smoke     (cached)
?       github.com/nomadcode/nomadcode-core/cmd/server  [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/adapters/a2a       (cached)
?       github.com/nomadcode/nomadcode-core/internal/adapters/mattermost       [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/adapters/openai    (cached)
ok      github.com/nomadcode/nomadcode-core/internal/adapters/plane     (cached)
?       github.com/nomadcode/nomadcode-core/internal/agent      [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/config     (cached)
?       github.com/nomadcode/nomadcode-core/internal/db [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/http       0.003s
?       github.com/nomadcode/nomadcode-core/internal/model      [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/notification       (cached)
ok      github.com/nomadcode/nomadcode-core/internal/protosocket        0.009s
ok      github.com/nomadcode/nomadcode-core/internal/scheduler  1.510s
?       github.com/nomadcode/nomadcode-core/internal/storage    [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/workflow   0.003s
ok      github.com/nomadcode/nomadcode-core/internal/workitem   (cached)
ok      github.com/nomadcode/nomadcode-core/internal/workitempipeline   (cached)
```

## 코드리뷰 결과

- 종합 판정: FAIL

### 차원별 평가

- Correctness: Fail
- Completeness: Fail
- Test coverage: Fail
- API contract: Pass
- Code quality: Pass
- Plan deviation: Fail
- Verification trust: Pass

### 발견된 문제

- Required: [services/core/internal/workflow/service.go](/config/workspace/nomadcode/services/core/internal/workflow/service.go:156)에서 `s.enqueuer == nil`일 때 이미 `QueueTask`로 canonical status를 `queued`로 바꾼 뒤 그대로 error를 반환합니다. 실제 queue handoff가 없는데 task가 `queued`로 남아 worker가 처리할 수 없는 상태가 됩니다. `nil` enqueuer도 enqueue failure로 취급해 `s.lifecycle.FailTask(ctx, id, "task enqueuer is not configured")`를 호출하거나, 의도적으로 상태를 바꾸지 않는 별도 정책을 코드와 테스트에 고정하세요.
- Required: [services/core/internal/workflow/service_test.go](/config/workspace/nomadcode/services/core/internal/workflow/service_test.go:511)에 계획이 요구한 nil enqueuer 케이스가 없습니다. `Service.EnqueueTask`가 nil enqueuer에서 어떤 canonical state와 metadata를 남기는지 검증하는 테스트를 추가하세요.

### 다음 단계

- FAIL: 위 Required 이슈를 해결하는 follow-up `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성한다.
