Skip to content

Bot-review harvest (16 fixes), deterministic style/locale CI, reviewer configs - #1198

Merged
debpalash merged 4 commits into
mainfrom
fix/bot-harvest-review-infra
Jul 20, 2026
Merged

Bot-review harvest (16 fixes), deterministic style/locale CI, reviewer configs#1198
debpalash merged 4 commits into
mainfrom
fix/bot-harvest-review-infra

Conversation

@debpalash

@debpalash debpalash commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Implements the "use the review bots properly" plan end-to-end.

The changelog linter validated this PR's own entries (and rejected my first draft — working as intended).

🤖 Generated with Claude Code

Summary

  • Fixed 16 CodeRabbit/Greptile findings across:

    • ASR fallback/preflight: introduced typed ASRModelMissingError and reran “no-download” missing-weight preflight per fallback candidate to prevent unintended multi‑GB auto-downloads; improved ws_transcribe “ASR model missing” preflight to use the client’s raw ?model= override value; strengthened openai_compat /v1/audio/transcriptions 409 payloads (OmniVoice-aware structured detail + human message).
    • VRAM release on dub-stream failures: added _loaded_asr tracking so the SSE transcription stream reliably force-unloads the loaded ASR backend on early terminal errors and disconnects, with consistent error + done emission.
    • MCP clone_voice robustness: added base64 data: URI stripping, strict base64 decode with typed “invalid base64” errors, and magic-byte extension sniffing for uploaded reference audio (plus improved HTTP/transport/JSON failure selection).
    • Safety/logging + install behavior: sanitized subprocess spawn errors to avoid leaking absolute interpreter/script paths; adjusted uv_subprocess_env() so UV_CACHE_DIR/UV_PYTHON_INSTALL_DIR overrides behave correctly across drives; improved sidecar/env override logic; added KittenTTS graceful degradation if chunk_text import is unavailable; tightened ASR memo reset hermeticity in tests.
  • Added deterministic CI quality gates:

    • Quiet changelog style lint for CHANGELOG.md (date-scoped rules + highlights/one-line bullet/credits/ref checks).
    • Locale parity ratchet tests enforcing key/placeholder parity vs en.json, rejecting corrupted _V_…__ placeholder tokens.
    • Restored 151 broken locale strings (including Vietnamese _V_0__-style corruption).
  • Improved frontend correctness and user-facing error detail:

    • Capture widget race: ensured late microphone errors can’t overwrite an already-final/terminal capture state.
    • Notifications stability: memoized visible-notification filtering and returned shape to avoid unstable references.
    • Gallery error messaging: updated gallery voice/profile error strings across locales to interpolate runtime {{message}}.
    • Dictation routing: restricted ASR→Dictation section mapping to documented dictation tags (with allowlist) for the UI model grouping.

UI changes

CaptureWidget.jsx (startRecording error handling)

Before:
[final/terminal pill shown]  ---- late mic error ----> overwrites pill/toast/error state

After:
if wsHadFinalRef.current === true:
  ignore late mic errors
  stop capture graph early
  preserve terminal pill/toast/error state
Visible notifications hook (useVisibleNotifications)

Before:
render -> filter visible notifications -> new array ref each time

After:
render -> useMemo(filter dismissedNotificationIds by level) -> stable array ref when inputs unchanged

Behavior flow

flowchart TD
  A[ws_transcribe preflight] --> B{ASR model missing?}
  B -->|Yes| C[Derive sherpamodel_id from raw ?model= override (_requested_model)\nclose/error uses the exact client override]

  D[dub_transcribe_stream SSE gen()] --> E[Preflight/load ASR\ntrack loaded backend in _loaded_asr]
  E --> F{Terminal exit / typed error / crash / disconnect?}
  F -->|Yes| G[Emit structured SSE error/done as needed]
  G --> H[Force-unload tracked ASR backend to release VRAM]
  H --> I[Clear _loaded_asr backend to avoid double-unload]

  J[Fallback ASR candidate load] --> K{Missing weights detected?}
  K -->|Yes| L[Raise typed ASRModelMissingError\n(no-download install CTA; no auto-download)]
  K -->|No| M[Load fallback normally]

  N[OpenAI-compat transcription 409] --> O{ASR backend missing (TTS-only install)?}
  O -->|Yes| P[Return structured 409 detail dict + human-readable message]
