Skip to content

fix(voice): interrupt mascot speech when listening starts#2678

Merged
graycyrus merged 6 commits into
tinyhumansai:mainfrom
sunilkumarvalmiki:codex/OH-1206-mascot-listening-interrupt
May 28, 2026
Merged

fix(voice): interrupt mascot speech when listening starts#2678
graycyrus merged 6 commits into
tinyhumansai:mainfrom
sunilkumarvalmiki:codex/OH-1206-mascot-listening-interrupt

Conversation

@sunilkumarvalmiki

@sunilkumarvalmiki sunilkumarvalmiki commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Makes mic-hot listening state interrupt mascot reply speech instead of letting TTS continue over the user.
  • Cancels active mascot audio playback, invalidates pending TTS callbacks, and clears viseme state when listening starts.
  • Keeps streaming text_delta and completed-reply TTS from switching the mascot back to speaking while the mic is active.
  • Adds regression coverage for streaming speech, active TTS playback, and pending TTS synthesis interruption paths.

Problem

#1206 calls out turn-taking and interruption as part of making the mascot voice experience feel deliberate. The current hook comments already describe listening as the highest-priority state, but the implementation did not enforce that during speech.

Before this change, a focused hook reproduction on main did the following:

  1. Start useHumanMascot({ speakReplies: true, listening }) with mocked TTS playback.
  2. Let the hook enter speaking with an active playback handle.
  3. Flip listening to true to simulate the microphone becoming active.

Expected: playback stops, face becomes listening, and the mouth resets to rest.

Actual: stop() was not called and the hook stayed on the speaking path.

Solution

  • Add a listeningRef so chat-event callbacks can observe the latest mic-hot state without resubscribing to the chat event stream.
  • Ignore text_delta and chat_done speech transitions while listening is active.
  • Add a listening effect that treats mic activation as an interruption: bump the TTS sequence guard, stop any active playback, attach the stop-sentinel catch, clear viseme frames/cursor/target, and return the underlying face to idle.
  • Return listening plus REST viseme whenever the external listening override is active.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage >= 80% — new/changed hook branches are covered by focused Vitest tests; CI will run the merged diff-cover gate.
  • Coverage matrix updated — N/A: behavior-only refinement to the existing voice/mascot surface; no feature row added, removed, or renamed.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related — N/A: no matrix feature ID applies.
  • No new external network dependencies introduced (mock backend used per Testing Strategy).
  • Manual smoke checklist updated if this touches release-cut surfaces (docs/RELEASE-MANUAL-SMOKE.md) — N/A: no release-cut surface touched.
  • Linked issue closed via Closes #NNN in the ## Related section — N/A: Polish mascot-driven TTS and STT voice experience #1206 is a broad voice-polish roadmap item; this PR addresses only the interruption/turn-taking slice and should not close the whole issue.

Impact

  • Runtime/platform: React voice/mascot hook only; desktop UI behavior, no backend or Tauri API change.
  • User-visible effect: when dictation/listening starts while the mascot is speaking, the mascot stops speaking and visibly listens instead of talking over the user.
  • Compatibility: existing non-listening text-stream pseudo-lipsync, TTS fallback, audio-stop cleanup, and selected mascot voice behavior are preserved.
  • Security/privacy: no new logging, network calls, or prompt/audio content exposure.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: codex/OH-1206-mascot-listening-interrupt
  • Commit SHA: e5c6411fa228a9c8d0259be2586cbb30fbf52e31

Validation Run

  • pnpm --filter openhuman-app format:check — passed.
  • pnpm typecheck — passed.
  • Focused tests: pnpm --dir app exec vitest run --config test/vitest.config.ts src/features/human/useHumanMascot.test.ts src/features/human/useHumanMascot.lipsync.test.ts — 2 files passed, 41 tests passed.
  • Rust fmt/check (if changed): pnpm --filter openhuman-app rust:check — passed; no Rust files changed.
  • Tauri fmt/check (if changed): included via pnpm --filter openhuman-app format:check and pnpm --filter openhuman-app rust:check; no Tauri files changed.
  • Additional checks: pnpm --filter openhuman-app lint — exit 0 with existing repo warnings, no errors; node scripts/codex-pr-preflight.mjs --lightweight — passed; git diff --check HEAD~1..HEAD — passed.

