자동매매봇 구현 인계

다른 Claude Code 세션에서 이어받기 위한 상태 기록.

한 줄 요약

19티켓 중 18건이 main 머지 완료. BE-34·BE-16 은 커밋·검증까지 끝나고 codex 리뷰 대기, BE-33·BE-17 은 미착수다.

이어받는 법

# 1. 현재 run 확인 — 티켓 노드 상태가 여기 있다
~/.harness/bin/harness run status
 
# 2. 다음 티켓 실행 (한 번에 하나. 메모리 여유 없으면 더 줄인다)
cd ~/.harness && ./bin/harness run dispatch --max-parallel 1 --only "implement[BE-33]"
  • run id: private-feature-20260830-140013
  • 대상 레포: /Users/biuea/stock-application (origin/main = 239b19a)
  • 워크트리 루트: /Users/biuea/stock-application-worktrees/
  • 티켓 경로는 이 볼트를 직접 가리키게 재지정했다. 세션 scratchpad 의존은 없다.

티켓 상태

티켓상태비고
DB-01·BE-01~09✅ 머지PR #194~#203
BE-27~32·DB-02✅ 머지PR #204~#210 (wave 1)
BE-10·11·12✅ 머지PR #211~#213
BE-19·23·25·26✅ 머지PR #214~#217 (wave 2)
BE-24✅ 머지PR #218
BE-13·14·15✅ 머지PR #219~#221 (wave 4)
BE-34커밋 2b3e772이 과제 마지막 p0 (제안 이중 집행) 포함. 검증 통과, 리뷰 대기
BE-16커밋 ca7001c+Controller·스케줄러. 검증 통과, 리뷰 대기
BE-33미착수Rich Domain 관용구 + LiveTradeExecutororder.domain 교차 참조 제거
BE-17미착수E2E 격리 시나리오

폐기: BE-18·20·21·22 는 후속 DAG 가 BE-30·28·32·29·DB-02·BE-25 로 흡수했다. 실행하지 않는다.

바로 다음에 할 일 — wave 5 재작업 (리뷰 1차 완료, REQUEST_CHANGES)

codex 1차 리뷰를 이미 돌렸다. 전문: Tickets/_rework/review-prompts/wave5-codex-verdict.md

verdict: REQUEST_CHANGES — p0 3건 · p1 2건. 그중 p0-1 은 이 세션에서 고쳤다(커밋 1ebbd16). 남은 4건이 다음 세션 작업이다.

고침 (커밋 1ebbd16)

  • [BE-16] p0 중복 autotrading.scheduler YAML 키로 운영 기동 실패 → 중복 블록 제거. 앞선 커밋에서 “크론 설정이 없다” 고 오판해 블록을 추가했는데 아래쪽에 이미 있었다. 테스트가 못 잡은 이유: ① 스케줄러 테스트가 중복 키를 허용하는 기본 Yaml() 로 직접 읽는다 ② src/test/resources/application.yml 이 운영 파일을 가린다. 전체 테스트 통과와 실제 기동 실패가 공존했다.

남은 것 — BE-34 3건 · BE-16 1건

등급티켓내용
p0BE-34수동 승인 경로가 선점 커밋 전에 외부 주문을 제출한다. ApproveOrderProposalUseCase 의 단일 트랜잭션 안에서 선점 저장과 브로커 호출이 함께 돈다. 브로커 호출 후 롤백되면 선점도 사라져 재시도가 같은 실주문을 다시 낸다. 경합 테스트도 전체 승인 경로를 하나의 TransactionTemplate 로 감싸 “외부 호출 전 커밋” 을 검증하지 않는다 — 지금 1회인 건 DB 락 덕이지 durable claim 덕이 아니다
p0BE-34집행 실패 종목의 당일 재진입 차단 미구현. 실패 원장을 당일·모드·심볼로 조회하는 API 도, RiskRejectReason 의 제외 사유도 없다. ACCEPTANCE_UNCONFIRMED 기록 후 다음 사이클에 같은 종목이 다시 제안된다. 티켓의 당일 제외·익일 해제 요구가 통째로 빠졌다
p1BE-34실패한 제안이 AUTO_EXECUTED + fillId=null 로 남는다. OrderProposalStatus 에 티켓이 요구한 EXECUTION_FAILED 가 없어 완료와 재조정 필요가 구분되지 않는다
p1BE-16존재하지 않는 제안 승인이 404 가 아니라 400 을 반환한다. 테스트도 잘못된 400 을 고정하고 있다

리뷰가 확인해 준 것 (재작업 불필요)

후보별 TX1 → 트랜잭션 밖 브로커 호출 → TX2 분리 · recovery 포지션·체결 저장 · ExecutionFailure.record() · releaseProtection·보호 점검·단계 평가의 프로덕션 호출부 · 조작 토큰 거부 기본 · execution_claimed 의 expand 호환과 실행 가능한 롤백.

재리뷰 실행법

codex exec --skip-git-repo-check --ephemeral \
  -o /tmp/wave5-review.json \
  -C /private/tmp/wt-wave4 -s read-only -m gpt-5.6-sol \
  -c 'model_reasoning_effort="high"' \
  -- "$(cat '/Users/biuea/Desktop/dpdpdndn/프로젝트/주식앱/자동매매봇/Tickets/_rework/review-prompts/wave5-codex-prompt.txt')" < /dev/null

