<!-- task=m-gito-http-webhook-consumer-readiness/03+01,02_http_scan_enqueue plan=0 tag=TEST -->

# Plan - TEST

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

`CODE_REVIEW-local-G05.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이 마지막 구현 단계다. 구현 후 active 파일을 유지하고 리뷰 준비 상태로 보고한다. 최종 판정, log rename, `complete.log`, archive 이동은 code-review 전용이다. 선택된 SDD 결정 또는 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 review stub의 `사용자 리뷰 요청`을 채우고 멈춘다. 구현 중 채팅으로 사용자에게 직접 묻거나 선택지를 제시하지 않는다.

## 배경

현재 `sync-bridge` Epic에서 `scan-enqueue`만 HTTP webhook delivery가 실제 bridge scan/enqueue까지 이어지는 증거가 부족하다. 기존 code는 HTTP receiver, main adapter, `gitosync.Bridge`가 분리되어 있어 unit test들이 각 계층을 다루지만, signed HTTP delivery가 adapter를 통해 scanner와 `EnqueueRoadmapCreationSync`까지 닿는 통합 증거가 없다. 이 계획은 production behavior를 넓히기보다 missing evidence를 deterministic test로 고정한다.

## 사용자 리뷰 요청 흐름

사용자 리뷰 요청은 선택된 SDD 결정 또는 선택된 Milestone lock 결정이 실구현을 차단할 때만 active `CODE_REVIEW-local-G05.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 환경, secret, 외부 서비스 준비, 검증 증거 공백은 사용자 리뷰 요청이 아니며 `검증 결과` 또는 follow-up으로 남긴다. 구현 에이전트는 직접 사용자에게 묻지 않는다.

## Archive Evidence Snapshot

- `agent-task/archive/2026/06/m-gito-http-webhook-consumer-readiness/01_payload_boundary/complete.log`: PASS; `payload-boundary`와 S02 완료.
- `agent-task/archive/2026/06/m-gito-http-webhook-consumer-readiness/02+01_http_receiver_idempotency/complete.log`: PASS; `receiver`, `idempotency`와 S01/S03 완료.
- 선행 의존성: `01`과 `02` 모두 archive `complete.log`로 충족.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/gito-http-webhook-consumer-readiness.md`
- Task ids:
  - `scan-enqueue`: HTTP receiver에서 받은 on-target event가 target branch fetch/scan 이후 `EnqueueRoadmapCreationSync`로 이어진다.
- Completion mode: check-on-pass

## Spec Targets

- SDD: `agent-roadmap/sdd/agent-ops-mcp-control-plane/gito-http-webhook-consumer-readiness/SDD.md`
- Acceptance scenarios:
  - `S04`: task=`scan-enqueue`; evidence=`bridge test proving accepted HTTP delivery reaches branch scan and one enqueue`
- 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/current.md`
- `agent-roadmap/phase/agent-ops-mcp-control-plane/PHASE.md`
- `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/gito-http-webhook-consumer-readiness.md`
- `agent-roadmap/sdd/agent-ops-mcp-control-plane/gito-http-webhook-consumer-readiness/SDD.md`
- `agent-task/archive/2026/06/m-gito-http-webhook-consumer-readiness/01_payload_boundary/complete.log`
- `agent-task/archive/2026/06/m-gito-http-webhook-consumer-readiness/02+01_http_receiver_idempotency/complete.log`
- `../gito/agent-contract/provided/gito-forgejo-branch-events-v1.md`
- `services/core/internal/http/gito_webhook.go`
- `services/core/internal/http/gito_webhook_test.go`
- `services/core/internal/http/handlers.go`
- `services/core/internal/http/handlers_test.go`
- `services/core/internal/http/router.go`
- `services/core/internal/gitosync/bridge.go`
- `services/core/internal/gitosync/bridge_test.go`
- `services/core/internal/gitosync/runner.go`
- `services/core/internal/gitosync/runner_test.go`
- `services/core/internal/gitosync/scanner.go`
- `services/core/internal/gitosync/scanner_test.go`
- `services/core/internal/gitoevents/events.go`
- `services/core/internal/gitoevents/events_test.go`
- `services/core/internal/gitoevents/client.go`
- `services/core/internal/gitoevents/client_test.go`
- `services/core/internal/config/config.go`
- `services/core/internal/config/config_test.go`
- `services/core/cmd/server/main.go`
- `services/core/README.md`
- `services/core/docker-compose.yml`
- `README.md`

### 테스트 환경 규칙

- test_env: `local`
- 읽은 env rule: `agent-test/local/rules.md`
- 매칭 profile: `agent-test/local/core-smoke.md`, `agent-test/local/workspace-ops-smoke.md`
- 적용 명령: core 변경은 최소 `cd services/core && go test ./...`; docs/roadmap 변경은 `git diff --check`.
- 이 계획의 fresh evidence가 필요하므로 Go test cache는 허용하지 않고 `-count=1`을 사용한다.

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

