Skip to content

Add bounded motion-preview clips - #8

Merged
Artsen merged 1 commit into
mainfrom
feat/motion-preview-clips
Jul 28, 2026
Merged

Add bounded motion-preview clips#8
Artsen merged 1 commit into
mainfrom
feat/motion-preview-clips

Conversation

@Artsen

@Artsen Artsen commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

Adds an explicit Still/Motion preview workflow for short, silent, runtime-only review clips. Motion previews use strict contract v1, the full Recipe v1/v2 source timeline, absolute source-frame indexes, verified bounded seek, bounded H.264 output, cancellable processing, and TTL/LRU caching without creating manifest records or library outputs.

Application version is now 0.4.0. Manifest/storage schemas remain v2, Recipe v1/v2 remain supported, and persistent video-job contract remains v2.

Frame semantics and processing

  • Resolves an inclusive start and exclusive end with rational frame conversion and source-boundary clipping.
  • Compiles Recipe v2 once against the complete source timeline; the clip never becomes a local timeline.
  • Passes absolute source-frame indexes to Recipe v1 and Recipe v2 processing.
  • Applies effects at source resolution before bounded downscaling.
  • Uses exact-position seek verification with discard-forward and bounded retry; unreliable alignment fails with a controlled inexact_seek error.
  • Produces H.264/yuv420p/fast-start MP4, no audio, no upscale, even dimensions, at most 960×720 and 30 fps.

Runtime manager

  • Dedicated runtime-only queue, separate from persistent video jobs, manifest state, and legacy task state.
  • Default capacity 3 and concurrency 1.
  • States: queued, preparing, processing, finalizing, verifying, ready, failed, canceled, expired.
  • Cooperative cancellation during seek, frame processing, and FFmpeg finalization.
  • Canonical SHA-256 cache key covers immutable source metadata, canonical recipe, frame window, output profile, contract version, and implementation version.
  • Active deduplication and ready cache hits.
  • Default 900-second TTL, 8-entry LRU, and 512 MiB byte limit.
  • Streaming leases defer eviction safely; startup cleans only the owned runtime directory; shutdown cancels and requests deletion of all ephemeral media.
  • Successful source deletion invalidates related previews.

API and discovery

Adds create, status, cancel, delete, and ranged GET/HEAD media endpoints. Create returns 202 for new/active work and 200 for a ready cache hit; validation/tool/capacity/not-found conditions use 400/503/429/404. Status and media are redacted and no-store.

Adds stable capabilities:

  • motion-preview-clips
  • cancellable-motion-previews
  • ephemeral-preview-cache

/metadata, /ready, /api/capabilities, the static manifest, source responses, and repository consistency checks now describe the motion-preview contract and operational bounds.

UI behavior

  • Still remains the default and the existing still-preview path remains intact.
  • Motion rendering is explicit; timestamp, recipe, seed, source, or window changes mark a ready clip Out of date without automatically starting work.
  • The previous ready clip remains playable while stale, updating, or after a recoverable failure.
  • Effect selection, Advanced disclosure, and responsive workspace navigation do not mark the clip stale or issue preview requests.
  • One revision-guarded request/timer pair polls with bounded backoff and ignores obsolete results.
  • Native playback is muted, looping, inline, and controlled; active work has contextual cancellation.
  • Terminal status text, phase-throttled live announcements, keyboard behavior, reduced motion, and responsive containment are covered.

Validation

  • python check.py: 372 passed.
  • Statement coverage: 96.55%; branch coverage: 90.04%; combined coverage: 95.39%.
  • Ruff formatting/lint, strict Mypy, repository consistency, JavaScript syntax, and whitespace checks pass.
  • npm run test:browser: 16 workflows passed.
  • Axe: zero serious or critical findings.
  • Real FFmpeg/FFprobe: 2 motion-preview integrations passed, covering landscape/portrait, 24/60 fps, and audio/no-audio inputs. Both outputs were silent H.264/yuv420p MP4 within dimension/FPS/duration bounds and reusable from cache.
  • Exact pre-resize processing tests confirm one full-source Recipe v2 compile, absolute indexes 2–5, bounded resize, and ordered progress. Existing still/full Recipe equivalence remains green.
  • Fake-capture tests cover exact, early/discard-forward, late/retry, invalid-position, failed, and canceled seek paths with no frame relabeling.
  • Manager/cache tests cover active and ready deduplication, capacity, queued cancellation, terminal conflicts, runtime-only manifest behavior, TTL, count/byte eviction, lease safety, source invalidation, startup cleanup, shutdown, and output-profile rejection.
  • API tests cover 202/200 creation, 400/404/429/503 errors, status/cancel/delete, no-store, media GET/HEAD, closed range, and multiple/unsatisfiable range rejection. Existing shared streaming coverage continues to cover open-ended and suffix ranges.
  • npm run review:ui-screens: 24 deterministic states passed and were manually inspected across 1440×900, 1280×720, 1024×768, 768×1024, 390×844, and 360×800.
  • Browser request-count assertion: one create request and two status polls for queued → processing → ready.

Representative local performance for a no-effect three-second window from a 1280×720 30 fps source:

  • admission: 337.10 µs
  • cache-key build: 23.81 µs average over 10,000
  • ready lookup: 18.80 µs average over 10,000
  • ready cache submission: 112.10 µs
  • first observed processed frame: 0.069 s
  • total processing/finalization/verification: 1.340 s
  • one ready-entry eviction: 218.90 µs
  • serialized ready snapshot: 932 bytes
  • test output: 34,297 bytes

These measurements are diagnostics, not cross-platform guarantees; the configured duration, queue, worker, dimensions, FPS, cache, history, stderr, timer, and lease bounds are the enforced behavior.

Known limitations

  • Motion previews are explicitly generated, capped at five seconds, reduced-resolution, at most 30 fps, silent, ephemeral, and do not survive restart or become library outputs.
  • Full renders remain authoritative.
  • Unusual VFR, damaged, or decoder-hostile inputs may fail strict seek verification.
  • There is no editable timeline, manual-event UI, parameter automation, stateful previous-frame processing, feedback/preroll contract, optical flow, or codec datamoshing.
  • The interface remains Flask/Jinja with dependency-free JavaScript.
  • Preview and persistent rendering use independent bounded coordinators; the persistent full-render default is still one worker.
  • Manifest writes remain single-process.
  • There is no authentication; the service remains loopback-only.

CI

GitHub Actions is green: quality passed in 41 seconds and browser passed in 59 seconds.

@Artsen
Artsen marked this pull request as ready for review July 28, 2026 15:27
@Artsen
Artsen merged commit 8f0dca8 into main Jul 28, 2026
2 checks passed
@Artsen
Artsen deleted the feat/motion-preview-clips branch August 2, 2026 02:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant