anchor.diff:  
   -spec handle_info(term(), state()) -> gs_noreply() | gs_stop(tuple()).
   handle_info({'EXIT', Pid, Reason}, #state{input_pid = Pid} = S) ->
  +    % Note: this callback clause will never get called useless, due to
  +    % the trap_exit issue mentioned above.  We leave it in here for
  +    % clarity, and in case this issue is fixed.
  +    lager:warning("stopping due to input_pid (~p) failure: ~p (self ~p)",
  +                  [Pid, Reason, self()]),
       {stop, {"input_processor exited", Reason}, S#state{input_pid = none}};
  -handle_info(_M, S) ->
  +handle_info(M, S) ->
  +    lager:warning("Ignoring unexpected info event: ~p (self ~p)", [M, self()]),
       {noreply, S}.
   
   -spec terminate(term(), state()) -> ok.
   terminate(normal, _S) ->
  -    lager:warning("job_coord terminating normally!"),
       ok;
   terminate(Reason, #state{jobinfo = #jobinfo{jobname = JobName}}) ->
       lager:warning("job coordinator for ~s dies: ~p", [JobName, Reason]).
  
positive.code: 
  -spec init({pid(), binary()}) -> gs_init() | {stop, term()}.
  init({Starter, JobPack}) ->
      try  {JobInfo, Hosts} = setup_job(JobPack, self()),
           Starter ! {job_started, JobInfo#jobinfo.jobname},
           {ok, init_state(JobInfo, Hosts)}
  
negative.code:                          gs_noreply();
                   (pipeline_done, state()) -> gs_noreply();
                   ({kill_job, term()}, state()) -> gs_noreply().
  handle_cast({start, Inputs}, S) ->
      {noreply, do_start(Inputs, S)};
  handle_cast({update_nodes, Hosts}, S) ->
      {noreply, do_update_nodes(Hosts, S)};
  handle_cast({inputs, {error, E}}, S) ->
      % TODO: log an appropriate job event.
      {stop, {"fetching inputs failed", E}, S#state{input_pid = none}};
  handle_cast({inputs, {ok, Inputs}}, S) ->
      {noreply, do_use_inputs(Inputs, S)};
  handle_cast({stage_done, Stage}, S) ->
      {noreply, do_stage_done(Stage, S)};
  