# Complete - m-webhook-revision-reconcile

## 완료 일시

2026-06-19

## 요약

Webhook revision reconcile의 expected-rev, dry-run, apply 작업을 3개 리뷰 루프 끝에 PASS로 완료했다.

## 루프 이력

| Plan | Review | Verdict | 메모 |
|------|--------|---------|------|
| `plan_local_G05_0.log` | `code_review_local_G05_0.log` | FAIL | apply idempotency key를 side effect 전에 선점해 실패 후 재시도가 duplicate로 막힐 수 있었다. |
| `plan_local_G05_1.log` | `code_review_local_G05_1.log` | FAIL | 후속 수정과 `TestRuntimeApplyReconcileRetryAfterPublishFailure`가 아직 반영되지 않았다. |
| `plan_local_G05_2.log` | `code_review_local_G05_2.log` | PASS | 선점 dedupe를 제거하고 `HandleRevision` delivery dedupe/rollback을 apply idempotency로 재사용했다. |

## 구현/정리 내용

- `DryRunReconcile`과 `ApplyReconcile` API를 추가해 expected revision conflict, dry-run drift/proposal, idempotent apply 결과를 반환한다.
- `ApplyReconcile`이 별도 선점 `RecordOnce`를 만들지 않고 `HandleRevision(ctx, provider, "reconcile:"+IdempotencyKey, revision)`의 기존 delivery dedupe 및 rollback 경로를 사용하도록 정리했다.
- `TestRuntimeApplyReconcileRetryAfterPublishFailure`를 추가해 첫 publish 실패 후 같은 idempotency key 재시도가 적용으로 성공하고, 성공 후 재호출은 duplicate로 수렴함을 검증했다.
- 리뷰 중 stale한 주석 표현을 현재 dedupe 설계에 맞게 정리했다.

## 최종 검증

- `cd services/core && go test ./internal/controlplane -run 'TestRuntimeReconcileExpectedRevisionConflict|TestRuntimeDryRunReconcileReportsDriftConflictProposal|TestRuntimeApplyReconcileIsIdempotent|TestRuntimeApplyReconcileRetryAfterPublishFailure' -count=1` - PASS; four focused controlplane tests passed.
- `cd services/core && go test ./...` - PASS; all core packages passed.
- `git diff --check` - PASS; no whitespace errors.

## Roadmap Completion

- Milestone: `agent-roadmap/phase/provider-change-request-integration/milestones/webhook-revision-reconcile.md`
- Completed task ids:
  - `expected-rev`: PASS; evidence=`agent-task/archive/2026/06/m-webhook-revision-reconcile_1/plan_local_G05_2.log`, `agent-task/archive/2026/06/m-webhook-revision-reconcile_1/code_review_local_G05_2.log`; verification=`cd services/core && go test ./internal/controlplane -run 'TestRuntimeReconcileExpectedRevisionConflict|TestRuntimeDryRunReconcileReportsDriftConflictProposal|TestRuntimeApplyReconcileIsIdempotent|TestRuntimeApplyReconcileRetryAfterPublishFailure' -count=1`
  - `dry-run`: PASS; evidence=`agent-task/archive/2026/06/m-webhook-revision-reconcile_1/plan_local_G05_2.log`, `agent-task/archive/2026/06/m-webhook-revision-reconcile_1/code_review_local_G05_2.log`; verification=`cd services/core && go test ./internal/controlplane -run 'TestRuntimeReconcileExpectedRevisionConflict|TestRuntimeDryRunReconcileReportsDriftConflictProposal|TestRuntimeApplyReconcileIsIdempotent|TestRuntimeApplyReconcileRetryAfterPublishFailure' -count=1`
  - `apply`: PASS; evidence=`agent-task/archive/2026/06/m-webhook-revision-reconcile_1/plan_local_G05_2.log`, `agent-task/archive/2026/06/m-webhook-revision-reconcile_1/code_review_local_G05_2.log`; verification=`cd services/core && go test ./internal/controlplane -run 'TestRuntimeReconcileExpectedRevisionConflict|TestRuntimeDryRunReconcileReportsDriftConflictProposal|TestRuntimeApplyReconcileIsIdempotent|TestRuntimeApplyReconcileRetryAfterPublishFailure' -count=1`
- Not completed task ids: 없음

## Spec Completion

- SDD: `agent-roadmap/sdd/provider-change-request-integration/webhook-revision-reconcile/SDD.md`
- Completed scenario ids:
  - `S08`: PASS; task=`expected-rev`; evidence=`agent-task/archive/2026/06/m-webhook-revision-reconcile_1/plan_local_G05_2.log`, `agent-task/archive/2026/06/m-webhook-revision-reconcile_1/code_review_local_G05_2.log`; verification=`TestRuntimeReconcileExpectedRevisionConflict`
  - `S09`: PASS; task=`dry-run`; evidence=`agent-task/archive/2026/06/m-webhook-revision-reconcile_1/plan_local_G05_2.log`, `agent-task/archive/2026/06/m-webhook-revision-reconcile_1/code_review_local_G05_2.log`; verification=`TestRuntimeDryRunReconcileReportsDriftConflictProposal`
  - `S10`: PASS; task=`apply`; evidence=`agent-task/archive/2026/06/m-webhook-revision-reconcile_1/plan_local_G05_2.log`, `agent-task/archive/2026/06/m-webhook-revision-reconcile_1/code_review_local_G05_2.log`; verification=`TestRuntimeApplyReconcileIsIdempotent`, `TestRuntimeApplyReconcileRetryAfterPublishFailure`
- Not completed scenario ids: 없음

## 잔여 Nit

- 없음

## 후속 작업

- 없음
