Files
suaveplan/openspec/archive/2026-05-25-enterprise-video-thumbnails/proposal.md
2026-05-27 23:29:53 +01:00

3.9 KiB
Raw Blame History

OpenSpec Change: enterprise-video-thumbnails

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 video plugin to the media super-category in scripts/folder-reorg/assignment.yml.

Affected dependents

None — fresh genesis migration, no existing consumers.