@@ -263,6 +263,51 @@ describe("runRuntimeAccountCheck", () => {
263263 expect ( saveFlaggedAccounts ) . not . toHaveBeenCalled ( ) ;
264264 } ) ;
265265
266+ it ( "propagates EBUSY from combined persistence without partial writes" , async ( ) => {
267+ const persistAccountAndFlaggedStorage = vi . fn ( async ( ) => {
268+ const error = new Error ( "busy" ) as Error & { code ?: string } ;
269+ error . code = "EBUSY" ;
270+ throw error ;
271+ } ) ;
272+ const saveAccounts = vi . fn ( async ( ) => { } ) ;
273+ const saveFlaggedAccounts = vi . fn ( async ( ) => { } ) ;
274+
275+ await expect (
276+ runRuntimeAccountCheck ( true , {
277+ hydrateEmails : async ( storage ) => storage ,
278+ loadAccounts : async ( ) => ( {
279+ version : 3 ,
280+ accounts : [ { email : "one@example.com" , refreshToken : "refresh-1" , accessToken : undefined , addedAt : 1 , lastUsed : 1 } ] ,
281+ activeIndex : 0 ,
282+ activeIndexByFamily : { codex : 0 } ,
283+ } ) ,
284+ createEmptyStorage : ( ) => ( { version : 3 , accounts : [ ] , activeIndex : 0 , activeIndexByFamily : { } } ) ,
285+ loadFlaggedAccounts : async ( ) => ( { version : 1 , accounts : [ ] } ) ,
286+ createAccountCheckWorkingState : ( flaggedStorage ) => ( { flaggedStorage, removeFromActive : new Set ( ) , storageChanged : false , flaggedChanged : false , ok : 0 , errors : 0 , disabled : 0 } ) ,
287+ lookupCodexCliTokensByEmail : async ( ) => null ,
288+ extractAccountId : ( ) => undefined ,
289+ shouldUpdateAccountIdFromToken : ( ) => false ,
290+ sanitizeEmail : ( email ) => email ,
291+ extractAccountEmail : ( ) => undefined ,
292+ queuedRefresh : async ( ) => ( { type : "failed" , reason : "invalid_grant" , message : "refresh failed" } ) ,
293+ isRuntimeFlaggableFailure : ( ) => true ,
294+ fetchCodexQuotaSnapshot : async ( ) => { throw new Error ( "should not probe quota in deep mode" ) ; } ,
295+ resolveRequestAccountId : ( ) => undefined ,
296+ formatCodexQuotaLine : ( ) => "quota" ,
297+ clampRuntimeActiveIndices : vi . fn ( ) ,
298+ MODEL_FAMILIES : [ "codex" ] ,
299+ saveAccounts,
300+ invalidateAccountManagerCache : vi . fn ( ) ,
301+ saveFlaggedAccounts,
302+ persistAccountAndFlaggedStorage,
303+ showLine : vi . fn ( ) ,
304+ } ) ,
305+ ) . rejects . toThrow ( "busy" ) ;
306+
307+ expect ( saveAccounts ) . not . toHaveBeenCalled ( ) ;
308+ expect ( saveFlaggedAccounts ) . not . toHaveBeenCalled ( ) ;
309+ } ) ;
310+
266311 it ( "treats cache lookup failures as a cache miss and still refreshes" , async ( ) => {
267312 const saveAccounts = vi . fn ( async ( ) => { } ) ;
268313 await runRuntimeAccountCheck ( false , {
0 commit comments