<!-- task=m-external-integration/01_plane_adapter plan=0 tag=PLANE -->

# Plane Adapter Expansion Plan

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 단계다. 구현 후 검증 명령을 실행하고 실제 stdout/stderr를 붙여 넣은 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자 결정, 사용자 소유 외부 환경, scope 충돌 없이는 안전하게 진행할 수 없는 경우에는 review stub의 `사용자 리뷰 요청` 섹션에 근거를 남기고 멈춘다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다.

## 배경

External Integration 마일스톤은 Plane work item 생성, comment, status update를 실제 adapter 흐름으로 닫아야 한다. 현재 Plane adapter는 lookup/comment/status projection은 HTTP로 구현되어 있지만 create는 `ErrNotImplemented`를 반환한다. 이 작업은 Plane provider 확장만 다루고 Jira/Mattermost는 sibling plan으로 분리한다.

## 사용자 리뷰 요청 흐름

구현 중 사용자-only blocker가 생기면 active `CODE_REVIEW-local-G06.md`의 `사용자 리뷰 요청` 섹션을 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식으로 채운다. `USER_REVIEW.md`, archive log, `complete.log` 작성은 code-review 전용이다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/external-integration/milestones/external-integration.md`
- Task ids:
  - `plane-adapter-expand`: Plane work item 생성, comment, status update adapter 확장
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/private/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/update-roadmap/SKILL.md`
- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/external-integration/PHASE.md`
- `agent-roadmap/phase/external-integration/milestones/external-integration.md`
- `agent-test/local/rules.md`
- `agent-test/local/core-smoke.md`
- `agent-ops/rules/project/domain/core/rules.md`
- `services/core/internal/adapters/plane/client.go`
- `services/core/internal/adapters/plane/client_test.go`
- `services/core/internal/workitem/provider.go`
- `services/core/internal/workitem/provider_test.go`
- `services/core/internal/workitempipeline/service.go`
- `services/core/internal/workitempipeline/service_test.go`
- `services/core/internal/http/handlers.go`
- `services/core/internal/http/handlers_test.go`
- `services/core/internal/http/router.go`
- `services/core/cmd/plane-smoke/main.go`
- `services/core/cmd/plane-smoke/main_test.go`
- `services/core/internal/config/config.go`
- `services/core/internal/config/config_test.go`
- `services/core/cmd/server/main.go`
- `services/core/go.mod`
- `services/core/README.md`
- `README.md`

### 테스트 환경 규칙

- test_env: `local`
- `agent-test/local/rules.md` 있음, 읽음.
- matched profile: `agent-test/local/core-smoke.md` 읽음.
- 적용 명령: 최소 `cd services/core && go test ./...`; 보조 `cd services/core && go vet ./...`.
- live Plane write smoke는 private `.env.plane.local`과 테스트용 work item이 있을 때만 실행한다. plan의 PASS 필수는 deterministic unit tests이며 live smoke는 실행 가능 시 추가 evidence로 기록한다.

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

- Plane create HTTP request: 기존 테스트 없음. `services/core/internal/adapters/plane/client_test.go`에 POST body/path/header 테스트 추가 필요.
- provider-neutral creator capability: 기존 계약 없음. `services/core/internal/workitem/provider_test.go`에 capability/interface 테스트 추가 필요.
- handler/pipeline 자동 create flow: 현재 `/api/integrations/plane/tasks`는 기존 work item 조회로 core task를 만든다. 이번 plan은 Plane native work item 생성 adapter까지만 닫고, HTTP API surface 확장은 필요하면 같은 plan 안의 좁은 endpoint로만 추가한다.

### 심볼 참조

- renamed/removed symbols: none.
- new/changed symbols expected: `workitem.Creator`, `workitem.CreateInput`, `workitem.CapabilityCreate`, `plane.CreateIssue`.

### 분할 판단

- split decision policy evaluated.
- shared task group: `agent-task/m-external-integration/`
- sibling plans:
  - `01_plane_adapter`: independent Plane adapter create/comment/status expansion.
  - `02_jira_adapter`: independent Jira adapter implementation.
  - `03_mattermost_adapter`: independent Mattermost REST adapter plus push evidence plan.
  - `04+01,02,03_adapter_boundary`: depends on 01, 02, 03 complete logs.
- This plan is single-subtask because the Plane change has one provider boundary and deterministic httptest coverage. It must not roll Jira or Mattermost into this subtask.

### 범위 결정 근거

- Exclude Jira adapter, Mattermost adapter, A2A, IOP native protocol, Plane parent/milestone/subtask control flow, MCP control plane.
- Plane board state and canonical task lifecycle stay separate per `agent-ops/rules/project/domain/core/rules.md`.
- Do not store tokens or sample secret values in tracked files.

### 빌드 등급

- build lane/grade: `local-G06` - bounded Go adapter/interface work with deterministic tests.
- review lane/grade: `local-G06` - review can compare HTTP paths, DTOs, and tests locally.

## 구현 체크리스트

- [ ] [PLANE-1] Plane create capability and adapter HTTP method를 구현한다.
- [ ] [PLANE-2] Plane adapter tests and optional smoke docs를 갱신한다.
- [ ] `cd services/core && go test ./...`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [PLANE-1] Plane create capability and adapter HTTP method

문제: `services/core/internal/adapters/plane/client.go:56`에 `CreateIssueInput`이 있지만 `services/core/internal/adapters/plane/client.go:166`의 `CreateIssue`는 log-only stub이고 `ErrNotImplemented`를 반환한다.

Before:

```go
// services/core/internal/adapters/plane/client.go:166
func (c *Client) CreateIssue(ctx context.Context, input CreateIssueInput) error {
	c.log(ctx, "plane create issue skipped", "title", input.Title)
	return ErrNotImplemented
}
```

해결 방법:

- `workitem`에 create facet을 추가한다.
- `plane.Client`가 create capability를 선언하고 `CreateIssue`에서 `POST /api/v1/workspaces/{workspace}/projects/{project}/work-items/`를 호출한다.
- input에는 workspace/project가 필요하므로 `CreateIssueInput`에 `WorkspaceSlug`, `ProjectID`, `Title`, `DescriptionHTML` 또는 `Description`를 둔다. 기존 필드명은 필요하면 호환 유지하되 빈 title은 `ErrInvalidInput`.
- provider-neutral `CreateWorkItem(ctx, workitem.CreateInput)`가 Plane create를 호출하도록 mapping한다.

수정 파일 및 체크리스트:

- [ ] `services/core/internal/workitem/provider.go`: `CapabilityCreate`, `Creator`, `CreateInput`, `CreateResult` 추가.
- [ ] `services/core/internal/adapters/plane/client.go`: compile-time `workitem.Creator` assertion, capability map, `CreateIssue` HTTP POST 구현.
- [ ] `services/core/internal/adapters/plane/client.go`: `workItemsPath(workspace, project)` helper 추가.
- [ ] `services/core/internal/adapters/plane/client.go`: invalid input과 missing config는 기존 error로 처리.

테스트 작성:

- 추가: `services/core/internal/adapters/plane/client_test.go`
  - `TestCreateIssuePostsWorkItem`: method/path/header/body/status 201 검증.
  - `TestCreateWorkItemMapsNeutralCreateInput`: provider-neutral input mapping 검증.
- 추가: `services/core/internal/workitem/provider_test.go`
  - capability constant/interface compile behavior가 기존 mapping을 깨지 않는지 확인.

중간 검증:

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

기대: Plane/workitem package tests pass.

## [PLANE-2] Plane adapter tests and optional smoke docs

문제: `services/core/cmd/plane-smoke/main.go:76`의 `PlaneClient`는 lookup/comment/status만 검증한다. live create는 test data를 만들 수 있으므로 기본 smoke에 바로 넣으면 위험하다.

해결 방법:

- unit tests로 create를 필수 검증한다.
- live smoke는 기본 read/write status/comment 흐름을 유지하고, create smoke는 별도 env flag가 있을 때만 수행하도록 설계한다. 해당 flag가 필요하면 `PLANE_SMOKE_CREATE_TITLE`처럼 명확한 이름을 쓰고 README에 destructive note를 남긴다.
- create smoke가 과해 보이면 이번 subtask에서는 README의 "Plane work item 생성 adapter 구현됨, live create smoke는 후속 수동 검증" 정도로만 정리한다.

수정 파일 및 체크리스트:

- [ ] `services/core/cmd/plane-smoke/main.go`: create smoke를 넣는다면 opt-in env와 redaction 유지.
- [ ] `services/core/cmd/plane-smoke/main_test.go`: opt-in config와 create call 검증.
- [ ] `services/core/README.md`: Plane create/comment/status adapter 구현 상태와 optional smoke 조건 업데이트.

테스트 작성:

- smoke command를 수정하면 `services/core/cmd/plane-smoke/main_test.go`에 config/run test 추가.
- README만 수정한다면 추가 테스트 없음. 단 `go test ./...`는 유지.

중간 검증:

```bash
cd services/core && go test ./cmd/plane-smoke ./internal/adapters/plane
```

기대: plane smoke and adapter tests pass.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/core/internal/workitem/provider.go` | PLANE-1 |
| `services/core/internal/workitem/provider_test.go` | PLANE-1 |
| `services/core/internal/adapters/plane/client.go` | PLANE-1 |
| `services/core/internal/adapters/plane/client_test.go` | PLANE-1 |
| `services/core/cmd/plane-smoke/main.go` | PLANE-2 |
| `services/core/cmd/plane-smoke/main_test.go` | PLANE-2 |
| `services/core/README.md` | PLANE-2 |

## 최종 검증

```bash
cd services/core && go test ./...
cd services/core && go vet ./...
```

기대: both commands exit 0. Go test cache output is acceptable unless implementation changes timing-sensitive behavior; use `-count=1` if a new test is flaky or time-sensitive.

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