> This doesn't speak to what I consider some of the most dangerous parts of OOP, which include the assumptions that tightly binding data and code is helpful,[...]
I don't agree at all. It's much more dangerous to separate data representation from the code that manipulates the data. I can't tell you how many bugs I've found and had to fix in large codebases (most of which are procedural-code-in-"OOP"-languages) that result from some horrific evolving arrays-and-records structure not recording intent and validity constraints properly (since that would require, you know, code). Instead, each interaction with the Holy Data Structure requires the code to go to confession, recite ten Hail Marys and five Our Fathers before receiving the Almighty's state-changing grace, mercy and peace; failure to do so will result in immediate confinement in purgatory, and possibly damnation.
I'm not being hyperbolic albeit a bit facetious about this. "Data" itself is the problem: it is subjective, and so requires a lot of tinkering for a programmer to grok. That tinkering transforms it into information, but only in the programmer's head, which is less than ideal since it's outside of the program. If that information fades away, it must again be rebuilt (or worse, be short circuited so a hotfix can go out to prod).
> and that statefulness is fine to freely sprinkle throughout your program.
I agree much more with this, with the condition that shared statefulness sprinkled throughout is the problem. An object should be treated with the same respect we would show a VM or even a person: decent ones would not tolerate having an external entity reach in and manipulate things like memory, nor would they be so care-free as to depend on and trust literally everything they are told. I think the big problem here is that few or no OO languages are powerful enough to allow for this kind of arrangement to be the norm. But it is a valid criticism and should be taken more seriously by OO language designers.
EDIT: I wanted to add one more thought, which is that when I'm working on a new feature or new codebase, I tend to model the problem first in a procedural style. Then I rewrite it as objects. I've had very little luck trying to do objects first (though I think this is just me), because decomposing the problem space is just hard to do de novo. But once I understand the problem, it's easier to see the constraints and issues.
Also, certain code that doesn't need to worry about things like noisy channels (e.g. Dijkstra's shortest path algorithm) is probably a good candidate for non-OO code. OO is good for the large amount of software that interacts with people across multiple machines and environments, rather than isolated from everything in just a single machine.