I mostly agree in practice, but I'd walk both ideas back slightly: Things which should always be the same should have a common name, and things which might differ should have separate names. Doing so gives you a strong foundation where developers making local changes are unlikely to break the global program (related ideas include preferring total functions (reasonable outputs for all inputs allowed by the type system) when possible, constraining type signatures to make that viable if it otherwise isn't, and giving names to things which are harder to misuse when that isn't practical (like `index_of_assume_sorted` instead of `index_of`)).
Connecting that idea back to the discussion:
1. IME, usually when code looks similar there exists a nice abstraction (a nice "name" future people will understand) for the similar bits. Allowing duplication to grow when you could have properly named things will eventually slow down development.
2. Functions with many parameters are rarely that kind of nice abstraction. The commonality is something much more contained, and functions with large parameter counts should usually be relegated to "entrypoints" or other locations where you're actually merging a thousand different concerns.
3. Bad abstractions are much more expensive than duplication. I have zero problems with committing duplicated code when there aren't any obvious solutions and letting a better plan materialize later.