8.6 KiB
8.6 KiB
Milestone: Plane Work Item Webhook Intake
위치
- Roadmap:
agent-roadmap/ROADMAP.md - Phase:
agent-roadmap/phase/agent-ops-mcp-control-plane/PHASE.md
목표
Plane에서 상위 work item 생성, 상태 변경, assignee 변경 이벤트가 발생하면 NomadCode Core가 이를 webhook으로 받아 Backlog + AGENT assignee 조건을 재검증하고 기존 Plane-origin Milestone creation sync pipeline을 시작한다. 이 마일스톤이 끝나면 사용자는 Plane UI에서 티켓을 만들고 AGENT에 assign하는 동작만으로 NomadCode authoring flow가 시작되는지 확인할 수 있다.
상태
[검토중]
구현 잠금
- 상태: 해제
- 결정 필요:
- dev Plane에서 호출할 NomadCode Core webhook URL은
http://toki-labs.com:18010/api/integrations/plane/webhook로 둔다.plane.toki-labs.com은 Plane의 동일 호스트/하위 도메인 차단 규칙에 걸리므로 사용하지 않는다. - Plane webhook 인증 방식은 Plane UI에서 발급한 webhook secret/signature 검증으로 둔다. secret 원문은 tracked 파일에 기록하지 않고 SOPS encrypted file
secrets/nomadcode.dev.sops.yaml의PLANE_WEBHOOK_SECRET으로 보관한다. - AGENT assignee로 사용할 Plane user id는
5d116a77-d3df-4f54-80bf-eca61e0118c4로 확인했다. - webhook-only live smoke는 기존 Backlog item
NOMAD-10,NOMAD-11의 AGENT assign 이벤트로 확인했다.
- dev Plane에서 호출할 NomadCode Core webhook URL은
범위
- Plane native webhook payload 샘플을 확보하고 work item 생성, 상태 변경, assignee 변경 이벤트에서 필요한 필드를 식별한다.
- NomadCode Core에 Plane raw webhook receiver endpoint를 추가한다.
- Plane webhook secret/signature 또는 동등한 shared-secret 검증을 구현하고, raw secret은 tracked 파일과 로그에 남기지 않는다.
- webhook payload는 변경 힌트로만 사용하고, 최종 trigger 판정 전 Plane API로 work item을 다시 조회한다.
- 기존
workitempipelinetrigger gate를 재사용해Backlog + AGENT assignee조건, actor/self guard, project sync setting, workspace provision, slot reservation 경계를 유지한다. - 중복 webhook, 재시도, NomadCode self mutation event가 들어와도 중복 task나 중복 Milestone authoring run을 만들지 않도록 idempotency 기준을 고정한다.
- dev Plane project에 webhook을 등록하고, 사용자가 Plane UI에서 상위 티켓 생성/assign만으로 NomadCode flow가 시작되는 smoke를 확인한다.
기능
Epic: [plane-webhook] Plane Webhook Intake
Plane에서 발생한 work item event를 NomadCode creation sync trigger로 안전하게 정규화한다.
- [payload-sample] dev Plane webhook payload 샘플과 이벤트 종류를 확보하고 receiver 입력 fixture 또는 문서화된 contract candidate로 남긴다. 검증: raw secret/token 없이 work item create/update, state change, assignee change 후보 payload shape를 확인한다.
- [webhook-receiver]
POST /api/integrations/plane/webhookreceiver를 추가하고 webhook auth 또는 shared-secret 검증을 통과한 요청만 처리한다. 검증: HTTP handler 테스트에서 인증 실패, payload 오류, 정상 accepted 응답을 확인한다. - [event-normalize] Plane webhook payload를 provider-neutral work item ref와 actor/change hint로 정규화하되, 최종 work item 상태는 Plane API 재조회 결과를 사용한다. 검증: payload 필드 누락 또는 stale event가 있어도 fetch 기반 trigger 판정으로 수렴한다.
- [trigger-dispatch]
Backlog + AGENT assignee이벤트만 기존workitempipeline.CreateTaskFromWorkItem경로로 넘기고 나머지는 side effect 없이 ignored 처리한다. 검증: ignored event가 workspace provision 또는 slot reservation을 발생시키지 않는다. - [loop-idempotency] duplicate webhook, provider retry, NomadCode self actor event를 중복 creation task 없이 처리한다. 검증: 같은 provider/work item/revision 재처리와 self actor 입력이 task 중복 생성으로 이어지지 않는다.
- [plane-registration] dev Plane project에 NomadCode webhook을 등록하고 운영자가 바꿔야 하는 URL, secret, event scope를 tracked 문서나 roadmap에 secret 없이 남긴다. 검증: Plane DB/UI에서 active project webhook이 존재하고 target이 NomadCode receiver를 가리키는지 확인한다.
- [live-smoke] Plane UI에서 상위 티켓을 만들고 Backlog 상태에서 AGENT에 assign하면 NomadCode task가 생성되고 Milestone authoring flow가 시작된다. 검증: 테스트 Plane 티켓 id, Core task id, authoring run 시작 또는 ignored 사유를 secret redaction 상태로 기록한다.
완료 리뷰
- 상태: [검토중]
- 요청일: 2026-06-15
- 완료 근거: Plane Webhook intake 및 normalized trigger dispatch, idempotency 처리가 구현 및 원격 배포되었으며, 2026-06-15 live smoke 테스트를 통해 Plane UI/API에서 새 Backlog 티켓 생성 및 AGENT assignee 지정 시 webhook 202 Accepted 수신 및 Core Task(e3c92411-4056-4b76-a879-66f7904125d0) 생성 및 실행이 시작되는 것을 검증 완료함.
- 리뷰 필요:
- 사용자가 완료 결과를 확인했다
- archive 이동을 승인했다
- 리뷰 코멘트: 없음
범위 제외
- Plane
Todo -> In Progress실행 lifecycle 시작 - Milestone Task를 Plane 하위 티켓으로 생성하거나 동기화하는 구현
- Gito
branch.updatedevent producer 또는 proto-socket consumer 구현 - Jira webhook intake
- provider polling 기반 reconcile loop 구현
- 사용자 승인 없는 archive 이동
작업 컨텍스트
- 관련 경로:
services/core/internal/http/,services/core/internal/workitempipeline/,services/core/internal/adapters/plane/,services/core/internal/scheduler/,services/core/internal/roadmapsyncpipeline/,services/core/internal/config/,packages/contracts/notes/,agent-roadmap/ - 표준선: Plane webhook payload는 신뢰할 source of truth가 아니라 wakeup hint로 취급하고, NomadCode는 Plane API 재조회와 기존 trigger gate로 실제 실행 여부를 결정한다.
- 선행 작업:
Milestone Work Item Creation Sync - 후속 작업:
Gito Branch Event Creation Sync Bridge,Milestone Execution Lifecycle Sync - 사용자 액션:
- NomadCode Core webhook endpoint는 dev Plane에서 접근 가능한
http://toki-labs.com:18010/api/integrations/plane/webhook로 사용한다. - webhook secret은 Plane UI에서 발급받았고
secrets/nomadcode.dev.sops.yaml에 SOPS로 저장했다. 구현 시PLANE_WEBHOOK_SECRETenv로 주입한다. raw secret 값은 roadmap/docs/log에 남기지 않는다. - AGENT assignee로 쓸 Plane 계정/id는
5d116a77-d3df-4f54-80bf-eca61e0118c4다. - webhook-only live smoke용 기존 Plane 티켓은
NOMAD-10,NOMAD-11을 사용했다. - live smoke 후 Plane UI에서
Todoprojection 또는 authoring 시작 상태를 확인한다.
- NomadCode Core webhook endpoint는 dev Plane에서 접근 가능한
- 확인 필요: Plane self-hosted webhook payload의 실제 event type, signature header, custom header 지원 여부를 dev Plane에서 확인해야 한다.
- 작은 작업 처리 결과:
webhook-receiver는 signed fixture/invalid signature/basic-auth bypass 테스트와 dev Core synthetic/live webhook smoke로 확인했다.plane-registration은 dev Plane active webhooke25a2d41-2c9f-4f5f-a0ce-cad6b993853f, targethttp://toki-labs.com:18010/api/integrations/plane/webhook,issue=True, response 202 발송 로그 8건으로 확인했다. 2026-06-15 live smoke에서 Plane issue93b677f5-7913-4111-ae05-916033ae533b에 대한 webhook 수신(202 Accepted) 및 Core Taske3c92411-4056-4b76-a879-66f7904125d0기동을 검증함. - payload fixture: assignee update 샘플은
services/core/internal/http/testdata/plane_webhook_issue_assignees_updated.json에 PII redaction 상태로 남겼다. create/state-change 후보는plane_webhook_issue_created.json,plane_webhook_issue_state_updated.json으로 추가했고 live create/state 로그 미확보로 관찰된 issue envelope 기반 synthetic candidate임을agent-test/plane-dev.md에 명시했다. normalize helper(normalizePlaneWebhookPayload)는 payload를 wakeup hint로만 보고 provider-neutral ref/actor/change hint만 추출한다. - plane-webhook 후속 plan:
agent-task/m-plane-work-item-webhook-intake/01_payload_normalization/PLAN-local-G06.md:[payload-sample],[event-normalize]agent-task/m-plane-work-item-webhook-intake/02+01_trigger_dispatch/PLAN-local-G07.md:[trigger-dispatch]agent-task/m-plane-work-item-webhook-intake/03+02_idempotency/PLAN-cloud-G06.md:[loop-idempotency]agent-task/m-plane-work-item-webhook-intake/04+01,02,03_live_smoke/PLAN-local-G05.md:[live-smoke]