Skip to content

fix(voice): ship the voice domain in the desktop build (#4901)#4917

Merged
M3gA-Mind merged 6 commits into
tinyhumansai:mainfrom
CodeGhost21:fix/4901-voice-transcription
Jul 15, 2026
Merged

fix(voice): ship the voice domain in the desktop build (#4901)#4917
M3gA-Mind merged 6 commits into
tinyhumansai:mainfrom
CodeGhost21:fix/4901-voice-transcription

Conversation

@CodeGhost21

@CodeGhost21 CodeGhost21 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Problem

Since PR #1061 the core runs in-process inside the Tauri shell, so the shell's dependency declaration is what actually ships. That declaration has carried default-features = false since the in-process move (app/src-tauri/Cargo.toml:135, dated 2026-05-16), back when the core crate had no [features] default list at all — a harmless no-op.

#4833 (implementing #4803) then made voice a default-ON compile-time feature so slim/headless builds could drop it. That collided with the pre-existing default-features = false: the desktop build stopped enabling voice, so the #[cfg(feature = "voice")] controller registrations in src/core/all.rs (lines 210, 641) were never compiled in, and the whole openhuman.voice_* namespace became unknown-method.

Because the gate is compile-time, restarting or reinstalling can never help — the code is absent from the binary. This is not a migration or data issue: a clean install of an affected release fails identically.

Evidence

  • hound — reachable only via voice = ["dep:hound", "dep:lettre"] — was absent from the shell's dependency graph (cargo tree -i hound → "did not match any packages") while present in the root crate's graph. Same probe, same worktree; the only difference is default-features = false.
  • Production Sentry confirms the whole namespace is down, not just STT:

Note: the issue hypothesised a missing/mis-bundled ggml-base-q5_1.bin. That is a red herring — the model is never reached, and the voice gate does not drop whisper-rs (it lives in the inference domain).

Solution

  • app/src-tauri/Cargo.toml — add features = ["voice"], plus a comment recording that default-features = false predates the core's defaults, so every default the core gains must be opted back in here.
  • app/src-tauri/src/lib.rsconst _: () = assert!(openhuman_core::openhuman::voice::VOICE_COMPILED_IN, ...). Cargo features are per-crate, so the shell cannot #[cfg] on the core's features; asserting the core's own always-compiled facade is the only way to detect a stubbed build. Placed alongside the existing compile_error! desktop-target guard.
  • src/openhuman/voice/mod.rs — expose VOICE_COMPILED_IN from the always-compiled facade (cfg!(feature = "voice")), so dependents can assert which build they got.
  • app/src/features/human/voice/sttClient.ts — throws a typed VoiceNotCompiledError carrying a stable VOICE_NOT_COMPILED_CODE, replacing two duplicated inline strings. The English message is kept deliberately (it is what reaches debug logs and Sentry) and retains the unavailable in this build substring, which MicComposer's PERMANENT_ERROR_PATTERNS matches to suppress a retry/backoff loop that can never succeed against a compile-time gate.
  • i18nMicComposer previously spliced the raw English error into the translated mic.transcriptionFailed template ("Transcription failed: {message}"), so the other 13 locales rendered a half-translated sentence. It now branches on the error code and renders mic.voiceNotCompiled, added to all 14 locales with real translations. Detection duck-types on code rather than instanceof, since the error crosses async/retry boundaries where prototypes can be stripped.
  • src/openhuman/voice/compile_status.rsVOICE_COMPILED_IN lives in a sibling module (AGENTS.md requires mod.rs be export-only), ungated so it exists in both gate states, with tests pinning it to cfg!(feature = "voice") rather than a literal so they hold for both builds.

Scope note: the same line also drops tokenjuice-treesitter (the core's other default). Not bundled here — the shell separately sets tinyjuice = { default-features = false }, suggesting the tree-sitter C build may be avoided deliberately. Filed as #4918, with #4919 to close the whole class in CI.

Merge note: the media gate (#4804/#4840) landed on main mid-review and hit this same trap — its author forwarded media and documented the rule in a comment, but voice stayed broken. The merge conflict was resolved by keeping both gates and merging the comments into one rule. Two of the core's three defaults have now been dropped at some point, which is the argument for #4919: a code comment is documentation, not enforcement.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — changed lines meet the gate. The Rust guard is verified red/green (see Impact); frontend paths covered by sttClient.test.ts / MicComposer.test.tsx (212 related tests pass).
  • Coverage matrix updated — N/A: behaviour-only bug fix, no feature rows added/removed/renamed
  • All affected feature IDs from the matrix are listed in the PR description under ## Related
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: no checklist change; voice smoke steps already covered. Verified manually on macOS (see Impact).
  • Linked issue closed via Closes #NNN in the ## Related section

Impact

Runtime/platform: desktop (macOS/Windows/Linux). Restores the entire openhuman.voice_* surface — transcription, TTS, availability checks, and the dictation server — all of which were absent from shipped builds.

Verification

Check Result
hound in shipped shell graph (proxy for voice) absent → present
Shell build without the fix fails error[E0080] with the guard message (red)
Shell build with the fix compiles, exit 0 (green)
Core cargo check, voice ON passes
Core cargo check, voice OFF (--no-default-features --features tokenjuice-treesitter) passes — facade parity intact, slim builds unaffected
Related Vitest suites 212 pass / 13 files
tsc --noEmit, ESLint, Prettier, cargo fmt --check clean
Manual: pnpm dev:app on macOS, mic → transcript → sent works

Binary size: re-adds hound + lettre to the desktop build. These were always intended to ship; their absence was the bug.

Compatibility / migration: none. No data, schema, or config involved — purely which code is compiled into the binary. Users on 0.58.19–0.61.x remain broken until they update to a release containing this fix.

Related

Closes #4901

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling when voice transcription isn’t available in the installed app version, replacing confusing “unknown method”/restart guidance with a clear message that voice transcription isn’t included and OpenHuman needs updating.
    • Ensured the mic UI shows the correct localized error state and doesn’t retry when voice support is missing.
  • Localization

    • Added the “voice transcription not compiled/available” message across all supported languages.
  • Tests

    • Updated and expanded voice-missing coverage to validate the localized error behavior.
    • Reduced test flakiness by waiting for async UI updates in a canvas validation test.

…4901)

The Tauri shell embeds the core in-process (tinyhumansai#1061), so its dependency
declaration is what actually ships. It has carried
`default-features = false` since the in-process move, back when the core
crate had no `[features] default` list at all — a harmless no-op.

tinyhumansai#4833 then made `voice` a default-ON compile-time feature so slim builds
could drop it. That silently collided with the pre-existing
`default-features = false`: the shipped app has been built WITHOUT the
voice domain ever since, so the `#[cfg(feature = "voice")]` controllers in
`src/core/all.rs` were never registered and every `openhuman.voice_*` RPC
answered "unknown method".

Evidence: `hound` (reachable only via `voice = ["dep:hound", ...]`) was
absent from the shell's dependency graph while present in the root crate's.
Sentry confirms in production — `voice_status` (46,735 events / 56 users)
and `voice_server_status` (46,592 / 52) both unknown-method, first seen
2026-07-14, hours after tinyhumansai#4833 landed, matching first bad release 0.58.19.

- Cargo.toml: opt `voice` back in explicitly, and document that every
  future core default must be re-added here.
- lib.rs: assert `VOICE_COMPILED_IN` at compile time. Cargo features are
  per-crate, so the shell cannot `#[cfg]` on the core's features; this
  const assert is the only way to make a voice-less desktop binary fail
  the build instead of failing silently at runtime. Verified red/green.
- sttClient.ts: the "restart to pick up the latest core sidecar" copy was
  written for tinyhumansai#1289 (a stale bundled sidecar, removed in tinyhumansai#1061) and cannot
  ever resolve a compile-time gate. Replaced with an accurate reason and a
  real action, keeping the "unavailable in this build" substring that
  MicComposer matches to suppress the pointless retry loop.

Tests asserting the misleading restart hint were pinning the bug; they now
assert the accurate message and that restart advice is not reintroduced.

Fixes tinyhumansai#4901
@CodeGhost21 CodeGhost21 requested a review from a team July 15, 2026 14:52
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: 0de71072-c39f-4f54-8767-b7064d592f45

📥 Commits

Reviewing files that changed from the base of the PR and between 9c3a8e1 and f8648f9.

📒 Files selected for processing (1)
  • app/src/components/flows/canvas/__tests__/EditableFlowCanvas.validation.test.tsx

📝 Walkthrough

Walkthrough

The desktop build now enables and verifies the core voice feature. STT clients convert missing voice RPCs into a structured unavailable-build error, and the microphone UI displays localized copy without retrying. A canvas validation test now waits for asynchronous metadata updates.

Changes

Voice build and runtime handling

Layer / File(s) Summary
Voice build contract and host guard
src/openhuman/voice/..., app/src-tauri/Cargo.toml, app/src-tauri/src/lib.rs
The core exposes VOICE_COMPILED_IN, the desktop dependency enables voice, and the host fails compilation when voice is absent.
STT missing-voice error mapping
app/src/features/human/voice/sttClient.ts, app/src/features/human/voice/sttClient.test.ts
Cloud and factory transcription paths replace unknown voice RPC errors with VoiceNotCompiledError and avoid restart advice.
Microphone localization and validation
app/src/features/human/MicComposer.tsx, app/src/features/human/MicComposer.test.tsx, app/src/lib/i18n/*
MicComposer renders localized missing-voice messages, preserves single-attempt behavior, and adds translations across supported locales.
Canvas validation timing
app/src/components/flows/canvas/__tests__/EditableFlowCanvas.validation.test.tsx
The validation test waits for asynchronous save metadata before asserting that saving is blocked.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MicComposer
  participant STTClient
  participant OpenHumanCore
  MicComposer->>STTClient: Request transcription
  STTClient->>OpenHumanCore: Call voice transcription RPC
  OpenHumanCore-->>STTClient: Return unknown method
  STTClient-->>MicComposer: Return VoiceNotCompiledError
  MicComposer-->>MicComposer: Display localized mic.voiceNotCompiled message
Loading

Possibly related PRs

Suggested labels: rust-core, bug

Suggested reviewers: graycyrus

Poem

A rabbit checks the voice-built gate,
Then hops past restart hints of late.
A missing call gets a proper name,
Localized words explain the same.
No retries—just carrots and tests!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes an unrelated EditableFlowCanvas test flake fix, which is outside the voice-transcription scope of #4901. Move the canvas test hardening into a separate PR or remove it from this change so the patch stays focused on voice-domain fixes.
✅ 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 is concise and accurately describes the main change: restoring the voice domain in the desktop build.
Linked Issues check ✅ Passed The changes address #4901 by restoring voice in the desktop build, replacing misleading restart errors, and adding compile-time safeguards plus tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

@coderabbitai coderabbitai Bot added bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels Jul 15, 2026

@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

🤖 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/voice/sttClient.ts`:
- Around line 16-18: Replace the hardcoded VOICE_NOT_COMPILED_MESSAGE in
sttClient.ts with a stable error code or typed error. At the UI presentation
boundary, detect that code/type and render translated copy through useT(),
adding the corresponding translation key and real value to every supported
locale.
- Around line 87-89: Limit the VOICE_NOT_COMPILED_MESSAGE rewrite in both
transcription paths at callCoreRpc sites
(app/src/features/human/voice/sttClient.ts:87-89 and
app/src/features/human/voice/sttClient.ts:163-165) to errors proven to originate
from the local core transport. Carry transport provenance or a structured error
kind through callCoreRpc, and preserve the original unknown-method message for
remote transports.

In `@src/openhuman/voice/mod.rs`:
- Around line 95-104: Move the VOICE_COMPILED_IN constant implementation from
src/openhuman/voice/mod.rs into a sibling module such as compile_status.rs,
preserving its cfg!(feature = "voice") behavior and documentation. Keep mod.rs
limited to module declarations and re-exports, including re-exporting
VOICE_COMPILED_IN from the new module.
🪄 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: 6658b7be-0414-47ee-beb2-cd0844cbb4db

📥 Commits

Reviewing files that changed from the base of the PR and between 45dc6c0 and 4515788.

⛔ Files ignored due to path filters (1)
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • app/src-tauri/Cargo.toml
  • app/src-tauri/src/lib.rs
  • app/src/features/human/MicComposer.test.tsx
  • app/src/features/human/MicComposer.tsx
  • app/src/features/human/voice/sttClient.test.ts
  • app/src/features/human/voice/sttClient.ts
  • src/openhuman/voice/mod.rs

Comment thread app/src/features/human/voice/sttClient.ts Outdated
Comment thread app/src/features/human/voice/sttClient.ts Outdated
Comment thread src/openhuman/voice/mod.rs Outdated
Conflict in app/src-tauri/Cargo.toml: the media feature gate (tinyhumansai#4804/tinyhumansai#4840)
landed on main and hit the same trap as tinyhumansai#4901 — `default-features = false`
silently dropping a default-ON core gate from the shipped desktop build. It
forwarded `media`; this branch forwards `voice`. Both are required, so the
resolution keeps both rather than either side.

Merged the two comments into one rule ("every default-ON gate must be
forwarded explicitly, a missing gate vanishes silently") and noted that
`tokenjuice-treesitter` is the remaining un-forwarded default (tinyhumansai#4918).

Verified after merge: `cargo tree -e features -i openhuman` resolves both
`feature "media"` and `feature "voice"`; shell `cargo check` green (so the
VOICE_COMPILED_IN assert passes); 212 related Vitest tests pass; fmt clean.
…t of mod.rs

Addresses review feedback on tinyhumansai#4917. Two of three findings were valid.

i18n (valid): `MicComposer` interpolated the raw English error into the
translated `mic.transcriptionFailed` template ("Transcription failed:
{message}"), so non-English locales rendered a half-translated sentence.
CI could not catch this — `i18n:english:check` scans locale files, not
service code.

  - sttClient now throws a typed `VoiceNotCompiledError` carrying a stable
    `VOICE_NOT_COMPILED_CODE`. The English message is kept deliberately: it
    is what reaches debug logs and Sentry.
  - `isVoiceNotCompiledError` duck-types on `code` rather than `instanceof` —
    the error crosses async/retry boundaries where prototypes can be stripped.
  - `MicComposer` branches on the code and renders `mic.voiceNotCompiled`.
  - Key added to all 14 locales with real translations (no em dashes, per
    AGENTS.md). `i18n:check` and `i18n:english:check` both pass.

mod.rs (valid): AGENTS.md requires mod.rs be export-only. Moved
`VOICE_COMPILED_IN` to a sibling `compile_status.rs`, deliberately ungated
(it must exist in both gate states — reporting which state we are in is its
purpose) and re-exported. Tests pin the const to `cfg!(feature = "voice")`
rather than a literal, so they hold for both builds.

transport provenance (skipped): not reachable. `setActiveCoreTransport` has
exactly one occurrence in the tree — its own definition — so `_activeTransport`
is always null and every `callCoreRpc` hits the local core. The
`unknown method` rewrite condition is also pre-existing, unchanged by tinyhumansai#4917.
Threading provenance through the shared RPC client for a dead path is not
minimal; it belongs with whatever work activates the iOS/tunnel transport.

Also fixes a latent test defect: MicComposer.test.tsx hand-listed its
sttClient mock exports, so any newly imported export silently resolved to
undefined and threw a TypeError at the call site. Now spreads importOriginal().

Verified: compile_status tests pass with voice ON and OFF (2/2 each); shell
cargo check green (const assert resolves via the re-export); 78 voice tests
pass; i18n checks, tsc, ESLint, Prettier, cargo fmt all clean; locale diff is
27 insertions / 0 deletions.
M3gA-Mind
M3gA-Mind previously approved these changes Jul 15, 2026

@M3gA-Mind M3gA-Mind 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.

PR #4917 — fix(voice): ship the voice domain in the desktop build (#4901)

Walkthrough

Since v0.58.19 the shipped desktop app carried default-features = false on its openhuman_core dependency, which silently dropped the default-ON voice compile-time gate added by #4833 — so every openhuman.voice_* controller was unregistered and answered "unknown method" at runtime (46k+ Sentry events). This PR re-forwards voice (and documents the whole forwarding rule), adds a compile-time const assert against the core's always-compiled VOICE_COMPILED_IN facade so a voice-less desktop binary now fails the build instead of shipping broken, and replaces the stale "restart to pick up the latest core sidecar" copy (obsolete since the sidecar was removed in #1061) with a typed VoiceNotCompiledError that drives a properly localized mic.voiceNotCompiled message across all 14 locales.

The diagnosis is precise, the fix is minimal and correct, tests are red/green verified, and the AGENTS.md conventions (mod.rs export-only, translations in every locale, no em dashes in translation values) are all respected. No blocking issues found — approving.

Changes

File Summary
app/src-tauri/Cargo.toml Add voice to the openhuman_core feature list; expand the comment into an enforced "forward every default-ON gate" rule.
app/src-tauri/Cargo.lock Re-adds hound + lettre (reachable only via the voice feature) to the shell graph.
app/src-tauri/src/lib.rs const _: () = assert!(openhuman_core::…::VOICE_COMPILED_IN, …) — turns a silent runtime gap into a build failure.
src/openhuman/voice/compile_status.rs New ungated module exposing VOICE_COMPILED_IN = cfg!(feature = "voice"), with tests pinning it to the gate in both build states.
src/openhuman/voice/mod.rs Re-export VOICE_COMPILED_IN from the always-compiled facade.
app/src/features/human/voice/sttClient.ts Introduce VoiceNotCompiledError + VOICE_NOT_COMPILED_CODE + isVoiceNotCompiledError; both STT paths throw the typed error on unknown method.
app/src/features/human/MicComposer.tsx Branch on isVoiceNotCompiledError to render localized mic.voiceNotCompiled instead of splicing raw English into {message}.
app/src/features/human/{sttClient,MicComposer}.test.* Updated + new tests for the not-compiled message, restart-copy removal, retry suppression, and localized rendering.
app/src/lib/i18n/*.ts (14) Add mic.voiceNotCompiled with real translations in every locale.

Actionable comments (1)

💡 Refactor / suggestion

1. app/src/features/human/voice/sttClient.ts:45 — make isVoiceNotCompiledError a type guard

The predicate returns a bare boolean, so callers that later need to read err.code/err.message after the check still have to cast err from unknown. Narrowing to VoiceNotCompiledError costs nothing (the class already carries code) and documents intent. This is polish, not a defect — the current call sites only branch on it.

Suggested change:

// before
export function isVoiceNotCompiledError(err: unknown): boolean {

// after
export function isVoiceNotCompiledError(err: unknown): err is VoiceNotCompiledError {

Nitpicks (1)

  • app/src/lib/i18n/en.ts:405 — a stray blank line now separates mic.voiceNotCompiled from the // Reflections block. Harmless (matches the section spacing) but slightly asymmetric with the other 13 locales, which inserted the key inline. Leave as-is or drop the blank line.

Questions for the author (0)

None.

Verified / looks good

  • Const assert is sound: assert!(const_bool, "literal") is valid in a const context, and VOICE_COMPILED_IN = cfg!(feature = "voice") evaluating to false triggers a genuine E0080 compile failure — matches the PR's red/green table. The message is a bare literal (no format args), which const panic requires.
  • mod.rs stays export-only (AGENTS.md): the constant lives in sibling compile_status.rs; mod.rs only re-exports it. compile_status.rs and its pub mod line are correctly ungated so they exist in both feature states, and stub.rs does not redefine the symbol, so there's no glob/explicit re-export collision when voice is OFF.
  • Retry suppression is intact: VoiceNotCompiledError.message retains the unavailable in this build substring, which PERMANENT_ERROR_PATTERNS matches → isTransientError returns false → the error rethrows through transcribeWithRetry/transcribeWithFallback without a WAV re-encode, and reaches finalizeRecording with its prototype intact.
  • Duck-typing on code (not instanceof) is the right call for an error crossing async/retry boundaries, and a pinning test (keeps the "unavailable in this build" substring) guards the coupling.
  • i18n complete: all 14 locale files (ar bn de en es fr hi id it ko pl pt ru zh-CN) carry mic.voiceNotCompiled; interpolation-free values, no U+2014 em dashes in any translation value.
  • Test coverage: the "does not retry permanent errors" and cloud/factory unknown method tests were updated to assert the new copy and the absence of the restart hint; a new MicComposer test proves the localized string (not raw developer copy) reaches onError.

Comment thread app/src/features/human/voice/sttClient.ts Outdated
@M3gA-Mind M3gA-Mind dismissed their stale review July 15, 2026 20:33

Retracting the APPROVED state — this review is intended as comment-only. The automated harness defaulted to approving, but the merge/approve decision is the human maintainer's. The technical findings below stand as review comments, not an approval.

@M3gA-Mind

Copy link
Copy Markdown
Collaborator

W5 review (comment-only — the maintainer decides merge)

I ran our review harness and then verified the substantive claims against the code myself. Two process notes up front:

  • The harness defaulted to posting an Approved review; I've dismissed that — this is a comment-only pass, the approve/merge call is the human's.
  • Its inline type-guard suggestion (below) still stands as a comment.

CI: the 2 "failures" are stale, not real

gh pr checks shows green, but the check-runs API lists 2 failures. Both are the same non-code checkPR Submission Checklist (the PR-template/description validator) — which ran three times on the head commit e21285d1:

time (UTC) conclusion
18:57:42 ❌ failure
19:00:10 ❌ failure
19:02:18 success

The two early failures were superseded by the 19:02 pass (the checklist re-runs on PR-description edits). Every substantive check is green — Rust Core Coverage, Rust Tauri Coverage, Frontend Checks (quality/i18n/docs/coverage), Rust Feature-Gate Smoke (gates off), Rust Quality (fmt/clippy), PR CI Gate. No real code failure. (The only open review state is CodeRabbit's earlier CHANGES_REQUESTED from 14:59 — worth a re-check against the current head.)

Fix correctness — sound

  • Root cause & fix confirmed against the diff. app/src-tauri/Cargo.toml: openhuman_core went features = ["media"]["media", "voice"]. That re-forwards the default-ON voice gate that default-features = false had been silently dropping, which is exactly why the whole openhuman.voice_* namespace answered "unknown method". Minimal, on-target.
  • Compile-time assert is robust. const _: () = assert!(openhuman_core::openhuman::voice::VOICE_COMPILED_IN, "...") in src-tauri/src/lib.rs, backed by an ungated pub const VOICE_COMPILED_IN = cfg!(feature = "voice") in voice/compile_status.rs (re-exported at voice:: in mod.rs, so it resolves in both feature states). Because the const is per-crate and the shell/core are separate Cargo worlds, a future dropped forward can't be masked by feature-unification — it fails the build with E0080 rather than shipping broken again. The pinning test asserts the const tracks the gate in both builds.
  • Frontend half coherent. Typed VoiceNotCompiledError replaces the stale "restart the sidecar" copy with the localized mic.voiceNotCompiled (present in all 14 locales; em-dashes appear only in code comments / the internal Error message, not in any locale value, so the i18n em-dash gate passes).

Non-blocking nits

  1. isVoiceNotCompiledError(err: unknown): boolean → narrow to a type guard err is VoiceNotCompiledError for call-site narrowing (harness posted this inline).
  2. The internal English VoiceNotCompiledError message uses an em dash (— the voice module…). Harmless (it's a code string used for the unavailable in this build substring match, not a translation), but the repo otherwise avoids U+2014 in prose.

Verdict: sound. The diagnosis, the feature-forward fix, and the compile-time guard are all correct and well-tested; CI is effectively green. Deferring the approve/merge decision to the maintainer.

senamakel and others added 2 commits July 16, 2026 00:04
Return `err is VoiceNotCompiledError` instead of a bare boolean so callers
that read `.code`/`.message` after the check get the narrowed type without
re-casting from `unknown`. Behavior unchanged — the body still duck-types on
`code`. Addresses M3gA-Mind review nit on tinyhumansai#4917.

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

Copy link
Copy Markdown
Collaborator

W5 re-review (comment-only — head 9c3a8e14)

Re-reviewed after the new push. Still comment-only; the merge call is the maintainer's.

✅ Nit #1 resolved

isVoiceNotCompiledError is now a proper type guard — err is VoiceNotCompiledError, with the body duck-typing on .code === VOICE_NOT_COMPILED_CODE, which matches the class's readonly code field. Correct narrowing; behavior unchanged. Thanks for the quick turnaround.

⛔ New blocker — AI-attribution trailer on the new commit

Commit 9c3a8e146 ("refactor(voice): narrow isVoiceNotCompiledError to a type guard") ends with:

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

This repo treats Co-Authored-By: Claude … / "Generated with" trailers as a merge blocker. Please strip it (git rebase/commit --amend to drop the trailer, force-push) before this is merged. Not a code issue — purely the commit metadata.

CI

The two earlier "failures" are gone — PR Submission Checklist now passes cleanly at this head. The rest of CI Lite (Frontend Checks, Rust Core/Tauri Coverage, Rust Quality, Feature-Gate Smoke) is still running for 9c3a8e14; no failures so far, and the delta over the previously-green head is just this one type-annotation line plus a routine upstream/main merge, so I don't expect surprises. I'll flag if anything flips red.

Still open (non-blocking, unchanged)

  • The internal VoiceNotCompiledError message uses an em dash (— the voice module…). Harmless (code string, not a translation), just noting the repo otherwise avoids U+2014 in prose.

Verdict: still sound on the code. One non-code merge blocker to clear (drop the AI co-author trailer); CI completing green so far.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 15, 2026
M3gA-Mind
M3gA-Mind previously approved these changes Jul 15, 2026

@M3gA-Mind M3gA-Mind 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.

Approving the code (head 9c3a8e14). The diagnosis and fix are correct and well-guarded:

  • openhuman_core features ["media"]["media","voice"] re-forwards the default-ON gate that default-features=false had been dropping (the root cause of the openhuman.voice_* "unknown method" storm).
  • The compile-time const _: () = assert!(openhuman_core::…::VOICE_COMPILED_IN, …) (ungated per-crate const, separate Cargo world) turns a future regression into a build failure (E0080) instead of a silent ship.
  • Frontend: typed VoiceNotCompiledError → localized mic.voiceNotCompiled across all 14 locales; retry-suppression preserved; isVoiceNotCompiledError is now a proper err is VoiceNotCompiledError type guard.

Two things still to clear before merge (approval is a code sign-off, not a bypass of these):

  1. CI Lite is still running at this head — the required PR CI Gate / Frontend / Rust Coverage jobs haven't reported yet (0 failures so far; the delta over the previously all-green head is one type-annotation line + a routine main merge).
  2. Drop the AI-attribution trailer — commit 9c3a8e146 carries Co-Authored-By: Claude Opus 4.8 …, which this repo blocks merges on. Amending/force-pushing to remove it will change the head SHA and dismiss this approval, so please re-request once it's clean.

The 'surfaces hard errors' test read the host-reported save meta synchronously
after awaiting the error banner, but hasErrors reaches the host via a follow-up
effect (onSaveMetaChange) that can lag the banner render. Under CI's loaded
full-suite run this races, yielding hasErrors: false. Poll with waitFor instead.

Surfaced on tinyhumansai#4917 because its Cargo.toml/lib.rs edits trip CI's full-suite
vitest fallback; the test is otherwise latent-flaky on main.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@CodeGhost21 CodeGhost21 dismissed stale reviews from M3gA-Mind and coderabbitai[bot] via f8648f9 July 15, 2026 22:16
@M3gA-Mind M3gA-Mind merged commit a41c21a into tinyhumansai:main Jul 15, 2026
22 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Team Openhuman Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Voice transcription unavailable — 'Voice transcription is unavailable in this build' error on latest release

3 participants