nomadcode/agent-task/m-agent-origin-milestone-creation-sync/01_scan_create_ledger/PLAN-cloud-G07.md

15 KiB

Plan - API

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

구현 후 active CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 반드시 실제 구현 내용과 검증 출력으로 채운다. 검증을 실행하고, active 파일은 그대로 둔 뒤 리뷰 준비를 보고한다. 최종 판정, log rename, complete.log, archive 이동은 code-review 스킬 전용이다.

선택된 Milestone의 구현 잠금 > 결정 필요 항목이 실구현을 막을 때만 review stub의 사용자 리뷰 요청 섹션을 채우고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 request_user_input을 호출하지 않는다. 환경, secret, 외부 서비스, 검증 evidence 공백은 사용자 리뷰 요청이 아니라 검증 결과나 follow-up 대상이다.

배경

Agent-origin push는 Gito branch.updated를 wakeup으로 받지만, Plane mutation 전에 after revision을 fetch/scan해서 active Milestone 상태를 다시 확인해야 한다. 현재 scanner, bridge, pipeline은 부분 구현되어 있으나 before..after diff hint와 전체 active index의 결합, missing-create idempotency, identity conflict evidence를 하나의 완료 단위로 고정해야 한다.

사용자 리뷰 요청 흐름

사용자 리뷰 요청은 선택된 Milestone lock decision만 active review stub의 사용자 리뷰 요청 섹션에 기록한다. 직접 사용자 prompt는 금지이며, code-review가 정당성을 검증하고 실제 USER_REVIEW.md 작성을 소유한다.

Roadmap Targets

  • Milestone: agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/agent-origin-milestone-creation-sync.md
  • Task ids:
    • scan-diff: Gito webhook의 before..after 변경 목록을 wakeup 힌트로 사용하되, after SHA 검증 뒤 active Milestone diff와 전체 active index를 함께 스캔한다.
    • missing-create: provider identity가 없는 active Milestone을 agent-origin 생성 후보로 판별하고 Plane work item을 생성한다.
    • identity-ledger: 생성된 Plane work item id를 roadmap_sync_identities에 filename slug 기준으로 upsert하고 revision/idempotency conflict를 구분한다.
  • Completion mode: check-on-pass

분석 결과

읽은 파일

  • agent-roadmap/current.md
  • agent-roadmap/phase/agent-ops-mcp-control-plane/PHASE.md
  • agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/agent-origin-milestone-creation-sync.md
  • agent-roadmap/sdd/agent-ops-mcp-control-plane/agent-origin-milestone-creation-sync/SDD.md
  • agent-contract/index.md
  • agent-contract/outer/gito-branch-webhook-consumer-v1.md
  • agent-test/local/rules.md
  • agent-test/local/core-smoke.md
  • agent-test/local/workspace-ops-smoke.md
  • services/core/internal/gitoevents/events.go
  • services/core/internal/gitoevents/events_test.go
  • services/core/internal/gitosync/scanner.go
  • services/core/internal/gitosync/scanner_test.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/roadmapsync/identity.go
  • services/core/internal/roadmapsync/milestone_parser.go
  • services/core/internal/roadmapsync/develop_match.go
  • services/core/internal/roadmapsync/develop_match_test.go
  • services/core/internal/roadmapsync/retry.go
  • services/core/internal/roadmapsync/retry_test.go
  • services/core/internal/roadmapsyncpipeline/service.go
  • services/core/internal/roadmapsyncpipeline/service_test.go
  • services/core/internal/storage/roadmap_sync_identities.go
  • services/core/internal/storage/roadmap_sync_identities_test.go
  • services/core/internal/storage/roadmap_sync_steps.go
  • services/core/internal/storage/roadmap_sync_steps_test.go
  • services/core/internal/adapters/plane/client.go
  • services/core/internal/adapters/plane/client_test.go
  • services/core/internal/workitem/provider.go
  • services/core/internal/http/gito_webhook.go
  • services/core/internal/http/gito_webhook_test.go
  • services/core/internal/config/config.go
  • services/core/internal/config/config_test.go
  • services/core/internal/scheduler/roadmap_sync_jobs.go
  • services/core/internal/scheduler/jobs.go
  • services/core/queries/roadmap_sync_identities.sql
  • services/core/queries/roadmap_sync_steps.sql
  • services/core/migrations/00006_create_roadmap_sync_identities.sql
  • services/core/migrations/00007_create_roadmap_sync_steps.sql
  • services/core/migrations/00009_add_roadmap_sync_milestone_id.sql

