@@ -207,14 +207,62 @@ describe("runRuntimeAccountCheck", () => {
207207 const saved = saveAccounts . mock . calls [ 0 ] ?. [ 0 ] ;
208208 expect ( saved . accounts [ 0 ] ) . toMatchObject ( {
209209 email : "fresh@example.com" ,
210- refreshToken : "fresh -refresh" ,
210+ refreshToken : "stale -refresh" ,
211211 accessToken : "cached-access" ,
212212 expiresAt : 70_000 ,
213213 accountId : "new-account" ,
214214 accountIdSource : "token" ,
215215 } ) ;
216216 } ) ;
217217
218+ it ( "uses combined persistence when flagging an invalid account removes it from active storage" , async ( ) => {
219+ const persistAccountAndFlaggedStorage = vi . fn ( async ( ) => { } ) ;
220+ const saveAccounts = vi . fn ( async ( ) => { } ) ;
221+ const saveFlaggedAccounts = vi . fn ( async ( ) => { } ) ;
222+
223+ await runRuntimeAccountCheck ( true , {
224+ hydrateEmails : async ( storage ) => storage ,
225+ loadAccounts : async ( ) => ( {
226+ version : 3 ,
227+ accounts : [ { email : "one@example.com" , refreshToken : "refresh-1" , accessToken : undefined , addedAt : 1 , lastUsed : 1 } ] ,
228+ activeIndex : 0 ,
229+ activeIndexByFamily : { codex : 0 } ,
230+ } ) ,
231+ createEmptyStorage : ( ) => ( { version : 3 , accounts : [ ] , activeIndex : 0 , activeIndexByFamily : { } } ) ,
232+ loadFlaggedAccounts : async ( ) => ( { version : 1 , accounts : [ ] } ) ,
233+ createAccountCheckWorkingState : ( flaggedStorage ) => ( { flaggedStorage, removeFromActive : new Set ( ) , storageChanged : false , flaggedChanged : false , ok : 0 , errors : 0 , disabled : 0 } ) ,
234+ lookupCodexCliTokensByEmail : async ( ) => null ,
235+ extractAccountId : ( ) => undefined ,
236+ shouldUpdateAccountIdFromToken : ( ) => false ,
237+ sanitizeEmail : ( email ) => email ,
238+ extractAccountEmail : ( ) => undefined ,
239+ queuedRefresh : async ( ) => ( { type : "failed" , reason : "invalid_grant" , message : "refresh failed" } ) ,
240+ isRuntimeFlaggableFailure : ( ) => true ,
241+ fetchCodexQuotaSnapshot : async ( ) => { throw new Error ( "should not probe quota in deep mode" ) ; } ,
242+ resolveRequestAccountId : ( ) => undefined ,
243+ formatCodexQuotaLine : ( ) => "quota" ,
244+ clampRuntimeActiveIndices : vi . fn ( ) ,
245+ MODEL_FAMILIES : [ "codex" ] ,
246+ saveAccounts,
247+ invalidateAccountManagerCache : vi . fn ( ) ,
248+ saveFlaggedAccounts,
249+ persistAccountAndFlaggedStorage,
250+ showLine : vi . fn ( ) ,
251+ } ) ;
252+
253+ expect ( persistAccountAndFlaggedStorage ) . toHaveBeenCalledWith (
254+ expect . objectContaining ( {
255+ accounts : [ ] ,
256+ } ) ,
257+ expect . objectContaining ( {
258+ version : 1 ,
259+ accounts : [ expect . objectContaining ( { refreshToken : "refresh-1" } ) ] ,
260+ } ) ,
261+ ) ;
262+ expect ( saveAccounts ) . not . toHaveBeenCalled ( ) ;
263+ expect ( saveFlaggedAccounts ) . not . toHaveBeenCalled ( ) ;
264+ } ) ;
265+
218266 it ( "treats cache lookup failures as a cache miss and still refreshes" , async ( ) => {
219267 const saveAccounts = vi . fn ( async ( ) => { } ) ;
220268 await runRuntimeAccountCheck ( false , {
0 commit comments