Great questions! I actually have a whole lot to say on this but that'd have to be a whole new article.
For greenfield, functional programming is the answer. You don't need to test "changes deeper down the call stack" because there's no such thing as a change. Pass a value, get a value back.
We've written large complex applications with two flavours of code:
Both flavours test-driven, not test-after.
You say that this legacy code is not necessarily bad but missing testability. Assuming this, I say the following:
The cost of fixing is still less than rewriting from scratch. See Joel Spolsky's article about "Things you should never do".
We’re a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.