통합 워크트리(/private/tmp/wt-wave4, 브랜치 integ/wave5)가 없으면 다시 만든다:

git fetch origin
git worktree add /private/tmp/wt-wave4 -b integ/wave5 origin/main   # 이미 있으면 checkout -B
cd /private/tmp/wt-wave4 && git merge --no-edit feat/BE-34 && git merge --no-edit feat/BE-16

리뷰가 BLOCKED — 리뷰 미실행 을 내면 메모리 부족이다 (도구 호스트가 못 뜬다). 아래 §6 정리를 먼저 하고 재실행한다.

BE-34·BE-16 남은 절차

BE-34·BE-16 은 커밋·검증이 끝났고 codex 리뷰만 남았다. 프롬프트를 그대로 보관해 뒀으니 이어서 실행하면 된다:

codex exec --skip-git-repo-check --ephemeral \
  -o /tmp/wave5-review.json \
  -C /private/tmp/wt-wave4 -s read-only -m gpt-5.6-sol \
  -c 'model_reasoning_effort="high"' \
  -- "$(cat '/Users/biuea/Desktop/dpdpdndn/프로젝트/주식앱/자동매매봇/Tickets/_rework/review-prompts/wave5-codex-prompt.txt')" < /dev/null

통합 워크트리(/private/tmp/wt-wave4, 브랜치 integ/wave5)가 없으면 다시 만든다:

git fetch origin
git worktree add /private/tmp/wt-wave4 -b integ/wave5 origin/main   # 이미 있으면 checkout -B
cd /private/tmp/wt-wave4 && git merge --no-edit feat/BE-34 && git merge --no-edit feat/BE-16

리뷰가 BLOCKED — 리뷰 미실행 을 내면 메모리 부족이다 (도구 호스트가 못 뜬다). 아래 §6 정리를 먼저 하고 재실행한다.

APPROVED 면 PR 2건 생성 → 머지. PR 본문 형식은 이전 PR(#218~#221)을 참고한다.

BE-34·BE-16 남은 절차

통합 브랜치 integ/wave5(/private/tmp/wt-wave4)에서 검증은 끝났다:

  • order 191 tests / 0 failures, autotrading 763 tests / 0 failures, 둘 다 exit 0

남은 건 codex 리뷰 → PR 2건 → 머지다. 리뷰 프롬프트는 _rework/ 옆에 없으니 아래 규칙으로 새로 쓴다.

반드시 지킬 것 (이 과제에서 실제로 사고가 난 것들)

  1. 테스트는 두 패키지를 모두 돌린다. *autotrading* 만 쓰면 order 패키지가 통째로 빠진다. 실제로 그 함정에 걸려 구현과 테스트가 모순인 채 “통과” 로 보고된 적이 있다.

    ./gradlew test -Dkotest.filter.specs='com.biuea.stock.order.*'
    ./gradlew test -Dkotest.filter.specs='*autotrading*'
    

    BUILD SUCCESSFUL 만 보지 말고 XML 의 tests= 건수를 확인한다 (0건 실행도 SUCCESSFUL 이다).

  2. 통합 브랜치에서 검증한다. 개별 티켓만 통과하고 합치면 깨지는 사고가 4번 났다 — DB-02 의 NOT NULL, BE-28 의 낡은 기대값, BE-11 의 Fake 계약, BE-16 의 @Scheduled 플레이스홀더.

  3. 리뷰는 codex 로 한다 (review.code). Claude 단일 런타임 리뷰로 wave 를 닫지 않는다. 이 과제에서 codex 가 p0 30건 이상을 잡았고, 대부분 “테스트는 통과하는데 프로덕션이 부르지 않는” 종류였다.

  4. 리뷰 지적을 정답지로 삼지 않는다. codex 도 두 번 틀렸다 (없는 파일 경로 인용, DTO 래퍼 오판). 외부 API 는 스펙 원문과 대조한다: curl -s https://openapi.tossinvest.com/openapi-docs/latest/openapi.json

  5. 거짓 완료를 확인한다. harness 가 이전 result.json 을 재사용해 “완료” 로 표시한 적이 있다. 커밋 해시가 실제로 바뀌었는지 본다.

  6. 메모리: 테스트 후 Gradle 워커와 Testcontainers 고아를 정리한다. 안 하면 누적돼 디스패치가 죽는다.

    ps -eo pid,command | grep -E "[k]otest.filter|[g]radle.internal.worker|[G]radleDaemon" | awk '{print $1}' | xargs -r kill -9
    docker ps --format '{{.Names}}\t{{.Image}}' | grep "mysql:8.0" | cut -f1 | xargs -r docker rm -f
    

BE-33·BE-17 착수 시

두 티켓 모두 ## 필수 배선 절이 있다 — 누락 시 반려다. BE-33 은 LiveTradeExecutororder.domain 타입 7개 직접 참조 제거가 핵심이다 (autotrading 도메인에 남은 마지막 교차 참조).

Document History

날짜변경 내용
2026-09-07세션 인계용 최초 작성