<!-- task=m-plane-origin-authoring-roundtrip-sync/06+05_plane_missing_create plan=0 tag=API -->

# Plan - API

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

구현 완료의 마지막 단계는 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이다. 선행 `05_canonical_id`의 `complete.log`가 없으면 구현을 시작하지 말고 검증 결과에 선행 미충족을 기록한다. 선택된 SDD/Milestone 결정이 막을 때만 review stub의 `사용자 리뷰 요청`을 채운다. 직접 사용자에게 묻거나 `USER_REVIEW.md`, `complete.log`, archive 이동을 수행하지 않는다.

## 배경

active Milestone 전체를 스캔해도 현재 bridge는 provider identity가 있는 문서만 Plane Todo projection으로 넘길 수 있다. SDD S11은 ledger와 Plane에서 발견되지 않는 active Milestone slug에 대해 Plane work item을 생성하고 slug ledger/marker를 남기라고 요구한다. 이 작업은 canonical id foundation 위에서 identity-less active doc을 생성 경로로 보내는 provider side-effect orchestration이다.

## 사용자 리뷰 요청 흐름

선택된 SDD 결정 또는 Milestone 잠금 결정만 review stub의 `사용자 리뷰 요청`에 기록한다. 외부 Plane credential 준비나 live service 접근 실패는 사용자 리뷰가 아니라 검증/환경 차단으로 기록한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/plane-origin-authoring-roundtrip-sync.md`
- Task ids:
  - `plane-missing-create`: active Milestone slug가 ledger와 Plane에서 발견되지 않으면 Plane work item을 생성하고, 생성된 Plane work item id를 slug ledger와 Milestone provider identity block 또는 동등한 sync marker에 기록한다.
- Completion mode: check-on-pass

## Spec Targets

- SDD: `agent-roadmap/sdd/agent-ops-mcp-control-plane/plane-origin-authoring-roundtrip-sync/SDD.md`
- Acceptance scenarios:
  - `S11`: task=`plane-missing-create`; evidence=`Plane adapter/reconcile tests or smoke proving missing active Milestone creates one Plane item and records ledger/marker`
- Completion mode: spec-check-on-pass

## 분석 결과

### 읽은 파일

- `agent-test/local/rules.md`
- `agent-test/local/core-smoke.md`
- `agent-test/local/workspace-ops-smoke.md`
- `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/plane-origin-authoring-roundtrip-sync.md`
- `agent-roadmap/sdd/agent-ops-mcp-control-plane/plane-origin-authoring-roundtrip-sync/SDD.md`
- `services/core/internal/gitosync/scanner.go`
- `services/core/internal/gitosync/scanner_test.go`
- `services/core/internal/gitosync/bridge.go`
- `services/core/internal/gitosync/bridge_test.go`
- `services/core/internal/roadmapsync/identity.go`
- `services/core/internal/roadmapsync/milestone_parser.go`
- `services/core/internal/roadmapsync/plane_format.go`
- `services/core/internal/roadmapsync/plane_projection.go`
- `services/core/internal/roadmapsync/plane_projection_test.go`
- `services/core/internal/roadmapsyncpipeline/service.go`
- `services/core/internal/roadmapsyncpipeline/service_test.go`
- `services/core/internal/storage/roadmap_sync_identities.go`
- `services/core/internal/workitem/provider.go`
- `services/core/internal/workitem/provider_test.go`
- `services/core/internal/adapters/plane/client.go`
- `services/core/internal/adapters/plane/client_test.go`

### 테스트 환경 규칙

test_env=`local`. core 변경 최소 검증은 `cd services/core && go test ./...`다. Plane live credential이 필요한 smoke는 이 plan의 필수 완료 조건이 아니다. provider side effect는 httptest/fake provider unit tests로 검증한다.

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

- identity-less active Milestone이 scanner/bridge에서 생성 후보로 보존되는 테스트가 없다.
- missing slug가 Plane create API를 한 번만 호출하고 ledger를 기록하는 pipeline test가 없다.
- 생성된 Plane work item id를 provider identity marker 또는 ledger에 남기는 테스트가 없다.

### 심볼 참조

- 변경 후보: `ScanOutput`, `ScannedMilestoneDoc`, `Bridge.enqueueDoc`, `workitem.Creator`, `roadmapsyncpipeline.Store`, `roadmapsyncpipeline.Service`.
- `CreateWorkItem`은 Plane adapter에 이미 구현되어 있다. bridge/pipeline은 아직 생성 facet을 사용하지 않는다.

### 분할 판단

split decision policy를 적용했다. 이 subtask는 `06+05_plane_missing_create`이며 predecessor `05_canonical_id`가 필요하다. 현재 active/complete predecessor는 없으므로 구현 시작 전 `agent-task/m-plane-origin-authoring-roundtrip-sync/05_canonical_id/complete.log` 또는 archive의 같은 index complete evidence가 필요하다. 06은 provider create side effect와 enqueue/pipeline orchestration이 함께 리뷰되어야 하므로 단일 subtask로 둔다.

### 범위 결정 근거

이 subtask는 Plane missing-create unit/fake 검증까지만 다룬다. live Plane full-cycle, Todo projection e2e, slot finalizer, slug conflict/reuse failure는 제외한다. canonical id schema 변경은 05 결과를 사용한다.

### 빌드 등급

`cloud-G06`: 외부 provider create side effect, scanner/bridge/pipeline orchestration, ledger update가 함께 변한다.

## 구현 체크리스트

- [ ] 선행 `05_canonical_id` complete evidence를 확인하고 없으면 구현하지 않는다.
- [ ] active scanner/bridge 결과가 provider identity 없는 active Milestone Markdown을 missing-create 후보로 보존하도록 타입과 tests를 조정한다.
- [ ] `roadmapsyncpipeline`에 Plane missing-create path를 추가해 canonical id lookup miss에서 `workitem.Creator.CreateWorkItem`을 한 번 호출하고 ledger/provider marker를 기록한다.
- [ ] Plane create 결과의 provider work item id가 slug identity row에 저장되고 title이 `[milestone-id] ...` 형태인지 tests로 검증한다.
- [ ] `cd services/core && go test ./internal/gitosync ./internal/roadmapsyncpipeline ./internal/adapters/plane ./internal/workitem`와 `cd services/core && go test ./...`를 통과시킨다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 의존 관계 및 구현 순서

`06+05_plane_missing_create`는 디렉터리명 기준으로 predecessor `05_canonical_id`에 의존한다. 구현 전 `05`의 `complete.log`가 active 또는 archive에 있어야 한다. 누락이면 이 plan의 구현을 시작하지 않는다.

### [API-1] Preserve Missing Active Milestone Candidates

문제: [scanner.go](/config/workspace/nomadcode/services/core/internal/gitosync/scanner.go:139)는 `ParseMilestoneIdentity` 실패 시 active path를 `ChangedFiles`에만 남기고 `Docs`에는 싣지 않는다. [bridge.go](/config/workspace/nomadcode/services/core/internal/gitosync/bridge.go:121)는 `out.Docs`만 순회하므로 identity 없는 active Milestone은 생성 후보가 되지 못한다.

해결 방법: active doc 타입에 `MilestoneID`, `Path`, `Markdown`, optional `Identity` 또는 `HasIdentity`를 포함한다. provider identity가 있으면 기존 projection enqueue를 유지하고, 없으면 missing-create enqueue/input으로 넘긴다.

수정 파일 및 체크리스트:
- [ ] `services/core/internal/gitosync/scanner.go`
- [ ] `services/core/internal/gitosync/scanner_test.go`
- [ ] `services/core/internal/gitosync/bridge.go`
- [ ] `services/core/internal/gitosync/bridge_test.go`

테스트 작성: 작성한다. identity-less active Milestone이 `Docs` 또는 `MissingCreateDocs`에 남고 archive candidate는 생성 후보가 아닌 테스트를 추가한다.

중간 검증: `cd services/core && go test ./internal/gitosync`.

### [API-2] Create Plane Work Item And Record Slug Ledger

문제: [service.go](/config/workspace/nomadcode/services/core/internal/roadmapsyncpipeline/service.go:113)는 develop match candidate가 ready일 때만 pipeline을 진행한다. missing active Milestone은 Plane work item id가 없으므로 `Expected` identity와 `Ref`를 만들 수 없다. [client.go](/config/workspace/nomadcode/services/core/internal/adapters/plane/client.go:236)는 `CreateWorkItem`을 제공하지만 pipeline provider interface는 creation facet을 받지 않는다.

해결 방법: canonical id lookup miss + missing provider identity input에서 `FormatPlaneProjection`으로 title/body를 만들고 `workitem.Creator.CreateWorkItem`을 호출한다. 생성 결과 ref를 slug identity row에 upsert하고, provider identity block injection 또는 ledger-only marker 중 05에서 정한 표준선에 맞춰 기록한다. 생성 후에는 same call에서 projection steps를 중복 실행하지 말고 created identity/next action을 명확히 반환한다.

수정 파일 및 체크리스트:
- [ ] `services/core/internal/roadmapsyncpipeline/service.go`
- [ ] `services/core/internal/roadmapsyncpipeline/service_test.go`
- [ ] `services/core/internal/roadmapsync/plane_format.go`
- [ ] `services/core/internal/roadmapsync/plane_format_test.go`
- [ ] `services/core/internal/workitem/provider.go`
- [ ] `services/core/internal/workitem/provider_test.go`
- [ ] `services/core/internal/adapters/plane/client.go`
- [ ] `services/core/internal/adapters/plane/client_test.go`

테스트 작성: 작성한다. fake creator가 한 번 호출되고, title prefix `[m1]`와 body projection이 전달되고, ledger upsert에 created work item id가 저장되는 pipeline test를 추가한다. Plane adapter httptest는 existing `CreateWorkItem` mapping이 유지되는지 보강한다.

중간 검증: `cd services/core && go test ./internal/roadmapsyncpipeline ./internal/adapters/plane ./internal/workitem`.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/core/internal/gitosync/scanner.go` | API-1 |
| `services/core/internal/gitosync/scanner_test.go` | API-1 |
| `services/core/internal/gitosync/bridge.go` | API-1 |
| `services/core/internal/gitosync/bridge_test.go` | API-1 |
| `services/core/internal/roadmapsyncpipeline/service.go` | API-2 |
| `services/core/internal/roadmapsyncpipeline/service_test.go` | API-2 |
| `services/core/internal/roadmapsync/plane_format.go` | API-2 |
| `services/core/internal/roadmapsync/plane_format_test.go` | API-2 |
| `services/core/internal/workitem/provider.go` | API-2 |
| `services/core/internal/workitem/provider_test.go` | API-2 |
| `services/core/internal/adapters/plane/client.go` | API-2 |
| `services/core/internal/adapters/plane/client_test.go` | API-2 |

## 최종 검증

`test -f agent-task/m-plane-origin-authoring-roundtrip-sync/05_canonical_id/complete.log || find agent-task/archive -path '*/m-plane-origin-authoring-roundtrip-sync/05_canonical_id/complete.log' -print -quit`

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

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

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