the scheduler reads .sdd/backlog/open/ each tick, filters out tasks whose dependencies are not yet satisfied, applies a fair-priority ordering (critical -> high -> medium -> low, with starvation guards), and emits the next ready task. the router then chooses the model and the cli agent: a contextual bandit with epsilon-greedy exploration over a feature vector (role, complexity, file scope, historical outcomes). bernstein routing explain <task-id> prints the candidate set, the bandit's chosen arm, and the regret estimate. source: src/bernstein/core/tasks/scheduler.py and src/bernstein/core/routing/.
canonical answer