Repository navigation
[Refactor]: centralize Codex auth-context error mapping across Responses and compact #2392
Description
Area
Proxy / Codex account routing
Problem
/v1/responses and /v1/responses/compact independently translate the same Codex auth-context exceptions into HTTP responses. The branches have already drifted: regular Responses handled CodexMainSubstitutionUnavailableError as a sanitized 401 before upstream I/O, while compact omitted that case until PR #2390.
The duplication is not byte-identical today. Regular Responses also performs safe account-label logging for CodexAuthContextError and handles ForwardAdmissionCredentialError; compact has a narrower reachable set. A mechanical shared catch block would therefore be wrong, but leaving two freehand exception matrices makes future drift likely.
Proposed boundary
Extract one small, pure mapper for the response contract shared by both endpoints. It should accept only the context needed to preserve intentional differences, for example the route namespace and an optional callback for the regular-path reauthentication log. Keep account selection, credential materialization, probe-lease ownership, and upstream request construction in their current modules.
The mapper should cover the common response shapes for:
CodexAccountCooldownErrorCodexMainProfileDrainingErrorCodexThreadAffinityExpiredErrorCodexAuthContextErrorCodexPoolAuthenticationErrorCodexDirectAuthenticationErrorCodexMainSubstitutionUnavailableError
Endpoint-only exceptions such as ForwardAdmissionCredentialError should remain explicit unless both call paths can actually produce them.
Acceptance criteria
- Both regular Responses and compact use the same shared mapping for their common Codex auth-context errors.
- Existing status codes, error types, messages, retry headers, and safe logging remain byte-for-byte compatible.
- Missing main-credential substitution remains a sanitized 401 and performs zero upstream I/O on both endpoints.
- Unknown exceptions still escape to the existing outer error handling; the helper must not turn arbitrary failures into authentication errors.
- Characterization tests cover the common matrix through both endpoint paths, including cooldown headers and thread-affinity 409.
structure/documentation records the mapper ownership and explains why account selection and transport remain outside it.
Non-goals
- No redesign of Codex account selection or pool rotation.
- No change to credential storage, auth modes, admission policy, or error wording.
- No broad server error-normalization refactor.
Why a separate PR
PR #2390 is a narrow user-visible bug fix and should not be blocked on a larger import-boundary refactor. This follow-up exists to remove the duplication that allowed the bug, with behavior-preserving characterization first.
Activity
lidge-jun commentedon Aug 22, 2026
리뷰 · 우선순위 44 / 80
설명: 이 이슈는 일반 응답 길과 압축 길이의 코덱스 인증 오류 표를 한 작은 매퍼로 모으자고 한다. 지금 CURRENT
devHEAD 는7185ecc80이다. 이번 시간에 origin/dev 가5e5059044에서 여기로 옮겼다. 착지한 코드는 2388 코덱스 설정 문자열 정규식 고침과 2391 WP8 실행 기록(문서만)이다. package.json 은 2.27.0 이다. src/config.ts 는 3975줄이다. src/runtime 폴더는 지금 HEAD 에 없다. 지금 HEAD 의 src/server/responses/core.ts 1514줄 catch 는 식힘, 배수, 스레드 만료, 재인증(계정 이름 로그 포함), 풀 인증, 직접 인증, ForwardAdmissionCredentialError, CodexMainSubstitutionUnavailableError 를 잡는다. 같은 HEAD 의 src/server/responses/compact.ts 397줄 catch 는 식힘, 배수, 스레드 만료, 재인증(로그 없음), 풀/직접 인증만 잡는다. 치환 실패는 다시 던진다. 입장 자격 오류는 337줄에서 먼저 잡는다. 이슈가 말한 대로 두 표는 바이트가 같지 않다. 그냥 한 catch 로 합치면 로그와 입장 오류 자리가 깨진다. PR 2390 이 압축 길에 치환 401 만 더한다. 그 PR 은 리뷰-레디이고 이 이슈의 매퍼는 넣지 않는다. 이슈도 2390 을 큰 리팩터에 묶지 말라고 했다. 매퍼는 공통 모양만 다루고 계정 고르기, 자격 만들기, 조사 임대, 위쪽 요청 만들기는 지금 모듈에 남긴다. 모르는 오류는 바깥으로 보낸다. 사용자 길이 버그가 아니라 모듈 경계 일이라서 44. 카탈로그 팁은 Ox Alpha x-preview-f-free + deepseek-v4-flash-vision-exp. Cursor 정적 카탈로그는 opus-4-8-fast / opus-5-fast. 2334 CursorCredentialRouter 는 여전히 연결되지 않았다. 2332 H2 는 discovery 전용. 2320 overflow + 2342 는 이미 dev. 2188 사이드카는 이미 dev. 2382 데스크톱 앱 재시작은 이미 dev. 2292 는 아직 연다.src/server/responses/core.ts 라인 1514 - 일반 길 catch. 재인증은 안전한 계정 이름을 로그로 남긴다. 압축 길에는 그 로그가 없다
src/server/responses/compact.ts 라인 397 - 압축 길 catch. 지금 HEAD 는 치환 실패를 다시 던진다. 2390 이 여기만 고친다
src/server/responses/compact.ts 라인 337 - ForwardAdmissionCredentialError 는 압축에서 먼저 잡힌다. 공통 catch 로 옮기면 자리가 달라질 수 있다
src/codex/auth-context.ts 라인 598 - CodexMainSubstitutionUnavailableError. 매퍼가 받아야 할 공통 오류 중 하나다
PR 2390 - 사용자 길이 구멍만 막는다. 이 이슈를 그 PR 에 넣지 말 것
메인테이너의 판단이 필요한 지점
너의 추천
2390 이 머지된 뒤에 새 PR 을 연다. 먼저 두 길의 공통 행렬 특징 테스트를 넣고, 그다음 매퍼만 옮긴다. 상태 코드와 말과 재시도 헤더를 바꾸지 않는다. 지금 닫지 말 것. 계정 고르기와 전송은 매퍼 밖에 둔다. types.ts/config.ts 스플릿과 겹치면 닫고 리베이스하지 않는다. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.
이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Aug 23, 2026
Closed by #2450, squash-merged to
dev.The shared classes now live in a pure leaf,
src/server/responses/codex-auth-error.ts: cooldown 429 with selector-aware body and Retry-After, draining 503, thread-affinity 409, generic reauthentication 401, the two message-preserving 401s, and the fail-before-I/O substitution 401.Four things stayed local on purpose rather than being folded in for tidiness: the regular-Responses pseudonymous reauth log (compact emits no equivalent, and adding one would be a behavior change),
ForwardAdmissionCredentialErrorin both admission paths (not an auth-context resolution error), compact's alternate-account draining branch (returnsnullto preserve the first account's rejection), and unmapped errors, which rethrow in both handlers.The pre-existing suites asserted status codes on both paths but not byte-level parity — exactly the gap this kind of refactor falls through — so a table-driven characterization at
tests/responses-compaction-routing.test.ts:174now pins identical status, serialized body, content type, cooldown and drain Retry-After, thread-affinity 409, zero upstream I/O for substitution, regular-only safe logging, and rejection of unknown errors.Evidence: 147 pass / 0 fail focused, full suite 14,521 pass / 11 skip / 0 fail across 906 files, typecheck exit 0, privacy:scan green, CI green.
lidge-jun commentedon Aug 23, 2026
Landed via #2450 at 9cebfc6