Skip to content

fix(media-use): clean up temporary TTS text directories - #5477

Merged
jrusso1020 merged 2 commits into
heygen-com:mainfrom
sunxiuguo:fix/5466-tts-temp-cleanup
Oct 12, 2026
Merged

jrusso1020 merged 2 commits into
heygen-com:mainfrom
sunxiuguo:fix/5466-tts-temp-cleanup

Conversation

@sunxiuguo

Copy link
Copy Markdown
Contributor

What

Clean up the per-call hf-txt-* directory used by the ElevenLabs and Kokoro paths in synthesizeOne. Add isolated regression tests and refresh the media-use skills manifest.

Why

Each synthesized line creates a temporary text directory. The text must remain available until its subprocess finishes, then only that call's directory should be removed, including when writing or synthesis fails.

Related work

Fixes #5466.

#5469 separately changes ElevenLabs Python text decoding to UTF-8. This PR does not include or replace that change.

How

  • Scope allocation, writing and the awaited provider call inside withTmpText, with cleanup in finally.
  • Keep existing synthesis results and original write/spawn errors. Cleanup is best effort: a removal failure must not replace those results or errors.
  • Test success, nonzero exit, missing output/executable, thrown spawn, allocation/write/removal failures, and overlapping calls without touching another call's or a pre-existing directory.
  • No credentials, real provider requests or model downloads are used by the new tests.

Test plan

Validated in an isolated Linux cloud environment against base 43be84d82ce9d576d369dd4db4255924240cca0f plus this exact patch:

  • Failing first on the original base: node --test --test-reporter=tap skills/media-use/audio/scripts/lib/tts.cleanup.test.mjs produced 13 failures and 4 passing controls.
  • HYPERFRAMES_MEDIA_HOME_REQUIRED=1 node --import ./packages/cli/scripts/test-home.mjs --test --test-reporter=tap skills/media-use/audio/scripts/lib/tts*.test.mjs: 40 passed on Node 22 and Node 24.
  • node --import ./packages/cli/scripts/test-home.mjs --test --test-reporter=tap 'skills/**/*.test.mjs' 'packages/cli/src/media-use/**/*.test.mjs' scripts/check-media-use-copy-parity.test.mjs scripts/creator-editing-capabilities.test.mjs: 895 passed, 2 Windows-only skips on Node 22.
  • bun install --frozen-lockfile, bun run build, bun run --filter '*' typecheck, bun run typecheck:scripts, bun run lint, bun run format:check, and bun packages/cli/scripts/gen-skills-manifest.ts --check passed.
  • Changed-file lint/format and comment-citation checks passed. Independent review reran the 40 focused tests and 4 dual-failure probes successfully.

Tests use isolated HOME/TMPDIR and synthetic provider executables. Native Windows/macOS and live providers were not tested; the new POSIX subprocess tests skip Windows. These are local validation results, not hosted CI results. Upstream main has advanced since the tested base; the current-main integration has not been locally rerun.

  • Unit tests added/updated
  • Manual live-provider testing performed
  • Comments explain the cleanup invariant

@sunxiuguo
sunxiuguo marked this pull request as ready for review October 12, 2026 00:27

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 7c5e306a. The change is correct and I found no blocker. I'm commenting instead of approving only because CI hasn't run: all 8 workflows are waiting on maintainer approval (action_required). I'll approve once they're green.

The fix. withTmpText creates the hf-txt-* folder, writes line.txt, awaits run(p), and removes the folder in a finally. The ElevenLabs and Kokoro paths both go through it. Because the spawn is awaited inside it, the folder can't be removed while the subprocess is still reading the file. Failures behave as before:

  • An error from mkdtempSync or writeFileSync, or a thrown spawn, still rejects synthesizeOne with the same error.
  • A nonzero exit, missing binary or missing output still resolves through synthResult.
  • An rmSync error is swallowed, so it can't replace the result or the original error.

writeTmpText had no other callers.

The test is collected. Test: skills runs every skills/**/*.test.mjs (find skills … -name "*.test.mjs"), and its path filter includes skills/**.

The monkeypatching takes effect. The child patches the node:fs and node:child_process module objects, calls syncBuiltinESMExports(), and only then imports tts.mjs. That updates the named bindings tts.mjs imports. The tests show it:

  • allocation, write and spawn-throw reject with the exact injected error object.
  • cleanup leaves exactly one folder behind.

Neither could happen if the patches didn't reach tts.mjs.

Mutations, locally:

  • With main's tts.mjs, 13/17 fail. The 4 that pass are the two allocation and two cleanup cases, which can't see a leak.
  • Letting the cleanup error propagate (dropping the inner catch) fails both cleanup cases.

Flakiness.

  • 17/17 passed in 5 back-to-back runs, about 1.1 s each.
  • Each case runs in its own child with its own TMPDIR, HOME and a PATH containing only the stubs. It uses absolute execPath shebangs, which are short on CI runners.
  • The concurrency case waits on a .started file with a 5 s deadline, then lets the slow child finish through a release file, also in a finally. Nothing depends on timing beyond 5–10 ms polls.
  • Skipping the tests on Windows is fine.

gen-skills-manifest --check is in sync. check-media-use-copy-parity.test.mjs fails locally with the same "both media-use copies must exist" list on main (the build-step copies aren't generated here). It doesn't involve tts.mjs.

— Rames

@jrusso1020
jrusso1020 enabled auto-merge October 12, 2026 20:57
@jrusso1020
jrusso1020 added this pull request to the merge queue Oct 12, 2026
Merged via the queue into heygen-com:main with commit 73d89b8 Oct 12, 2026
56 checks passed
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.

media-use tts.mjs leaves one hf-txt-* temp directory per synthesized line

2 participants