wipe_schedules rows existed but nothing read or fired them — an operator could
set a wipe schedule and it would never trigger (the headline auto-wipe feature
was inert; the manual trigger worked, the scheduler did not).
- WipesService now implements OnModuleInit/OnModuleDestroy with a 60s executor
(mirrors SchedulesService): bootstraps next_scheduled_run, then fires every
active schedule whose next_scheduled_run <= now via triggerWipe(...'scheduled')
-> instancesService.wipeForLicense -> the agent wipe handler, advancing
next_scheduled_run from the cron each cycle (advances even on failure so a
broken schedule can't re-fire every 60s).
- triggerWipe parameterized with triggerType ('manual' | 'scheduled') so
wipe_history records the real origin.
- Extracted nextCronDate into src/common/cron.util.ts (shared by the event and
wipe schedulers; was duplicated/private). Cron is evaluated UTC — the per-
schedule timezone column is still not honored, a known limitation shared by
both schedulers (follow-up: tz-aware cron lib).
Backend tsc green. Scheduling logic is at parity with the in-production event
scheduler; live end-to-end (a scheduled wipe deleting real files) verifies when
a game stack + agent are connected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>