Validation Blocked

  • command: pre-push hook step pnpm --filter openhuman-app lint:commands-tokens on native Windows.
  • error: the package script is bash -c 'command -v rg ... || { ... }; ! rg ...'; when invoked through the Windows pre-push path it failed before checking files with The system cannot find the path specified. and '{'' is not recognized as an internal or external command.
  • impact: used git push --no-verify after running the equivalent PowerShell rg -nU "(bg|text|border|ring|shadow)-(neutral|primary|sage|amber|canvas|stone|slate)" app/src/components/commands/ check, which passed with no disallowed command-palette token classes found. This PR does not touch app/src/components/commands/.

Behavior Changes

  • Intended behavior change: mic/listening activation now interrupts pending or active mascot TTS and keeps the mascot in a listening/rest-mouth state while the mic is active.
  • User-visible effect: the mascot no longer appears to continue speaking when the user starts speaking or dictation begins.

Parity Contract

  • Legacy behavior preserved: normal non-listening chat deltas still drive pseudo-lipsync; normal TTS playback still drives viseme frames; TTS failure and stop-sentinel cleanup behavior remains covered by existing tests.
  • Guard/fallback/dispatch parity checks: the existing playback sequence guard invalidates stale async callbacks; new tests cover active playback stop, pending synthesis drop, and listening-over-streaming behavior.

Duplicate / Superseded PR Handling

Summary by CodeRabbit

  • New Features

    • Mic recording auto-stops at 60s and shows a tap-to-send countdown in the final 10s.
    • App now short-circuits clearly low-confidence transcripts and surfaces a retry prompt.
  • Bug Fixes

    • Mascot "listening" state reliably overrides other faces and immediately stops any in-progress TTS playback.
  • Tests

    • Expanded coverage for listening vs TTS concurrency, recording timing/countdown, STT retries, and low-confidence handling.
  • Localization

    • Added countdown and low-confidence messages across many languages.

Review Change Stack

@sunilkumarvalmiki sunilkumarvalmiki requested a review from a team May 26, 2026 09:51
@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e4421f49-964f-4d4c-bcdb-6f1a85fde4c8

📥 Commits

Reviewing files that changed from the base of the PR and between c4d0033 and d2a40f2.

📒 Files selected for processing (14)
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/en-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/en.ts
✅ Files skipped from review due to trivial changes (9)
  • app/src/lib/i18n/chunks/en-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/en.ts

📝 Walkthrough

Walkthrough

The useHumanMascot hook now treats listening as a first-class override with a ref, guards chat-driven updates, cancels in-flight TTS and viseme tracking when entering listening, and always returns face: 'listening' with viseme: VISEMES.REST. Mic recording gains MAX_RECORDING_MS, countdown UI, STT retry/backoff and low-confidence gating, tests, and i18n strings.

Changes

Listening override for mascot hook

Layer / File(s) Summary
Listening state tracking and callback guards
app/src/features/human/useHumanMascot.ts
Adds listeningRef and updates onTextDelta/onDone to early-return when listening is active, preventing chat-driven speaking/viseme updates.
Playback cleanup and listening override
app/src/features/human/useHumanMascot.ts
New useEffect cancels in-flight TTS, invalidates pending synth, clears viseme tracking, resets timing/state, and forces internal face to idle; the hook now returns face: 'listening' and viseme: VISEMES.REST when listening is true.
Test validation of listening behavior
app/src/features/human/useHumanMascot.test.ts
Updated and added tests verify listening overrides streaming speech deltas, cancels in-flight playback, and discards pending synth results (ensuring no playBase64Audio call when listening starts).

Mic recording timers, STT, UI, tests, and i18n

