2026-06-25 (목) 개발일지
오늘의 트러블슈팅 — 브리지·시뮬레이터·트레일링 3종 이슈
오늘은 세 프로젝트에서 서로 다른 성격의 이슈를 잡았다. bit-scalp에선 트레일링 스탑 로직이 TP 조정 시 SL을 함께 움직이는 버그, home_assistant에선 Voice PE → Claude 브리지 연결이 HTTP 503으로 끊기는 문제, 그리고 demo_apps iOS 시뮬레이터에서 destination 이름 매칭 실패로 빌드가 설치까지 안 가는 상황이었다.
bit-scalp — 동적 트레일링 스탑이 TP를 올릴 때 SL을 줄이는 오류
“1번 동기화 2번 새값으로 갱신하는데 지금 왜 SL을 줄이는 거야? TP를 높이면 더 힘든 상황이야?” — 이 질문에서 시작됐다. 동일한 트레일링 로직 내에서 TP를 상승 조정할 때 SL까지 같이 줄어들고 있었다.
처음엔 단순히 SL 갱신 조건문이 TP 조건문보다 먼저 평가되는 실행 순서 문제라고 짐작했다. 하지만 코드를 따라가보니 더 근본적인 문제였다. TP와 SL의 새 값 계산이 같은 함수 블록 안에서 순차적으로 일어나는데, TP 계산에 사용된 시드값이 SL 계산에도 그대로 전달되고 있었다. 분기 구조가 아니라 하나의 흐름 안에서 TP를 먼저 올린 다음 SL을 다시 계산하면서, TP 조정분이 SL에도 영향을 미친 것이다.
calculate_trailing() 안에서 new_tp를 2% 올린 직후 new_sl을 다시 구할 때, 원본 시드가 아니라 이미 TP가 반영된 시장값을 기준으로 SL을 1% 내리고 있었다. SL은 “고정 유지 또는 TP와 동일 비율”이라는 원래 의도와 달리 TP 상승분을 따라 내려가고 있었다.
해결은 단순했다. TP 업데이트와 SL 업데이트를 완전히 분리했다. TP 변조가 SL 계산에 영향을 주지 않도록 new_sl 계산 이전에 new_tp 값을 백업해두는 방식이 아니라, 아예 두 계산을 별도의 분기로 나누고 SL 계산 시점에는 시드값을 고정했다.
| 항목 | Before | After |
|---|---|---|
| TP/SL 계산 격리 | 순차 실행, 동일 시드 | 분기 분리, 시드 고정 |
| SL 변조 여부 | TP 상승 시 SL 1% 감소 | TP와 무관하게 SL 유지 |
검증은 백테스트로 3개월 구간을 돌려봤다. 이전에는 TP 상승 12건 중 9건에서 SL이 동시에 감소했는데, 수정 후에는 단 1건도 SL 변동이 발생하지 않았다. 아직 라이브 반영 전이라 실거래 검증은 남았다.
home_assistant — Voice PE → 브리지 Claude 연결 HTTP 503
음성 파이프라인에서 브리지가 Claude로 메시지를 전달하지 못했다. 마이크는 정상 작동했고 Voice PE도 “듣고 있음” 상태를 보여줬지만, 실제로 Claude가 응답을 생성하지 않았다.
첫 번째 의심은 네트워크였다. echo로 Voice PE 자체의 입력/출력 루프는 정상임을 확인했다. curl로 브리지 엔드포인트에 직접 때려봤더니 HTTP 503. Service Unavailable. 브리지는 살아있지만 Claude 쪽 라우팅이 깨져 있었다.
브리지 설정을 열어보니 Claude 엔드포인트 URL이 /v1/messages가 아니라 /v1/message로 끝나고 있었다. 한 글자 차이지만 Anthropic API는 이걸 다른 엔드포인트로 본다. 503은 브리지가 Claude API에 연결을 시도했지만 URL이 틀려서 API 서버가 뱉은 응답이었다.
해결은 설정 파일에서 URL 경로를 /v1/messages로 수정하고 브리지를 재시작한 것뿐이다. 재시작 후 첫 음성 명령에서 정상적으로 Claude 응답이 돌아왔다. 브리지 로그에 200 OK가 찍히는 걸 확인하고 종료했다.
demo_apps iOS — 시뮬레이터 destination 이름 매칭 실패
Android 에뮬레이터를 종료하고 iOS 시뮬레이터로 전환하는 과정에서 xcodebuild가 destination을 찾지 못했다. iPhone 16 Pro라는 이름으로 빌드를 시도했지만 “An eligible device could not be found” 에러.
처음엔 시뮬레이터가 부팅되지 않았을 거라고 생각했다. xcrun simctl boot로 직접 부팅을 시도했는데, 부팅은 정상적으로 완료됐지만 여전히 destination 매칭이 실패했다.
원인은 이름 불일치였다. xcrun simctl list로 확인해보니 기기 이름이 “iPhone 16 Pro”가 아니라 “iPhone 16 Pro (iOS 18.4)”로 등록되어 있었다. 공백과 괄호까지 포함한 전체 이름이 아니면 -destination에서 매칭되지 않는 것이다.
해결은 UDID로 직접 지정하는 방식이었다. xcrun simctl list devices available에서 UDID를 추출한 뒤, -destination "id=<UDID>"로 빌드했다.
xcodebuild -project OmnitraceDemo.xcodeproj \
-scheme OmnitraceDemo \
-destination "id=<UDID>" \
-configuration Debug \
-sdk iphonesimulator \
build
✅ BUILD SUCCEEDED. 앱이 시뮬레이터에 설치되고 수동모드(인증번호 입력 화면)로 정상 실행됐다. 프로세스 pid 42834로 동작 확인.
남은 과제: 수동모드에서 autoDemo로 전환하려면 -autoDemo 런치 인자를 추가해야 하는데, 이번 빌드에는 포함되지 않았다. 다음 배포 때 반영할 예정.
오늘의 한줄
TP/SL 격리 실패, URL 오타 한 글자, 시뮬레이터 이름 불일치 — 셋 다 기본기 문제였고, 셋 다 로그 하나 보고 원인을 찾았다.