Skip to content

feat: export AutoClip clips into the Library (mp4 storage, preview, download, retry) - #53

Merged
SomeRandmGuyy merged 14 commits into
mainfrom
feat/clips-to-library-tasks-4-10
Sep 18, 2026
Merged

SomeRandmGuyy merged 14 commits into
mainfrom
feat/clips-to-library-tasks-4-10

Conversation

@SomeRandmGuyy

@SomeRandmGuyy SomeRandmGuyy commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Continues #51/#52 (schema, budget guard, streaming storage). This PR is Tasks 4-9 of docs/superpowers/plans/2026-09-16-clips-to-library.md, plus a final-review fix wave.

Summary

  • Task 4: ingestFile/attachThumbnail in library-pipeline.server.ts — disk-streamed ingest and thumbnail-as-version-row, so nothing is buffered in memory.
  • Task 5: clip-export.server.ts — resumable exportClipStep state machine (Crayo export → poll → download → ingest → thumbnail), fully unit-tested against a fake Crayo client, shared by both the background job and the synchronous callers.
  • Task 6: media-fetch-job.server.ts gains an exporting phase — the background AutoClip job now actually exports and stores clips instead of ingesting only thumbnails.
  • Task 7: the synchronous direct-file /autoclip and manual /export paths do the same via exportClipToLibrary.
  • Task 8: GET /api/library/file?download=1 and signLibraryAssetsFn — signed preview/download URLs.
  • Task 9: clip player + Download + Retry in Agent results and the Library, backend label, "Filebase" copy fixed to "Library". Includes a mid-task fix (appendLibraryClips) so the two synchronous paths' results show up in the UI the same way the background job's do.
  • Final-review fix wave: local-disk storage_key was double-joining to a 404 (Critical, now fixed); checksum-duplicate ingests now correctly record external_ref (idempotency); external_ref now has a unique index with conflict-safe insert handling; archiveAsset now cleans up an asset's thumbnail version too.

Verified

  • tsc --noEmit: 0 errors. npm test: 397 total, 396 pass, 0 fail, 1 pre-existing named skip.
  • Settings/Agent/Library all boot with zero console/page errors against a completely fresh local database (confirms the new migration applies cleanly).
  • Every task went through an independent spec+quality review; the branch as a whole went through a final whole-branch review (opus) plus one fix wave and one scoped re-review, per this repo's subagent-driven-development process. Full ledger: .superpowers/sdd/2026-09-16-clips-to-library/progress.md (git-ignored, available in this checkout for anyone continuing the work).

Known, deliberately unfixed

  • Two acknowledged IDOR-shaped findings (signLibraryAssetsFn, retryClipExportFn): both match the identical authorization pattern already used by their own pre-existing sibling functions in the same files (getLibraryAssetFn/listLibraryAssetsFn, getAgentRunFn/cancelAgentRunFn) — verified independently three times across reviews. This is ClippyOS's existing, established design (single shared workspace, any authenticated staff member can act on any asset/run), not something this PR introduces.
  • Sync-path timeout risk (Important Crayo.io Integration #2 from the final review): the direct-file /autoclip path now does real export work inside Vercel's 300s function budget, with no resumability if it times out. Explicitly deferred to live verification (below) rather than fixed speculatively.
  • Two residual findings from the fix wave's own re-review, neither blocking: (a) the old non-unique external_ref index gets recreated by ensureLibrarySchema's DDL on every start, redundant but harmless; (b) under a narrow concurrent-insert race for the same Crayo project id, ingestFile doesn't consume insertAsset's new conflict-recovery value, so that specific race now surfaces as a thrown ASSET_MISSING + an orphaned version row instead of a silent duplicate asset. Real, not exploitable, not data-loss, but should get a small follow-up (have ingestFile catch the conflict the same way its checksum-duplicate branch already does).
  • Several cosmetic/UX minors are listed in the ledger (Crayo's real failure message is discarded in favor of a fixed string; /export has no spend guard unlike the other two paths; the thumbnail shows as a confusing "v0" in the version-history UI; signed URLs can outlive an open results panel; ingestFile doesn't respect the operator's maxUploadMb setting).

Not yet done

No real Crayo export has been run against this code. Local dev's database is in-memory and loses all keys on every restart, so I could not enter a Crayo key myself (and wouldn't — that's the operator's key to enter, not mine to handle). Before merging, please:

  1. Open Settings on the local dev server (or a preview deploy) and connect Crayo.
  2. Run /autoclip on a short (1-3 min) direct mp4 link with 2-3 clips, and watch it end to end: does it fit inside the 300s function budget on the synchronous path? does the clip actually land in the Library, playable, downloadable?
  3. If the sync path is close to or over the timeout, cap its clip count or fall back to the background job path even for direct files — that's the one thing this PR left for a live run to decide rather than guessing at.

SomeRandmGuyy and others added 14 commits September 16, 2026 21:45
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The new Agent-results UI reads outputs.libraryClips at the top level, but only
the background media-fetch job set it there directly. The synchronous
crayo.run_autoclip (direct-file) and crayo.export_project steps left their
libraryClips nested at outputs[step.id] instead, so those two paths showed
nothing in the new clip preview/Download/Retry block. Lift and accumulate
libraryClips from every step's result onto outputs.libraryClips, additive to
the existing per-step outputs[step.id] copy.
…mbnail cleanup

Final-review fix wave for clips-to-library (Tasks 4-10):
- ingestFile/attachThumbnail now persist the plain relative key as storage_key
  instead of writeLibraryFile/writeLibraryBytes's return value, which is an
  absolute path on the local-disk backend and doubles onto ROOT on read/delete.
- ingestFile's checksum-duplicate branch now backfills external_ref onto the
  pre-existing asset so a retried Crayo export is found by
  findAssetByExternalRef instead of spending another credit.
- media_assets.external_ref gets a unique partial index (new migration 0033 +
  matching ensureLibrarySchema DDL), and insertAsset treats a unique-violation
  on external_ref as "already exists" (via a new isUniqueViolation helper in
  mappers.ts) instead of a hard failure, closing the check-then-act race.
- archiveAsset now also deletes the thumbnail version's bytes and clears
  thumbnail_version_id, so archived assets stop leaking storage and no longer
  get a signed thumbnailUrl for a video that's gone.
@vercel

vercel Bot commented Sep 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
clippyos Ready Ready Preview Sep 16, 2026 11:19pm UTC

Request Review

@vercel

vercel Bot commented Sep 16, 2026

Copy link
Copy Markdown

Deployment failed for project clippyos with the following error:

Hobby accounts are limited to daily cron jobs. This cron expression (*/15 * * * *) would run more than once per day. Upgrade to the Pro plan to unlock all Cron Jobs features on Vercel.

Learn More: https://vercel.link/3Fpeeb1

@SomeRandmGuyy

Copy link
Copy Markdown
Contributor Author

@claude can you fix

@SomeRandmGuyy
SomeRandmGuyy merged commit 60a01b6 into main Sep 18, 2026
1 of 6 checks passed

This branch was successfully deployed

1 active deployment
Preview – clippyos — bce06942 Deployed Sep 16, 2026 by vercel[bot]
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