<!-- task=m-gito-protosocket-consumer-wire-readiness/02+01_bridge_e2e plan=0 tag=TEST -->

# Plan - TEST

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

`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이 필수입니다. 구현 후 검증을 실행하고 실제 stdout/stderr를 붙인 뒤 active 파일을 그대로 두고 리뷰 준비를 보고하세요. 최종 판정, log rename, `complete.log`, archive 이동은 code-review-skill 전용입니다.

구현 중 사용자만 결정할 수 있는 범위 변경, 사용자 소유 외부 환경/secret, 또는 scope conflict가 없이는 안전하게 진행할 수 없으면 review stub의 `사용자 리뷰 요청` 섹션에 근거와 재개 조건을 채우고 멈추세요. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않으며, `USER_REVIEW.md`, archive log, `complete.log`를 만들지 않습니다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 닫을 수 있는 증거 공백은 사용자 리뷰가 아닙니다.

## 배경

`gitoevents`와 `gitosync`는 각각 단위 테스트가 있지만, 실제 binary proto-socket consumer에서 branch scan과 `EnqueueRoadmapCreationSync`까지 이어지는 한 흐름의 검증은 없습니다. 이 계획은 선행 binary transport가 완료된 뒤, Gito `branch.updated` 한 건이 target branch 재검증 후 정확히 하나의 creation sync job으로 수렴함을 확인하는 integration-style test를 추가합니다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록합니다. 구현 에이전트의 직접 사용자 질문은 금지되며, code-review가 해당 요청을 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정합니다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/gito-protosocket-consumer-wire-readiness.md`
- Task ids:
  - `bridge-e2e`: wire-compatible consumer, branch scan, `EnqueueRoadmapCreationSync`까지 이어지는 integration test 또는 dev smoke 추가
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/agent-ops-mcp-control-plane/PHASE.md`
- `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/gito-protosocket-consumer-wire-readiness.md`
- `/config/workspace/gito/agent-contract/index.md`
- `/config/workspace/gito/agent-contract/provided/gito-forgejo-branch-events-v1.md`
- `agent-test/local/rules.md`
- `agent-test/local/core-smoke.md`
- `agent-test/local/workspace-ops-smoke.md`
- `services/core/internal/gitoevents/client.go`
- `services/core/internal/gitoevents/events.go`
- `services/core/internal/gitoevents/client_test.go`
- `services/core/internal/gitoevents/events_test.go`
- `services/core/internal/gitosync/runner.go`
- `services/core/internal/gitosync/bridge.go`
- `services/core/internal/gitosync/bridge_test.go`
- `services/core/internal/gitosync/scanner.go`
- `services/core/internal/gitosync/scanner_test.go`
- `services/core/internal/protosocket/server.go`
- `services/core/internal/protosocket/server_test.go`
- `services/core/internal/protosocket/tasks_test.go`
- `services/core/internal/scheduler/roadmap_sync_jobs.go`
- `services/core/internal/workitem/provider.go`
- `services/core/go.mod`

### 테스트 환경 규칙

`test_env=local`입니다. `agent-test/local/rules.md`, `agent-test/local/core-smoke.md`, `agent-test/local/workspace-ops-smoke.md`를 읽었습니다. 적용 명령은 `cd services/core && go test ./...`와 `git diff --check`입니다. 이 plan은 core integration-style unit test를 추가하므로 Go test cache보다 fresh run이 더 낫고, focused command에는 `-count=1`을 사용합니다.

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

현재 `bridge_test.go`는 fake scanner/reader/enqueuer로 `Bridge.Handle` semantics를 검증합니다. `scanner_test.go`는 git command sequence를 검증합니다. 하지만 실제 wire consumer -> scanner -> bridge -> enqueuer를 한 테스트에서 연결하지 않습니다.

### 심볼 참조

none. Exported API rename/remove 없이 test-only fakes나 helper를 추가합니다.

### 분할 판단

split decision policy를 평가했습니다. 이 plan은 `02+01_bridge_e2e`라서 predecessor index `01`에 의존합니다. 현재 active predecessor는 `agent-task/m-gito-protosocket-consumer-wire-readiness/01_wire_transport_decode/`이고 아직 `complete.log`가 없습니다. 구현은 해당 predecessor가 PASS하여 active 또는 archive `complete.log`가 생긴 뒤 시작해야 합니다.

### 범위 결정 근거

이 plan은 e2e 성격의 테스트와 필요한 test seam만 다룹니다. Production transport 구현은 `01_wire_transport_decode` 범위이고, reconnect/backoff/log 정책은 `03+01_failure_ops` 범위입니다. 실제 Plane API나 real River queue는 사용하지 않고 fake enqueuer로 job args를 검증합니다.

### 빌드 등급

`cloud-G07`입니다. binary protocol, async event delivery, git scan fake, scheduler job args를 한 번에 검증하는 넓은 context가 필요합니다.

## 구현 체크리스트

- [ ] 선행 `01_wire_transport_decode`의 active 또는 archived `complete.log`를 확인한 뒤 구현을 시작한다.
- [ ] binary proto-socket test server/client 흐름에서 Gito `event.subscribe` 후 `branch.updated` event를 발행하는 integration-style test를 추가한다.
- [ ] fake scanner/reader/enqueuer를 조합해 target branch 재검증 후 `EnqueueRoadmapCreationSync`가 정확히 한 번 호출되는지 assert한다.
- [ ] duplicate event나 no-milestone event가 같은 test fixture에서 추가 enqueue로 번지지 않는지 최소 한 케이스를 포함한다.
- [ ] `git diff --check`와 `cd services/core && go test ./...`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 의존 관계 및 구현 순서

이 subtask directory의 `+01`이 runtime dependency source of truth입니다. `01_wire_transport_decode`가 `complete.log`를 만들기 전에는 구현하지 않습니다. 현재 확인 시점에는 predecessor complete evidence가 없습니다.

### [TEST-1] Add wire-to-bridge integration test

문제: [gitosync/bridge.go](/config/workspace/nomadcode/services/core/internal/gitosync/bridge.go:100)는 event를 scan/enqueue로 넘기고 [gitosync/runner.go](/config/workspace/nomadcode/services/core/internal/gitosync/runner.go:88)는 runner를 조립하지만, 둘이 실제 binary event stream과 함께 검증되지 않습니다.

해결 방법: `services/core/internal/gitosync/runner_test.go` 또는 새 test file에서 in-process proto-socket server를 띄우고, `NewRunner`가 연결하게 합니다. server는 subscribe request를 확인한 뒤 contract-shaped `branch.updated` broadcast를 보냅니다. Bridge에는 fake scanner/reader/enqueuer를 연결하고 enqueued job count와 args를 검증합니다.

수정 파일 및 체크리스트:

- [ ] `services/core/internal/gitosync/runner_test.go`에 e2e-style test를 추가한다.
- [ ] fake scanner는 event `After` revision을 읽어 `ScanOutput`을 반환한다.
- [ ] fake enqueuer는 `RoadmapCreationSyncJobArgs`를 capture한다.
- [ ] expected `Ref`, `TodoStateID`, `RoadmapRevision`, `MilestoneMarkdown`, `ExternalSource/ExternalID`를 assert한다.

테스트 작성: 필수. 테스트명 예: `TestWireConsumerEventEnqueuesCreationSyncOnce`.

중간 검증:

```bash
cd services/core && go test ./internal/gitosync -run TestWireConsumerEventEnqueuesCreationSyncOnce -count=1
```

### [TEST-2] Keep side-effect boundaries visible in e2e fixture

문제: [gitoevents/client.go](/config/workspace/nomadcode/services/core/internal/gitoevents/client.go:133)는 milestone path가 없으면 handler를 호출하지 않고, [gitosync/bridge.go](/config/workspace/nomadcode/services/core/internal/gitosync/bridge.go:106)는 duplicate revision을 skip합니다. e2e fixture가 happy path만 검증하면 중복 Plane mutation 방지 근거가 약합니다.

해결 방법: same test file에 duplicate branch.updated event 또는 no-milestone event를 추가하고 enqueuer call count가 1로 유지되는지 확인합니다. 기존 unit tests를 중복하지 않도록 wire path에서 최소 케이스만 둡니다.

수정 파일 및 체크리스트:

- [ ] duplicate event 또는 no-milestone event case를 추가한다.
- [ ] timeout이 있는 channel receive를 써서 async test가 hang하지 않도록 한다.
- [ ] test helper는 1초 안팎 timeout으로 deterministic하게 실패하도록 한다.

테스트 작성: 필수. `TEST-1`과 같은 test 또는 별도 test로 작성합니다.

중간 검증:

```bash
cd services/core && go test ./internal/gitosync -count=1
```

## 수정 파일 요약

| 파일 | 항목 |
| --- | --- |
| `services/core/internal/gitosync/runner_test.go` | TEST-1, TEST-2 |
| `services/core/internal/gitosync/bridge_test.go` | TEST-2 if existing fake helpers are reused |

## 최종 검증

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

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