Chris,
You are correct that the scheduler will preempt a job as soon as the constraints say so, with no regard to the remaining time in the capture. You are also correct that the scheduler does not start jobs a little early to take slewing/focusing/alignment/guiding-startup times into account.
From my perspective, these are risk-reward tradeoff, where in this case we minimized risk and made the (complicated) scheduler a little bit less complex, and reduced the chances of introducing a bugs to save some capture time. Currently the scheduler currently has no notion of remaining time in the current capture (though, of course, it could be coded in). I'm not minimizing your concern, I know capture time is valuable, but in this case we decided to keep it simpler. Looking back, in this case I'm happy with the decision to keep this one simpler.
If you want to check out the logic, you can trace it starting from here:
invent.kde.org/education/kstars/-/blob/m.../scheduler.cpp#L3894 If checkJob() returns false, the job will be preempted.
Hy
PS It is also true that there are parts of the system that do wait until capture ends before preempting--the meridian flip logic waits until the capture ends before starting the flip process.