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.
Area
Proxy / Codex account routing
Problem
/v1/responsesand/v1/responses/compactindependently translate the same Codex auth-context exceptions into HTTP responses. The branches have already drifted: regular Responses handledCodexMainSubstitutionUnavailableErroras 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
CodexAuthContextErrorand handlesForwardAdmissionCredentialError; 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:
CodexAccountCooldownErrorCodexMainProfileDrainingErrorCodexThreadAffinityExpiredErrorCodexAuthContextErrorCodexPoolAuthenticationErrorCodexDirectAuthenticationErrorCodexMainSubstitutionUnavailableErrorEndpoint-only exceptions such as
ForwardAdmissionCredentialErrorshould remain explicit unless both call paths can actually produce them.Acceptance criteria
structure/documentation records the mapper ownership and explains why account selection and transport remain outside it.Non-goals
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.