# Contract: nomadcode.gito-branch-webhook-consumer.v1

## 범위

이 계약은 NomadCode Core가 Gito의 signed HTTP `branch.updated` webhook delivery를 수신해 develop checkout fetch/scan 및 roadmap creation sync wakeup으로 넘기는 외부 소비 경계를 정의한다.

원문 제공 계약은 Gito `agent-contract/provided/gito-forgejo-branch-events-v1.md`의 `gito.forgejo-branch-events.v1`이다. 이 문서는 NomadCode가 소비자로서 강제하는 endpoint, headers, enablement, response 의미만 기록한다.

## 비범위

- Forgejo/Git provider webhook을 직접 수신하거나 정규화하는 책임은 Gito에 있다.
- Gito event 생성, branch watch, webhook subscription 저장/전송 책임은 Gito에 있다.
- IOP model execution port와 Responses API 동작은 NomadCode task execution dependency이며 이 webhook 소비 계약의 schema가 아니다.

## Endpoint

### `POST /api/integrations/gito/webhook`

Gito가 delivery하는 `branch.updated` JSON payload를 수신한다. Basic Auth를 우회하는 public callback 경계이며, request body HMAC 서명으로 검증한다.

Headers:

| Field | Required | Meaning |
| --- | --- | --- |
| `X-Gito-Event` | 필수 | 고정값 `branch.updated`. 다른 값은 `400`으로 거부한다. |
| `X-Gito-Delivery` | 필수 | stable delivery id. HTTP layer idempotency key로 사용한다. |
| `X-Gito-Signature` | 필수 | request body에 대한 HMAC-SHA256 hex digest. `sha256=` prefix와 raw hex를 모두 허용한다. |

Request body minimum shape:

```json
{
  "type": "branch.updated",
  "repo_id": "nomadcode",
  "branch": "develop",
  "before": "old-sha",
  "after": "new-sha",
  "changed_files": [
    {
      "path": "README.md",
      "change_type": "modified"
    }
  ]
}
```

Accepted payload rules:

| Field | Required | Meaning |
| --- | --- | --- |
| `type` | 선택 | 있으면 `branch.updated`여야 한다. |
| `repo_id` | 필수 | `GITO_REPO_ID`와 같을 때만 처리 대상이다. |
| `branch` | 필수 | `GITO_BRANCH` 또는 기본값 `develop`과 같을 때만 처리 대상이다. |
| `before` | 선택 | 이전 revision SHA. 내부 bridge로 전달한다. |
| `after` | 선택 | 새 revision SHA. 있으면 revision idempotency key에 포함한다. |
| `changed_files` | 선택 | 있으면 object list여야 한다. wakeup 힌트이며 source-of-truth로 단정하지 않는다. |

Response handling:

| Status | Body | Meaning |
| --- | --- | --- |
| `202` | `{"status":"accepted"}` | 대상 repo/branch event를 처리했다. |
| `202` | `{"status":"ignored"}` | repo 또는 branch가 target과 달라 side effect 없이 ack했다. |
| `202` | `{"status":"duplicate"}` | 같은 delivery id 또는 같은 `repo_id:branch:after` revision을 이미 처리했다. |
| `400` | error object | event type, delivery id, JSON, payload shape가 잘못됐다. |
| `401` | error object | signature가 없거나 검증에 실패했다. |
| `413` | error object | body가 1 MiB 제한을 넘었다. |
| `500` | error object | 내부 handler가 실패했다. 재시도 가능하다. |
| `503` | error object | consumer enablement 입력이 준비되지 않았다. |

## Enablement

NomadCode Core는 아래 값이 모두 있을 때 Gito HTTP webhook consumer를 wiring한다.

| Env | Required | Meaning |
| --- | --- | --- |
| `GITO_WEBHOOK_SECRET` | 필수 | `X-Gito-Signature` 검증용 signing secret. raw value는 tracked docs에 쓰지 않는다. |
| `GITO_REPO_ID` | 필수 | target repo id. |
| `GITO_DEVELOP_REPO_PATH` | 필수 | fetch/scan할 develop checkout path. Core container에서 접근 가능해야 한다. |
| `ROADMAP_CREATION_TODO_STATE_ID` 또는 `PLANE_TODO_STATE_ID` | 필수 | Plane-origin roadmap creation sync projection 대상 Todo state id. |
| `GITO_BRANCH` | 선택 | 기본값 `develop`. |
| `GITO_REMOTE_NAME` | 선택 | 기본값 `origin`. |

## Environment Port Profiles

포트 profile은 같은 remote host에서 local용 환경과 dev용 환경을 동시에 분리 운영하기 위한 기본값이다. Endpoint path, headers, body schema는 profile과 무관하게 동일하다.

| Profile | NomadCode Core URL | Gito source URL | Preview | DB/cache 후보 | Subscription target |
| --- | --- | --- | ---: | ---: | --- |
| remote local | `http://127.0.0.1:18010` | `http://127.0.0.1:18060` | `13010` | `15410/16310` | `http://127.0.0.1:18010/api/integrations/gito/webhook` |
| remote dev | `http://127.0.0.1:18011` | `http://127.0.0.1:18061` | `13011` | `15411/16311` | `http://127.0.0.1:18011/api/integrations/gito/webhook` |

NomadCode Core container 내부 listen은 `8080`을 유지하고 host publish만 `18010` 또는 `18011`로 분리한다. IOP dev model endpoint `http://toki-labs.com:18083/v1`은 NomadCode 실행 dependency이며 이 계약이 소유하는 port가 아니다.

## Consumer Responsibilities

- NomadCode는 `branch.updated`를 wakeup signal로만 받아들인다.
- NomadCode는 Plane, agent-roadmap, 기타 source-of-truth mutation 전에 target checkout을 fetch/scan해 실제 revision 상태를 재확인한다.
- `changed_files`는 relevance 판단 힌트이며 단독 증거가 아니다.
- raw webhook secret, token, provider credential, private endpoint 원문은 tracked 문서나 로그에 기록하지 않는다.

## Evidence

- `services/core/internal/http/gito_webhook.go`
- `services/core/internal/config/config.go`
- `services/core/internal/http/router.go`
- `services/core/docker-compose.yml`
- `services/core/README.md`
- `../gito/agent-contract/provided/gito-forgejo-branch-events-v1.md`
