<!-- task=m-milestone-work-item-creation-sync/01_project_sync_store plan=2 tag=REVIEW_REVIEW_API -->

# Implementation Plan - REVIEW_REVIEW_API

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

구현 완료는 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운 뒤에만 성립한다. 검증을 실행하고, 실제 변경/출력을 기록하고, active 파일은 그대로 둔 채 리뷰 준비를 보고한다. 종료 처리, log rename, `complete.log`, archive 이동은 code-review 스킬 전용이다. 구현 중 사용자만 결정할 수 있는 범위 변경, 외부 환경/secret 준비, scope 충돌이 있으면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 근거를 적고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하거나 `USER_REVIEW.md`를 만들지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 공백은 사용자 리뷰 요청이 아니다.

## 배경

G07에서 `GetActiveProjectSyncSettingByTarget`의 오류 경계는 `pgx.ErrNoRows`와 일반 DB error를 구분하도록 수정됐다. 하지만 follow-up의 필수 검증이었던 provider/tenant/project parameter 전달 테스트가 아직 실제 args를 assertion하지 않아, wrong args/order regression을 잡지 못한다. 이 plan은 테스트 신뢰도 회복만 다룬다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 해당 섹션은 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식을 따른다. 구현 에이전트는 직접 사용자 프롬프트를 만들지 않고, code-review가 사용자 리뷰 요청의 타당성과 실제 `USER_REVIEW.md` 작성을 판단한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md`
- Task ids:
  - `project-store`: Project sync 설정을 Core DB에 저장하는 persistence 경계를 정한다.
- Completion mode: check-on-pass

## 분석 결과

### 이전 루프

- Archived plan: `agent-task/m-milestone-work-item-creation-sync/01_project_sync_store/plan_local_G07_1.log`
- Archived review: `agent-task/m-milestone-work-item-creation-sync/01_project_sync_store/code_review_local_G07_1.log`
- Verdict: FAIL

### 실패 근거

- `services/core/internal/storage/project_sync_store_test.go:61`의 `mockDBTX.QueryRow`가 SQL text만 기록하고 args를 버린다.
- `services/core/internal/storage/project_sync_store_test.go:316`의 `TestStoreCalls_PassProviderTenantProjectParams`는 호출 횟수와 query text만 확인한다. `Store`가 `provider`, `tenant`, `project`를 잘못 전달해도 테스트가 통과한다.

### 테스트 환경 규칙

- 선택한 `test_env`: `local`.
- core 변경이므로 최소 `cd services/core && go test -count=1 ./...`를 실행한다.
- task artifact와 문서성 변경이 있으므로 `git diff --check`를 최종 확인에 포함한다.

### 범위 결정 근거

- 제품 동작 코드는 이미 G07에서 오류 경계가 수정됐으므로, 새 production behavior 변경은 하지 않는다.
- DB schema, SQLC query, `projectsync.Config` helper는 건드리지 않는다.
- 테스트 helper와 assertions만 고쳐 G07의 남은 required evidence gap을 닫는다.

### 빌드 등급

- `local-G08`: 남은 이슈는 명확한 테스트 assertion 누락이며 deterministic local review로 확인 가능하다.

## 구현 체크리스트

- [ ] `mockDBTX.QueryRow`가 SQL text와 `args`를 모두 기록하고, tests가 recorded args를 검증할 수 있게 한다.
- [ ] `CreateProjectSyncRecord`, `GetActiveProjectSyncSettingByTarget`, `DeactivateProjectSyncSetting` 각각이 expected provider/tenant/project args를 전달하는지 assertion한다. create는 full `CreateProjectSyncSettingParams` field order도 확인한다.
- [ ] `cd services/core && go test -count=1 ./internal/storage ./internal/projectsync`, `cd services/core && go test -count=1 ./...`, `git diff --check`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_API-1] Assert storage query args

- 문제: 현재 storage test mock은 `args`를 버리므로 provider/tenant/project 전달 테스트가 이름과 달리 실제 전달값을 검증하지 못한다.
- 해결 방법: `mockDBTX`에 `queryCalls` 또는 동등한 구조를 추가해 SQL text와 args slice를 함께 기록한다. `TestStoreCalls_PassProviderTenantProjectParams` 또는 각 메서드별 test에서 expected args와 recorded args를 `reflect.DeepEqual` 또는 명시 assertion으로 비교한다.
- 수정 파일 및 체크리스트:
  - [ ] `services/core/internal/storage/project_sync_store_test.go`
- 테스트 작성: create는 `[provider, tenant, project, git_remote_url, source_branch, workspace_id, workspace_base_path, repo_dir_name]`, get/deactivate는 `[provider, tenant, project]`가 정확한 순서로 전달되는지 검증한다. wrong args/order가 들어오면 실패하는 assertion이어야 한다.
- 중간 검증: `cd services/core && go test -count=1 ./internal/storage ./internal/projectsync`.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `services/core/internal/storage/project_sync_store_test.go` | REVIEW_REVIEW_API-1 |

## 최종 검증

```bash
cd services/core && go test -count=1 ./internal/storage ./internal/projectsync
cd services/core && go test -count=1 ./...
git diff --check
```

기대 결과: 세 명령 모두 exit code 0. Go test cache output은 허용하지 않으므로 `-count=1`을 유지한다.

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