"앱이 확신 못 할 때 정직한 수는 추측이 아냐 — 명확히 라벨된 선택을 너한테 건네는 거야."
실패한 refresh 는 숨길 에러가 아냐
Keep 한테 quote refresh 를 요청했는데 primary provider 가 실패하면, 유혹적이지만 틀린 수가 셋 있어: stale 값을 조용히 내기, fallback 으로 조용히 swap, 일반 500 으로 터지기. Keep 은 아무것도 안 해. 409 — 해결이 필요한 conflict 의 HTTP 상태 — 를 candidate fallback payload 와 함께 반환해. 그 409 는 confirmation challenge 야: 'primary 가 답 안 했어; 대신 쓸 수 있는 fallback 이 여기 있어; 원해?' 진행 거부가 막다른 길이 아니라 구조화된 질문이 돼.
일급 응답으로서의 confirmation
핵심 설계 아이디어는 '뭔가 확인이 필요해' 를 에러나 조용한 기본값이 아니라 정당하고 구조화된 API 응답으로 다루는 거야. FallbackConfirmationRequired 는 정확한 candidate 를 붙인 409 로 매핑돼서, 프론트엔드가 진짜 선택을 렌더할 수 있어 — 어느 provider, 어느 ticker, 무슨 값을 보여주며 — 사람이 완전한 정보로 받거나 거절해. 대안과 비교해: 조용한 swap 은 선택을 안 줘; 500 은 정보를 안 줘; stale 값은 거짓말을 줘. payload 딸린 409 는 agency 를 줘.
끝까지 정직한 상태
409 는 더 넓은 규칙의 한 사례야: Keep 의 도메인 에러는 뭉뚱그린 500 대신 정직한 HTTP 상태를 지녀.
FallbackConfirmationRequired→ candidate payload 딸린 409- 나쁜 입력값 → 400
- 없는 simulation run → 404
- provider/runtime 실패 → 503
각 상태가 client 한테 뭐가 잘못됐고 retry·입력수정·확인 중 뭐가 옳은 다음 수인지에 대해 참인 걸 말해. 이 전부에 일반 500 이면 호출자가 필요한 정보를 정확히 지워. 그리고 새 provider 실패는 진짜 RuntimeError → 503 을 raise 하지, 데이터인 척하는 sentinel 값을 절대 안 내.