Loading

Tests & CI

  • Added/expanded regression tests for:
    • typed asr_model_missing behavior under invalid ?model= overrides,
    • dub-stream early termination/unload behavior,
    • fallback preflight “no auto-download” vs cached success,
    • MCP _decode_ref_audio/_sniff_audio_ext (data-URI stripping, invalid base64 -> None, magic-bytes extension inference),
    • subprocess spawn error sanitization (no absolute-path leakage),
    • uv_subprocess_env cross-drive behavior with pinned UV_CACHE_DIR/UV_PYTHON_INSTALL_DIR,
    • frontend timing/race around connect-time typed asr_model_missing during mic setup,
    • notification dismissal row-action behavior and model grouping mapping rules.
  • Added tests/test_changelog_style.py and tests/test_locale_parity.py to enforce deterministic changelog + 21-locale parity with ratchet baselines.

Reviewer/merge-process configuration

  • Updated ​.coderabbit.yaml, greptile.json, and CLAUDE.md to:
    • require Harvest-bot (CodeRabbit + Greptile) review triage before merge,
    • enforce concise “comment only” review brevity,
    • lock down changelog “Unreleased” formatting and allowlisted credit/ref rules,
    • enforce lockfile/version consistency when dependency/version files change,
    • require harvest-before-merge and validation of review suggestions,
    • disable extra non-essential review walkthrough/sections and finishing-touch reporting.

debpalash and others added 2 commits July 20, 2026 09:47
… + reviewer configs

Harvested and verified every CodeRabbit/Greptile finding from PRs #1175,
#1189, #1192, #1195: 16 real ones fixed (fallback ASR preflight bypass,
VRAM release on stream exit, typed 409 parity, uv env independence,
path-privacy in errors, MCP clone_voice hardening, CaptureWidget WS
guard, test hygiene), 4 refuted with evidence, rest documented as
deliberate design or deferred.

Deterministic CI replaces hand-enforcement: tests/test_changelog_style.py
(quiet one-liner format) and tests/test_locale_parity.py (21-locale
key/placeholder lockstep with a ratchet baseline) — the latter surfaced
and fixes 151 already-broken locale strings. CodeRabbit/Greptile carry
the house rules via .coderabbit.yaml + greptile.json; CLAUDE.md gains
the harvest-before-merge and never-accept-as-is rules.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Ignoring CodeRabbit configuration file changes. For security, only the configuration from the base branch is applied for open source repositories.

📝 Walkthrough

Walkthrough

This PR adds typed ASR missing-model handling, reliable streaming cleanup, audio validation, sanitized subprocess errors, frontend race protection, stricter model classification, locale parity checks, changelog linting, and expanded review and merge policies.

Changes

Runtime and quality enforcement

