# Milestone: Forgejo Branch Event MVP

## 위치

- Roadmap: `agent-roadmap/ROADMAP.md`
- Phase: `agent-roadmap/phase/control-plane-foundation/PHASE.md`

## 목표

NomadCode가 `develop` 같은 source-of-truth branch 변경을 즉시 감지할 수 있도록 Forgejo push webhook을 Gito가 수신하고, watched branch 변경을 `branch.updated` normalized event로 변환해 proto-socket `event` channel로 전달하는 MVP를 만든다.

## 상태

[완료]

## 승격 조건

- 없음

## 구현 잠금

- 상태: 해제
- 결정 필요: 없음

## 범위

- Forgejo push webhook REST callback
- webhook signature 검증과 provider payload normalization
- in-memory branch watch bootstrap
- proto-socket `event.subscribe`와 `branch.updated` broadcast
- `../nomadcode` proto-socket client 소비 smoke를 1차 MVP 검증선으로 둔다
- MVP 이후 durable storage/outbox, revision cursor, duplicate push idempotency hardening 경계

## 기능

### Epic: [forgejo-intake] Forgejo branch intake

Forgejo push event를 Gito 내부 revision event 입력으로 변환한다.

- [x] [push-callback] `POST /callbacks/forgejo/push` callback을 추가한다. 검증: `services/core/internal/controlplane` 테스트가 watched branch push 수신 시 `branch.updated` event 생성을 확인한다.
- [x] [signature] `FORGEJO_WEBHOOK_SECRET` 기반 `X-Forgejo-Signature` HMAC-SHA256 검증을 추가한다. 검증: `services/core/internal/provider/forgejo` 테스트가 plain/prefixed signature를 확인한다.
- [x] [push-normalize] Forgejo `ref`, `before`, `after`, commit file list를 `RevisionEvent` 후보로 정규화한다. 검증: `services/core/internal/provider/forgejo` 테스트가 branch/ref/changed file mapping을 확인한다.

### Epic: [branch-watch] Watched branch event routing

특정 repo/branch에 listener를 걸고 일치하는 provider event만 내부 event로 흘린다.

- [x] [watch-bootstrap] `POST /api/listeners/branches` in-memory branch watch bootstrap을 추가한다. 검증: `services/core/internal/controlplane` 테스트가 `nomadcode/develop` watch 등록 후 Forgejo push matching을 확인한다.
- [x] [event-record] watched branch만 in-memory event record로 남기고 unwatched branch는 `matched=false`로 처리한다. 검증: `services/core/internal/controlplane` 테스트가 unwatched branch push를 무시하는지 확인한다.
- [x] [watch-store] branch watch와 revision cursor를 Postgres store로 옮긴다. 검증: restart 이후에도 watch/cursor가 유지되고 duplicate push가 idempotent하게 처리된다.

### Epic: [nomadcode-consume] NomadCode event consumption contract

NomadCode가 Gito branch event를 내부 runtime event로 받을 수 있게 계약과 proto-socket 표면을 맞춘다.

- [x] [protosocket-event] `/proto-socket` WebSocket upgrade와 `event.subscribe`, `event.list` MVP action을 추가한다. 검증: `services/core/internal/controlplane` registry test가 event channel action 상태를 확인한다.
- [x] [contract] `gito.forgejo-branch-events.v1` 제공 계약을 만든다. 검증: `agent-contract/index.md`가 계약 id와 원문 경로를 가리킨다.
- [x] [connection-filter] proto-socket subscription payload 기준으로 connection별 event filtering을 추가한다. 검증: subscription filter unit test와 `event.subscribe` handler test가 repo/branch/action matching을 확인한다.
- [x] [consumer-smoke] `../nomadcode`의 proto-socket client가 `branch.updated`를 수신하는 smoke 또는 fixture를 추가한다. 검증: NomadCode client/core 테스트가 `branch.updated` envelope를 wakeup signal로 해석한다.

## 완료 리뷰

- 상태: 승인됨
- 요청일: 2026-06-13
- 완료 근거:
  - `consumer-smoke`: `agent-task/archive/2026/06/m-forgejo-branch-event-mvp/01_consumer_smoke/complete.log`의 Roadmap Completion PASS.
  - `watch-store`: `agent-task/archive/2026/06/m-forgejo-branch-event-mvp/02+01_watch_store/complete.log`의 Roadmap Completion PASS.
  - 모든 기능 Task가 evidence와 함께 `[x]` 상태라 Milestone을 `[검토중]` 완료 후보로 전환했다.
  - 종료 전 코드 레벨 검토에서 기존 dev/runtime DB에 남은 legacy `revision_cursors_repo_id_fkey` 흡수 이슈를 발견해 작은 migration 보정과 회귀 테스트를 추가했고, 전체 검증을 재통과했다.
- 리뷰 필요:
  - [x] 사용자가 완료 결과를 확인했다
  - [x] archive 이동을 승인했다
- 리뷰 코멘트: 코드 레벨 종료 검토 완료. 큰 이슈 없음. 작은 legacy FK 호환 보정 반영 후 archive 승인됨.

## 범위 제외

- PR/MR 생성이나 review/check/comment provider API
- persistent event outbox 전체 구현
- Redis fanout
- NomadCode Plane mutation 구현
- IOP CLI agent authoring 실행
- Flutter UI

## 작업 컨텍스트

- 관련 경로: `services/core/internal/controlplane/`, `services/core/internal/provider/forgejo/`, `services/core/internal/protosocket/`, `services/core/internal/gitengine/`, `agent-contract/provided/gito-forgejo-branch-events-v1.md`, `packages/contracts/notes/gito-control-plane.md`
- 표준선(선택): Forgejo webhook은 wakeup signal이고, NomadCode는 `branch.updated` 수신 후 target branch revision과 roadmap 변경을 직접 재검증해야 한다.
- 선행 작업: Runtime Scaffold and Contract Baseline
- 후속 작업: Operation Event Outbox, Provider Adapter Foundation
- 확인 필요: 없음
- 현재 작업현황(2026-06-13): Gito 쪽 Forgejo push callback, signature 검증, push payload normalization, branch watch routing, proto-socket event subscribe/list/filtering, 제공 계약, NomadCode consumer smoke, Postgres watch/cursor/delivery idempotency 검증까지 모두 완료했다. active task는 없고 완료 산출물은 `agent-task/archive/2026/06/m-forgejo-branch-event-mvp/01_consumer_smoke/`와 `agent-task/archive/2026/06/m-forgejo-branch-event-mvp/02+01_watch_store/`에 있다.
- 검증 현황(2026-06-13): `consumer-smoke`는 NomadCode proto-socket branch event service focused/full integration tests와 analyze, diff check가 PASS했다. `watch-store`는 code-server 동반 Postgres로 `GITO_TEST_DATABASE_URL="$DATABASE_URL" go test -v -count=1 ./internal/storage`를 skip 없이 PASS했고, legacy revision cursor FK migration 회귀 테스트도 PASS했다. `services/core` focused/full tests, `go vet`, `./bin/test`, `./bin/lint`, `./bin/build`, `git diff --check`가 PASS했다. NomadCode `flutter analyze --no-fatal-infos`는 exit 0이며 기존 Mattermost `avoid_print` info 13건만 남았다.
- 남은 MVP 항목(우선순위): 없음.
- 현재 작업 포커스: 완료 및 archive 이동 완료 후 다음 Milestone `Repo Registry and Workspace Lease`로 전환한다.