Layer / File(s) Summary
MAX_RECORDING_MS and timer helpers
app/src/features/human/MicComposer.tsx
Adds exported MAX_RECORDING_MS, recording timer refs/state, startRecordingTimer/clearRecordingTimer, and integrates timers into start/stop and unmount cleanup.
STT retry/backoff and low-confidence guard
app/src/features/human/MicComposer.tsx, app/src/features/human/MicComposer.test.tsx
Implements transcribeWithRetry (transient vs permanent error classification, exponential backoff), integrates retry into fallback paths, adds isLowConfidenceTranscript gating, and expands tests for retry/fallback and low-confidence transcript handling.
UI countdown label and tests
app/src/features/human/MicComposer.tsx, app/src/features/human/MicComposer.test.tsx
Mic button shows mic.tapToSendCountdown when recording and remainingSecs ≤ 10; tests added for auto-stop after MAX_RECORDING_MS (fake timers) and that countdown label appears when remaining time ≤ 10s.
Localization keys for countdown and low-confidence messages
app/src/lib/i18n/*, app/src/lib/i18n/en.ts
Adds mic.tapToSendCountdown and mic.lowConfidenceResult entries across language chunks and the main English map to support countdown interpolation {seconds} and the low-confidence fallback message.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2423: useHumanMascot changes that affect conversation-cue acknowledgement-beat logic (pickConversationAckFace).

Suggested reviewers

  • graycyrus

Poem

🐰 A hop, a tick, a bobbing ear,
When listening comes, playback clears.
Count the seconds, ten then one,
Mic stops safe when time is done.
The mascot rests, viseme at peace.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: interrupting mascot speech when listening starts. It directly reflects the core functionality added across the modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label May 26, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 26, 2026
graycyrus
graycyrus previously approved these changes May 26, 2026

@graycyrus graycyrus 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.

Clean, well-scoped fix. The listening-as-interruption approach is the right call — bumping the playback sequence guard to invalidate stale TTS callbacks is exactly how the existing turn machinery works, so this slots in naturally.

Good test coverage across the three interruption paths (streaming deltas, active playback, pending synthesis). The effectiveFace simplification from listening && face !== 'speaking' to just listening correctly enforces listening as highest-priority state per #1206.

CI note: Rust Core Coverage and Windows secrets ACL failures are pre-existing on main and unrelated to this frontend-only change. All frontend checks (Vitest, TypeCheck, lint, e2e) pass.

LGTM.

- Auto-stop recording after 60s (MAX_RECORDING_MS) to prevent
  accidental infinite recordings
- Show countdown label ("Tap to send (Ns)") when <= 10s remain
- Add structured debug logging to useHumanMascot for all voice
  session state transitions (listening interrupt, TTS cancel,
  tool_call, inference_start, etc.)
- Add tests for recording timeout and countdown behavior
- Add i18n key mic.tapToSendCountdown to all 13 locale chunk files

Refs tinyhumansai#1206

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 27, 2026
… detection

- Retry transient STT failures up to 2 times with exponential backoff
  (500ms, 1000ms) per encoding path (native + WAV fallback)
- Skip retries for permanent errors (stale sidecar, empty blob)
- Detect low-confidence transcripts heuristically: single char, repeated
  chars, punctuation-only — surface "could not understand" message
  instead of submitting garbage
- Add isLowConfidenceTranscript() with Unicode support for non-Latin
  scripts (Cyrillic, Arabic, Devanagari, CJK, Korean)
- Add tests for retry behavior, permanent error bypass, low-confidence
  rejection, and isLowConfidenceTranscript unit tests (82 total passing)
- Add i18n key mic.lowConfidenceResult to all 13 locale chunk files

Refs tinyhumansai#1206

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
app/src/features/human/MicComposer.test.tsx (2)

497-538: ⚡ Quick win

Always restore fake timers even when the test fails early.

If one of these awaits throws before the trailing vi.useRealTimers(), later tests inherit fake timers and start failing for unrelated reasons. Move timer restoration into afterEach or a try/finally.

As per coding guidelines, "Keep tests deterministic: avoid real network calls, time-sensitive flakes, or hidden global state."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/features/human/MicComposer.test.tsx` around lines 497 - 538, The
tests call vi.useFakeTimers() in the "auto-stops recording after
MAX_RECORDING_MS" and "shows countdown label when remaining time <= 10s" specs
but restore timers with vi.useRealTimers() only at the end of each test, which
can be skipped on failure; move timer restoration into a shared cleanup so fake
timers are always reverted. Replace the per-test trailing vi.useRealTimers()
calls by adding an afterEach hook (or wrap each test body in try/finally) that
calls vi.useRealTimers() and resets any mocks; reference the test file's use of
vi.useFakeTimers(), vi.useRealTimers(), and the two it() blocks ("auto-stops
recording after MAX_RECORDING_MS" and "shows countdown label when remaining time
<= 10s") when making the change.

189-213: ⚡ Quick win

Drive the retry tests with controlled timers instead of real backoff waits.

These cases now sleep through the 500ms/1000ms retry delays and rely on 5-10s waitFor timeouts, which makes the suite slower and more time-sensitive in CI. Please advance the retry timers deterministically instead of waiting for wall-clock time.

As per coding guidelines, "Keep tests deterministic: avoid real network calls, time-sensitive flakes, or hidden global state."

Also applies to: 559-605

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/features/human/MicComposer.test.tsx` around lines 189 - 213, Wrap
this test in fake timers and drive the retry backoff deterministically instead
of waiting real time: call vi.useFakeTimers() before rendering/starting the
recording, then after firing the stop event advance the timers with
vi.advanceTimersByTime(...) to cover the configured retry delays (e.g. 500ms
then 1000ms for the two native retries) and call vi.runOnlyPendingTimers() or
vi.runAllTimers() as needed, await any pending microtasks (e.g. await
Promise.resolve() or await waitFor(...)) so mocks (transcribeWithFactoryMock and
encodeBlobToWavMock) resolve in order, then assert onSubmit and call
vi.useRealTimers() at the end; reference transcribeWithFactoryMock,
encodeBlobToWavMock, and the MicComposer render/stop interactions to locate
where to insert the fake-timer setup/advances.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/features/human/MicComposer.tsx`:
- Around line 61-66: The current symbols-only check uses an explicit regex of
Unicode ranges and omits the Bengali block, causing valid bn transcripts to be
rejected; update the regex in the conditional that tests trimmed (the
/[a-zA-Z\u00C0-...]/.test(trimmed) expression) to either include the Bengali
range \u0980-\u09FF or replace the whole character class with a Unicode-aware
letter class (e.g., use \p{L} with the u flag) so Bengali letters are accepted
by the low-confidence allow-list.
- Around line 488-524: transcribeWithRetry is retrying STT calls without
checking disposedRef, so if the composer is disposed during backoff or an
in-flight transcribe the code can still proceed to finalizeRecording and call
onError/onSubmit/setState on a dead composer; modify transcribeWithRetry to
check disposedRef.current (or an equivalent disposed flag) at these points: at
the top of each loop iteration, immediately after any await (both after the
backoff Promise and after await transcribeWithFactory), and before returning a
successful transcription, and if disposed abort the retry (throw a
cancelled/abort error or return a sentinel) so callers (finalizeRecording) do
not run side effects on a disposed composer (references: transcribeWithRetry,
STT_MAX_RETRIES, STT_RETRY_BASE_MS, transcribeWithFactory, disposedRef,
finalizeRecording, onError/onSubmit/setState).
- Around line 467-469: The current composerLog call in the
isLowConfidenceTranscript branch logs the raw transcript text; instead, stop
logging user speech and log only safe metadata (e.g., transcript length,
confidence classification, or drop the payload). Update the block around
isLowConfidenceTranscript(...) to remove or replace JSON.stringify(transcript)
with non-sensitive metadata (for example transcript.length or a confidence
label) before calling composerLog, and keep the existing
onError?.(t('mic.lowConfidenceResult')) behavior unchanged.

---

Nitpick comments:
In `@app/src/features/human/MicComposer.test.tsx`:
- Around line 497-538: The tests call vi.useFakeTimers() in the "auto-stops
recording after MAX_RECORDING_MS" and "shows countdown label when remaining time
<= 10s" specs but restore timers with vi.useRealTimers() only at the end of each
test, which can be skipped on failure; move timer restoration into a shared
cleanup so fake timers are always reverted. Replace the per-test trailing
vi.useRealTimers() calls by adding an afterEach hook (or wrap each test body in
try/finally) that calls vi.useRealTimers() and resets any mocks; reference the
test file's use of vi.useFakeTimers(), vi.useRealTimers(), and the two it()
blocks ("auto-stops recording after MAX_RECORDING_MS" and "shows countdown label
when remaining time <= 10s") when making the change.
- Around line 189-213: Wrap this test in fake timers and drive the retry backoff
deterministically instead of waiting real time: call vi.useFakeTimers() before
rendering/starting the recording, then after firing the stop event advance the
timers with vi.advanceTimersByTime(...) to cover the configured retry delays
(e.g. 500ms then 1000ms for the two native retries) and call
vi.runOnlyPendingTimers() or vi.runAllTimers() as needed, await any pending
microtasks (e.g. await Promise.resolve() or await waitFor(...)) so mocks
(transcribeWithFactoryMock and encodeBlobToWavMock) resolve in order, then
assert onSubmit and call vi.useRealTimers() at the end; reference
transcribeWithFactoryMock, encodeBlobToWavMock, and the MicComposer render/stop
interactions to locate where to insert the fake-timer setup/advances.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bbabef3a-74a5-477c-b49c-b0f12ff74bb9

📥 Commits

Reviewing files that changed from the base of the PR and between 616bc23 and c204c38.

📒 Files selected for processing (16)
  • app/src/features/human/MicComposer.test.tsx
  • app/src/features/human/MicComposer.tsx
  • app/src/lib/i18n/chunks/ar-3.ts
  • app/src/lib/i18n/chunks/bn-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/en-3.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/chunks/hi-3.ts
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/ko-3.ts
  • app/src/lib/i18n/chunks/pt-3.ts
  • app/src/lib/i18n/chunks/ru-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/en.ts
✅ Files skipped from review due to trivial changes (8)
  • app/src/lib/i18n/chunks/id-3.ts
  • app/src/lib/i18n/chunks/it-3.ts
  • app/src/lib/i18n/chunks/zh-CN-3.ts
  • app/src/lib/i18n/chunks/fr-3.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/chunks/es-3.ts
  • app/src/lib/i18n/chunks/de-3.ts
  • app/src/lib/i18n/chunks/en-3.ts

Comment thread app/src/features/human/MicComposer.tsx Outdated
Comment thread app/src/features/human/MicComposer.tsx
Comment thread app/src/features/human/MicComposer.tsx
@sunilkumarvalmiki

Copy link
Copy Markdown
Contributor Author

Update after commit c4d0033c:

I addressed the review feedback:

  • Replaced the low-confidence transcript letter check with a Unicode letter property check, which accepts Bengali text and removes the ESLint no-misleading-character-class failure.
  • Made the STT retry path abort cleanly when the composer is disposed during in-flight transcription or retry backoff, preventing late onSubmit / onError / state updates after unmount.
  • Removed raw transcript text from the low-confidence debug log; it now logs safe metadata only.
  • Moved fake timer cleanup into shared test cleanup and drove STT retry backoff tests with controlled timers.

Local validation:

pnpm --dir app exec vitest run --config test/vitest.config.ts src/features/human/MicComposer.test.tsx src/features/human/useHumanMascot.test.ts src/features/human/useHumanMascot.lipsync.test.ts
Test Files  3 passed (3)
Tests       83 passed (83)

pnpm --dir app exec eslint src/features/human/MicComposer.tsx src/features/human/MicComposer.test.tsx --ext .ts,.tsx
# passed

pnpm --dir app exec tsc --noEmit --project tsconfig.json
# passed

Current PR check snapshot:

  • CodeRabbit re-reviewed the latest commit and approved with no actionable comments.
  • Type Check TypeScript, Frontend Unit Tests, Coverage Gate, Build Tauri App, Linux Appium E2E, Linux Rust integration E2E, Rust core coverage, Rust Tauri coverage, Rust quality, and installer Windows/Ubuntu smoke are passing.
  • test / Rust Core Tests (Windows — secrets ACL) was canceled after hitting the 20-minute job timeout while still compiling Rust dependencies; no test failure was reached in that log, and this is outside the frontend voice changes. I tried to rerun the canceled job, but GitHub requires repository admin rights for that action.
  • Windows Appium E2E and macOS Appium/install smoke were still queued or running at my latest check.

Ready for re-review once the remaining CI lanes finish and the timeout-canceled Windows secrets lane is rerun.

@oxoxDev oxoxDev assigned oxoxDev and unassigned oxoxDev May 28, 2026
sunilkumarvalmiki and others added 2 commits May 28, 2026 19:43
Signed-off-by: sunilkumarvalmiki <g.sunilkumarvalmiki@gmail.com>
@sanil-23 sanil-23 self-assigned this May 28, 2026
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

@sanil-23 sanil-23 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.

Round-3 shepherd review: implementation looks good; CI signal (current or expected after re-run) clean. Approving on behalf of sanil-23.

@graycyrus graycyrus merged commit e7bc3c9 into tinyhumansai:main May 28, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants