Skip to content

fix(tests): neutralize inherited voice TTS state - #40648

Closed
hanzckernel wants to merge 1 commit into
NousResearch:mainfrom
hanzckernel:fix/test-voice-tts-isolation
Closed

fix(tests): neutralize inherited voice TTS state#40648
hanzckernel wants to merge 1 commit into
NousResearch:mainfrom
hanzckernel:fix/test-voice-tts-isolation

Conversation

@hanzckernel

@hanzckernel hanzckernel commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Neutralize inherited HERMES_VOICE, HERMES_VOICE_TTS, and HERMES_VOICE_DEBUG in scripts/run_tests_parallel.py pytest subprocesses.
  • Neutralize the same flags when the root tests/conftest.py is imported, before pytest imports test modules for collection.
  • Keep those runtime flags forced to 0 after each fixture teardown, while allowing individual tests to opt in temporarily with monkeypatch.
  • Add regressions for runner subprocess inheritance, collection-time reads, and background work that reads HERMES_VOICE_TTS after fixture teardown.

Root cause

Runtime voice/TTS state is held in process-wide env vars. A live interactive Hermes process can have HERMES_VOICE_TTS=1; if tests inherit that value, gateway tests that complete fake assistant turns can call the real TTS stack and play audio. One existing fixture text is partial answer complete, which is why local test runs can audibly speak that phrase.

A function-scoped autouse fixture alone is too late for module-level reads during pytest collection. Simply deleting the flags with monkeypatch is also insufficient: fixture teardown restores inherited values while background gateway work may still be running.

Existing issue / PR check

Related but not covering this fix:

Neither covers inherited test-process state, collection-time reads, or teardown restoring TTS while background gateway work is still running.

Verification

  • HERMES_VOICE=1 HERMES_VOICE_TTS=1 HERMES_VOICE_DEBUG=1 ... pytest tests/test_run_tests_parallel.py: 8 passed.
  • Real gateway regression with all three inherited flags set to 1: 1 passed.
  • Collection-time subprocess probe and post-teardown subprocess probe both passed.
  • Ruff and git diff --check: passed.
  • One-commit invariant and clean worktree verified before push.
  • Exact-SHA independent review and post-fix closure: clean.

@alt-glitch alt-glitch added type/test Test coverage or test infrastructure P3 Low — cosmetic, nice to have tool/tts Text-to-speech and transcription labels Jun 6, 2026
@hanzckernel
hanzckernel force-pushed the fix/test-voice-tts-isolation branch from 1a4cd08 to 0ad148c Compare July 13, 2026 21:52

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for covering both the runner subprocess and direct-pytest collection paths. The premise remains valid on current main: scripts/run_tests_parallel.py:263 forwards os.environ unchanged, and tui_gateway/server.py:9316-9328 starts speak_text when _voice_tts_enabled() is true; that helper reads HERMES_VOICE_TTS at tui_gateway/server.py:13362-13364.

Problems

  • tests/test_run_tests_parallel.py:343 and :393 write generated probe modules into the source checkout's tests/ directory. The finally blocks clean up ordinary failures, but process interruption can leave untracked artifacts.

Suggested changes

  • Preserve the collection-time regression but place its probe in a temporary test root that explicitly loads the root conftest, rather than creating files under tests/.

Automated hermes-sweeper review.

"""Direct pytest runs must neutralize voice flags before module import."""
repo_root = Path(__file__).resolve().parent.parent
nonce = f"{os.getpid()}-{int(time.time() * 1000)}"
probe = repo_root / "tests" / f"_tmp_voice_collection_probe_{nonce}.py"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This probe is created inside the source checkout. Even with the finally cleanup below, an interrupted pytest process can leave an untracked Python file under tests/; please keep the probe in a temporary test root while explicitly loading the root conftest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation tool/tts Text-to-speech and transcription type/test Test coverage or test infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants