Refactor @concurrency assignment out into methods.
Refactor Runner#stats.
Make everything except Runner#execute private.
No need to sync STDOUT/STDERR; we don't see logs until the end anyway.
No need for #execute_sequential: one worker in "parallel" is fine.
Merge #execute_parallel into #execute.
Extract worker cleanup into #stop_workers.
Push summary logic in #execute down into #print_summary.
Extract stat dump in #execute into #dump_stats.
Extract exit status calculation into #exit_status.

Also rename the worker's status to worker_status to avoid confusion.
Exit with the maximum worker status instead of their sum.

Summing meant the status would change depending on the number of workers that had failing specs, which is misleading. Using the max means the status will be:

  * 2 if any worker failed;
  * otherwise, 1 if any spec failed;
  * otherwise, 0.
Comment grammar.
Rename EXIT_FAILED to EXIT_ERROR: 'failed' is for spec failure.
Add constants for all the exit codes we use.
Extract worker invocation from #spawn_workers to #invoke_worker.
Use our exit codes in the rspec runner.
Push the responsibility for exiting successfully into the runner.
Add a .gitignore for bundler-related stuff.
Remove workers from a new @running list as they exit, not @workers.
Calculate the exit status from all workers, not just completed ones.

This means failed workers will always fail the overall test run, as they should.