Why would pipe-> finalize not be called for an observable when the observable completes, but a callback in subscribe would be called?

The key point is that you subscribe to output and not to output.pipe(...).

In other words, output.pipe(finalize(....)) creates a new Observable starting from the output Observable. So the code should look like this

this.sweepRunner.start(parameters).then(output => {
        const newObservable = output.pipe(finalize(() => {
            console.log("Finalize called");
            this.stateController.requestAction(
                this.stateController.patchActionFor<IDetectionLaserMotorState>(StateProperties.detectionMotorState)({
                    LRPosition: this.optimalState.position}))}))


        newObservable.subscribe(null, null, () => {
            console.log("completed?");
        });
    });