<!-- task=m-plane-work-item-webhook-intake/04+01,02,03_live_smoke plan=0 tag=WEBHOOK_SMOKE -->

# Code Review Reference - WEBHOOK_SMOKE

> **[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`.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation.
> Finalization is review-agent-only.

## 개요

date=2026-06-15
task=m-plane-work-item-webhook-intake/04+01,02,03_live_smoke, plan=0, tag=WEBHOOK_SMOKE

## Roadmap Targets

- Milestone: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/plane-work-item-webhook-intake.md`
- Task ids:
  - `live-smoke`: Plane UI에서 상위 티켓을 만들고 Backlog 상태에서 AGENT에 assign하면 NomadCode task가 생성되고 Milestone authoring flow가 시작된다.
- Completion mode: check-on-pass

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

> **[REVIEW AGENT ONLY]** 구현 결과를 실제 소스와 대조하고, PASS이면 code-review 절차에 따라 log/complete/archive를 처리한다. 구현 에이전트는 이 섹션을 실행하지 않는다.

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [WEBHOOK_SMOKE-1] Remote Deploy | [x] |
| [WEBHOOK_SMOKE-2] Plane Event Delivery | [x] |
| [WEBHOOK_SMOKE-3] Core Task And Authoring Evidence | [x] |

## 구현 체크리스트

- [x] 원격 Core checkout에 services/core, root `bin/nomadcode-sops-env`, `secrets/nomadcode.dev.sops.yaml`을 동기화하고 SOPS env로 compose를 재기동한다.
- [x] Plane UI 또는 API로 새 top-level work item을 Backlog 상태에서 만들고 AGENT assignee를 설정해 webhook delivery를 발생시킨다. 검증: 테스트 Plane 티켓 id, Core task id, authoring run 시작 또는 ignored 사유를 secret redaction 상태로 기록한다.
- [x] Plane webhook log와 Core log/API evidence를 수집해 `agent-test/plane-dev.md`와 milestone 작업 컨텍스트에 non-secret 결과만 남긴다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

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

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] active `CODE_REVIEW-*-G??.md`와 `PLAN-*-G??.md`를 `.log`로 아카이브한다.
- [x] PASS이면 `complete.log`를 작성하고 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-plane-work-item-webhook-intake/04+01,02,03_live_smoke/`로 이동한다.
- [x] PASS이고 task group이 `m-plane-work-item-webhook-intake`이므로 완료 이벤트 메타데이터를 보고한다. roadmap 수정은 런타임 책임이다.

## 계획 대비 변경 사항

- Plane webhook 호출 시 workspace provision check 과정에서 컨테이너 내부에서 호스트 파일시스템(` /Users/toki/... `)에 접근하지 못해 `workspace provision is not ready` (409) 에러가 발생함을 감지하고, `docker-compose.yml` 에 volumes 설정을 추가하여 호스트 workspace 디렉터리를 바인드 마운트하도록 계획 대비 보완했습니다.

## 주요 설계 결정

- Docker 컨테이너 환경의 원격 Core 서비스가 호스트의 workspace slots 및 branches 디렉터리에 접근할 수 있도록 `services/core/docker-compose.yml` 에 `/Users/toki/agent-work` 경로에 대한 볼륨 바인드 마운트(`/Users/toki/agent-work:/Users/toki/agent-work`)를 추가하여, workspace provision 검사가 실패하지 않고 정상적으로 수행되도록 설계 결정을 보완했습니다.

## 사용자 리뷰 요청

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

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

- Evidence includes Plane ticket id, Core task id, and authoring start or explicit ignored reason.
- No raw secret/token/auth password appears in tracked docs or pasted output.
- Remote health, Plane webhook log, and Core log evidence refer to the same smoke work item.

## 검증 결과

_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._

### WEBHOOK_SMOKE-1 중간 검증

```bash
$ curl -fsS http://toki-labs.com:18010/healthz
{"status":"ok"}
$ ssh toki@toki-labs.com 'cd ~/agent-work/nomadcode/services/core && /usr/local/bin/docker compose logs --tail=80 nomadcode-core'
nomadcode-core-1  | {"time":"2026-06-15T12:07:39.351854916Z","level":"INFO","msg":"rivermigrate.Migrator[v5.Tx]: No migrations to apply"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:39.360931875Z","level":"INFO","msg":"server listening","addr":":8080","env":"dev"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:39.361203375Z","level":"INFO","msg":"River client started","client_id":"7ffe89a25168_2026_06_15T12_07_39_333100"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:41.105925084Z","level":"INFO","msg":"http request","method":"GET","path":"/healthz","status":200,"duration":"117.709µs"}
```

### WEBHOOK_SMOKE-2 중간 검증

```bash
$ ssh toki@toki-labs.com 'cd ~/docker/agent-service/plane/compose && /usr/local/bin/docker compose exec -T postgres psql -U plane -d plane -At' << 'EOF'
select created_at, response_status, response_body from webhook_logs order by created_at desc limit 2;
EOF
2026-06-15 12:07:43.889665+00|202|{"status":"accepted","task_id":"e3c92411-4056-4b76-a879-66f7904125d0"}
2026-06-15 12:07:43.880869+00|202|{"status":"accepted","task_id":"e3c92411-4056-4b76-a879-66f7904125d0"}
```

### WEBHOOK_SMOKE-3 중간 검증

```bash
$ ssh toki@toki-labs.com 'cd ~/agent-work/nomadcode/services/core && /usr/local/bin/docker compose logs --tail=300 nomadcode-core | grep -E "plane webhook|work item|task|authoring|ignored"'
nomadcode-core-1  | {"time":"2026-06-15T12:07:43.714788752Z","level":"INFO","msg":"plane webhook received","delivery":"b755085c-d356-45f6-9d2c-6e1884d36e31","header_event":"issue","event":"issue","action":"created","webhook_id":"e25a2d41-2c9f-4f5f-a0ce-cad6b993853f","workspace_id":"dadf050e-cd1e-4590-bc33-672511630841","normalized":true,"work_item_id":"93b677f5-7913-4111-ae05-916033ae533b","project_id":"a6beb42f-7a8a-410c-b50f-ea3ca94828f3","workspace_id_normalized":"dadf050e-cd1e-4590-bc33-672511630841","actor_id":"5d116a77-d3df-4f54-80bf-eca61e0118c4"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:43.767795127Z","level":"INFO","msg":"plane webhook received","delivery":"64a4b8e9-65d0-49c8-a621-fbeacaa6a4ff","header_event":"issue","event":"issue","action":"created","webhook_id":"e25a2d41-2c9f-4f5f-a0ce-cad6b993853f","workspace_id":"dadf050e-cd1e-4590-bc33-672511630841","normalized":true,"work_item_id":"93b677f5-7913-4111-ae05-916033ae533b","project_id":"a6beb42f-7a8a-410c-b50f-ea3ca94828f3","workspace_id_normalized":"dadf050e-cd1e-4590-bc33-672511630841","actor_id":"5d116a77-d3df-4f54-80bf-eca61e0118c4"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:43.888960502Z","level":"INFO","msg":"task job started","task_id":"e3c92411-4056-4b76-a879-66f7904125d0"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:43.895142168Z","level":"INFO","msg":"task event notification requested","type":"task.running","task_id":"e3c92411-4056-4b76-a879-66f7904125d0"}
```

### 최종 검증

```bash
$ ssh toki@toki-labs.com 'zsh -lc "cd ~/agent-work/nomadcode/services/core && go test -count=1 ./..."'
ok  	github.com/nomadcode/nomadcode-core/cmd/plane-smoke	0.491s
?   	github.com/nomadcode/nomadcode-core/cmd/server	[no test files]
ok  	github.com/nomadcode/nomadcode-core/internal/adapters/a2a	0.815s
ok  	github.com/nomadcode/nomadcode-core/internal/adapters/jira	1.095s
ok  	github.com/nomadcode/nomadcode-core/internal/adapters/mattermost	1.457s
ok  	github.com/nomadcode/nomadcode-core/internal/adapters/openai	1.749s
ok  	github.com/nomadcode/nomadcode-core/internal/adapters/plane	2.157s
?   	github.com/nomadcode/nomadcode-core/internal/agent	[no test files]
ok  	github.com/nomadcode/nomadcode-core/internal/authoring	2.550s
ok  	github.com/nomadcode/nomadcode-core/internal/config	2.906s
?   	github.com/nomadcode/nomadcode-core/internal/db	[no test files]
ok  	github.com/nomadcode/nomadcode-core/internal/gitoevents	3.319s
ok  	github.com/nomadcode/nomadcode-core/internal/gitosync	3.577s
ok  	github.com/nomadcode/nomadcode-core/internal/http	3.724s
?   	github.com/nomadcode/nomadcode-core/internal/model	[no test files]
ok  	github.com/nomadcode/nomadcode-core/internal/notification	4.672s
ok  	github.com/nomadcode/nomadcode-core/internal/projectsync	4.994s
ok  	github.com/nomadcode/nomadcode-core/internal/protosocket	4.622s
ok  	github.com/nomadcode/nomadcode-core/internal/roadmapsync	4.684s
ok  	github.com/nomadcode/nomadcode-core/internal/roadmapsyncpipeline	4.995s
ok  	github.com/nomadcode/nomadcode-core/internal/scheduler	7.042s
ok  	github.com/nomadcode/nomadcode-core/internal/storage	4.883s
ok  	github.com/nomadcode/nomadcode-core/internal/workflow	4.804s
ok  	github.com/nomadcode/nomadcode-core/internal/workitem	4.844s
ok  	github.com/nomadcode/nomadcode-core/internal/workitempipeline	4.819s

$ curl -fsS http://toki-labs.com:18010/healthz
{"status":"ok"}

$ ssh toki@toki-labs.com 'cd ~/docker/agent-service/plane/compose && /usr/local/bin/docker compose exec -T postgres psql -U plane -d plane -At' << 'EOF'
select created_at, response_status, response_body from webhook_logs order by created_at desc limit 2;
EOF
2026-06-15 12:07:43.889665+00|202|{"status":"accepted","task_id":"e3c92411-4056-4b76-a879-66f7904125d0"}
2026-06-15 12:07:43.880869+00|202|{"status":"accepted","task_id":"e3c92411-4056-4b76-a879-66f7904125d0"}

$ ssh toki@toki-labs.com 'cd ~/agent-work/nomadcode/services/core && /usr/local/bin/docker compose logs --tail=300 nomadcode-core | grep -E "plane webhook|work item|task|authoring|ignored"'
nomadcode-core-1  | {"time":"2026-06-15T12:07:43.714788752Z","level":"INFO","msg":"plane webhook received","delivery":"b755085c-d356-45f6-9d2c-6e1884d36e31","header_event":"issue","event":"issue","action":"created","webhook_id":"e25a2d41-2c9f-4f5f-a0ce-cad6b993853f","workspace_id":"dadf050e-cd1e-4590-bc33-672511630841","normalized":true,"work_item_id":"93b677f5-7913-4111-ae05-916033ae533b","project_id":"a6beb42f-7a8a-410c-b50f-ea3ca94828f3","workspace_id_normalized":"dadf050e-cd1e-4590-bc33-672511630841","actor_id":"5d116a77-d3df-4f54-80bf-eca61e0118c4"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:43.767795127Z","level":"INFO","msg":"plane webhook received","delivery":"64a4b8e9-65d0-49c8-a621-fbeacaa6a4ff","header_event":"issue","event":"issue","action":"created","webhook_id":"e25a2d41-2c9f-4f5f-a0ce-cad6b993853f","workspace_id":"dadf050e-cd1e-4590-bc33-672511630841","normalized":true,"work_item_id":"93b677f5-7913-4111-ae05-916033ae533b","project_id":"a6beb42f-7a8a-410c-b50f-ea3ca94828f3","workspace_id_normalized":"dadf050e-cd1e-4590-bc33-672511630841","actor_id":"5d116a77-d3df-4f54-80bf-eca61e0118c4"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:43.888960502Z","level":"INFO","msg":"task job started","task_id":"e3c92411-4056-4b76-a879-66f7904125d0"}
nomadcode-core-1  | {"time":"2026-06-15T12:07:43.895142168Z","level":"INFO","msg":"task event notification requested","type":"task.running","task_id":"e3c92411-4056-4b76-a879-66f7904125d0"}

$ git diff --check
(clean)
```

## 코드리뷰 결과

- 종합 판정: PASS
- 차원별 평가:
  - correctness: Pass
  - completeness: Pass
  - test coverage: Pass
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Pass
  - verification trust: Pass
- 발견된 문제: 없음
- 다음 단계: PASS이므로 active plan/review를 log로 아카이브하고, `complete.log` 작성 후 task 디렉터리를 `agent-task/archive/2026/06/m-plane-work-item-webhook-intake/04+01,02,03_live_smoke/`로 이동한다. `m-plane-work-item-webhook-intake` completion event metadata를 보고하며 roadmap 수정은 런타임 책임으로 둔다.
