So, as best I can determine:
1. WorkflowRun.Owner#getOrNull() is pretty much incompatible with lazy loading of the FlowExecution-- either we violate its premise of not blocking (in which case, why bother with it) or we accept bogus nulls when lazy load hasn't happened. We may consider switching consumers of that API to blocking calls maybe (it is only used a tiny number of places).
2. The WorkflowRun.executionPromise field can be null freely since it is only initialized on first run... we could solve this with a lazy-initialization on the getter, but that really mandates synchronization and I cannot determine which of 3 objects we should be synchronizing on (the run, the copyLogsGuard, or LOADING_RUNS). NPEs that could be thrown within getOrNull when loading the build are, um, swallowed if your log level is >FINE (it only logs them).
3. We could add null checks for the executionPromise in the first few places it's touched, and have getOrNull take advantage of that
4. WorkflowRun#getExecutionPromise is (aside from the Owner.getOrNull) exclusively used in tests to wait until the run begins.