anchor.diff:  -type filter_pred() :: fun((#xmlel{}) -> boolean()) | none.
   -export_type([filter_pred/0]).
   
  +-export_type([t/0]).
  +
   %% Private
   -export([connection_step/2]).
   
  
positive.code:     Fun.
  
  connect(Props) ->
      Transport = proplists:get_value(transport, Props, tcp),
      Server = proplists:get_value(server, Props, <<"localhost">>),
      Host = proplists:get_value(host, Props, Server),
      NewProps = lists:keystore(host, 1, Props, {host, Host}),
  
negative.code: %%% Helpers
  %%%===================================================================
  
  %% TODO: drop
  get_module_old(tcp) -> escalus_tcp;
  get_module_old(ws) -> escalus_ws;
  get_module_old(bosh) -> escalus_bosh.
  
  %% TODO: drop
  is_deprecated_connection_module(M) when M == tcp; M == ws; M == bosh -> true;
  is_deprecated_connection_module(_) -> false.
  
  -spec get_module(module() | atom()) -> ?MODULE:t().
  get_module(M) when is_atom(M) ->
      case is_deprecated_connection_module(M) of
          true ->
              %% This function is a natural extension point - we could extend Escalus freely
              %% by providing modules that implement escalus_connection behaviour.
              %% However, due to this mapping (predefined atom -> module name)
              %% we limit this flexibility.
              %% TODO: Let's remove this limitation in the future.
              Msg = io_lib:format("~s:get_module/1 called with transport '~s' (use a module name instead)",
                                  [?MODULE, M]),
              escalus_compat:complain(Msg),
              get_module_old(M);
          false ->
              M
      end.
  
  get_connection_steps(UserSpec) ->
      case lists:keyfind(connection_steps, 1, UserSpec) of
  