The teams that I have worked with still apply the philosophy you’re describing, but they consider PRs to be the “commit”, i.e. the smallest thing that is sane to apoly individually.
Then the commits in the PR are not held to the standard of being acceptable to apply, and they are squashed together when the PR is merged.
This allows for a work flow in which up until the PR is merged the “history of developing the PR” is preserved but once it is merged, the entire PR is applied as one change to the main branch.
This workflow combined with stacked PRs allows developers to think in terms of the “smallest reviewable and applicable change” without needing to ensure that during development their intermediate states are safe to apply to main.
Squashing is fine if you’re just making a mess of temporary commits as you work and you don’t want to keep any of those changes separate in master, but that’s not a useful review workflow. A lot of times I’ve built a feature in a way that decomposed naturally into e.g. two commits: one to do a preparatory refactor (which might have a lot of noisy and repetitive changes, like changing a function signature) and another to actually change the behavior. You want those changes to be separate because it makes the changes easier to review; the reviewer quickly skims the first commit, observes that it’s a mechanical refactor, and the change in behavior has its own, smaller commit without all the noise.
“What if there’s feedback and you need to make changes after the code review?” Then I do the same thing I did before I posted the code review: make separate “fixup” commits and do an interactive rebase to squash them into my commits. (And yes, I do validate that the intermediate commits build cleanly.)
There’s nothing you get from stacked PR’s that you don’t also get from saying “please review my feature branch commit by commit”.
Doesn’t this mean that a first review might request that a specific change be reverted, and then a later reviewer reviews that reversion? That’s essentially reviewing a noop, but understanding the it’s a noop requires carefully checking all previous now-invalidated changes.