어떤 모델을, 언제, 어디에 — 프리미엄 모델 타깃 투입 전략

retrospectivemulti-modelmodel-selectionrefactoringcost

세션 한도 알림을 본 건 Sprint 243이었습니다.

Gatekeeper가 서드파티 Action 8종 16건의 SHA 핀 작업을 돌리던 중이었어요. .out 파일에 남은 건 두 줄이었습니다. "session limit · resets 7:10pm." 에이전트는 작업 도중에 멈춰 있었고, working tree에는 핀 diff가 그대로 남아 있었죠. 반응은 놀람보다는 "아, 맞다. 이 모델이었지"에 가까웠어요.

Fable 5가 출시된 날은 2026년 6월 10일이었습니다. 저는 그날 바로 전환했어요. 그리고 그날의 첫 스프린트 지시가 "모든 코드 보안점 및 개선점을 분석해서 리스트업한 뒤 스프린트 계획을 수립하라"였습니다.


문제

성능이 더 좋은 모델이 생겼다. 그런데 그게 항상 옳은 선택인지는 다른 질문이었다.

전환 당일, 전 코드베이스 감사를 시켰더니

Fable 5로 전환하자마자 시킨 첫 일이 전 코드베이스 감사라는 건, 지금 생각해도 적절한 시험이었습니다. "더 잘하는지 보자"가 아니라 "가장 어려운 걸 시켜보자"에 가까운 결정이었어요.

결과는 ADR-030이었습니다. AlgoSu에서 영구 ADR 10번째.

3축 병렬 탐색 — 보안 표면, 코드 품질, CI·인프라 — 을 돌리고, 의심스러운 결론은 전부 코드 직접 Read로 검증했습니다. 그 과정에서 오판 5건을 걸러냈어요. Saga 보상 트랜잭션이 "없다"고 분석했지만 실재했고, Monaco lazy-load가 "미적용"이었지만 next/dynamic으로 이미 처리돼 있었습니다. 탐색(커버리지)과 검증(정확도)을 분리한 덕에 오판이 걸러졌어요.

최종 결론은 High Risk 0건이었습니다. 기초 태세가 견고했다는 확인이기도 했어요. Medium 3건, Low 5건, 개선 7건. 그리고 이를 처리하는 5스프린트 로드맵 — S239~243 — 이 세워졌습니다.


5 스프린트를 돌렸습니다

  1. S239@Public() SSOT · 이벤트 API DTO 검증 · 프롬프트 신뢰경계 격리 · HeaderSanitizer
    완료

    보안 quick wins

  2. S240암호화 키 로테이션 런북 · DLQ redrive 런북 (docs only)
    완료

    운영 런북

  3. S241study.service 823줄→5 서비스 · saga-orchestrator 516줄→3 모듈
    완료

    BE 분해

  4. S242AddProblemModal 805줄→4파일 · settings 844→252 · Redis 로깅 정합
    완료

    FE 분해

  5. S243Action SHA 핀 8종 · CI 인라인 스크립트 추출 · CSP 스파이크(보류)
    완료

    공급망·CSP·CI

로드맵은 예상대로 소화됐습니다. 그런데 성능보다 눈에 들어온 건 비용이었어요.

토큰 소모가 명확히 달랐습니다. 추론 깊이가 깊다는 건 — 모델이 한 번에 안고 추론하는 컨텍스트가 넓다는 건 — 곧 토큰 소모가 크다는 뜻이기도 했어요. Sprint 243 한 스프린트에서 Gatekeeper가 SHA 핀 체인을 돌리다가 세션 한도에 닿은 건 처음이었습니다. Fable 5로 전환한 이후 처음 겪은 세션 중단이었어요.


결정

일상 스프린트는 Opus/Sonnet 유지. 대형 리팩토링 주기에는 프리미엄 모델을 타깃 투입한다.

회귀는 추출 경계에 모인다

Sprint 241~242를 돌리면서 한 가지 패턴이 반복됐어요.

분해 리팩토링의 회귀는 분해 경계에 모인다는 것.

study.service.ts를 5개 파일로 쪼갰을 때, 잘못된 건 각 파일 안의 로직이 아니었어요. 파일 사이의 경계였습니다. redis.keys O(N) 문제는 분리 전부터 코드에 있었는데, 분리를 통해 비로소 Critic의 시야에 들어왔어요. FE 분해에서도 비슷했습니다. 번역 키 래핑 누락은 auto-critic이, setError(null) 초기화 탈락은 전체-base 머지 게이트 R1이, 파생 상태 처리 누락은 R2가 잡았습니다. 커밋 단위 리뷰 5회는 이 중 어느 것도 잡지 못했고, R3에서야 CLEAN이 났어요.

더 강한 모델이라면 이걸 1패스에 잡을 잠재력이 있습니다. auto-critic·머지 게이트 R1/R2에서 나온 발견을 최초 커밋 리뷰에서 잡는다면, 그 라운드 비용이 절감돼요. ADR-030 5스프린트 로드맵을 예로 들면:

Critic 누적 라운드 (S241~242)
15 라운드
BE 7 + FE 8 (머지 게이트 포함)
경계 회귀 발견 건수
6건
auto-critic·머지 게이트 R1/R2 적발 — 커밋 단위 리뷰는 미탐

경계 회귀 발견이 전부 커밋 단위 리뷰를 통과하고 auto-critic·전체-base 머지 게이트에서 나왔습니다. 프리미엄 모델의 깊은 추론이 R1에서 이를 잡는다면 — auto-critic 라운드와 머지 게이트를 여러 회 돌리는 비용을 아끼는 셈이에요.

이게 가설에 불과하다는 건 압니다. 실측으로 증명하진 않았어요. 하지만 ADR-030 로드맵을 직접 돌리면서 느낀 건, "회귀가 경계에 모인다"는 패턴을 아는 모델이 처음부터 경계를 더 꼼꼼히 보는 경향이 있다는 것이었습니다.


프리미엄 모델이 ROI를 가지는 조건

전략의 핵심은 선택적 투입입니다.

일상 스프린트 — 기능 추가, 버그 수정, 문서 갱신 — 는 Opus/Sonnet으로 충분합니다. 이미 정해진 패턴 위에서 코드를 추가하는 작업에서 추론 깊이의 차이는 크게 드러나지 않아요. 비용 효율이 압도합니다.

프리미엄 모델이 ROI를 가지는 건 다른 경우입니다:

  1. "일반 모델로 하면 머지 게이트가 여러 라운드 도는 영역" — 추출 경계가 많은 대규모 분해, 보안 감사, 크로스커팅 리팩토링. 라운드 절감이 비용 절감으로 직결되는 구조예요.
  2. "기술부채 원금을 상환하는 작업" — ADR-030 같은, 과거에 쌓인 문제를 한꺼번에 정리하는 스프린트. 여기서 1회성 비용을 쓰면, 이후 일반 모델로 작업하는 스프린트들의 품질이 같이 올라가요.
  3. "처음 봐야 하는 영역" — 전 코드베이스를 처음부터 다시 보는 감사, 새로운 도메인 설계. 컨텍스트 없이 시작하는 작업일수록 추론 깊이의 차이가 납니다.

이게 이번 6 스프린트에서 얻은 핵심 통찰이에요. 프리미엄 모델에 투자하는 건 그 스프린트 하나를 위해서가 아니라, 이후 n 스프린트의 기준선을 올리기 위해서입니다. 기술부채를 갚는 것처럼, 이자(라운드 비용)를 줄이는 원금 상환이에요.


단서 — 이 전략이 성립하지 않는 경우

이 전략을 "늘 프리미엄 모델을 쓰자"로 해석하면 틀립니다.

몇 가지 전제가 있어요.

첫 번째, 전면 리팩토링은 수익 체감이 빠릅니다. ADR-030 분해가 효과 있었던 건 823줄, 516줄 같은 명확한 "원금"이 있었기 때문이에요. 이미 잘 분리된 코드베이스에서의 추가 분해는 회귀 리스크 대비 이득이 작아요. 고통이 명확한 곳에 투입하는 것이지, 모든 곳에 투입하는 게 아닙니다.

두 번째, 대형 모델이 무조건 더 정확하지는 않습니다. ADR-030 분해는 결국 일반 모델(Opus/Sonnet 기반 에이전트들)로 처리했습니다. 프리미엄 모델이 설계하고 감사했지만, 실행은 일반 에이전트 체인이 맡았어요. 리뷰와 실행을 분리하는 것도 하나의 전략이에요.

세 번째, 비용은 실재합니다. S243에서 세션 한도에 닿은 건 경고였습니다. 모든 스프린트를 프리미엄 모델로 돌리면 — 토큰 소모, 세션 중단 리스크, 비용이 함께 올라가요. 선택적 투입이어야 하는 이유예요.


결과

6 스프린트가 가르쳐준 것은 성능의 한계가 아니라 투입 시점의 중요성이었다.

앞선 글과 이 글

종속 없는 하네스를 향해에서 저는 특정 모델에 종속되지 않는 시스템에 대해 썼어요. Critic을 교체가 아닌 추가로 들이고, 어떤 모델이라도 자리를 바꿀 수 있는 하네스를 향해가고 있다는 기록이었습니다.

이 글은 그 후속입니다. 모델 종속에서 해방된 다음의 질문 — "그래서 어떤 모델을, 언제, 어디에 쓸 것인가" 에 대한 답이에요.

그 자유가 생기기 전까지는 이 질문이 성립하지 않아요. 종속돼 있으면 선택이 없으니까요. 하네스가 모델 스왑을 지원하고, Critic 자리에 어느 모델이든 앉힐 수 있게 된 뒤에야 — 비로소 전략이 생기고, 타이밍을 고를 수 있게 됩니다.

