Joyuno's Dev Blog

2026-09-01 (화) 개발일지

dev-blog

오늘은 세 프로젝트에서 각각 다른 성격의 이슈를 처리했다. 게임 blanks.py의 placeholder 마커가 정답 텍스트와 충돌한 케이스, cockpit effort 기본값 조정, demo_apps Android 네트워크 정리까지. 특히 blanks.py는 “내가 실수했나” 싶었다가 계획서 자체의 결함이었던 경우라 기록해둔다.

blanks.py placeholder 충돌 — blank id와 정답 텍스트가 겹쳐서 마커가 그대로 노출된 케이스

SK 트랙 빈칸 콘텐츠 계약 테스트(test_blank_template.py)를 돌렸는데 실패했다. 마커 ⟨1⟩이 제거되지 않고 최종 문자열에 그대로 남아 있었다. 처음엔 내 parse_template 구현이 잘못됐다고 생각했다. MARKER_OPEN/CLOSE 상수 값을 다시 확인하고, derive_reference_solution에서 치환 로직을 추적했지만 정규식 패턴 자체는 문제가 없었다.

테스트 코드는 계획서에서 그대로 가져온 계약 코드라 건드릴 수 없었다. 결국 _placeholder() 함수 반환값을 로그로 찍었다. 알고 보니 blank id=1인 빈칸의 정답 텍스트가 "1"이었고, _placeholder()도 아스키 숫자 "1"을 반환하도록 되어 있었다. 마커 치환 후에도 ⟨1⟩ → 1이 되면서 정답 "1"과 외형상 동일해져, “치환이 일어난 것처럼 보이지만 실은 마커가 그대로 남은” 상태였다. 문자열 레벨에서 보면 "1"이 "1"으로 대체된 셈이니 변화가 없었던 것.

진짜 원인은 _placeholder()가 아스키 숫자를 반환하는 계획서 원본 코드의 결함이었다.

해법은 단순했다. _placeholder()에서 아스키 숫자 대신 유니코드 첨자 숫자(₁, ₂, ₃)를 반환하도록 수정했다. 이렇게 하면 정답 텍스트와 절대 겹치지 않는다. 테스트는 계약이므로 손대지 않았고, 구현만 고쳤다.

구분 _placeholder() 반환값 충돌 가능성
before "1" (ASCII) 정답 "1"과 충돌
after "₁" (U+2081) 정답 텍스트와 겹칠 수 없음

검증: 수정 후 전체 테스트 14건 통과. _site/ 재빌드해서도 문제 없음을 확인. 계획서 원본의 결함을 구현 단계에서 발견해서 고친 케이스로, 테스트가 결국 계약 역할을 제대로 해줬다.

cockpit effort 기본값 ultracode → high — 불필요한 토큰 소모를 줄인 결정

cockpit이 새로 띄우는 모든 세션이 ultracode effort로 시작하고 있었다. 대부분의 세션은 단순 파일 탐색이나 질문에 가까운데, ultracode는 복잡한 다단계 작업에나 필요한 수준이다. 토큰이 불필요하게 소모된다는 인식에서 출발했다.

agents.ts:43을 열어 기본값을 확인했다. 주석이나 변경 이력을 보니 예전에는 모든 세션이 복잡한 작업을 수행했지만, 지금은 사용 패턴이 다양해져서 ultracode가 오히려 과했다. 빈번한 간단 작업마다 ultracode가 걸리면 토큰 비용만 올라간다.

해결은 간단했다. agents.ts:43의 기본 effort를 ultracode → high로 변경했다. 필요할 때만 세션 안에서 /effort ultracode로 수동으로 올리면 된다.

제약 정리

  • 신규 세션: 기본 high로 시작 → 필요시 세션 내에서 조정
  • 기존에 이미 떠 있는 tmux 세션: 이 변경이 바로 적용되지 않음 — session/tmux.ts 로직대로 재접속만으로는 명령이 재실행되지 않기 때문. 해당 세션은 사용자가 직접 조정하거나 세션을 새로 띄워야 반영됨

검증: agents.test.ts 테스트 통과. Windows 인스톨러 빌드(release/Lepons Cockpit Setup 1.0.0.exe)도 이상 없음.

demo_apps Android .10 하드코딩 — 백엔드 이전 후 남은 레거시 정리

demo_apps에서 Android 기기가 lepons 경유 파일 조회에 실패하고 있었다. iOS는 정상이었다. iOS 세션 데이터는 계속 누적 중(events 1876 / traces 200 / snapshots 540)이었고, Android는 재시작 후 새 세션으로 시작됐다(events 36 / traces 9 / snapshots 6).

가장 먼저 의심한 건 네트워크 설정 차이였다. 백엔드 mock은 이미 .18 엔드포인트로 정상 가동 중이었는데, Android 쪽 빌드 설정과 네트워크 정책 파일에서 .10 하드코딩이 그대로 남아 있었다. build.gradle.kts와 network_security_config.xml 두 곳이었다.

파일 하드코딩 값 수정 후
build.gradle.kts 10.x.x.x 18.x.x.x
network_security_config.xml 10.x.x.x 18.x.x.x

백엔드가 먼저 이전됐는데 Android 설정이 따라가지 못한 케이스. 수정 후 Android에서도 파일 조회가 정상 동작했고, 두 세션 모두 같은 session_id를 유지한 채 누적되는 걸 확인했다.

오늘의 한줄

계획서의 결함을 테스트가 잡아내고, 기본값의 과잉을 사용 패턴 분석이 바로잡았다 — 기록해둔 결정이 아니라, 다시 확인한 결정만 신뢰하자.