fix(media-use): fall back to bundled SFX#2257
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
Reviewed at c288c0bf.
Well-scoped for +325. Bulk of the diff is docs (plan + spec = ~120 LOC) and test infra (~140 LOC); the core code change (bundled provider + remediation state + advisory plumbing) is ~65 LOC.
Design correctness checks all pass:
-
Provider cascade order —
bundledSfxProviderregistered as second in thesfxarray atregistry.mjs:52; heygen tried first, bundled only fires on catalog failure. Sibling testsfx cascade: HeyGen catalog first, bundled library remains the local fallbacklocks this in and matches thevoice cascadeshape (HeyGen TTS + Kokoro) already sanctioned. -
Advisory gating — the four-condition guard at
resolve.mjs:432-442(provider === "bundled.sfx" && !localOnly && !args.provider && heygenRemediation) correctly closes all three false-fire holes:--local-only(user didn't want catalog anyway),--provider bundled.sfx(user explicitly forced local), healthy-catalog-miss (heygen returned empty, no remediation set). Test matrix atresolve.test.mjs:184-227covers each of those negative paths withadvisory === undefinedassertions — good ratchet. -
pendingRemediationstate discipline — module-scoped singleton, consume-once viaconsumeHeygenRemediation()(returns and clears). Onlynot_found/outdatedclassifications ever populate it (heygen-cli.mjs:100). The negative testdoes not record non-install remediationcovers 401 / quota / generic — those legitimate-but-not-actionable failures don't leak into the advisory. Test hygiene callsconsumeHeygenRemediation()at the top of each test to drain residual state. -
Bundled search algorithm — tiered scoring (exact 100 / substring 50 / token-overlap count), deterministic alphabetical tie-break. For the reported
--intent whooshcase,whoosh→whoosh.mp3at score 100 (exact),whoosh-cinematic/whoosh-shortat 50. First result is stable. Score-zero filter (score > 0) correctly excludes non-overlap entries. -
Node version —
import.meta.dirnameis Node 20.11+; CLI package'sengines.node: ">=22"atpackages/cli/package.json:71is safely above. Sibling pattern already used acrossscripts/, so no new precedent.
Nits
-
🟡
ext: ".mp3"hardcoded atbundled-sfx-provider.mjs:41. All 19 bundled files are.mp3today (verified againstaudio/assets/sfx/), so this is correct as-shipped. But if the library ever grows a.wavor.oggvariant, the extension label diverges from the actual file. Trivial to derive:ext: extname(best.entry.file) || ".mp3",
Won't fire today; defensive against future manifest edits.
-
🟡
pendingRemediationis a single process-global slot. Under the current CLI single-shot invocation (one resolve per process), that's fine — one heygen failure records → one bundled win consumes. But if the resolver is ever embedded (in-process batch mode, tests running multiple resolves without spawning) two concurrent resolves could cross-consume each other's state. The consume-once discipline mitigates but doesn't eliminate. Worth a comment on the export declaring the "one resolve per process" assumption, or scoping the remediation state to a passed-in context if that assumption ever weakens. -
🟡 Provider metadata
provenanceshape divergence —heygen.audio.soundsreturns{ track_id, score, query },bundled.sfxreturns{ library_key }. Both are useful for their sources but downstream consumers readingrecord.provenance.*need to accommodate the union. Not a bug, just an interface-shape observation; a shared discriminated union type would surface this in the type system if the codebase ever moves to TS for these scripts. -
🟡 The two docs (
plans/2026-07-13-media-use-sfx-cli-advisory.md+specs/2026-07-13-media-use-sfx-cli-advisory-design.md) match the implementation shape exactly. No drift. If the team's convention is to keep these post-implementation, great; if they're intended as scaffolding to delete after landing, they'll accumulate. Non-blocking either way.
LGTM. Nice discipline — plan + spec + tests + tight code.
Addressed in The provenance observation is intentionally unchanged: provider-specific provenance is already a source-shaped union ( |
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
R2 reviewed at fcc6ecb1, delta from R1 head c288c0bf.
Both R1 nits addressed:
- Manifest-derived extension —
extensionForBundledSfxFile(best.entry.file)atbundled-sfx-provider.mjs:48now derives the ext from the actual filename (extname(filename) || ".mp3"). All 19 bundled entries are currently.mp3so behavior is unchanged today, but a future.wav/.oggaddition tomanifest.jsonno longer requires touching the provider. Test asserts all three shapes (.wav,.ogg, extensionless fallback). - Remediation singleton assumption documented —
pendingRemediationatheygen-cli.mjs:92-94now carries a comment explicitly stating this is fine becauseresolve.mjsis a single-shot CLI, and calling out the migration path (per-resolve context) if resolve ever becomes an in-process/concurrent API.
LGTM from my side.
jrusso1020
left a comment
There was a problem hiding this comment.
Approving on Rames-D's go (R2 delta clean, nit round addressed) + Magi's CI-green confirmation. Verified at final head fcc6ecb1: CI green, no changes-requested, mergeable.
What
Make
media-use resolve --type sfxfall back to the shipped SFX library when the HeyGen CLI/catalog is unavailable. The remote catalog remains the first choice.Why
CLI 0.7.53 documents a bundled 19-file SFX fallback, but the resolver registry exposed only
heygen.audio.sounds. On a machine without the HeyGen CLI, even--intent whooshfailed withno provider could resolvealthoughwhoosh.mp3was installed with the skill.How
audio/assets/sfx/manifest.json.Test plan
bun run test:skills(219 passed)node --test skills/media-use/scripts/lib/registry.test.mjs skills/media-use/scripts/resolve.test.mjsnpx oxfmt --check skills/media-use/scripts/lib/bundled-sfx-provider.mjs skills/media-use/scripts/lib/registry.mjs skills/media-use/scripts/lib/registry.test.mjs skills/media-use/scripts/resolve.test.mjsnpx oxlint skills/media-use/scripts/lib/bundled-sfx-provider.mjs skills/media-use/scripts/lib/registry.mjs skills/media-use/scripts/lib/registry.test.mjs skills/media-use/scripts/resolve.test.mjsbun packages/cli/scripts/gen-skills-manifest.ts --check