Two bugs in PrintScheduler._check_previous_success:
- Lookback excluded 'cancelled' so user cancellations were walked past
- Lookback included 'skipped', so one skip cascaded indefinitely
Swap to ['completed', 'failed', 'cancelled', 'aborted'] and accept
both 'completed' and 'cancelled' as predecessor success. Real
'failed' / 'aborted' still gate.
One-shot migration in run_migrations resets only the skipped items
whose true predecessor was cancelled — surgical reversal of the exact
bug fingerprint, leaves genuine failure-gated skips alone. Portable
across SQLite and Postgres, idempotent on re-run.