Fable 5로 전환한 날, 저는 출시 직후의 모델을 전 코드베이스 감사에 투입했습니다. 결과가 좋았어요. 하지만 더 중요한 건 그 뒤였습니다. 언제 다시 투입할지를 알게 된 것. 그리고 그 판단이 단순한 성능 비교가 아니라 — 기술부채 상환 타이밍이라는 프레임으로 정착된 것이에요.

다음 대형 리팩토링이 필요한 순간이 오면, 저는 그때 다시 프리미엄 모델을 꺼낼 겁니다. 지금은 아니에요. 이미 깨끗해진 경계 위에서 일상 스프린트가 잘 돌아가고 있으니까요.

관련 ADR

이 글의 결정이 기록된 의사결정 문서

sprint-238

전 코드베이스 보안점·개선점 분석 리스트업 + 스프린트 계획 수립 (ADR-030)

fable 모델 전환 후 첫 스프린트. /start 인자 '모든 코드 보안점 및 개선점 분석 → 리스트업 → 스프린트 계획 수립'으로 시작. 3축 병렬 탐색(보안 표면/코드 품질/CI·인프라) 후 sprint-99 교훈에 따라 핵심 의심 항목 전수를 파일 직접 Read로 재검증 — 그 결과 예비 보고 5건이 오판/기해소/격하로 판명(Saga 보상 실재·Monaco 지연 로드 기적용·SP196 GIN 기해소·ShareLinkGuard 양호·키 네이밍은 컨벤션), 신규 발견 1건 추가(POST /api/events 비인증+plain interface라 ValidationPipe 검증 0). 결론 High Risk 0건, Medium 3건(S-1 @Public 부재·S-2 events DTO·S-3 CSP unsafe-inline)+Low 5건+개선 7건을 ADR-030(신규 영구 ADR, KR+EN)으로 SSOT화하고 처리 로드맵 Sprint 239~243 확정(quick wins→런북→BE 분해→FE 분해→공급망). 검증: ADR 게이트 6종 통과(index 영구 10·EN 186/186·links 0·i18n 0·doc-refs clean·conversion PASS), Critic(Codex gpt-5.5 --base aea9528) R1 CLEAN, PR #426 CI green auto-merge squash 22da1f3.

sprint-241

BE 분해 — ADR-030 Q-1(BE) + Q-2

ADR-030 처리 로드맵 3순위 스프린트. 동작 불변 리팩토링 2건 완료 — coverage threshold 유지 + Critic auto 2라운드 → 발견 4건 전수 수정. Q-1(BE): gateway study.service.ts(823줄·28메서드) → 도메인별 5서비스(StudyMemberService·StudyStatsService·StudyAccessService·MembershipCacheService·study.service 잔존) + 공유 타입으로 분리. StudyController가 3서비스 직접 주입(위임 보일러플레이트 0). 신규 5서비스 + controller 전부 100% coverage. Q-2: saga-orchestrator.service.ts(516줄) → SagaQuotaService(AI 한도·CB 소유)·SagaTimeoutService(재개·타이머·lifecycle)·잔존 Orchestrator(advance*/compensate*)의 3서비스 분해. 소비자 6곳 호출부 변경 0. Critic auto-critic R1(gatekeeper 산출물, base 241af57): M-1 redis.keys O(N)·L-1 structured logging 패턴 불일치 발견. Critic R1(conductor 산출물, base 606edb1): app.module.init.spec 주석 드리프트·fake timer 격리 패턴 불일치 발견. 4건 전수 수정 후 R2(base 3dc4b13) CLEAN. gateway coverage 98.66/96.94/96.83/98.93(threshold 98/95/96/98), submission coverage 98.69/94.13/98.93/99.04(threshold 97/92/96/97) 전부 유지.

sprint-242

FE 분해 + 테스트 (ADR-030 Q-1 FE + Q-7 + Redis 로깅 이월)

ADR-030 처리 로드맵 4순위 스프린트. FE 대형 파일 3종 분해 + Sprint 241 이월 Redis 로깅 정합 완료. D(Redis 이월): 이월 3파일+인접 3파일 총 6종 on-error 2-인자 구조화 패턴 정합. Q-1(FE): AddProblemModal(805줄)→add-problem/ 4파일(206/271/263/220) + re-export shim 20줄 + 65 tests / settings(844줄)→243줄+6섹션+28 tests / edit(748줄)→465줄+5섹션+22 tests(기존 훅 3종 활용). Critic auto-critic 5회(D Low1·A CLEAN·B/C M-1+L-1·L-1수정분 Medium잔존2·잔존봉합분 Low1) + 머지게이트 전체-base R1(M-1)→R2(P3)→R3 CLEAN — 발견 전수 수정. frontend 171 suites/1769 tests, coverage 88.06/80.68/85.34/88.58(threshold 81/71/82/83 전부 유지). gateway 854+/98.66/96.94/96.83/98.93, submission 387/98.69/94.13/98.93/99.04. 3서비스 tsc 0/lint 0.

관련 글