The special sauce is already present in how the shim and loader/binder work. We could do an upgrade by installing a new set of files side-by-side and automatically rolling 4.x apps forward to this version. The crux of the problem is framework entrypoints: if we can ensure that all of our entrypoints go through some shim that does version/path selection we can easily lay down a new version and make it behave as the old one. We have shims for most entrypoints (COM, CreateProcess, hosting, perfcounters, clickonce, finding the framework directory, etc), but we still have enough apps that use the framework without going through these, and those are the apps that break when we change the path. I am not saying that these apps are the ones that are at fault here, though. We need to do better at providing the right set of APIs / documentation so that folks don't take dependencies on the absolute paths to framework binaries.
The reason why we can't keep old code around is our compat contract around not changing file paths. The old apps would be expecting to get code from the same path as the new ones and we can't have that resolve to the same file. In some cases we can't even move the old file out of the way since it is open without FILE_SHARE_DELETE.