tl;dr
The Observation framework does not require isolating your @Observable objects to the main actor. Rather than assuming that the lack of a warning message is a bug, we can be pretty confident that the main thread checker is doing its job and no isolation of the main actor is needed.
A few observations:
Yes, when using ObservableObject, WWDC videos repeatedly advised isolating this to the main actor, to make sure that UI updates happen on the main thread.
You are correct that with @Observable with SwiftUI, the WWDC videos and official documentation lack formal assurances that explicit isolation to the main actor is no longer needed, but experience has confirmed this to be the case. But, they certainly haven’t warned us that we should isolate it to the main actor, like they did with ObservableObject.
While I agree that greater clarity would be appreciated, I do not share your opinion that this means that this means that “it could lead to crashes” nor that it is an unaddressed “pretty major bug”. It feels like a deficiency in the documentation, more than anything else.
To use your turn of phrase, I think this is a “non issue”: With SwiftUI, you do not have to isolate the @Observable to the main actor. (You may want to for other reasons; see point 6, below.)
For what it is worth, while Apple’s documentation is sorely silent on this point, the fact that main actor isolation is not required has been discussed by others (e.g., https://www.sobyte.net/post/2023-08/observation-framework).
As an aside, you said:
I see a lot of posts about this from around the initial release of Async/Await talking about using await MainActor.run {} at the point the state variable is updated.
Yes, there were a lot of those. I think those stemmed from developers who were used to the DispatchQueue.main.async {…} pattern.
But, IMHO, that is code smell. If the property is properly isolated to the main actor, this isn’t needed. In fact, if you see WWDC 2019 Swift concurrency: Update a sample app, they demonstrate the transition from GCD to MainActor.run {…} and finally to just isolate to the correct actor, rendering MainActor.run unnecessary.
Also a bit tangential to the question at hand, but you said:
On some ways similar to the fact that many of the early posts I have seen related to @Observable have examples of an @Observable ViewModel instantiated in the view as an @State variable, but in fact this is not needed as that is addressed behind the scenes for all properties of an @Observable type.
I am not sure if I follow you. If you have an @Observable class, you would generally declare that as a @State property in the View. (Yes, we don’t need @StateObject any more, a view generally would store the view model in a @State property.)
You said:
Also, Thread.current is unavailable in asynchronous contexts, so says the warning. And I have read that in a sense you simply aren't concerned with what thread an async task is on.
The retirement of Thread.current has nothing to do with this current topic. It is not available from Swift concurrency because it could lead one to draw incorrect conclusions. If you really care about the threading model underpinning Swift concurrency, I would suggest watching WWDC 2019 Swift concurrency: Behind the scenes. But just because the Thread API is not available from Swift concurrency, it does not mean that we do not care about making sure we have the right actor isolation. It just means that we should not dwell on threads, per se.
Now, let’s come back to the @Observable object that has some Task updating some observed property. As soon as you change the “Strict concurrency checking” build setting to “Complete” and/or adopt Swift 6, you will quickly realize that the compiler will complain if it is unable to reason about your object’s thread-safety. (And please, avoid the @unchecked Sendable trick to silence really meaningful warnings; only use that if you cannot use actors or value types to ensure thread safety and have, instead, used some legacy synchronization mechanism to manually implement thread-safety.) Using actor-isolation in your @Observable object is the modern and easiest way to achieve thread-safety for mutable types.
This is a long winded way of saying that just because @Observable doesn’t require isolation to the main actor, that you might not choose to do so, anyway. You can isolate your @Observable class to any global actor for reasons of thread-safety, and often the main actor is a fine choice.
So, if you really are afraid that the absence of warnings stems from a bug in the main thread checker and that this might cause problems (a concern I do not share), then just isolate this @Observable object to the main actor and call it a day. You will generally want to isolate it to a global actor, anyway, and the main actor is generally an adequate solution (as long as you never do anything slow and synchronous directly from the main actor). Personally, for an object driving the UI, I would generally isolate it to the main actor for thread-safety reasons, anyway.