11import { describe , expect , test } from "bun:test" ;
22import type { AdmissionQueue } from "../subagent/admission.js" ;
3- import {
4- createCorbitsRetryPolicy ,
5- MAX_BLIND_WAIT_MS ,
6- type CorbitsRetryPolicyOptions ,
7- } from "./retry-policy.js" ;
3+ import { createCorbitsRetryPolicy , type CorbitsRetryPolicyOptions } from "./retry-policy.js" ;
84
95const HTML_503 = `<!DOCTYPE html><html><body>503 Service Unavailable Cloudflare</body></html>` ;
106
@@ -108,9 +104,9 @@ describe("createCorbitsRetryPolicy", () => {
108104 raw : { error : { message : "Too Many Requests" } } ,
109105 } ,
110106 } ) ;
111- // Remapped to retryable -> paced retry capped at the blind-wait ceiling ,
112- // not abort on moderate Retry-After.
113- expect ( decision ) . toEqual ( { kind : "retry" , delayMs : MAX_BLIND_WAIT_MS } ) ;
107+ // Remapped to retryable -> paced retry honors the server's Retry-After ,
108+ // not abort on moderate Retry-After and not a capped 30s wait .
109+ expect ( decision ) . toEqual ( { kind : "retry" , delayMs : 45_000 } ) ;
114110 } ) ;
115111
116112 test ( "stamped Codex usage-limit 429 retries as retryable, not long-quota abort" , async ( ) => {
@@ -125,7 +121,7 @@ describe("createCorbitsRetryPolicy", () => {
125121 raw : "You have hit your ChatGPT usage limit" ,
126122 } ,
127123 } ) ;
128- expect ( decision ) . toEqual ( { kind : "retry" , delayMs : MAX_BLIND_WAIT_MS } ) ;
124+ expect ( decision ) . toEqual ( { kind : "retry" , delayMs : 45_000 } ) ;
129125 } ) ;
130126
131127 test ( "stamped xAI usage/quota body still aborts on long retryAfterMs" , async ( ) => {
@@ -179,7 +175,7 @@ describe("createCorbitsRetryPolicy", () => {
179175 } ;
180176 expect ( await decide ( bare429 ) ) . toEqual ( { kind : "abort" } ) ;
181177 current = "xai/thegreataxios" ;
182- expect ( await decide ( bare429 ) ) . toEqual ( { kind : "retry" , delayMs : MAX_BLIND_WAIT_MS } ) ;
178+ expect ( await decide ( bare429 ) ) . toEqual ( { kind : "retry" , delayMs : 45_000 } ) ;
183179 } ) ;
184180
185181 // CL-6910: the harness only surfaces `inference.error` to the director
@@ -247,7 +243,7 @@ describe("createCorbitsRetryPolicy", () => {
247243 raw : { error : { message : "Too Many Requests" } } ,
248244 } ,
249245 } ;
250- expect ( await decide ( bare429 ) ) . toEqual ( { kind : "retry" , delayMs : MAX_BLIND_WAIT_MS } ) ;
246+ expect ( await decide ( bare429 ) ) . toEqual ( { kind : "retry" , delayMs : 45_000 } ) ;
251247 current = "openai" ;
252248 expect ( await decide ( bare429 ) ) . toEqual ( { kind : "abort" } ) ;
253249 } ) ;
@@ -321,7 +317,7 @@ describe("createCorbitsRetryPolicy", () => {
321317 expect ( await decide ( situation ( 3 ) ) ) . toEqual ( { kind : "abort" } ) ;
322318 } ) ;
323319
324- test ( "retryable 429 caps a long Retry-After at the blind-wait ceiling" , async ( ) => {
320+ test ( "retryable 429 honors a Retry-After above the blind-wait ceiling" , async ( ) => {
325321 const decide = policy ( { providerId : "codex/abk-labs" } ) ;
326322 const decision = await decide ( {
327323 attempt : 1 ,
@@ -333,7 +329,22 @@ describe("createCorbitsRetryPolicy", () => {
333329 retryAfterMs : 120_000 ,
334330 } ,
335331 } ) ;
336- expect ( decision ) . toEqual ( { kind : "retry" , delayMs : MAX_BLIND_WAIT_MS } ) ;
332+ expect ( decision ) . toEqual ( { kind : "retry" , delayMs : 120_000 } ) ;
333+ } ) ;
334+
335+ test ( "retryable 429 with a day-long Retry-After aborts instead of hanging" , async ( ) => {
336+ const decide = policy ( { providerId : "codex/abk-labs" } ) ;
337+ const decision = await decide ( {
338+ attempt : 1 ,
339+ elapsedMs : 0 ,
340+ error : {
341+ category : "retryable" as const ,
342+ message : "Too Many Requests" ,
343+ statusCode : 429 ,
344+ retryAfterMs : 86_400_000 ,
345+ } ,
346+ } ) ;
347+ expect ( decision ) . toEqual ( { kind : "abort" } ) ;
337348 } ) ;
338349
339350 test ( "retryable 429 without Retry-After keeps the fixed backoff" , async ( ) => {
0 commit comments