code: func addPhaseRunner(e *Runner, parentRunner *phaseRunner, phase Phase) {
  	// computes contextual information derived by the workflow managed by the Runner.
  	use := cleanName(phase.Name)
  	generatedName := use
  	selfPath := []string{generatedName}
  
  	if parentRunner != nil {
  		generatedName = strings.Join([]string{parentRunner.generatedName, generatedName}, phaseSeparator)
  		use = fmt.Sprintf("%s%s", phaseSeparator, use)
  		selfPath = append(parentRunner.selfPath, selfPath...)
  	}
  
  	// creates the phaseRunner
  	currentRunner := &phaseRunner{
  		Phase:         phase,
  		parent:        parentRunner,
  		level:         len(selfPath) - 1,
  		selfPath:      selfPath,
  		generatedName: generatedName,
  		use:           use,
  	}
  
  	// adds to the phaseRunners list
  	e.phaseRunners = append(e.phaseRunners, currentRunner)
  
  	// iterate for the nested, ordered list of phases, thus storing
  	// phases in the expected executing order (child phase are stored immediately after their parent phase).
  	for _, childPhase := range phase.Phases {
  		addPhaseRunner(e, currentRunner, childPhase)
  	}
  }
docs: // addPhaseRunner adds the phaseRunner for a given phase to the phaseRunners list