- HTTP receiver acceptance/idempotency는 `services/core/internal/http/gito_webhook_test.go`가 커버한다.
- Bridge scan/enqueue는 `services/core/internal/gitosync/bridge_test.go`와 proto-socket wire test가 커버한다.
- HTTP receiver -> main adapter -> bridge scan/enqueue 통합 경로는 현재 공백이다.

### 심볼 참조

- renamed/removed symbol: 없음.

### 분할 판단

- split decision policy를 먼저 평가했다.
- shared task group: `agent-task/m-gito-http-webhook-consumer-readiness`
- sibling: `03+01,02_http_scan_enqueue`, predecessors `01`, `02`.
- predecessor `01`: archive `agent-task/archive/2026/06/m-gito-http-webhook-consumer-readiness/01_payload_boundary/complete.log`로 충족.
- predecessor `02`: archive `agent-task/archive/2026/06/m-gito-http-webhook-consumer-readiness/02+01_http_receiver_idempotency/complete.log`로 충족.
- 이 subtask는 HTTP receiver와 bridge의 통합 evidence만 다루므로 새 하위 split은 만들지 않는다.

### 범위 결정 근거

- Gito producer, outbound webhook delivery worker, subscription API는 Gito repo 책임이므로 제외한다.
- Plane lifecycle, Milestone 하위 티켓 동기화, Flutter UI는 Milestone 범위 제외에 있으므로 제외한다.
- production behavior 변경은 테스트가 실패해 필요한 경우에만 최소 보정한다.

### 빌드 등급

- `local-G05`: 여러 core package 경계를 잇는 통합 테스트지만 behavior와 검증이 deterministic하고 외부 서비스가 필요 없다.

## 구현 체크리스트

- [ ] signed HTTP `branch.updated` delivery가 `gitoBridgeHTTPAdapter`를 통해 scanner와 `EnqueueRoadmapCreationSync`까지 한 번 도달하는 통합 테스트를 추가한다. 검증: `cd services/core && go test -count=1 ./cmd/server`.
- [ ] 테스트가 드러내는 compile/import 또는 adapter wiring 문제만 최소 수정한다.
- [ ] 최종 검증으로 `cd services/core && go test -count=1 ./cmd/server ./internal/http ./internal/gitosync`와 `cd services/core && go test -count=1 ./...`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [TEST-1] HTTP webhook to bridge enqueue evidence

#### 문제

- `services/core/internal/http/gito_webhook.go:185`는 verified event를 `GitoBranchEventHandler`로 넘긴다.
- `services/core/cmd/server/main.go:171`은 handler를 `gitoBridgeHTTPAdapter`로 설정한다.
- `services/core/cmd/server/main.go:251`은 HTTP event를 `gitoevents.BranchUpdatedEvent`로 변환한다.
- `services/core/internal/gitosync/bridge.go:100`은 scanner와 enqueuer를 호출한다.
- 이 전체 경로를 signed HTTP request에서 한 번에 증명하는 test가 없다.

#### 해결 방법

`services/core/cmd/server/main_test.go`를 새로 만들고 package `main` test에서 unexported `gitoBridgeHTTPAdapter`를 직접 사용한다. Test fake는 `gitosync.Scanner`, `workitem.Reader`, `gitosync.Enqueuer`를 구현한다. `apphttp.NewHandler(nil, nil, nil, nil)`에 Gito webhook config와 adapter를 설정하고 signed HTTP request를 `ReceiveGitoWebhook` 또는 router로 전달한다.

Before:

```go
// services/core/cmd/server/main.go:247
type gitoBridgeHTTPAdapter struct {
	bridge *gitosync.Bridge
}

func (a *gitoBridgeHTTPAdapter) Handle(ctx context.Context, ev apphttp.GitoBranchUpdatedEvent) error {
	return a.bridge.Handle(ctx, gitoevents.BranchUpdatedEvent{
		RepoID: ev.RepoID,
		Branch: ev.Branch,
		Before: ev.Before,
		After:  ev.After,
	})
}
```

After: production code should remain as-is unless the new test exposes an actual wiring bug.

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

- [ ] `services/core/cmd/server/main_test.go` 추가.
- [ ] fake scanner가 HTTP body의 `before`/`after` 값을 받은 event를 기록한다.
- [ ] fake enqueuer가 exactly one `scheduler.RoadmapCreationSyncJobArgs`를 기록한다.
- [ ] response가 `202 Accepted`인지 확인한다.
- [ ] job `RoadmapRevision`이 HTTP payload의 `after` revision인지 확인한다.

#### 테스트 작성

- 작성: `TestGitoHTTPWebhookDeliveryEnqueuesCreationSyncOnce`
- 목적: signed HTTP delivery -> HTTP receiver -> main adapter -> bridge scanner -> enqueuer 경로를 한 번에 증명한다.

#### 중간 검증

```bash
cd services/core && go test -count=1 ./cmd/server
```

Expected: PASS.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/core/cmd/server/main_test.go` | TEST-1 |
| `services/core/cmd/server/main.go` | TEST-1, 테스트가 드러낸 최소 보정이 있을 때만 |

## 최종 검증

```bash
cd services/core && go test -count=1 ./cmd/server ./internal/http ./internal/gitosync
cd services/core && go test -count=1 ./...
git diff --check
```

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