Is this a good way of managing parallel go routines when I care about ordering of results?
The answer to "Can I be sure...?" is no, there is nothing in your code that ensures that.  That is why results sometimes go missing.

Missing results are a sign of a data race.  You can use the Go race detector to find and fix these problems.  Data races are categorically dangerous.  They can corrupt memory.

You might be able to find and fix the problem by adding more synchronization, but your code is too complex as it is.  Since you asked, a pattern you should probably be using is a particular producer-consumer pattern.  It has two parts, 1) a producer goroutine that sends data to a channel and closes the channel after sending the last value, and 2) a consumer goroutine with a for loop that ranges over the channel.  With this pattern you should be able to dispense with the select statement, the stage complete channel, and the control routine wait group.

Your code that begins for i, some_data := range my_data is what I'm calling a producer.  It produces data on the channel stage_one_channel.  Following wg.Wait(), you should replace the line stage_complete &lt;- true with close(stage_one_channel).

Replace your for loop containing the select statement with a separate for loop for each stage, something like

for new_stage_one_results := range stage_one_channel {
    ...
}


When this for loop completes, you are sure that all data has been received from stage_one_channel and processed by the loop body.  This is the synchronization your code is missing.  Your current mechanism only waits for data to be sent, not received and processed.

When the last loop completes, your program can exit.  You could retain some of your mechanism for waiting for this, but simpler would be swap what you currently have in your main goroutine for the "consumer" code that you currently have in that first function literal.  That is, run your producers in one or more separate goroutines so you can have your consumers--the last one especially--in main.  When the last consumer has processed the last data, you know your program is done, with nothing else to wait for.

Finally, let me reinforce, if go run -race says you have a problem, you have a problem.