anchor.diff:  % New state:
   % Actor PID (as before)
   % Actor type name (as before)
  -% Protocol |-> Conversation ID mapping (as we can be involved in mult protocols)
  +% Protocol <-|-> Conversation ID mapping (as we can be involved in mult protocols)
   % Protocol |-> Role mapping (where Role is the role we can play in a protocol)
   % Monitors (Protocol |-> Monitor Instance)
   % Active protocol
  
positive.code:   case AddRoleResult of
      {ok, NewStateData} ->
        error_logger:info_msg("INFO: Actor ~w with PID ~p registered for role
                               ~w.", [NewStateData#conv_state.actor_type_name,
                                      NewStateData#conv_state.actor_pid,
                                      RoleName]),
        {reply, ok, setup, NewStateData};
      {error, Err} ->
        error_logger:warning_msg("WARN: Actor ~w could not fulfil role ~w: ~p",
                                 [StateData#conv_state.actor_type_name,
                                  RoleName,
                                  Err]),
        {reply, {error, Err}, CurrentState, StateData}
    end.
  
  handle_terminate_conversation(ConversationID, CurrentState, StateData) ->
    ActorName = StateData#conv_state.actor_type_name,
    ActorPID = StateData#conv_state.actor_pid,
    CurrentCID = StateData#conv_state.conversation_id,
    if ConversationID == CurrentCID ->
         error_logger:info_msg("INFO: Actor ~w with PID ~p exiting conversation ~p.~n",
                               [ActorName, ActorPID, ConversationID]),
         {next_state, idle, freshen_state(StateData)};
       ConversationID =/= CurrentCID ->
         error_logger:warning_msg("WARN: Terminate conversation (ID ~p) called for monitor in " ++
                                  " different conversation (ID ~p) in actor type ~w with PID ~p.~n",
                                 [ConversationID, CurrentCID, ActorName, ActorPID]),
         {next_state, CurrentState, StateData}
    end.
  
  % Idle / setup have identical (boring) behaviours for async messages,
  % as most setup messages are synchronous.
  handle_setup_async(Inv = {invitation, _, _}, CurrentState, StateData) ->
    error_logger:error_msg("ERROR: Monitor got asynchronous invitation message ~p~n", [Inv]),
    {stop, error_invitation_async, StateData};
  handle_setup_async({terminate_conversation, ConvID}, CurrentState, StateData) ->
    handle_terminate_conversation(ConvID, CurrentState, StateData);
  handle_setup_async(Msg = {message, _MsgData}, CurrentState, StateData) ->
    error_logger:warning_msg("WARN: Got message (~p) in idle state: ignoring.~n ", [Msg, StateData]),
    {next_state, CurrentState, StateData};
  handle_setup_async(Other, CurrentState, StateData) ->
    error_logger:warning_msg("WARN: Got unhandled asynchronous message (~p) in ~p state: ignoring.",
                             [Other, CurrentState]),
    {next_state, CurrentState, StateData}.
  
  
  % Here, we deliver the message to the attached actor (which is a gen_server).
  
negative.code: %  | {next_state,NextStateName,NewStateData,Timeout}
  %  | {next_state,NextStateName,NewStateData,hibernate}
  
  handle_invitation(ProtocolName, RoleName, ConversationID, StateData) ->
    AddRoleResult = add_role(ProtocolName, RoleName, ConversationID, StateData),
    % Try and add the role.
    % If we succeed, add the role to the conversation_roles list, set the
    % conversation ID, and transition to setup.
  