3.9 KiB
OpenSpec Change: enterprise-video-thumbnails
- Change ID:
enterprise-video-thumbnails - Package:
@suaveplan/video-thumbnails - Category:
media/ Plugin:video - Target path:
packages/media/video/video-thumbnails - Status: PROPOSED
- Date: 2026-05-25
- Design: ./design.md
- Spec delta: ./specs/video-thumbnails/spec.md
- Upstream:
../suaveplan/packages/universal/video-thumbnails - Enterprise audit:
../suaveplan/enterprise/video-thumbnails.md
Summary
Migrate @suaveplan/video-thumbnails from main into the genesis monorepo at enterprise quality. The package generates video thumbnails (single-frame extraction at arbitrary timestamps, batched time-based extracts, sliding-window sampling) and sprite sheets (NxM grid via ffmpeg tile filter) over JPEG/PNG/WebP outputs, on top of an injectable FfmpegRunner and the bundled @ffmpeg-installer/ffmpeg binary surfaced through fluent-ffmpeg. The migration adds OTel histograms/counters, structured VideoThumbnailsError (extends SuaveplanError) codes via defineCodes, Zod-validated option boundaries, AbortSignal propagation, a sliding-window extractor that upstream lacked, and 100/100/100/100 coverage using real fixture videos generated on-the-fly with ffmpeg (no mocks).
Parity Checklist
| Capability | Upstream | Migrated | Notes |
|---|---|---|---|
Single-frame extract ThumbnailGenerator.generate |
✅ | ✅ | Same timestamp, fit, outputDir, format, quality semantics. |
Multi-timestamp extract generateMultiple |
✅ | ✅ | AbortSignal-aware. |
getMetadata via ffprobe |
✅ | ✅ | Through FfmpegRunner.probe. |
isAvailable() |
✅ | ✅ | Through runner.isAvailable(). |
Sprite-sheet SpriteSheetGenerator.generate |
✅ | ✅ | Same N×M tile algorithm; auto-detect duration. |
CommandExecutor injection |
✅ | ⬆️ | Replaced with the stronger FfmpegRunner interface (typed extract, tile, probe, isAvailable); default = FluentFfmpegRunner. |
Error codes THUMBNAIL_* |
✅ | ⬆️ | Re-issued under VIDEO_THUMBNAILS.* namespace via defineCodes. Added: RUNNER_UNAVAILABLE, INVALID_TIMESTAMP, INVALID_OPTIONS, ABORTED. |
| Sliding-window extraction | 🚫 | ⬆️ | New extractSlidingWindow(count, durationSeconds) evenly samples N frames. |
| OTel counters + histograms | 🚫 | ⬆️ | video_thumbnails.extract.duration_ms, extract.total{outcome,format}, sprite_sheet.duration_ms, sprite_sheet.frames. |
| Zod option validation | 🚫 | ⬆️ | All public surfaces validate at the boundary. |
AbortSignal propagation |
🚫 | ⬆️ | Threaded through FfmpegRunner (kills the child process). |
| Output jpeg / png / webp | partial | ✅ | All three exercised against real ffmpeg + fixtures. |
| 100/100/100/100 coverage | 🚫 | ✅ | Vitest istanbul, no mocks, real fixtures. |
Current-state audit (genesis)
Package does not exist on genesis. Status: – in STATUS.md. Direct upstream consumers in genesis: none. The video plugin is added to the media super-category in scripts/folder-reorg/assignment.yml as part of this change (the closed-vocabulary supercategory list is unchanged).
Dependencies
- Workspace:
@suaveplan/error - External (via catalog
audio):fluent-ffmpeg,@ffmpeg-installer/ffmpeg,@types/fluent-ffmpeg - External (other catalogs):
tslib(build),zod(forms),@opentelemetry/api(observability) - Dev:
@suaveplan/testing(workspace:^),vitest+@vitest/coverage-istanbul(testing)
Impact
- Adds package
packages/media/video/video-thumbnails. - Adds spec capability
video-thumbnails. - Adds
videoplugin to themediasuper-category inscripts/folder-reorg/assignment.yml.
Affected dependents
None — fresh genesis migration, no existing consumers.