Suppose a server receives a burst of 100 requests, each carrying one job. Give it four workers and a channel with room for eight jobs. Assume no job finishes while the burst arrives. Four jobs can be running and eight can be queued. If every request has already launched a goroutine that sends its job, the other 88 goroutines can be waiting to send. The queue has a bound. That waiting population needs a separate one.
A buffered channel limits the values stored inside it. It does not decide how many goroutines reach a blocking send. Moving the send into a new goroutine only moves the wait. An unbuffered channel makes sender and receiver synchronize at the exchange, but it still does not cap the number of senders that arrive.
For this design, I would name the admission owner as the request entry point. It must obtain a place before launching additional work, or return a saturation result when no place is available. If admission waits instead, that wait also needs a population limit and a deadline. Otherwise the queue has merely moved upstream.
I would name the request handler as the owner of signaling cancellation when the caller leaves, and the workers as owners of checking that signal before starting queued work and at useful stopping points. A cancellation signal alone does not tell us when a place is released. The admission owner needs a rule that counts a job until it actually stops occupying the resource being limited.
For a batch already limited to twelve small jobs, launching twelve goroutines directly can be reasonable. A worker pool then adds coordination without necessarily improving the bound. Which component owns the limit when requests keep arriving?