<!-- task=m-workflow-core/03+01_failure_policy plan=0 tag=WFC-FAILURE -->

# Code Review Reference - WFC-FAILURE

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> Fill implementation-owned sections, run verification, and stop with active files in place for review. Finalization is review-agent-only.

## 개요

date=2026-06-01
task=m-workflow-core/03+01_failure_policy, plan=0, tag=WFC-FAILURE

## Roadmap Targets

- Milestone: `agent-roadmap/phase/workflow-core/milestones/workflow-core.md`
- Task ids:
  - `failure-policy`: 실패 task 처리 기준
- Completion mode: check-on-pass

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

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

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [WFC-FAILURE-1] structured failure metadata | [x] |
| [WFC-FAILURE-2] scheduler timeout classification | [x] |

## 구현 체크리스트

- [x] [WFC-FAILURE-1] failure metadata keys and lifecycle failure input/wrapper를 추가한다.
- [x] [WFC-FAILURE-2] scheduler timeout/error paths가 structured failure type을 남기도록 연결한다.
- [x] 중간 및 최종 검증 명령을 실행하고 출력 원문을 review stub에 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

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

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

## 계획 대비 변경 사항

계획에 제시된 내용을 완벽히 준수하여 구현하였으며, 별도의 변경 사항은 없습니다.

## 주요 설계 결정

1. **완벽한 하위 호환성 유지**: `FailTask(ctx, id, message)` 메서드의 원래 시그니처를 완전히 그대로 유지하되, 내부적으로 신규 정의된 `FailTaskWithMetadata`를 호출하도록 위임하여 기존 모든 호출처(Call site)에 영향을 주지 않으면서도 structured metadata 저장 혜택을 누릴 수 있게 했습니다.
2. **에러 메시지 정규화 및 트림 처리**: 실패 에러 메시지(`Message`)의 앞뒤 공백을 Trim하고, 공백이거나 비어 있는 경우 데이터베이스나 메타데이터의 지저분한 상태를 방지하기 위해 일관적인 기본 대체값(`unknown failure`)을 사용하도록 구현했습니다.
3. **Wait Type 자동 해제**: 작업 실패 시 `wait_type` 메타데이터 키를 명시적으로 `nil`로 덮어씌움으로써 더 이상 불필요하게 대기(Wait) 상태로 인지되지 않도록 초기화 로직을 결합했습니다.
4. **Failure 유형 구조화**: `workflow.FailureType` 문자열 타입을 도입하고 `timeout`, `execution`, `enqueue`를 상수로 선언하여 예외 상황 구분을 명확히 했습니다.
5. **타임아웃 자동 분류**: 스케줄러 워커(`TaskWorker.markFailed`)에서 Context 타임아웃(`context.DeadlineExceeded`) 발생 시 failure_type을 `FailureTypeTimeout`으로, 그 외의 에러는 `FailureTypeExecution`으로 정밀 분류하여 canonical failure metadata를 메타데이터 `failure_type` 및 `failed_at`으로 보강 기록하도록 연결하였습니다.

## 사용자 리뷰 요청

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

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

- Timeout이 DB `error`와 metadata `failure_type=timeout` 양쪽에 관찰 가능한지 확인한다.
- 기존 `FailTask` call site compatibility가 깨지지 않았는지 확인한다.
- metadata에 secret/payload 원문이 들어가지 않는지 확인한다.

## 검증 결과

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

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

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

$ cd services/core && go test -count=1 ./...
ok      github.com/nomadcode/nomadcode-core/cmd/plane-smoke     0.004s
?       github.com/nomadcode/nomadcode-core/cmd/server  [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/adapters/a2a       0.009s
?       github.com/nomadcode/nomadcode-core/internal/adapters/mattermost       [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/adapters/openai    0.008s
ok      github.com/nomadcode/nomadcode-core/internal/adapters/plane     0.009s
?       github.com/nomadcode/nomadcode-core/internal/agent      [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/config     0.005s
?       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       0.002s
ok      github.com/nomadcode/nomadcode-core/internal/protosocket        0.011s
ok      github.com/nomadcode/nomadcode-core/internal/scheduler  1.509s
?       github.com/nomadcode/nomadcode-core/internal/storage    [no test files]
ok      github.com/nomadcode/nomadcode-core/internal/workflow   0.004s
ok      github.com/nomadcode/nomadcode-core/internal/workitem   0.003s
ok      github.com/nomadcode/nomadcode-core/internal/workitempipeline   0.003s
```

## 코드리뷰 결과

- 종합 판정: PASS
- 차원별 평가:
  - correctness: Pass
  - completeness: Pass
  - test coverage: Pass
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Pass
  - verification trust: Pass
- 발견된 문제:
  - Nit: `services/core/internal/workflow/model.go:49`, `services/core/internal/workflow/lifecycle.go:262` - `gofmt -l`이 두 파일을 보고하지만 실제 `gofmt -d` 차이는 빈 줄 정리뿐입니다. 다음 편집 시 `gofmt`로 정리하면 됩니다.
- 다음 단계: PASS 종결 절차를 진행한다. `complete.log`를 작성하고 active task 디렉터리를 archive로 이동한다.

검증 참고: 현재 `agent-test/local/rules.md`가 이 환경에서 새 테스트 실행을 금지하므로 `go test`는 재실행하지 않았다. 대신 review stub의 stdout/stderr, 실제 테스트 코드, 호출부, `gofmt -d` 출력, 선행 task `01_lifecycle_model`의 `complete.log`를 대조했다.
