@@ -5,13 +5,27 @@ function jsonRejection(status: number, error: Record<string, unknown>): Response
55 return Response . json ( { error } , { status } ) ;
66}
77
8+ function jsonPayload ( status : number , payload : Record < string , unknown > ) : Response {
9+ return Response . json ( payload , { status } ) ;
10+ }
11+
812describe ( "Codex pre-stream quota rejection classification" , ( ) => {
913 test . each ( [
10- [ 429 , "code" , "usage_limit_exceeded" ] ,
11- [ 429 , "type" , "insufficient_quota" ] ,
12- [ 402 , "code" , "insufficient_quota" ] ,
13- ] as const ) ( "accepts structured reset-eligible exhaustion on HTTP %i" , async ( status , field , code ) => {
14- const result = await classifyCodexPreStreamRejection ( jsonRejection ( status , { [ field ] : code } ) ) ;
14+ [ 429 , "nested code" , { error : { code : "usage_limit_exceeded" } } , "usage_limit_exceeded" ] ,
15+ [ 429 , "nested type" , { error : { type : "insufficient_quota" } } , "insufficient_quota" ] ,
16+ [ 402 , "nested code" , { error : { code : "insufficient_quota" } } , "insufficient_quota" ] ,
17+ [ 429 , "root code" , { code : "usage_limit_exceeded" } , "usage_limit_exceeded" ] ,
18+ [ 402 , "root type" , { type : "insufficient_quota" } , "insufficient_quota" ] ,
19+ [ 429 , "matching code and type" , {
20+ error : { code : "usage_limit_exceeded" , type : "usage_limit_exceeded" } ,
21+ } , "usage_limit_exceeded" ] ,
22+ ] as const ) ( "accepts exact %s reset-eligible exhaustion on HTTP %i" , async (
23+ status ,
24+ _schema ,
25+ payload ,
26+ code ,
27+ ) => {
28+ const result = await classifyCodexPreStreamRejection ( jsonPayload ( status , payload ) ) ;
1529 expect ( result ) . toEqual ( {
1630 kind : "reset-eligible-exhaustion" ,
1731 status,
@@ -21,6 +35,72 @@ describe("Codex pre-stream quota rejection classification", () => {
2135 } ) ;
2236 } ) ;
2337
38+ test . each ( [
39+ [ "leading and trailing whitespace" , { error : { code : " usage_limit_exceeded " } } ] ,
40+ [ "uppercase" , { error : { code : "USAGE_LIMIT_EXCEEDED" } } ] ,
41+ [ "mixed case" , { type : "Insufficient_Quota" } ] ,
42+ [ "trailing whitespace at the root" , { code : "insufficient_quota " } ] ,
43+ ] as const ) ( "rejects the %s near-miss" , async ( _case , payload ) => {
44+ const result = await classifyCodexPreStreamRejection ( jsonPayload ( 429 , payload ) ) ;
45+ expect ( result ) . toMatchObject ( {
46+ kind : "generic-rate-limit" ,
47+ alternateRetryEligible : true ,
48+ resetCreditEligible : false ,
49+ } ) ;
50+ expect ( result ) . not . toHaveProperty ( "semanticCode" ) ;
51+ } ) ;
52+
53+ test . each ( [
54+ [ "primitive error with a root code" , {
55+ error : "opaque" ,
56+ code : "usage_limit_exceeded" ,
57+ } ] ,
58+ [ "matching root and nested codes" , {
59+ code : "usage_limit_exceeded" ,
60+ error : { code : "usage_limit_exceeded" } ,
61+ } ] ,
62+ [ "unknown root and eligible nested codes" , {
63+ code : "unknown" ,
64+ error : { code : "usage_limit_exceeded" } ,
65+ } ] ,
66+ [ "eligible root code with an empty nested error" , {
67+ code : "usage_limit_exceeded" ,
68+ error : { } ,
69+ } ] ,
70+ ] as const ) ( "fails closed for ambiguous schemas: %s" , async ( _case , payload ) => {
71+ const result = await classifyCodexPreStreamRejection ( jsonPayload ( 429 , payload ) ) ;
72+ expect ( result ) . toMatchObject ( {
73+ kind : "generic-rate-limit" ,
74+ alternateRetryEligible : true ,
75+ resetCreditEligible : false ,
76+ } ) ;
77+ expect ( result ) . not . toHaveProperty ( "semanticCode" ) ;
78+ } ) ;
79+
80+ test . each ( [
81+ [ "nested unknown code and eligible type" , {
82+ error : { code : "unknown" , type : "insufficient_quota" } ,
83+ } ] ,
84+ [ "root eligible code and unrelated type" , {
85+ code : "usage_limit_exceeded" ,
86+ type : "rate_limit_error" ,
87+ } ] ,
88+ [ "two different eligible values" , {
89+ error : { code : "usage_limit_exceeded" , type : "insufficient_quota" } ,
90+ } ] ,
91+ [ "eligible code and non-string type" , {
92+ error : { code : "usage_limit_exceeded" , type : null } ,
93+ } ] ,
94+ ] as const ) ( "fails closed for code/type disagreement: %s" , async ( _case , payload ) => {
95+ const result = await classifyCodexPreStreamRejection ( jsonPayload ( 429 , payload ) ) ;
96+ expect ( result ) . toMatchObject ( {
97+ kind : "generic-rate-limit" ,
98+ alternateRetryEligible : true ,
99+ resetCreditEligible : false ,
100+ } ) ;
101+ expect ( result ) . not . toHaveProperty ( "semanticCode" ) ;
102+ } ) ;
103+
24104 test ( "keeps a generic 429 with Retry-After out of reset-credit eligibility" , async ( ) => {
25105 const response = jsonRejection ( 429 , {
26106 type : "rate_limit_error" ,
0 commit comments