@@ -1031,6 +1031,32 @@ describe("reload-if-idle waits for the reactor's message run", () => {
10311031 expect ( state . fatalBuildError ) . toBeNull ( ) ;
10321032 } ) ;
10331033
1034+ test ( "an MCP change requested while its approval is live defers rebuild until the resumed run ends" , async ( ) => {
1035+ const { state, services, push, builds } = await lifecycleWithOpenRun ( ) ;
1036+ const mcp = wireLateMcp ( state , services ) ;
1037+ // `runWhileAgentBusy` is the approval surface's occupancy bracket: the
1038+ // operator has a live ask while the parked reactor run remains open.
1039+ await runWhileAgentBusy ( state , async ( ) => {
1040+ mcp . connectLateMCPServer ( {
1041+ name : "linear" ,
1042+ url : "https://l.test/mcp" ,
1043+ } ) ;
1044+ await drainStream ( ) ;
1045+ await services . sessionOps . awaitTail ( ) ;
1046+ expect ( state . pendingReload ) . toBe ( true ) ;
1047+ expect ( builds ( ) ) . toBe ( 1 ) ;
1048+ } ) ;
1049+
1050+ // The resumed MCP tool and its next model turn remain inside run-1, so
1051+ // reload cannot close the agent until the reactor reports this boundary.
1052+ push ( runEnded ( "run-1" ) ) ;
1053+ await drainStream ( ) ;
1054+ await services . sessionOps . awaitTail ( ) ;
1055+ expect ( builds ( ) ) . toBe ( 2 ) ;
1056+ expect ( state . pendingReload ) . toBe ( false ) ;
1057+ expect ( state . fatalBuildError ) . toBeNull ( ) ;
1058+ } ) ;
1059+
10341060 test ( "a run that ends into an immediately following run rebuilds only after the successor ends" , async ( ) => {
10351061 const { state, services, push, builds } = await lifecycleWithOpenRun ( ) ;
10361062 state . pendingReload = true ;
0 commit comments