Skip to content

[Refactor]: centralize Codex auth-context error mapping across Responses and compact #2392

Closed

Description

@Ingwannu

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:

  • CodexAccountCooldownError
  • CodexMainProfileDrainingError
  • CodexThreadAffinityExpiredError
  • CodexAuthContextError
  • CodexPoolAuthenticationError
  • CodexDirectAuthenticationError
  • CodexMainSubstitutionUnavailableError

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

  1. lidge-jun commented on Aug 22, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 44 / 80

    설명: 이 이슈는 일반 응답 길과 압축 길이의 코덱스 인증 오류 표를 한 작은 매퍼로 모으자고 한다. 지금 CURRENT dev HEAD 는 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 에 넣지 말 것

    메인테이너의 판단이 필요한 지점

    • 매퍼를 새 잎으로 둘지, core.ts 옆에 둘지. 이슈는 작은 순수 매퍼를 원한다
    • 재인증 로그 콜백을 매퍼 인자로 받을지. 압축 길은 지금 로그가 없다
    • 2390 머지 뒤에만 이 PR 을 열지. 베이스가 그 세 줄을 포함해야 특징 테스트가 맞다

    너의 추천
    2390 이 머지된 뒤에 새 PR 을 연다. 먼저 두 길의 공통 행렬 특징 테스트를 넣고, 그다음 매퍼만 옮긴다. 상태 코드와 말과 재시도 헤더를 바꾸지 않는다. 지금 닫지 말 것. 계정 고르기와 전송은 매퍼 밖에 둔다. types.ts/config.ts 스플릿과 겹치면 닫고 리베이스하지 않는다. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.

    이 댓글은 grok-bot이 작성했습니다

  2. lidge-jun commented on Aug 23, 2026

    @lidge-jun
    Owner

    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), ForwardAdmissionCredentialError in both admission paths (not an auth-context resolution error), compact's alternate-account draining branch (returns null to 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:174 now 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.

  3. lidge-jun commented on Aug 23, 2026

    @lidge-jun
    Owner

    Landed via #2450 at 9cebfc6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, planslanded-via-maintainerOriginal PR closed after landing via a maintainer merge train

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions