Description

Identify every video_asset hosted only on Vimeo (no youtube platform id) and produce a migration manifest — asset id, vimeo id, title, interview slug, current transcript/caption status. This is the discovery gate for the Vimeo→YouTube re-upload; nothing migrates until this set is known and reviewed.

Acceptance Criteria

Implementation Plan

Discovery gate: inventory Vimeo-only assets → migration manifest

Sole hosting source (verified)

Detection rule (Vimeo-only)

An asset is in the migration set iff its platforms[] contains a platform == "vimeo" entry AND contains NO platform == "youtube" entry (compare on presence of asset_id). Ruby detection (read-only):

pids = ->(it,n){ (it["platforms"]||[]).select{|p| p["platform"]==n}.map{|p| p["asset_id"]} }
vimeo_only = items.select{|it| !pids.(it,"vimeo").empty? && pids.(it,"youtube").empty? }

Result computed during planning: 27 Vimeo-only assets (none has >1 vimeo id).

Transcript / caption status

Manifest format (review surface for sign-off)

Generate _data/vimeo_migration_manifest.yml from a small read-only bin/ script (build/inspection input, not a hand-edited data file). Per-entry shape:

generated_at: <iso8601>
source: _data/video_assets.yml
total_vimeo_only: 27
items:
  - asset_id: dave-thomas-software-craftsmanship-north-america-2013
    vimeo_id: '90550222'
    vimeo_url: https://vimeo.com/90550222
    title: '...'
    interview_slug: dave-thomas-...-2013   # null for standalone
    primary_platform: vimeo
    duration_seconds: 861                  # from vimeo platform entry (integrity ref for TASK-246)
    thumbnail_local: /assets/vimeo/thumbs/ugtastic/90550222.jpg
    transcript_id: dave-thomas-...-2013     # null if none
    transcript_status: structured           # structured | none
    transcript_turns: 61
    caption_readiness: caption-ready        # caption-ready | needs-transcription
    youtube_id: null                        # populated by TASK-253
    migration_state: pending                # pending|downloaded|uploaded|unlisted|public|retired

Acceptance mapping

Boundary

Structure/data only — no content edits to titles/descriptions. Manifest is generated, reviewed, then TASK-246 consumes it.

Comments

author: claude created: 2026-07-04 14:48 — Executed initial inventory: generated _data/vimeo_migration_manifest.yml — 27 Vimeo-only assets (platforms has a vimeo entry, no youtube entry), 19 caption-ready (structured transcript with turns), 8 need transcription. Each entry carries asset_id, vimeo_id/url, title, interview_slug, primary_platform, duration_seconds, thumbnail, transcript_status+turns, caption_readiness, youtube_id (null, filled by TASK-253), migration_state (pending). Count matches the independent track-agent survey. NOT committed — awaiting review. AC#3 (commit as review surface) pending the user’s commit. Generator should be promoted to bin/ with merge-preserve on migration_state before TASK-253 starts flipping states. —

author: claude created: 2026-07-04 14:53 — Manifest committed to master as 62de73b (not pushed) — AC#3 (review surface committed) satisfied. Done. Note: promote the generator to bin/ with merge-preserve on migration_state before TASK-253 begins flipping states. —

Definition of Done