SDD 기준

  • SDD: agent-roadmap/sdd/agent-ops-mcp-control-plane/agent-origin-milestone-creation-sync/SDD.md
  • 상태: [승인됨], SDD 잠금 해제, 사용자 리뷰 없음.
  • Targeted scenarios: S01=scan-diff, S02=missing-create, S03=identity-ledger.
  • Evidence Map rows: S01 requires gitosync scanner/bridge unit and webhook handler tests; S02 requires roadmapsyncpipeline missing-create idempotency test; S03 requires storage identity conflict/upsert test.
  • 구현 checklist는 changed_files 단독 신뢰 금지, after SHA verification, missing identity create idempotency, slug/provider conflict evidence 순서로 역산한다.

테스트 환경 규칙

  • test_env: local.
  • agent-test/local/rules.md present/read.
  • Matched profiles read: agent-test/local/core-smoke.md, agent-test/local/workspace-ops-smoke.md.
  • 적용 명령: git diff --check, cd services/core && go test ./..., 필요 시 cd services/core && go vet ./....
  • Current preflight: repo root /config/workspace/nomadcode, branch main, HEAD d80abe83579dd0d6fbc86b1a74c83db6d18c756d, go version go1.26.2 linux/arm64, git version 2.43.0.
  • 원격 runner 검증이 필요하면 toki@toki-labs.com:$HOME/agent-work/nomadcode를 현재 변경과 동기화한 뒤 같은 명령을 실행한다. 현재 계획 작성 시에는 local checkout에서 git diff --check, focused go test, go vet를 PASS로 확인했다.

테스트 커버리지 공백

  • scan-diff: existing scanner tests cover after mismatch, active index, archive exclusion, duplicate active slug. Gap: event changed_files or before..after hint is not carried through HTTP handler/scanner as an explicit relevance hint.
  • missing-create: bridge and pipeline tests cover identity-less docs, Plane create, and create result ledger upsert. Gap: same slug+same revision duplicate retry should assert no duplicate create after ledger exists.
  • identity-ledger: storage tests cover slug upsert and provider-work-item unique conflict. Gap: pipeline should expose conflict/not-ready reason without provider mutation for existing slug bound to a different provider item.

심볼 참조

  • No renamed or removed symbols planned in this subtask. New fields or helper symbols must be grepped before use.

분할 판단

  • Split decision policy evaluated before file selection.
  • Shared task group: agent-task/m-agent-origin-milestone-creation-sync/.
  • Sibling subtasks:
    • 01_scan_create_ledger: independent foundation for S01-S03.
    • 02+01_identity_backfill: depends on 01 because it needs created identity rows and work item ids.
    • 03+01,02_self_loop_update_conflict: depends on 01 and 02 because self-loop is meaningful after backfill.
    • 04+01,02,03_field_smoke: depends on all prior subtasks.
  • This plan is the first independent subtask; no predecessor completion is required.

범위 결정 근거

  • Exclude identity backfill commit/push, self-loop no-op, provider identity update projection, conflict policy hardening, and field smoke. Those are separate dependent plans.
  • Exclude Plane Todo -> In Progress lifecycle and child ticket sync per Milestone 범위 제외.

빌드 등급

  • cloud-G07: core/provider/DB/webhook behavior spans multiple packages and external contract semantics; local tests are strong, but a wrong implementation could pass unit tests while violating Gito/Plane sync promises.

구현 체크리스트

  • scan-diff 경로에서 Gito changed_files/before..after는 wakeup hint로만 보존하고, after SHA fetch/verify와 active Milestone scan 없이는 enqueue하지 않는다. 검증: changed_files만 신뢰하지 않고 origin/developafter SHA가 일치할 때만 sync job이 enqueue된다.
  • missing-create 경로에서 identity-less active Milestone이 Plane create 후보가 되고, 같은 milestone slug와 revision 재처리에서 duplicate create가 발생하지 않도록 ledger/idempotency 테스트를 보강한다. 검증: 같은 milestone slug와 revision을 재처리해도 중복 Plane work item을 만들지 않는다.
  • identity-ledger 경로에서 filename slug 기준 upsert와 provider work item conflict가 provider mutation 없이 conflict로 구분되는지 pipeline/storage 테스트를 보강한다. 검증: 기존 slug가 다른 provider work item에 묶여 있으면 provider mutation 없이 conflict로 멈춘다.
  • git diff --check, focused go test -count=1, focused go vet를 실행한다.
  • CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

[API-1] Scan Hint And Revision Gate

문제

services/core/internal/http/gito_webhook.go:22의 HTTP event shape는 changed_files를 handler seam으로 전달하지 않고, services/core/internal/gitosync/scanner.go:133은 전체 active/archive tree만 읽는다. SDD S01은 before..after 변경 목록을 wakeup hint로 보존하되 after 검증 뒤 scan해야 한다.

해결 방법

HTTP/proto-socket event에서 이미 존재하는 gitoevents.ChangedFile 형태를 bridge/scanner 입력까지 유지하고, scanner는 hint를 로그/결정 근거로만 사용한다. enqueue 여부는 계속 git fetch, git rev-parse refs/remotes/<remote>/<branch>, target revision active index scan 결과로만 결정한다.

Before:

