generators were already cached across jobs but only implicitly — the first
job per config silently paid the whole model load. adds:
- POST /api/generators/preload: load a model into memory ahead of time
(async, idempotent; state loading/ready/failed)
- GET /api/generators: what's resident or in flight
- POST /api/generators/unload: shutdown + free VRAM (409 while inference
jobs run)
cache key builder shared with the job path and pinned by a test so preload
and job lookup can't drift apart.