Not sure why don't you like go's context model. It works pretty well in our production system.
I can see people would like to pass the context implicitly. But I don't have a strong opinion. Explicitness is not that bad.
Go's context is fine to signal cancellation, but it lacks a way to wait for that cancellation to complete gracefully. And the fact that it is also an arbitrary bag of values is concerning. It worries me that it started "polluting" the stdlib's API without solving those issues first. Dave Cheney wrote a good article about it: https://dave.cheney.net/2017/08/20/context-isnt-for-cancella...
Context is problematic because it infects everything. If a function gains context support, every call to it has to be updated, and if you're going to do it right (and not just use context.Background()), every function calling those functions need to be updated, and so on. And the context has to be passed downwards, too. It's turtles all the way up and down.
There's been talk of adding context to io.Reader and io.Writer, which would of course affect pretty much every single Go codebase. For backwards compatibility/convenience you therefore see a lot of APIs with complementary functions Foo and FooCtx, one which takes a context and one that doesn't. That's awkward, and even less elegant when interfaces are involved.
And the network packages (sockets, etc.), of course, have a parallel, non-complementary mechanism to provide timeouts and cancelation that doesn't use contexts. (The key/value pair context stuff is also unfortunate, in my opinion. It's not typesafe, and results in awkward APIs.)
All of this happened because goroutines, as designed, cannot be forcibly terminated. I don't know what the better solution is. I'm not sure why the runtime cannot provoke a panic at the next context switch, but I bet there's a good technical reason. It's unfortunate.
But it's not unreasonable that a large part of any codebase needs "contexts", and so if everyone wants it, why not make it mandatory? Make it an implicit argument threaded through every function call, a bit like "this" in languages such as C++ and Java. The compiler could optimize it away from those codepaths that are guaranteed not to need it. Go has a lot of built-in generic magic, adding some global helpers to set a scope's context wouldn't be too bad.
The other route is to imitate Erlang's processes, which have their own heap, and so killing a process doesn't leave cruft behind. Given how goroutines are allowed to share memory, that's not likely to happen.
I see. Now I see a strong point of favoring implicitly passing the context - attaching the context to a go routine local variable (no such thing yet), so the aspect of context passing can be decoupled. Of course for some logic we probably still want to do some explicit context stitching, but that won't pollute most of interfaces. Would that address your concern?
Go context is a step in the very right direction, but we have not yet the destination. First there is legacy libraries that do not implement it. Second even system-level support misses pieces. For an example, try to cancel a read from a pile using it.