Thanks.
Your code doesn't do step 2, and that's why your changes are lost.
But again, even without doing that, the document is regularly saved, so the fact that the very last changes are not saved is, from my point of view, unexpected behaviour.
I came across NSDocument.updateChangeCount(_:) some time ago, but concluded that I shouldn't interfere with automatic saving done by the text view. For instance, when using your latest code, if I type anything in an empty document, then undo all the changes and try to close the now empty document, it presents a save panel. This doesn't happen when I just let the text view track the changes (which is also what I would expect).
The documentation for that method reads:
If you are implementing undo and redo in an app, you should increment the change count every time you create an undo group and decrement the change count when an undo or redo operation is performed.
Note that if you are using the NSDocument default undo/redo features, setting the document’s edited status by updating the change count happens automatically. You only need to invoke this method when you are not using these features.
Since the documentation says that I don't need to call that method when I use the default undo mechanism and, like I explained above, doing so introduces unwanted behaviour, I'm a little wary. I even had this code in my production app for some time many years ago, but then removed it again, possibly because it caused other unwanted side effects or bugs (although I don't remember exactly right now). I think I also tried implementing my own undo mechanism for text views, but quickly figured out that going beyond a basic implementation (registering a new undo group for each typed letter, which is a pain for the user to undo and not what they're used to) would take too much time.
It looks to me like the default undo mechanism would need to be nudged when the user tries to close a document or the app. Would that be something AppKit could do automatically in a future release, and can I nudge it somehow now?