@@ -1903,7 +1903,11 @@ describe("AccountManager", () => {
19031903 expect ( score ) . toBe ( 100 ) ;
19041904 } ) ;
19051905
1906- it ( "recordSuccess clears stale auth failure state and persists the healed account" , ( ) => {
1906+ it ( "recordSuccess clears stale auth failure state and persists the healed account" , async ( ) => {
1907+ const { saveAccounts } = await import ( "../lib/storage.js" ) ;
1908+ const mockSaveAccounts = vi . mocked ( saveAccounts ) ;
1909+ mockSaveAccounts . mockClear ( ) ;
1910+
19071911 const now = Date . now ( ) ;
19081912 const stored = {
19091913 version : 3 as const ,
@@ -1923,19 +1927,58 @@ describe("AccountManager", () => {
19231927 const manager = new AccountManager ( undefined , stored ) ;
19241928 const account = manager . getCurrentAccount ( ) ! ;
19251929 account . consecutiveAuthFailures = 2 ;
1926- const saveSpy = vi
1927- . spyOn ( manager , "saveToDiskDebounced" )
1928- . mockImplementation ( ( ) => { } ) ;
19291930
19301931 manager . recordSuccess ( account , "codex" , "gpt-5.1" ) ;
1932+ await manager . flushPendingSave ( ) ;
19311933
19321934 expect ( account . consecutiveAuthFailures ) . toBe ( 0 ) ;
19331935 expect ( account . coolingDownUntil ) . toBeUndefined ( ) ;
19341936 expect ( account . cooldownReason ) . toBeUndefined ( ) ;
1935- expect ( saveSpy ) . toHaveBeenCalledTimes ( 1 ) ;
1937+ expect ( mockSaveAccounts ) . toHaveBeenCalledTimes ( 1 ) ;
1938+ const persisted = mockSaveAccounts . mock . calls [ 0 ] ?. [ 0 ] ;
1939+ expect ( persisted ?. accounts [ 0 ] ?. consecutiveAuthFailures ?? 0 ) . toBe ( 0 ) ;
1940+ expect ( persisted ?. accounts [ 0 ] ?. coolingDownUntil ) . toBeUndefined ( ) ;
1941+ expect ( persisted ?. accounts [ 0 ] ?. cooldownReason ) . toBeUndefined ( ) ;
19361942 } ) ;
19371943
1938- it ( "recordSuccess does not clear an active cooldown from a newer concurrent failure" , ( ) => {
1944+ it ( "recordSuccess clears stale cooldown metadata when only the reason remains" , async ( ) => {
1945+ const { saveAccounts } = await import ( "../lib/storage.js" ) ;
1946+ const mockSaveAccounts = vi . mocked ( saveAccounts ) ;
1947+ mockSaveAccounts . mockClear ( ) ;
1948+
1949+ const now = Date . now ( ) ;
1950+ const stored = {
1951+ version : 3 as const ,
1952+ activeIndex : 0 ,
1953+ accounts : [
1954+ {
1955+ refreshToken : "token-1" ,
1956+ addedAt : now ,
1957+ lastUsed : now ,
1958+ cooldownReason : "network-error" as const ,
1959+ } ,
1960+ ] ,
1961+ } ;
1962+
1963+ const manager = new AccountManager ( undefined , stored ) ;
1964+ const account = manager . getCurrentAccount ( ) ! ;
1965+
1966+ manager . recordSuccess ( account , "codex" , "gpt-5.1" ) ;
1967+ await manager . flushPendingSave ( ) ;
1968+
1969+ expect ( account . coolingDownUntil ) . toBeUndefined ( ) ;
1970+ expect ( account . cooldownReason ) . toBeUndefined ( ) ;
1971+ expect ( mockSaveAccounts ) . toHaveBeenCalledTimes ( 1 ) ;
1972+ const persisted = mockSaveAccounts . mock . calls [ 0 ] ?. [ 0 ] ;
1973+ expect ( persisted ?. accounts [ 0 ] ?. coolingDownUntil ) . toBeUndefined ( ) ;
1974+ expect ( persisted ?. accounts [ 0 ] ?. cooldownReason ) . toBeUndefined ( ) ;
1975+ } ) ;
1976+
1977+ it ( "recordSuccess does not clear an active cooldown from a newer concurrent failure" , async ( ) => {
1978+ const { saveAccounts } = await import ( "../lib/storage.js" ) ;
1979+ const mockSaveAccounts = vi . mocked ( saveAccounts ) ;
1980+ mockSaveAccounts . mockClear ( ) ;
1981+
19391982 const now = Date . now ( ) ;
19401983 const stored = {
19411984 version : 3 as const ,
@@ -1955,16 +1998,14 @@ describe("AccountManager", () => {
19551998 const manager = new AccountManager ( undefined , stored ) ;
19561999 const account = manager . getCurrentAccount ( ) ! ;
19572000 account . consecutiveAuthFailures = 2 ;
1958- const saveSpy = vi
1959- . spyOn ( manager , "saveToDiskDebounced" )
1960- . mockImplementation ( ( ) => { } ) ;
19612001
19622002 manager . recordSuccess ( account , "codex" , "gpt-5.1" ) ;
2003+ await manager . flushPendingSave ( ) ;
19632004
19642005 expect ( account . consecutiveAuthFailures ) . toBe ( 2 ) ;
19652006 expect ( account . coolingDownUntil ) . toBe ( now + 60_000 ) ;
19662007 expect ( account . cooldownReason ) . toBe ( "auth-failure" ) ;
1967- expect ( saveSpy ) . not . toHaveBeenCalled ( ) ;
2008+ expect ( mockSaveAccounts ) . not . toHaveBeenCalled ( ) ;
19682009 } ) ;
19692010
19702011 it ( "recordRateLimit updates health and drains token bucket" , ( ) => {
0 commit comments