The clarifying concept that you need to consider is that of the executor. That's the actual execution environment in which async code runs — not the actor, not the task.
Originally, there were only 2 executors: the MainActor executor (which runs things sequentially on the main dispatch queue), and the concurrent global executor (which runs things concurrently on non-sequential dispatch queues). Last year, a third executor was added — the non-actor executor — to run async code that is not isolated to an actor, and this year you can create additional custom executors as necessary.
This is not documented very extensively in API docs, because there isn't (or at least wasn't, before we got custom executors) explicit API relating to executors. They were something of an implementation detail — although a good understanding of how concurrency works has always required some knowledge of executors.
There is a fairly detailed explanation of how "modern" executors fit into the picture in SE-0338.
In regard to your specific question, most of the code in your fragment runs on the MainActor executor because async functions "stick" to the current executor unless there's a formal reason why they can't.
Tasks you add to a task group are formally required to run on the concurrent global executor. The documentation (TaskGroup | Apple Developer Documentation, see "Task execution order") says this without using the word "executor".
The other common example of a formal executor requirement is Task.detached, which is defined to run on the global concurrent executor, unlike Task.init.
Note that I haven't used the word "thread" in any of the above. That's because concurrency (on Apple platforms) runs on top of GCD, where code executes on dispatch queues, not on threads. Of course, code submitted to a dispatch queue eventually executes on some thread or other, but there's no simple mental model for that. In particular, it's surprising but possible that code submitted to the main queue doesn't have to run on the main thread, if GCD realizes it can safely avoid a thread switch.
In general, reasoning about threads, or even about how GCD relates to executors, isn't useful when reasoning about Swift concurrency.