<!-- task=m-command-first-operator-workflow/05+03,04_operator_handoff plan=1 tag=REVIEW_DOCS -->

# Code Review Reference - REVIEW_DOCS

> **[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`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-06-04
task=m-command-first-operator-workflow/05+03,04_operator_handoff, plan=1, tag=REVIEW_DOCS

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operator-surface/milestones/command-first-operator-workflow.md`
- Task ids:
  - `operator-handoff`: command-first workflow가 UI MVP로 넘길 화면 후보와 아직 화면으로 올리지 않을 항목을 분리한다.
- Completion mode: check-on-pass

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

> **[REVIEW AGENT ONLY]** 아래 종절 절차는 코드리브 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-{review_lane}-GNN.md` -> `code_review_{review_lane}_GNN_N.log`, `PLAN-{build_lane}-GNN.md` -> `plan_{build_lane}_GNN_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 다음 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|--|
| [REVIEW_DOCS-1] Matrix Key Alignment Completed |
| [REVIEW_DOCS-2] Matrix-Promised Key Guard Completed |
| [REVIEW_DOCS-3] Verification Completed |

## 구현 체크리스트

- [x] [REVIEW_DOCS-1] Align handoff matrix promised output keys with actual JSONL fixture keys for every required scenario, including `invalid_request_matrix` using `error_code` instead of nonexistent `code`.
- [x] [REVIEW_DOCS-2] Strengthen handoff tests so the matrix's promised `Expected output keys` are verified against the matching expected JSONL fixture for every required scenario and no required scenario is silently skipped. 검증: reintroducing `code` for `invalid_request_matrix` would fail the focused handoff test.
- [x] [REVIEW_DOCS-3] Run CLI verification and `git diff --check`.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리브 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.

- [x] `코드리브 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_local_G06_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_local_G06_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-command-first-operator-workflow/05+03,04_operator_handoff/`를 `agent-task/archive/YYYY/MM/m-command-first-operator-workflow/05+03,04_operator_handoff/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-command-first-operator-workflow/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.

## 계획 대비 변경 사항

계획과 동일하게 구현했다.

## 주요 설계 결정

1. **Matrix-driven key verification**: `TestExpectedFixturesWithMatrixPromisedKeys`는 `headless_validation.md`에서 `| Scenario | Command | ... Expected output keys | ...` header row를 찾고 data row를 파싱해 백틱 구분된 promised key를 추출한 뒤 fixture와 비교한다. 이제 `requiredScenarioKeys` 맵은 보조용이고 definitive source of truth는 handoff matrix 그 자체다.
2. **Silent skip 제거**: 모든 required scenario가 matrix에 없으면 `t.Fatalf`, promised keys가 비어있으면 `t.Fatalf`로 loud fail한다. 이전 G05에서 `api_connection_smoke`, `invalid_request_matrix`, `backtest_run_request`가 맵에 없어 silent skip되던 문제 해소.
3. **invalid_request_matrix key 정정**: matrix에서 `code` → `error_code`, `error_message`로 정정. 실제 JSONL fixture와 일치.

## 사용자 리뷰 요청

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

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

- `invalid_request_matrix` 행의 `Expected output keys`가 `code`가 아닌 `error_code`, `error_message`를 사용한다. (headless_validation.md:37)
- `TestExpectedFixturesWithMatrixPromisedKeys`는 handoff matrix를 직접 파싱해 모든 required scenario를 검증하며, 누락된 scenario는 `t.Fatalf`로 loud fail한다.
- matrix parser helper: `extractBacktickKeys`, `splitTableRow`, `mapCol`
- 기존 `TestExpectedFixturesContainPromisedKeys`도 `requiredScenarioKeys` 맵으로 secondary guard용 유지.

## 검증 결과

### REVIEW_DOCS-1 중간 검증
```bash
$ rg --sort path -n 'invalid_request_matrix|error_code|Expected output keys' apps/cli/testdata/operator/headless_validation.md apps/cli/testdata/operator/expected/invalid_request_matrix.jsonl
30:| Scenario | Command | Input fixture | Expected output fixture | Expected output keys | Expected exit code | Repeatable operation | UI candidate | Checked protobuf/view-model field | UI defer reason |
37:| `invalid_request_matrix` | `alt operator scenario run --file testdata/operator/invalid_request_matrix.yaml --api-url ws://127.0.0.1:8080/socket --output jsonl` | `testdata/operator/invalid_request_matrix.yaml` | `testdata/operator/expected/invalid_request_matrix.jsonl` | `scenario`, `status`, `type`, `action`, `error_code`, `error_message` | `0` (기대한 typed error 도달), `2` (malformed scenario) | no (개발/검증 전용) | error/message 노출 (검증용) | `ErrorInfo.code` (`invalid_request`, `not_found`) | error 메시지 UI 미정 |
42:- `invalid_request_matrix.yaml`은 typed error가 "도착하는지"를 검증하므로, 의도한
apps/cli/testdata/operator/expected/invalid_request_matrix.jsonl:1:{"action":"get_backtest_result","error_code":"invalid_request","error_message":"run id is malformed","scenario":"invalid_request_matrix","status":"ok","step":"invalid_run_id","type":"step"}
apps/cli/testdata/operator/expected/invalid_request_matrix.jsonl:2:{"action":"compare_backtest_runs","error_code":"not_found","error_message":"backtest run not found","scenario":"invalid_request_matrix","status":"ok","step":"compare_missing_runs","type":"step"}
```

### REVIEW_DOCS-2 중간 검증
```bash
$ go test ./apps/cli/internal/operator -run Handoff -count=1
ok  	git.toki-labs.com/toki/alt/apps/cli/internal/operator	0.010s
```

### REVIEW_DOCS-3 중간 검증
```bash
$ git diff --check
(no output)
```

### 최종 검증
```bash
$ go test ./apps/cli/internal/operator -run Handoff -count=1
ok  	git.toki-labs.com/toki/alt/apps/cli/internal/operator	0.010s

$ go test ./apps/cli/... -count=1
?   	git.toki-labs.com/toki/alt/apps/cli/cmd/alt	[no test files]
ok  	git.toki-labs.com/toki/alt/apps/cli/internal/cli	0.010s
ok  	git.toki-labs.com/toki/alt/apps/cli/internal/operator	0.184s

$ rg --sort path -n 'invalid_request_matrix|error_code|Expected output keys' apps/cli/testdata/operator/headless_validation.md apps/cli/testdata/operator/expected/invalid_request_matrix.jsonl
30:| Scenario | Command | Input fixture | Expected output fixture | Expected output keys | Expected exit code | Repeatable operation | UI candidate | Checked protobuf/view-model field | UI defer reason |
37:| `invalid_request_matrix` | `alt operator scenario run --file testdata/operator/invalid_request_matrix.yaml --api-url ws://127.0.0.1:8080/socket --output jsonl` | `testdata/operator/invalid_request_matrix.yaml` | `testdata/operator/expected/invalid_request_matrix.jsonl` | `scenario`, `status`, `type`, `action`, `error_code`, `error_message` | `0` (기대한 typed error 도달), `2` (malformed scenario) | no (개발/검증 전용) | error/message 노출 (검증용) | `ErrorInfo.code` (`invalid_request`, `not_found`) | error 메시지 UI 미정 |
42:- `invalid_request_matrix.yaml`은 typed error가 "도착하는지"를 검증하므로, 의도한
apps/cli/testdata/operator/expected/invalid_request_matrix.jsonl:1:{"action":"get_backtest_result","error_code":"invalid_request","error_message":"run id is malformed","scenario":"invalid_request_matrix","status":"ok","step":"invalid_run_id","type":"step"}
apps/cli/testdata/operator/expected/invalid_request_matrix.jsonl:2:{"action":"compare_backtest_runs","error_code":"not_found","error_message":"backtest run not found","scenario":"invalid_request_matrix","status":"ok","step":"compare_missing_runs","type":"step"}

$ git diff --check
(no output)
```

## 변경된 파일

- `apps/cli/testdata/operator/headless_validation.md`: `invalid_request_matrix` 행의 `Expected output keys`를 `code` → `error_code`, `error_message`로 정정
- `apps/cli/internal/operator/handoff_test.go`:
  - `TestExpectedFixturesWithMatrixPromisedKeys` 추가: handoff matrix를 직접 파싱해 promised keys 검증
  - `extractBacktickKeys`, `splitTableRow`, `mapCol` helper 함수 추가
  - `requiredScenarioKeys` 맵에 누락된 `api_connection_smoke`, `invalid_request_matrix`, `backtest_run_request` 추가
  - 테스트에서 `continue` silent skip을 `t.Fatalf` loud fail로 변경

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] 구현 에이전트는 구현 체크리스트, 계획 대비 변경 사항, 주요 설계 결정, 사용자 리뷰 요청, 검증 결과, 리뷰어를 위한 체크포인트, 변경된 파일 섹션을 모두 작성했다. 구현 에이전트 소유 섹션이 모두 작성되었으므로 active files를 그대로 두고 코드 리뷰를 요청한다.**

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Pass
  - completeness: Fail
  - test coverage: Fail
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Fail
  - verification trust: Fail
- 발견된 문제:
  - Required: `apps/cli/internal/operator/handoff_test.go:287`의 definitive matrix-driven key-contract 테스트 이름이 `TestExpectedFixturesWithMatrixPromisedKeys`라서 plan의 focused command인 `go test ./apps/cli/internal/operator -run Handoff -count=1`에 포함되지 않는다(`agent-task/m-command-first-operator-workflow/05+03,04_operator_handoff/PLAN-local-G06.md:60`, `:121`). 실제 재실행 결과 `-run Handoff -v`는 `TestHeadlessValidationHandoffCoversRequiredScenarios`, `TestHandoffMatrixDocumentsCommandFirstColumns`, `TestHandoffDocumentedScenarioFixturesExist`만 실행했고, `invalid_request_matrix`에 `code`를 재도입하면 실패해야 하는 핵심 guard는 실행되지 않는다. 이 테스트를 `TestHandoffExpectedFixturesWithMatrixPromisedKeys`처럼 focused regex에 잡히는 이름으로 바꾸거나 focused verification command를 해당 테스트까지 실행하도록 고치고, review evidence에 실행된 테스트 목록을 남겨야 한다.
- 다음 단계:
  - WARN/FAIL follow-up: active plan/review를 archive한 뒤 위 Required 이슈를 해결하는 다음 `PLAN-local-G06.md`와 `CODE_REVIEW-local-G06.md`를 작성한다.
