Files
sweetman.eth f6e9010f52 feat(music-video): split recoup-music-video out of recoup-internal-marketing (#132)
* feat(music-video): split recoup-music-video out of recoup-internal-marketing

references/music-video.md was 377 lines of hard-won craft living inside the
internal daily-marketing run, gated behind the recoup-internal keyword and
therefore unreachable by customers — while its own routing table sent
customer-facing work to recoup-content-make-video, whose backend has been
cold since April.

Promotes it to a customer-facing skill. recoup-internal-marketing keeps a
routing row and loses the file; nothing else about it changes, and
seedance.md's run log stays where it is.

v1 is generated-song only. The source doc already split on provenance, and
taking that branch drops every rights gate — no master-recording consent, no
label or producer sign-off, no featured-voice gate — because there is no
master. Casting invented characters was already the default, so the likeness
gate goes too. Bringing your own song is v2 and is named as out of scope so
nobody improvises those gates.

Three changes for leaving the internal workspace:

- Scaffolds from scratch. There is no content/letal-xlug/ in a customer
  sandbox. hyperframes is pinned to 0.7.5 for the documented reason.
- Paid steps go through the Recoup API with RECOUP_ACCESS_TOKEN, never a fal
  key in the sandbox, so credits meter and our key stays server-side.
- Composes FOR the free tier's 15 seconds rather than truncating a long film
  to them. A truncated film is the worst possible first impression.

Ends by printing the media URL as JSON on stdout, which is what the chat
renders a player from.

Implements row 10 of recoupable/app#2052

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KcNQAfA3nS7BTrMB3bXsnX

* fix(music-video): match the shipped api#887/docs#328 contract, drop unavailable lip-sync

This skill was drafted before api#887 and docs#328 shipped and drifted
from what actually exists:

- Stills and motion now call POST $RECOUP_API/api/content/image and
  /api/content/video (matching the /api/music pattern already used
  for the song step), not raw fal — the skill's own rule ("never put
  an API key in the sandbox") ruled out the fal.subscribe() snippet
  it still had.
- Dropped the OmniHuman/lip-sync row entirely: /api/content/video is
  pinned to H3 Max only, with no mode or model parameter — lip-sync
  isn't reachable from the sandbox at all right now. Reframed the
  mouth-visible/no-mouth scene-table split around framing choices
  instead of a model choice, and moved lip-sync to "Not yet (v2)".
- Fixed H3 Max pricing to the verified rate: promo is $0.02/s at 768P
  (not $0.04) through 2026-09-07 (not 2026-09-01); standing rate
  $0.08/s was already right. Billing scales the unit count at 768P,
  not a separate per-second rate.
- prompt_expansion_mode: "disabled" isn't a valid value on the real
  schema (balanced | quality, default balanced).
- Vendored the missing skills/recoup-internal-marketing/references/
  hooks.md copy the split PR left out — the skill referenced it but
  never carried it, which failed portability_lint.

All five validation gates pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KcNQAfA3nS7BTrMB3bXsnX

* fix(music-video): resolve merge conflicts with main, drop stale OmniHuman mention

Merged origin/main (#133, #134) into this branch. The real conflict was
skills/recoup-internal-marketing/references/music-video.md — main edited it
while this branch deletes/renames it into recoup-music-video/SKILL.md; git's
three-way merge resolved cleanly since the two edits touched different
sections, and both of #133's craft additions (the muse-image plate-lock test
finding, the expanded content-filter trigger list) landed in the new skill.

Two follow-up fixes the merge itself didn't cover:
- skills/recoup-internal-marketing/SKILL.md:180 referenced the now-deleted
  references/music-video.md by backtick path (portability_lint treats that
  as a live file reference) — reworded to name the new skill instead.
- video-formats.md's routing-table row for music video still said "OmniHuman
  for mouths" — stale since api#887 shipped H3-Max-only, no lip-sync route.

Pre-existing on main, not touched here: recoup-minimax-music-3 (#134) fails
portability_lint/check_resolvable/run_resolver_eval on its own — missing
references/video-pipeline.md and no RESOLVER.md route. Out of scope for
this PR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KcNQAfA3nS7BTrMB3bXsnX

* fix(minimax-music-3): fix the pre-existing CI break from #134

main itself has been red since #134 merged 2026-09-02 — confirmed
against its own CI run (33697344025), not just this branch:

- recoup-minimax-music-3/SKILL.md referenced another skill's file by
  backtick path (`references/video-pipeline.md`, which lives in
  recoup-internal-marketing), which portability_lint correctly reads
  as a same-skill file that must exist in this skill's own directory.
  Reworded as a plain-prose handoff to the other skill, matching the
  house convention used everywhere else in this repo (name the skill,
  don't backtick a path into it).
- The skill had no RESOLVER.md route and no resolver-eval fixture, so
  check_resolvable and run_resolver_eval would have failed it too the
  moment portability_lint stopped blocking the job at step 1.

Out of scope for the music-video split this PR is actually about, but
it was blocking CI on this branch (and on main) regardless of what
this PR touches, so fixed here rather than leaving main red.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KcNQAfA3nS7BTrMB3bXsnX

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 15:46:55 -05:00
..