<!-- task=m-milestone-work-item-creation-sync/02+01_iop_authoring_bridge plan=0 tag=API -->

# Plan - API IOP Authoring Bridge

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

`CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 반드시 채운다. 검증 명령을 실행하고 실제 출력과 구현 메모를 남긴 뒤 active 파일을 유지한 채 리뷰 준비를 보고한다. 사용자 전용 결정, 사용자 소유 외부 환경, 범위 충돌로 막히면 review stub의 `사용자 리뷰 요청`에 근거를 기록하고 멈춘다. 구현 중 사용자에게 직접 질문하거나 `request_user_input`을 호출하지 않는다.

## 배경

현재 OpenAI-compatible client는 `/v1/responses` 호출과 flat string metadata를 지원한다. Milestone은 IOP CLI 직접 실행이 아니라 `model`, `input`, `metadata.workspace`만으로 workspace-bound authoring run을 시작해야 한다. 이 plan은 01 topology 완료 후 Plane 티켓을 slot workspace의 1회 authoring run으로 연결한다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active review stub의 `사용자 리뷰 요청`에 기록한다. 직접 사용자 프롬프트는 금지이며, code-review가 `USER_REVIEW.md` 작성 여부를 판단한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md`
- Task ids:
  - `cycle-iop-http-ready`: IOP Edge OpenAI-compatible HTTP(`/v1/responses`) workspace agent 실행 통로를 선행 조건으로 확인한다.
  - `cycle-authoring-run`: Plane 티켓 제목/본문과 provider work item identity를 입력으로 `slots/<index>` workspace에서 1회 authoring run을 실행한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/domain/core/rules.md`
- `agent-ops/rules/project/domain/contracts/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/core-smoke.md`
- `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md`
- `services/core/internal/model/model.go`
- `services/core/internal/adapters/openai/client.go`
- `services/core/internal/adapters/openai/client_test.go`
- `services/core/internal/scheduler/jobs.go`
- `services/core/internal/scheduler/jobs_test.go`
- `services/core/internal/workitempipeline/service.go`
- `services/core/internal/workitem/provider.go`
- `services/core/cmd/server/main.go`
- `services/core/internal/config/config.go`
- `packages/contracts/notes/flutter-core-api-candidates.md`

### 테스트 환경 규칙

- test_env: `local`.
- `agent-test/local/rules.md`, `agent-test/local/core-smoke.md` 읽음.
- core 코드 변경 필수 검증: `cd services/core && go test ./...`.
- protocol/contract note 변경 시 `git diff --check`도 실행한다.
- 외부 IOP credential 없이 unit test와 httptest 기반 request-shape 검증으로 닫는다.

### 테스트 커버리지 공백

- 실제 IOP Edge 원격 실행은 credential/외부 서비스가 필요하므로 unit test에서 mock HTTP server로 request shape와 failure mapping을 검증한다.
- agent가 실제 Milestone 파일을 작성하고 push하는 e2e는 03 develop match plan과 연결되며 여기서는 authoring request/result state까지만 검증한다.

### 심볼 참조

- renamed/removed symbols: none.

### 분할 판단

- split decision policy를 평가했다.
- 이 plan은 `02+01_iop_authoring_bridge`이며 predecessor `01_workspace_topology` complete.log가 필요하다. 현재 missing.
- 03/04/05는 이 plan의 authoring result와 metadata를 소비하므로 별도 dependent plan으로 분리했다.

### 범위 결정 근거

- Plane Todo projection, identity map persistence, idempotency retry는 후속 plan으로 제외한다.
- A2A path는 현 Milestone의 1차 통로가 아니므로 변경하지 않는다.

### 빌드 등급

- build: `cloud-G07`. 외부 protocol shape, scheduler execution boundary, metadata contract가 맞물려 있어 더 넓은 reasoning과 review가 필요하다.

## 구현 체크리스트

- [ ] `model.GenerateInput.Metadata`가 `metadata.workspace` object를 표현할 수 있게 additive typed metadata 구조를 도입하고 기존 flat metadata 호환을 유지한다.
- [ ] IOP workspace authoring request builder를 추가해 slot path, Plane ticket title/body, provider identity, project sync 설정, roadmap 작성 지시를 `/v1/responses` payload에 담는다.
- [ ] authoring run 상태 모델 `in_progress`, `succeeded`, `failed`와 stale 판단 기준을 저장 가능한 typed metadata 또는 새 persistence 경계로 남긴다.
- [ ] scheduler 또는 work item pipeline에서 Plane-origin authoring mode task가 일반 model completion과 구분되어 IOP HTTP bridge를 호출하도록 연결한다.
- [ ] `cd services/core && go test ./...`와 `git diff --check`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 의존 관계 및 구현 순서

- `01_workspace_topology`의 `complete.log`가 필요하다. 현재 active predecessor만 있고 complete.log는 missing이다.

### [API-1] Responses Metadata Workspace Shape

#### 문제

[services/core/internal/model/model.go](/config/workspace/nomadcode/services/core/internal/model/model.go:12)는 `Metadata map[string]string`만 제공한다. Milestone은 `metadata.workspace` object를 요구한다([milestone-work-item-creation-sync.md](/config/workspace/nomadcode/agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md:54)).

#### 해결 방법

기존 callers를 깨지 않도록 `Metadata map[string]string`은 유지하고, `ExtraMetadata map[string]any` 또는 typed `WorkspaceMetadata`를 추가한다. OpenAI adapter는 둘을 병합하되 key 충돌은 typed workspace가 이기게 한다.

```go
// Before: services/core/internal/adapters/openai/client.go:144
type responsesRequest struct {
    Metadata map[string]string `json:"metadata,omitempty"`
}
```

```go
// After
type responsesRequest struct {
    Metadata map[string]any `json:"metadata,omitempty"`
}
```

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

- [ ] `services/core/internal/model/model.go`
- [ ] `services/core/internal/adapters/openai/client.go`
- [ ] `services/core/internal/adapters/openai/client_test.go`

#### 테스트 작성

- `TestGenerateCallsResponsesAPI`에 `metadata.workspace.path`, `metadata.workspace.source_branch`, provider identity assertion을 추가한다.
- 기존 flat `task_id`, `source` metadata가 유지되는지 검증한다.

#### 중간 검증

```bash
cd services/core && go test ./internal/adapters/openai
```

### [API-2] Authoring Run Builder

#### 문제

[services/core/internal/scheduler/jobs.go](/config/workspace/nomadcode/services/core/internal/scheduler/jobs.go:210)는 task payload를 generic prompt로 바꿀 뿐 Plane ticket/workspace authoring request를 만들지 않는다.

#### 해결 방법

`internal/authoring` 또는 `internal/workitempipeline` 하위에 request builder를 추가한다. 입력은 Plane work item title/body, `CheckoutMetadata`, provider identity이며 출력은 `model.GenerateInput`이다. prompt에는 roadmap Milestone 생성/갱신 지시와 provider identity 보존 지시를 넣는다.

```go
// Before: services/core/internal/scheduler/jobs.go:225
return model.GenerateInput{
    Input: input,
    Instructions: instructions,
    Metadata: map[string]string{...},
}
```

```go
// After
if authoring, ok := BuildAuthoringGenerateInput(task); ok {
    return authoring
}
```

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

- [ ] `services/core/internal/authoring/request.go`
- [ ] `services/core/internal/authoring/request_test.go`
- [ ] `services/core/internal/scheduler/jobs.go`
- [ ] `services/core/internal/scheduler/jobs_test.go`

#### 테스트 작성

- Plane-origin metadata와 payload가 있을 때 workspace-bound generate input이 만들어지는지 검증한다.
- 일반 task는 기존 generic prompt behavior를 유지하는지 검증한다.

#### 중간 검증

```bash
cd services/core && go test ./internal/authoring ./internal/scheduler
```

### [API-3] Authoring State Boundary

#### 문제

Milestone은 authoring run 최소 상태와 stale/failed 기준을 요구하지만([milestone-work-item-creation-sync.md](/config/workspace/nomadcode/agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md:88)), 현재 workflow status는 generic task status뿐이다.

#### 해결 방법

첫 slice에서는 별도 attempt table을 만들지 않고 task metadata에 `authoring_run_state`, `authoring_updated_at`, `authoring_failure_type`를 기록한다. scheduler completion은 IOP HTTP call 성공만으로 Plane projection까지 가지 않는다.

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

- [ ] `services/core/internal/workflow/model.go`
- [ ] `services/core/internal/workflow/lifecycle.go`
- [ ] `services/core/internal/scheduler/jobs.go`
- [ ] `services/core/internal/scheduler/jobs_test.go`

#### 테스트 작성

- 성공 시 `authoring_run_state=succeeded`, 실패 시 `failed` metadata가 남는지 lifecycle fake로 검증한다.
- timeout은 별도 상태가 아니라 `updated_at` 기준 stale 판정 helper로 검증한다.

#### 중간 검증

```bash
cd services/core && go test ./internal/workflow ./internal/scheduler
```

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/core/internal/model/model.go` | API-1 |
| `services/core/internal/adapters/openai/client.go` | API-1 |
| `services/core/internal/adapters/openai/client_test.go` | API-1 |
| `services/core/internal/authoring/request.go` | API-2 |
| `services/core/internal/authoring/request_test.go` | API-2 |
| `services/core/internal/scheduler/jobs.go` | API-2, API-3 |
| `services/core/internal/scheduler/jobs_test.go` | API-2, API-3 |
| `services/core/internal/workflow/model.go` | API-3 |
| `services/core/internal/workflow/lifecycle.go` | API-3 |

## 최종 검증

```bash
cd services/core && go test ./...
git diff --check
```

Go test cache output is acceptable for unchanged packages; changed packages must appear in output or be rerun directly as 중간 검증.

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