A batch is a scheduling policy
The companion accepts one owned batch and creates a bounded number of C++20 jthreads, available in this C++23 baseline. Compared with a raw std::thread that requires every path to arrange join or detach, jthread attaches cooperative stop and join to its scoped owner. Workers claim indices under a mutex and compute outside that lock. A lock_guard releases its mutex on every ordinary scope exit, including exception unwinding; a unique_lock is used for waits because the wait must unlock and reacquire it. Results have fixed submission-order slots, so completion order does not grow an unbounded result queue.
This is not a general streaming executor. Its run_batch call waits until all workers join, and it does not claim UI responsiveness or asynchronous I/O. Internal parallel work and a nonblocking public interface are different decisions.
Next compare run_batch with AssetPipeline: the latter keeps a bounded set of workers alive, admits image descriptors, and exposes try_take for a caller that must continue handling events. Its short mutex acquisitions can contend, so it is not a lock-free algorithm. The following checkpoints give submission, retained results, shutdown, and publication concrete implementations.
Trace two workers claiming four jobs. Mark which state needs the mutex and which data each worker owns or reads independently.