// services/core/internal/http/gito_webhook.go:22
type GitoBranchUpdatedEvent struct {
    RepoID string
    Branch string
    Before string
    After  string
}

After:

type GitoBranchUpdatedEvent struct {
    RepoID       string
    Branch       string
    Before       string
    After        string
    ChangedFiles []gitoevents.ChangedFile
}

수정 파일 및 체크리스트

  • services/core/internal/http/gito_webhook.go: validated changed_files를 typed event로 전달한다.
  • services/core/internal/http/gito_webhook_test.go: changed_files가 handler로 전달되고 malformed shape는 400인 테스트를 유지/보강한다.
  • services/core/internal/gitosync/scanner.go: hint와 full active scan의 책임을 주석/결과 타입에 명시한다.
  • services/core/internal/gitosync/scanner_test.go: hint가 비어 있거나 다른 파일만 있어도 after verified active index가 source of truth임을 테스트한다.
  • services/core/internal/gitosync/runner_test.go: wire event changed_files가 scanner로 유지되는 assertion을 추가한다.

테스트 작성

Regression tests required for S01. Add or update tests named around ChangedFilesAreHintOnly in HTTP/gitosync packages.

중간 검증

cd services/core && go test -count=1 ./internal/http ./internal/gitoevents ./internal/gitosync

Expected: PASS, no duplicate enqueue when after is not verified.

[API-2] Missing Create And Ledger Idempotency

문제

services/core/internal/gitosync/bridge.go:137 builds missing-create jobs, and services/core/internal/roadmapsyncpipeline/service.go:158 creates Plane work items when no existing identity row exists. The existing path needs explicit same-slug/same-revision duplicate retry coverage and conflict evidence for S02/S03.

해결 방법

Keep the existing missing-create branch, but make tests assert that a persisted slug identity prevents a second create and that provider-work-item unique conflicts return SyncActionConflict before any additional provider mutation.

Before:

// services/core/internal/roadmapsyncpipeline/service.go:158
} else if in.Expected.WorkItemID == "" && in.Ref.ID == "" {
    creator, ok := s.provider.(workitem.Creator)
    ...
    createRes, err := creator.CreateWorkItem(ctx, workitem.CreateInput{...})

After:

// same branch, but covered by an existing-row retry test:
// found=true with completed develop_matched must not call CreateWorkItem again.

수정 파일 및 체크리스트

  • services/core/internal/roadmapsyncpipeline/service_test.go: add duplicate retry test for missing-create existing identity.
  • services/core/internal/roadmapsyncpipeline/service_test.go: assert conflict result does not call create/body/status after upsert conflict.
  • services/core/internal/storage/roadmap_sync_identities_test.go: keep provider work item unique conflict coverage aligned with slug upsert.

테스트 작성

Regression tests required for S02/S03. No production behavior change is needed if existing code already satisfies the tests; if a test fails, fix the minimal production path.

중간 검증

cd services/core && go test -count=1 ./internal/roadmapsyncpipeline ./internal/storage ./internal/gitosync

Expected: PASS; fake provider CreateWorkItem call count stays one across duplicate retry.

[API-3] Review Stub Completion

문제

Roadmap completion requires review evidence copied from active CODE_REVIEW-*-G??.md; implementation is incomplete until the review stub is filled.

해결 방법

Fill completion table, checklist, plan deviations, design decisions, and exact command outputs in CODE_REVIEW-cloud-G07.md.

수정 파일 및 체크리스트

  • agent-task/m-agent-origin-milestone-creation-sync/01_scan_create_ledger/CODE_REVIEW-cloud-G07.md: fill implementation-owned sections only.

테스트 작성

No test file; this is required implementation evidence.

중간 검증

git diff --check

Expected: no output.

수정 파일 요약

파일 항목
services/core/internal/http/gito_webhook.go API-1
services/core/internal/http/gito_webhook_test.go API-1
services/core/internal/gitosync/scanner.go API-1
services/core/internal/gitosync/scanner_test.go API-1
services/core/internal/gitosync/runner_test.go API-1
services/core/internal/roadmapsyncpipeline/service.go API-2
services/core/internal/roadmapsyncpipeline/service_test.go API-2
services/core/internal/storage/roadmap_sync_identities_test.go API-2
agent-task/m-agent-origin-milestone-creation-sync/01_scan_create_ledger/CODE_REVIEW-cloud-G07.md API-3

최종 검증

git diff --check
cd services/core && go test -count=1 ./internal/http ./internal/gitoevents ./internal/gitosync ./internal/roadmapsync ./internal/roadmapsyncpipeline ./internal/storage
cd services/core && go vet ./internal/http ./internal/gitoevents ./internal/gitosync ./internal/roadmapsync ./internal/roadmapsyncpipeline ./internal/storage

Expected: all commands exit 0. Fresh -count=1 is required for Go tests; cached output is not acceptable for this plan.

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