Layer / File(s) Summary
Typed ASR preflight and stream cleanup
backend/api/routers/*, backend/services/asr_backend.py, tests/test_asr_model_missing.py
ASR fallback and override paths emit typed missing-model payloads, while dubbing streams unload loaded backends on completion, errors, and disconnects.
Audio, subprocess, and installation robustness
backend/mcp_server.py, backend/services/sidecar_install.py, backend/services/subprocess_backend.py, backend/services/tts_backend.py, tests/*
Reference audio supports data URIs and detected formats; uv preserves pinned variables; subprocess errors sanitize paths; KittenTTS falls back when chunking imports are unavailable.
Frontend state and model classification
frontend/src/api/hooks.ts, frontend/src/components/*, frontend/src/components/settings/models/sections.js, frontend/src/test/*
Notification filtering is memoized, late microphone failures no longer overwrite terminal WebSocket errors, and dictation routing uses an explicit tag allowlist.
Locale placeholders and gallery errors
frontend/src/i18n/locales/*, tests/test_locale_parity.py
Gallery failures interpolate {{message}}, Vietnamese placeholders are corrected, and locale keys and placeholder sets are validated against English.
Changelog and review policy enforcement
.coderabbit.yaml, greptile.json, CLAUDE.md, CHANGELOG.md, tests/test_changelog_style.py
Automated review rules, merge workflow directives, quiet changelog formatting, and date-scoped changelog tests are added or updated.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Capture
  participant ASRPreflight
  participant ASRStream
  participant ModelBackend
  Client->>Capture: start recording with model override
  Capture->>ASRPreflight: validate requested model
  ASRPreflight-->>Capture: typed missing-model error or proceed
  Client->>ASRStream: start dubbing transcription
  ASRStream->>ModelBackend: load ASR backend
  ModelBackend-->>ASRStream: backend instance
  ASRStream-->>Client: SSE result, error, and done events
  ASRStream->>ModelBackend: unload backend on every terminal path
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 6 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is broad and readable, but it is not conventional-commit style and lacks the required scope and issue reference. Rewrite it as a conventional commit with scope, e.g. fix(review): ..., and include the issue reference in the title or body.
Description check ⚠️ Warning The description covers the work, but it does not follow the required template sections and leaves Type, Testing, Checklist, and Release cadence incomplete. Reformat the PR body to match the template with explicit Summary, Changes, Type, Testing, Checklist, and Release cadence sections.
Docstring Coverage ⚠️ Warning Docstring coverage is 46.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
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.
Cross-Platform Default Parity ✅ Passed PASS: sidecar_install.py:229-269 mirrors setup.rs:226-246; same-volume rule, explicit pins respected, no platform-divergent default found.
I18n Completeness (21 Locales) ✅ Passed HEAD only changes .coderabbit.yaml/greptile.json; no frontend code or locale files changed, and the repo has 21 locale JSONs, so no i18n keys to audit.
Local-First Guarantee ✅ Passed PASS: touched paths stay local/optional (mcp_server.py:119-131, asr_backend.py:2482-2517); PR adds no required cloud calls, keys, or telemetry and blocks silent downloads.
Backward Compatibility ✅ Passed No DB schema/migration changes; ASR preflights fail open and preserve installed repos, and uv cache handling only co-locates new installs—no forced reinstall/re-download.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/bot-harvest-review-infra

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.

_model = _model_task.result()
except Exception as e:
logger.exception("transcribe preflight: model load failed (job=%s)", job_id)
logger.exception("transcribe preflight: model load failed (job=%r)", job_id)
preflight_payload = e.payload
except Exception as e:
logger.exception("transcribe preflight: ASR load failed (job=%s)", job_id)
logger.exception("transcribe preflight: ASR load failed (job=%r)", job_id)
yield ev
except Exception as e: # noqa: BLE001 — last-resort stream finalizer
logger.exception("transcribe stream crashed (job=%s)", job_id)
logger.exception("transcribe stream crashed (job=%r)", job_id)
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR closes the loop on a multi-PR bot-review harvest: 16 real findings are fixed with regression tests, 151 corrupted Vietnamese locale strings are restored, and deterministic CI gates (changelog linter + 21-locale parity ratchet) prevent both classes of drift from recurring.

  • VRAM guard (dub_core.py): _loaded_asr dict parked in the outer closure lets gen()'s finally fire-and-forget an executor unload on every exit path — crash, early terminal return, and GeneratorExit (client disconnect) — not just the normal completion path. The normal path sets _loaded_asr["backend"] = None to prevent double-unload.
  • Fallback preflight (asr_backend.py): ASRModelMissingError + backend_id threading through _offline_asr_repo / asr_model_missing_error ensure the no-download check runs against the specific candidate being loaded, not the persisted global preference, before ensure_loaded() can auto-download multi-GB weights. capture_ws.py passes the raw ?model= string so the preflight follows execution to the Whisper path when an invalid override is given.
  • Quality gates: test_changelog_style.py (lint with epoch-scoped grandfathering), test_locale_parity.py (ratchet + corrupted-token detection, now using warnings.warn for improvements per previous review thread), _clear_asr_installed_memo fixture upgraded to clear stale module aliases, OMNIVOICE_MODEL sentinel is now unconditional to prevent dev-shell leakage.

ASCII before/after — CaptureWidget terminal-state race:

BEFORE  WS error frame ──► wsHadFinalRef=true  Pill: ⚠ No ASR model
        Mic fails late  ──► toast.error("Mic error")  ← OVERWRITES pill/toast

AFTER   WS error frame ──► wsHadFinalRef=true  Pill: ⚠ No ASR model
        Mic fails late  ──► if wsHadFinalRef: stopCaptureGraph(); return  ← preserved

Important Files Changed

Filename Overview
backend/api/routers/dub_core.py Adds _loaded_asr closure + gen() finally block for fire-and-forget executor unload on all exit paths; ASRModelMissingError caught in the ASR-load try/except to surface the typed download CTA. Implementation is correct; companion regression test has a small theoretical race (see comment).
backend/services/asr_backend.py Introduces ASRModelMissingError, backend_id threading through _offline_asr_repo/asr_model_missing_error, and per-candidate preflight in load_active_asr_backend fallback loop. Correctly gates on tried being non-empty so callers handle the first-iteration check.
backend/api/routers/capture_ws.py Passes raw ?model= query param as sherpa_model_id when spec is None so the preflight follows the Whisper execution path instead of the (possibly-installed) persisted sherpa preference. Covered by test_capture_ws_invalid_override_still_preflights_whisper.
backend/mcp_server.py Adds _decode_ref_audio (data-URI stripping + validated base64) and _sniff_audio_ext (magic-byte container detection) helpers; clone_voice catches httpx errors with structured JSON responses. M4A extended-header caveat documented in-code per previous thread.
backend/services/sidecar_install.py uv_subprocess_env now independently gates UV_CACHE_DIR and UV_PYTHON_INSTALL_DIR, returning None only when both are user-pinned. Prevents managed-Python downloads staying on the system drive when only UV_CACHE_DIR is pinned cross-drive.
backend/services/subprocess_backend.py _os_exec_refusal builds the user-visible spawn error from errno/strerror only, avoiding the home-directory path leak that str(OSError) embeds via exc.filename. Log lines reduced to basename-only.
tests/test_locale_parity.py New locale parity test with ratchet, placeholder-match, and corrupted-token checks. Ratchet now uses warnings.warn (not pytest.fail) for improvements, addressing the previous thread's CI-blocking concern.
tests/test_changelog_style.py Deterministic changelog linter with date-epoch scoping, allowlist for owner-authored infra entries, and self-tests that verify each rule actually fires.
frontend/src/components/CaptureWidget.jsx Adds wsHadFinalRef guard in the startRecording catch block so a late mic error/rejection doesn't clobber the already-terminal asr_model_missing state.
frontend/src/api/hooks.ts useVisibleNotifications memoizes the filtered array with useMemo and strips raw data from the return to prevent consumers accidentally reading the unfiltered list.
frontend/src/i18n/locales/vi.json Restores 31 V_0_-corrupted placeholder tokens to their correct {{name}} forms. The locale parity test now gates this class of corruption for all 21 locales.

Reviews (2): Last reviewed commit: "config(review-bots): concise high-signal..." | Re-trigger Greptile

Comment thread backend/services/asr_backend.py
Comment thread tests/test_locale_parity.py
Comment thread backend/mcp_server.py

@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: 2

🧹 Nitpick comments (1)
backend/tests/conftest.py (1)

88-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the stale-module-alias lookup into a shared helper per file. Both _clear_asr_installed_memo and its sibling asr_model_installed fixture independently re-implement the identical import types + vars(test_module) scan for a services.asr_backend alias, now duplicated twice per file (four copies total across the two conftest files). One drift in this correctness-sensitive lookup (e.g., a third target module name) means editing four near-identical blocks instead of one.

  • backend/tests/conftest.py#L88-L111: factor the alias-scan (currently inlined in both asr_model_installed L56-84 and _clear_asr_installed_memo L88-111) into a module-level helper, e.g. _asr_backend_module_aliases(request) -> dict[int, types.ModuleType], and have both fixtures call it.
  • tests/conftest.py#L192-L218: apply the same extraction against asr_model_installed (L157-188) and _clear_asr_installed_memo (L192-218).
♻️ Proposed helper (apply the same shape in both files)
+def _asr_backend_module_aliases(request):
+    """services.asr_backend plus any stale module-typed alias the test
+    module itself holds (see docstrings on the fixtures below)."""
+    import types
+    mod = sys.modules.get("services.asr_backend")
+    targets = {} if mod is None else {id(mod): mod}
+    test_module = getattr(request, "module", None)
+    if test_module is not None:
+        for val in vars(test_module).values():
+            if (isinstance(val, types.ModuleType)
+                    and getattr(val, "__name__", "") == "services.asr_backend"):
+                targets[id(val)] = val
+    return targets.values()
+
 def _clear_asr_installed_memo(request):
     def _clear_all():
-        import types
-        mod = sys.modules.get("services.asr_backend")
-        targets = {} if mod is None else {id(mod): mod}
-        test_module = getattr(request, "module", None)
-        if test_module is not None:
-            for val in vars(test_module).values():
-                if (isinstance(val, types.ModuleType)
-                        and getattr(val, "__name__", "") == "services.asr_backend"):
-                    targets[id(val)] = val
-        for m in targets.values():
+        for m in _asr_backend_module_aliases(request):
             getattr(m, "_INSTALLED_REPO_MEMO", set()).clear()
     _clear_all()
     yield
     _clear_all()
🤖 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 `@backend/tests/conftest.py` around lines 88 - 111, Extract the duplicated
stale-module alias scan into a shared module-level helper in
backend/tests/conftest.py, such as _asr_backend_module_aliases(request), and
update both asr_model_installed and _clear_asr_installed_memo to reuse it. Apply
the same extraction and fixture updates in tests/conftest.py, including the
affected _clear_asr_installed_memo site at tests/conftest.py lines 192-218;
preserve the canonical module handling and deduplication by module identity.
🤖 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 `@backend/api/routers/dub_core.py`:
- Around line 1324-1334: Update the ASR cleanup around _b.unload() in the
finally block and the normal completion path to dispatch unload execution
through a thread-pool executor instead of calling it directly from the async
path. In the finally block, schedule the background cleanup so client-disconnect
CancelledError cannot abort the unload, while preserving the existing warning
logging for unload failures.

In `@tests/test_changelog_style.py`:
- Around line 85-86: Rename the generator variable `l` to `line` in both `any`
expressions defining `has_subsections` and `has_highlights`, updating each
`startswith` and `strip` reference while preserving the existing checks.

---

Nitpick comments:
In `@backend/tests/conftest.py`:
- Around line 88-111: Extract the duplicated stale-module alias scan into a
shared module-level helper in backend/tests/conftest.py, such as
_asr_backend_module_aliases(request), and update both asr_model_installed and
_clear_asr_installed_memo to reuse it. Apply the same extraction and fixture
updates in tests/conftest.py, including the affected _clear_asr_installed_memo
site at tests/conftest.py lines 192-218; preserve the canonical module handling
and deduplication by module identity.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 48647cb4-b345-467a-8deb-3b27a86b6890

📥 Commits

Reviewing files that changed from the base of the PR and between c4f2621 and 07c44dc.

📒 Files selected for processing (49)
  • .coderabbit.yaml
  • CHANGELOG.md
  • CLAUDE.md
  • backend/api/routers/capture_ws.py
  • backend/api/routers/dub_core.py
  • backend/api/routers/openai_compat.py
  • backend/mcp_server.py
  • backend/services/asr_backend.py
  • backend/services/sidecar_install.py
  • backend/services/subprocess_backend.py
  • backend/services/tts_backend.py
  • backend/tests/conftest.py
  • docs/generation-parameters.md
  • docs/install/macos.md
  • docs/install/troubleshooting.md
  • frontend/src/api/hooks.ts
  • frontend/src/components/CaptureWidget.jsx
  • frontend/src/components/settings/models/sections.js
  • frontend/src/i18n/locales/ar.json
  • frontend/src/i18n/locales/de.json
  • frontend/src/i18n/locales/es.json
  • frontend/src/i18n/locales/fr.json
  • frontend/src/i18n/locales/hi.json
  • frontend/src/i18n/locales/id.json
  • frontend/src/i18n/locales/it.json
  • frontend/src/i18n/locales/ja.json
  • frontend/src/i18n/locales/ko.json
  • frontend/src/i18n/locales/nl.json
  • frontend/src/i18n/locales/pl.json
  • frontend/src/i18n/locales/pt.json
  • frontend/src/i18n/locales/ru.json
  • frontend/src/i18n/locales/sv.json
  • frontend/src/i18n/locales/th.json
  • frontend/src/i18n/locales/tr.json
  • frontend/src/i18n/locales/uk.json
  • frontend/src/i18n/locales/vi.json
  • frontend/src/i18n/locales/zh-CN.json
  • frontend/src/i18n/locales/zh-TW.json
  • frontend/src/test/CaptureWidgetSetupRace.test.jsx
  • frontend/src/test/LogsFooterNotifications.test.jsx
  • frontend/src/test/modelStoreGrouping.test.jsx
  • greptile.json
  • tests/backend/services/test_binary_preflight.py
  • tests/conftest.py
  • tests/test_asr_model_missing.py
  • tests/test_changelog_style.py
  • tests/test_locale_parity.py
  • tests/test_mcp_mount.py
  • tests/test_uv_cross_drive.py

Comment thread backend/api/routers/dub_core.py Outdated
Comment thread tests/test_changelog_style.py Outdated
- fallback preflight pins the candidate backend id (Greptile) — also the
  CI empty-cache failure: deep-import fall-through tests get the
  asr_model_installed fixture
- locale ratchet: improvement warns instead of failing CI (CodeRabbit)
- stream-exit ASR unload runs on the GPU pool fire-and-forget instead of
  blocking the event loop (CodeRabbit)
- E741 rename; M4A ftyp sniff scope documented (CodeRabbit)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment on lines +1341 to +1343
lambda f: f.cancelled()
or (f.exception() and logger.warning(
"Failed to unload ASR backend: %s", f.exception()))

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/api/routers/dub_core.py (1)

1279-1282: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Blocking call inside async path (normal completion).

The finally block was successfully updated to dispatch the unload to the GPU pool, but the normal completion path still calls _asr_backend.unload() directly. As noted in the previous review, this blocks the ASGI event loop (due to gc.collect() and CUDA cache drops) and degrades responsiveness for all concurrent requests.

Since this path does not run under GeneratorExit, you can simply await the executor dispatch using the existing loop and _gpu_pool.

🚀 Proposed fix to prevent event loop blocking
-            try:
-                _asr_backend.unload()
-            except Exception as e:
+            try:
+                await loop.run_in_executor(_gpu_pool, _asr_backend.unload)
+            except Exception as e:
🤖 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 `@backend/api/routers/dub_core.py` around lines 1279 - 1282, Update the
normal-completion cleanup path around _asr_backend.unload() to dispatch
unloading through the existing loop and _gpu_pool, awaiting the executor result
instead of calling unload directly. Preserve the current exception handling and
warning message while ensuring the async event loop is not blocked.
🧹 Nitpick comments (1)
backend/api/routers/dub_core.py (1)

1348-1351: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Suppress Ruff blind-exception warning.

You can add a noqa comment to silence the BLE001 warning for this best-effort fallback, maintaining consistency with the outer stream finalizer.

✨ Proposed fix to silence the warning
-                    try:
-                        _b.unload()
-                    except Exception as e:
+                    try:
+                        _b.unload()
+                    except Exception as e:  # noqa: BLE001 - best-effort teardown
🤖 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 `@backend/api/routers/dub_core.py` around lines 1348 - 1351, Add a Ruff `noqa:
BLE001` suppression to the broad exception handler around `_b.unload()` in the
ASR backend cleanup path, matching the existing outer stream finalizer
convention while preserving the best-effort warning log.

Source: Linters/SAST tools

🤖 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.

Outside diff comments:
In `@backend/api/routers/dub_core.py`:
- Around line 1279-1282: Update the normal-completion cleanup path around
_asr_backend.unload() to dispatch unloading through the existing loop and
_gpu_pool, awaiting the executor result instead of calling unload directly.
Preserve the current exception handling and warning message while ensuring the
async event loop is not blocked.

---

Nitpick comments:
In `@backend/api/routers/dub_core.py`:
- Around line 1348-1351: Add a Ruff `noqa: BLE001` suppression to the broad
exception handler around `_b.unload()` in the ASR backend cleanup path, matching
the existing outer stream finalizer convention while preserving the best-effort
warning log.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e04104f3-0296-48f6-858d-116b6e93a05e

📥 Commits

Reviewing files that changed from the base of the PR and between 07c44dc and 0c7428b.

📒 Files selected for processing (6)
  • backend/api/routers/dub_core.py
  • backend/mcp_server.py
  • backend/services/asr_backend.py
  • backend/tests/test_asr_deep_import_fallback.py
  • tests/test_changelog_style.py
  • tests/test_locale_parity.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/test_locale_parity.py
  • backend/mcp_server.py
  • tests/test_changelog_style.py

Owner directive: no fluff on PRs. Greptile: logic-only comments at max
strictness, no diagrams/confidence sections, summary collapsed.
CodeRabbit: three-sentence findings, no sequence diagrams or ASCII
sketches, collapsed walkthrough, no per-push status comments, finishing
touches off. Both: comment only when a finding changes what merges.

Co-Authored-By: Claude Fable 5 <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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.coderabbit.yaml (1)

120-127: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Synchronize the changelog policy with the shipped format.

Both review configurations would flag the current CHANGELOG.md because its Unreleased content includes ### CI and ### Docs entries without (#NNN) references.

  • .coderabbit.yaml#L120-L127: update the rule or change CHANGELOG.md and its parity tests.
  • greptile.json#L15-L19: apply the same rule change so the two reviewers enforce one contract.
🤖 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 @.coderabbit.yaml around lines 120 - 127, Synchronize the CHANGELOG.md review
policy with the shipped Unreleased format: update the rule at .coderabbit.yaml
lines 120-127 and apply the identical contract at greptile.json lines 15-19, or
consistently update CHANGELOG.md and its parity tests instead. Ensure both
reviewers handle the existing CI and Docs sections without conflicting reference
requirements.
🤖 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 `@greptile.json`:
- Around line 3-5: Update the commentTypes configuration in the Greptile
instructions to retain syntax alongside logic, or widen the list to cover all
categories required by the review policy; do not leave syntax excluded.

---

Outside diff comments:
In @.coderabbit.yaml:
- Around line 120-127: Synchronize the CHANGELOG.md review policy with the
shipped Unreleased format: update the rule at .coderabbit.yaml lines 120-127 and
apply the identical contract at greptile.json lines 15-19, or consistently
update CHANGELOG.md and its parity tests instead. Ensure both reviewers handle
the existing CI and Docs sections without conflicting reference requirements.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 95b2ffde-c3cb-4242-913b-e17aea1dca38

📥 Commits

Reviewing files that changed from the base of the PR and between 0c7428b and 8357e89.

📒 Files selected for processing (2)
  • .coderabbit.yaml
  • greptile.json

Comment thread greptile.json
Comment on lines +3 to +5
"instructions": "Review as a panel of senior domain experts (ML inference, audio DSP, desktop systems). Comment ONLY on findings that would change what gets merged: a concrete bug, a violated house rule from CLAUDE.md, a real security/data risk. Per finding: at most three sentences — failure mode, line, fix. No praise, no restating the diff, no diagrams or mockups, no style commentary (CI linters gate style), no info-level observations. If nothing meets the bar, leave no comments. OmniVoice is a fully-local desktop app (no cloud, no API keys, no telemetry): flag any new outbound network call that is not GitHub Issues or a HuggingFace model download.",
"commentTypes": ["logic"],
"strictness": 3,

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== greptile.json =="
nl -ba greptile.json | sed -n '1,80p'

echo
echo "== repo files mentioning greptile/commentTypes =="
rg -n --hidden --glob '!**/.git/**' 'commentTypes|greptile' .

echo
echo "== candidate docs around Greptile config =="
fd -a -H -I 'CLAUDE.md|README.md|greptile.*|\.coderabbit.*' .

Repository: debpalash/OmniVoice-Studio

Length of output: 224


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== greptile.json =="
nl -ba greptile.json | sed -n '1,120p'

Repository: debpalash/OmniVoice-Studio

Length of output: 224


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== exact greptile.json lines =="
nl -ba greptile.json | sed -n '1,40p'

echo
echo "== any local mention of commentTypes semantics =="
rg -n --hidden --glob '!**/.git/**' 'commentTypes|syntax|logic|Greptile' . || true

Repository: debpalash/OmniVoice-Studio

Length of output: 236


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== greptile.json =="
python3 - <<'PY'
from pathlib import Path
for i, line in enumerate(Path("greptile.json").read_text().splitlines(), 1):
    print(f"{i:>4} {line}")
PY

echo
echo "== local mentions of Greptile/commentTypes =="
rg -n --hidden --glob '!**/.git/**' 'commentTypes|Greptile|greptile' . || true

Repository: debpalash/OmniVoice-Studio

Length of output: 6755


🌐 Web query:

Greptile config commentTypes logic syntax official docs

💡 Result:

In Greptile, the commentTypes configuration allows you to filter the categories of feedback generated during code reviews [1][2]. Syntax and Configuration The setting is defined as an array of strings within your configuration file, either.greptile/config.json (recommended) or the legacy root greptile.json [3][1]. { "commentTypes": ["logic", "syntax"] } Valid Options By default, all four categories are enabled [1][2]. You can restrict the feedback to any subset of the following strings [4][1]: - logic: Flags business logic issues, algorithmic problems, and potential bugs [1][2]. - syntax: Flags language-specific best practices and proper usage patterns [1][2]. - style: Flags code formatting, naming conventions, and structural consistency [1][2]. - info: Provides informational comments about code context and patterns [4][1]. Key Details - Scope: The array you provide completely replaces the default [1]. If you specify only one type (e.g., ["logic"]), Greptile will ignore all other categories [1]. - Hierarchy: If using.greptile/config.json in a monorepo or nested directory structure, child configurations can override parent settings [3][1]. - Recommendation: Greptile officially recommends using.greptile/config.json for new and existing repositories [4][1].

Citations:


Keep syntax in Greptile’s commentTypes list.
Line 4 replaces the default categories, so ["logic"] drops every non-logic finding. That can hide real merge blockers from Greptile; add syntax back at minimum, or widen the set to match the review policy.

🤖 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 `@greptile.json` around lines 3 - 5, Update the commentTypes configuration in
the Greptile instructions to retain syntax alongside logic, or widen the list to
cover all categories required by the review policy; do not leave syntax
excluded.

Source: MCP tools

@debpalash
debpalash merged commit e7cb322 into main Jul 20, 2026
16 checks passed
@debpalash
debpalash deleted the fix/bot-harvest-review-infra branch July 20, 2026 04:52
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.

2 participants