|Think about Loose Coupling|
Your thoughts about rewrites seem unorthodox to me. Let me clarify what I think of new projects, rewrites, and refactoring.
Subversion, git, and Mercurial are not rewrites of CVS. They are new projects with similar goals. If they had the exact same feature sets they'd be called clones. There's no rewriting at all. There's just a fresh writing.
A total rewrite is when you start writing the same project over from scratch. You throw your existing code base in the bin and plan to eventually ship a new version that started from different empty files. It probably won't pass the same external tests, and unit tests likely won't resemble the old ones. It likely uses an improved framework or a completely different one based on different concepts.
A partial rewrite is when you rewrite some portion -- a module, a source file, a few functions -- over from scratch. Most of the external tests will still work so long as you don't change too many features at the same time. Unit tests for the rewritten portions will likely need to change unless you carefully stick to the same API and internal interfaces as before.
Refactoring is when you clean up existing code and don't remove any code until you've got the replacement ready so it passes the same unit tests. You don't violate separation of concerns at all while refactoring. You just clean up what's there between change orders. The APIs between modules don't change. The internal interfaces stay the same except among very closely related functions or methods, and you end up with basically the same program. All external tests of the program pass without change. Most unit tests don't change, and the very few that do are just minor tweaks. The implementation is just clearer and maybe the execution path is shorter for the most common cases. Bugs probably don't even get fixed, although they are likely to be easier to notice by reasoning about the code. You're just cleaning the code, and you can generate a new ticket for the newly found bugs.
A change order is executed from any feature requests or bug tickets. This is when functionality changes without a rewrite. Let's talk about bugs first. Generally just enough lines are changed to fix behavior for a bug, and the code around it is only cleaned up at this point if necessary to make the bug fix manageable. The test changes for the bug are to test the fixed behavior and to test for the buggy behavior as well to see if it returns. This often means boundary checking or a little fuzzing.
The feature request might be to add, change, or remove a feature. The amount of code change can vary. The only tests that should need to change are those relating to the feature itself in the external tests. The unit tests should change for any new or removed APIs and internal interfaces adjusted for the feature.
What I like to do with a project is to take all the bug-fix change orders and implement them. Then I validate against my tests. Then I refactor the whole program. Then I take the feature requests and apply those. Then I refactor the whole program again. Then, if necessary, I optimize. Then, if I can refactor the optimized code without killing the performance, I refactor again. Then the process starts over with new change orders. Does it always happen this way? Of course not. I'd like that, though.
If I took the project over from another team, I'd try to refactor it all up front before making any changes in functionality. Then I'd start with the above process.
This seems quite a bit different from the terminology you're using. I understand not throwing away an important code base. Saying that's what someone writing a new alternative to an unrelated project is doing doesn't seem quite accurate to me, though. Git and subversion are based on different ideas for accomplishing different but similar tasks compared to CVS for example. People wanting to rewrite CVS would be trying to end up with something that is CVS but with none of the original code. The other change tracking systems were written with something better than CVS in mind and didn't have any code already bugfixed and tested for their something better.