AFAICS the Transfer being complete is a genuine entry point for the pump, as such it has a lot to do with when the pump wakes up. Another way to look at this is that the only way for the Transfer to become completed is to inject some event into it, which means placing the check at that location.

The theoretical / philosophical difference is basically about whether we treat this condition as an input or not. The semantic difference is in response to which events we evaluate `isComplete`. And the performance difference is whether we produce `onTermination` together with the last `onNext` result or afterwards. What about the following:
~~~scala
val running = TransferPhase(NeedsInputAndDemandOrCompletion) { () =>
  if (primaryInputs.inputsDepleted) nextPhase(terminate)
  else {
    emits = transformer.onNext(primaryInputs.dequeueInputElement())
    if (transformer.isComplete) emitAndThen(terminate)
    else emitAndThen(running)
  }
}

// this should live in Transfer.scala
val Always = new TransferState {
  def isReady = true
  def isComplete = false
}

val terminate = TransferPhase(Always) { () =>
  emits = transformer.onTermination(errorEvent)
  emitAndThen(completedPhase)
}