I think of two more explanations regarding my question.
Explanation 1 (based on my understanding of how RBI works):
The difference is due to the way how RBI works. IIUC RBI analysis of a funciton is performed based on its parameter types, body, and signatures of callees. In OP's code b() looks like a plain old function if judged from its signature. If compiler allows b() to compile, it would be impossible for RBI to catch data race issue in caller's code (see @bbrk24's code for example). In my code b()'s signature indicates it's an async function executed on global executors, so RBI has enough information to make the decision in its caller code.
Explanation 2 (based on the rules in SE-0414 and SE-0430):
According to SE-0414 a non-sendable closure's region is the merge of its non-sendable captured parameters. In OP's code, class A's instance's region might be actor-isolated (i.e. when the instance is an actor's property) or disconnected (i.e. when the instance is a local variable), and so is the task closure capturing it. On the other hand, according to SE-0430 a sending function parameter requires that the argument value be in a disconnected region. The mismatch causes the compile failure.
There is no closure in my code, so it compiles.
I prefer explanation 2 over 1 because 1 requires knowledge of implementation details but 2 is based on documented rules. I also prefer explaiantion 2 over @CrystDragon's because Swift concurrency takes a great effort to develop concepts like sendable, sending, etc. and rules about them so IMO it's better to think in these terms.
Just to clarify, I didn't mean I find a data race scenario which compiler fails to catch. I meant my code could easily lead to usage like the following:
func run() async { let obj = A() Task { await obj.b() } await obj.b() }
Or let me put it this way, can you think of any valid way to use my code other than the above usage (with the second await obj.b() commented out)? I doubt it. That's why I think, while my code is valid, it isn't very useful or a good pattern.