@@ -367,6 +367,47 @@ describe("server-channels auto restart", () => {
367367 expect ( startAccount ) . toHaveBeenCalledTimes ( 2 ) ;
368368 } ) ;
369369
370+ it ( "lets manual stops cancel recovery backoff after recovery stop times out" , async ( ) => {
371+ const releaseFirstTask = createDeferred ( ) ;
372+ const startAccount = vi . fn (
373+ async ( { abortSignal } : { abortSignal : AbortSignal } ) =>
374+ await new Promise < void > ( ( resolve ) => {
375+ abortSignal . addEventListener ( "abort" , ( ) => { } , { once : true } ) ;
376+ void releaseFirstTask . promise . then ( resolve ) ;
377+ } ) ,
378+ ) ;
379+ installTestRegistry (
380+ createTestPlugin ( {
381+ startAccount,
382+ } ) ,
383+ ) ;
384+ const manager = createManager ( ) ;
385+
386+ await manager . startChannels ( ) ;
387+ const recoveryStopTask = manager . stopChannel ( "discord" , DEFAULT_ACCOUNT_ID , {
388+ manual : false ,
389+ } ) ;
390+ await vi . advanceTimersByTimeAsync ( 5_000 ) ;
391+ await recoveryStopTask ;
392+
393+ releaseFirstTask . resolve ( ) ;
394+ await waitForMicrotaskCondition (
395+ ( ) => hoisted . sleepWithAbort . mock . calls . length > 0 ,
396+ "expected recovery restart backoff to be scheduled" ,
397+ ) ;
398+ expect ( hoisted . sleepWithAbort ) . toHaveBeenCalledWith ( 10 , expect . any ( AbortSignal ) ) ;
399+
400+ await manager . stopChannel ( "discord" , DEFAULT_ACCOUNT_ID ) ;
401+ await vi . advanceTimersByTimeAsync ( 10 ) ;
402+ await flushMicrotasks ( ) ;
403+
404+ const account = manager . getRuntimeSnapshot ( ) . channelAccounts . discord ?. [ DEFAULT_ACCOUNT_ID ] ;
405+ expect ( startAccount ) . toHaveBeenCalledTimes ( 1 ) ;
406+ expect ( account ?. running ) . toBe ( false ) ;
407+ expect ( account ?. restartPending ) . toBe ( false ) ;
408+ expect ( manager . isManuallyStopped ( "discord" , DEFAULT_ACCOUNT_ID ) ) . toBe ( true ) ;
409+ } ) ;
410+
370411 it ( "marks enabled/configured when account descriptors omit them" , ( ) => {
371412 installTestRegistry (
372413 createTestPlugin ( {
0 commit comments