Skip to content

Phase 1 Wave 2: per-OS install docs + Settings UI + error→docs deeplinks - #94

Merged
debpalash merged 5 commits into
mainfrom
phase-1-wave-2-docs-settings-ui
May 20, 2026
Merged

Phase 1 Wave 2: per-OS install docs + Settings UI + error→docs deeplinks#94
debpalash merged 5 commits into
mainfrom
phase-1-wave-2-docs-settings-ui

Conversation

@debpalash

@debpalash debpalash commented May 20, 2026

Copy link
Copy Markdown
Owner

Summary

Phase 1 Wave 2 of the v0.3.x stabilisation milestone. Closes 11 requirements in one PR:

  • INST-02, INST-06, DOCS-01..05 — splits the 600-line README install section into self-contained per-OS docs (docs/install/{macos,windows,linux,docker}.md + troubleshooting.md + engines/cosyvoice.md + features/diarization.md + setup/huggingface-token.md), plus the docs-drift CI gate (scripts/validate-install-docs.py) and its B-5 self-test suite (10 tests).
  • INST-03 — macOS Gatekeeper docs anchor (backend detection lives in Wave 3 per the plan).
  • INST-12 (full) — Windows torch.compile OOM workaround. Docs section in windows.md#torch-compile-oom + Settings → Performance toggle (backend /api/settings/perf/torch-compile-disabled + frontend PerformancePanel). Honoured by new backend/services/engine_env.build_engine_env() helper on win32.
  • AUTH-03 (UI half) — Settings → API Keys panel. Consumes the Wave 1 resolver state endpoint, renders 3 source rows (App / Env / HF CLI) with masked previews, whoami status, and an Active badge on whichever source is serving the cascade. Save/Clear actions round-trip to the Wave 1 POST/DELETE endpoints. REQUIREMENTS.md row flipped to Done.
  • error→docs deeplinks — new backend/core/links.py (single source of truth for the repo URL; resolves Tauri config → pyproject fallback per checker B-6), new backend/core/error_docs_map.py + TS mirror at frontend/src/utils/errorDocsMap.ts, ErrorBoundary wired to render an "Open docs for this error" button that classifies the error message and opens the right docs anchor via the existing Tauri opener path.

Deeplink-map symbol: backend/core/error_docs_map.lookup() / frontend/src/utils/errorDocsMap.openDocsFor().

Docs files added (8)

  • docs/install/macos.md (Gatekeeper anchor)
  • docs/install/windows.md (torch-compile-oom anchor, setx warning)
  • docs/install/linux.md (AppImage white-screen anchor, .deb ffprobe anchor, restricted-networks section)
  • docs/install/docker.md (LAN access anchor)
  • docs/install/troubleshooting.md (top 10 install errors with cause/fix/issue links)
  • docs/engines/cosyvoice.md (closes Help with installation off (CosyVoice 3) #55 docs half)
  • docs/features/diarization.md (pyannote license + fallback behaviour)
  • docs/setup/huggingface-token.md (3-source cascade end-to-end)

README dropped from 585 → 405 lines.

Test results

  • 8 new test files, 53 new tests, all green.
  • Wave 1 regression: tests/backend/services/test_token_resolver.py tests/backend/services/test_settings_store.py tests/backend/core/test_logging_filter.py tests/backend/test_engine_spawn_token.py35 passed.
  • Phase 0 smoke: tests/smoke/4 passed.
  • Frontend: bunx vitest run51 passed across 7 files.
  • python scripts/validate-install-docs.py → exit 0.

CI changes

.github/workflows/ci.yml gains a new "Validate install docs against desktop-prod.sh" step in the existing test job (Linux-only — docs are platform-agnostic). The validator's own B-5 self-tests run as part of the existing pytest tests/ step.

Test plan

  • All new tests pass
  • Wave 1 tests still pass
  • Phase 0 smoke still passes
  • python scripts/validate-install-docs.py runs clean
  • Manual: open the running app, navigate to Settings → Credentials, verify the API Keys panel renders 3 rows with the cascade state
  • Manual: navigate to Settings → Credentials, verify the Performance toggle renders disabled on macOS/Linux with the explainer, enabled on a Windows host
  • Manual: open https://github.com/debpalash/OmniVoice-Studio/blob/main/docs/install/macos.md#gatekeeper-quarantine after merge — must 404-free
  • Manual: trigger an error in a child of ErrorBoundary, confirm the "Open docs for this error" button opens the right docs anchor in the browser

See .planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md for the full implementation report, the 4-class taxonomy lock, drift-site acknowledgments (per checker W-3), and the Phase 2 SubprocessBackend integration note for engine_env.build_engine_env.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • "Open docs for this error" button on error screens.
    • API Keys panel: view/save/clear HuggingFace token across App/Env/CLI with test button.
    • Performance panel: Windows-only "Disable torch.compile" toggle.
  • Documentation

    • Complete platform install guides (macOS, Windows, Linux, Docker), expanded troubleshooting, diarization, CosyVoice engine, and revised Hugging Face token setup; condensed Quickstart.
  • Chores

    • CI step added to validate install docs; updated .gitignore.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds per-OS installation docs and README updates; a CI validator ensuring docs' validated code blocks match scripts/desktop-prod.sh; backend repo/DEEPLINK URL and error-docs mapping; settings storage and perf toggle API; centralized engine env builder and sonitranslate integration; frontend ErrorBoundary docs action; ApiKeys and Performance settings UIs; and tests across layers.

Changes

Phase 1 Wave 2: Installation, Error UX, Settings

Layer / File(s) Summary
Repository URL and error docs contract
backend/core/links.py, backend/core/error_docs_map.py, frontend/src/utils/errorDocsMap.ts, tests/backend/core/test_links.py, tests/backend/core/test_error_docs_map.py, frontend/src/utils/errorDocsMap.test.ts
Exports a single PROJECT_REPO_URL/PROJECT_REPO_BLOB_MAIN, maps error-class keys → docs URLs, provides lookup/classify/url-open helpers, and enforces a locked 4-class taxonomy across backend and frontend.
Backend perf setting API & non-secret settings
backend/services/settings_store.py, backend/api/routers/settings.py, tests/backend/test_perf_settings.py
Adds get_text/set_text for plain-text settings, exposes GET/PUT /api/settings/perf/torch-compile-disabled persisting "1"/"0", and tests persistence, client-address rejection, and storage semantics.
Engine env builder & sonitranslate wiring
backend/services/engine_env.py, backend/services/sonitranslate.py, tests/backend/test_perf_settings.py
Introduces build_engine_env(base_env..., inject_hf_token=True) that injects HF token and on Windows conditionally sets TORCH_COMPILE_DISABLE from persisted flag; sonitranslate.start() now uses this helper.
Installation documentation, validator, and CI/metadata
docs/install/*, docs/setup/huggingface-token.md, README.md, scripts/validate-install-docs.py, tests/scripts/test_validate_install_docs.py, .github/workflows/ci.yml, .gitignore, .planning/*
Adds full per-OS install guides, token/setup/troubleshooting docs, updates README quickstart, introduces a CI validator that compares <!-- validate --> code block contents to scripts/desktop-prod.sh with normalization and skip markers; integrates validator into CI; updates .gitignore and planning traceability docs.
ErrorBoundary docs action & styles
frontend/src/components/ErrorBoundary.jsx, frontend/src/components/ErrorBoundary.test.jsx, frontend/src/components/WaveformErrorBoundary.css
Adds an "Open docs for this error" button wired to classifyError/openDocsFor, with new styles and tests validating classification-to-open behavior.
Frontend ApiKeys & Performance panels
frontend/src/components/settings/ApiKeysPanel.jsx, frontend/src/components/settings/ApiKeysPanel.css, frontend/src/components/settings/ApiKeysPanel.test.jsx, frontend/src/components/settings/PerformancePanel.jsx, frontend/src/components/settings/PerformancePanel.css, frontend/src/components/settings/PerformancePanel.test.jsx, frontend/src/pages/Settings.jsx
Introduces ApiKeysPanel showing App/Env/HF-CLI cascade with save/clear/test flows and masking; PerformancePanel exposes Windows-only torch.compile toggle with GET/PUT; both have CSS, tests, and are composed into Settings page (HF_TOKEN filtered from legacy renderer).

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

"A rabbit hops through docs and tests,
validating every nest—
tokens stored, errors linked, CI blessed." 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.46% 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
Title check ✅ Passed The PR title clearly summarizes the main deliverables: per-OS install docs, Settings UI panels, and error-to-docs deeplinks, which are the primary focus of Phase 1 Wave 2.
Description check ✅ Passed The PR description is comprehensive and well-structured, including a clear summary, detailed list of changes, docs files added, test results, CI changes, and a test plan. It follows the template structure and provides sufficient context.
Linked Issues check ✅ Passed The PR fulfills the requirement from linked issue #55 by adding comprehensive CosyVoice 3 documentation (docs/engines/cosyvoice.md) with installation steps, configuration guidance, and troubleshooting for common failure modes.
Out of Scope Changes check ✅ Passed All changes are properly scoped to the Phase 1 Wave 2 requirements. Documentation additions, Settings UI, error-docs integration, and infrastructure (CI validator, links resolver) are directly tied to the 11 closed requirements.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch phase-1-wave-2-docs-settings-ui

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 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: 5

🧹 Nitpick comments (2)
tests/scripts/test_validate_install_docs.py (1)

75-94: ⚡ Quick win

Lock the file+line diagnostic contract with an explicit line-number assertion.

This test should also assert the exact :line to prevent regressions in drift-location reporting.

Proposed assertion addition
 def test_drift_introduced_fails(validator_module, tmp_path, capsys):
@@
     assert code == 1
     assert "macos.md" in out.err
+    assert "docs/install/macos.md:5" in out.err
     assert "this-line-does-not-exist-in-the-script" in out.err
🤖 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 `@tests/scripts/test_validate_install_docs.py` around lines 75 - 94, Update the
test_drift_introduced_fails to assert the exact file:line diagnostic by checking
the stderr contains the specific line number for the failing snippet; locate the
test function test_drift_introduced_fails and after calling
validator_module.main(root=...) and reading capsys.readouterr(), add an
assertion that out.err includes the "macos.md:NN" pattern (replace NN with the
expected line number where the invalid line appears in the generated diagnostic)
so the file+line contract is locked down and regressions in drift-location
reporting are prevented.
backend/services/sonitranslate.py (1)

150-158: ⚡ Quick win

Avoid duplicate HF token resolution in start().

build_engine_env() already resolves/injects HF token by default, so resolving again here duplicates work and can add startup latency.

♻️ Proposed fix
-    from services import engine_env, token_resolver
-    resolved = token_resolver.resolve()
-    env = engine_env.build_engine_env()
+    from services import engine_env, token_resolver
+    resolved = token_resolver.resolve()
+    env = engine_env.build_engine_env(inject_hf_token=False)
🤖 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/services/sonitranslate.py` around lines 150 - 158, Remove the
redundant token resolution in start(): drop the call to token_resolver.resolve()
and the conditional block that sets env["HF_TOKEN"] and env["YOUR_HF_TOKEN"],
and rely on engine_env.build_engine_env() to populate HF token already; update
the start() function to only call env = engine_env.build_engine_env() (keeping a
brief comment if desired) and ensure downstream code reads HF_TOKEN from env
rather than resolving again.
🤖 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
@.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md:
- Line 17: Update the DOCS-02 closure note (the table row labelled "DOCS-02") so
its description reflects the actual scope: replace "Per-OS install pages live
and end-to-end." with wording about implementing error→docs mapping and deeplink
support (e.g., "Error-to-docs mapping and deeplink support implemented and
validated"). Ensure you edit the table cell for DOCS-02 in the SUMMARY.md so it
accurately describes the error→docs/deeplink work.

In @.planning/REQUIREMENTS.md:
- Around line 221-223: Update the requirements table to fix traceability:
replace the current note for DOCS-02 so it describes the "error→docs map"
requirement instead of "per-OS install pages" (ensure the DOCS-02 cell text
matches the intended error-to-documentation mapping), and remove or reconcile
the duplicate INST-12 entry so there's a single INST-12 row with the correct
status (choose either Done or Pending as the authoritative status and delete the
other duplicate row or merge notes). Ensure the table remains syntactically
valid after editing.

In `@docs/install/linux.md`:
- Around line 106-127: Update the Restricted networks section to include an
Aliyun fallback and explicit Russia guidance: add a second UV_DEFAULT_INDEX
example pointing to https://mirrors.aliyun.com/pypi/simple as a China fallback
alongside the existing Tsinghua mirror, keep the UV_PYTHON_INSTALL_MIRROR,
UV_PYTHON_PREFERENCE, UV_HTTP_TIMEOUT and UV_HTTP_RETRIES lines as-is, and
append a short note that Russia currently has no blessed PyPI mirror and users
should tunnel via VPN/proxy (or use an organization-approved internal mirror) to
reach the default PyPI index.

In `@frontend/src/components/settings/PerformancePanel.test.jsx`:
- Around line 46-49: The test currently clicks the 'torch-compile-toggle'
immediately after waiting for its existence which can be disabled initially;
update the test to wait until the toggle is enabled before clicking by changing
the waitFor call that now only checks getByTestId to assert the element is not
disabled (e.g., waitFor(() =>
expect(screen.getByTestId('torch-compile-toggle')).not.toBeDisabled())) and then
call fireEvent.click on screen.getByTestId('torch-compile-toggle'); keep
references to the same testid and functions (screen.getByTestId, waitFor,
fireEvent.click) so the PUT will fire reliably.

In `@scripts/validate-install-docs.py`:
- Around line 100-108: The code records block_start from the marker line
(pending_marker[0]) so reported drift line numbers point to the marker rather
than the first command line; change the logic so you capture the first body line
number (e.g., set body_start = i before appending the first element to
block_lines) and append body_start (not block_start) to blocks along with the
joined block_lines and skip flag; apply the same change to the duplicate
occurrence around the block handling at the other location referenced (the
similar code at lines 167-168).

---

Nitpick comments:
In `@backend/services/sonitranslate.py`:
- Around line 150-158: Remove the redundant token resolution in start(): drop
the call to token_resolver.resolve() and the conditional block that sets
env["HF_TOKEN"] and env["YOUR_HF_TOKEN"], and rely on
engine_env.build_engine_env() to populate HF token already; update the start()
function to only call env = engine_env.build_engine_env() (keeping a brief
comment if desired) and ensure downstream code reads HF_TOKEN from env rather
than resolving again.

In `@tests/scripts/test_validate_install_docs.py`:
- Around line 75-94: Update the test_drift_introduced_fails to assert the exact
file:line diagnostic by checking the stderr contains the specific line number
for the failing snippet; locate the test function test_drift_introduced_fails
and after calling validator_module.main(root=...) and reading
capsys.readouterr(), add an assertion that out.err includes the "macos.md:NN"
pattern (replace NN with the expected line number where the invalid line appears
in the generated diagnostic) so the file+line contract is locked down and
regressions in drift-location reporting are prevented.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 610288f7-e06e-4600-89ac-2bdff1e93599

📥 Commits

Reviewing files that changed from the base of the PR and between a32828e and c071645.

📒 Files selected for processing (37)
  • .github/workflows/ci.yml
  • .gitignore
  • .planning/REQUIREMENTS.md
  • .planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md
  • README.md
  • backend/api/routers/settings.py
  • backend/core/error_docs_map.py
  • backend/core/links.py
  • backend/services/engine_env.py
  • backend/services/settings_store.py
  • backend/services/sonitranslate.py
  • docs/engines/cosyvoice.md
  • docs/features/diarization.md
  • docs/install/docker.md
  • docs/install/linux.md
  • docs/install/macos.md
  • docs/install/troubleshooting.md
  • docs/install/windows.md
  • docs/setup/huggingface-token.md
  • frontend/src/components/ErrorBoundary.jsx
  • frontend/src/components/ErrorBoundary.test.jsx
  • frontend/src/components/WaveformErrorBoundary.css
  • frontend/src/components/settings/ApiKeysPanel.css
  • frontend/src/components/settings/ApiKeysPanel.jsx
  • frontend/src/components/settings/ApiKeysPanel.test.jsx
  • frontend/src/components/settings/PerformancePanel.css
  • frontend/src/components/settings/PerformancePanel.jsx
  • frontend/src/components/settings/PerformancePanel.test.jsx
  • frontend/src/pages/Settings.jsx
  • frontend/src/utils/errorDocsMap.test.ts
  • frontend/src/utils/errorDocsMap.ts
  • scripts/validate-install-docs.py
  • tests/backend/core/test_error_docs_map.py
  • tests/backend/core/test_links.py
  • tests/backend/test_perf_settings.py
  • tests/scripts/__init__.py
  • tests/scripts/test_validate_install_docs.py

| INST-06 | Done | `scripts/validate-install-docs.py` + CI gate (`.github/workflows/ci.yml` new "Validate install docs" step). |
| INST-12 | Done (full) | Windows torch.compile OOM docs in `windows.md#torch-compile-oom` + Settings → Performance toggle (backend `/api/settings/perf/torch-compile-disabled` + frontend `PerformancePanel`). Honoured by `backend/services/engine_env.build_engine_env()` on win32. |
| DOCS-01 | Done | `docs/install/troubleshooting.md` ships 10 entries with cause / fix / linked-issue. |
| DOCS-02 | Done | Per-OS install pages live and end-to-end. |

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Correct DOCS-02 closure note to match the actual requirement.

DOCS-02 is the error→docs mapping/deeplink work, not per-OS install pages.

Proposed wording fix
-| DOCS-02 | Done | Per-OS install pages live and end-to-end. |
+| DOCS-02 | Done | Error→docs mapping shipped (`backend/core/error_docs_map.py` + `frontend/src/utils/errorDocsMap.ts`) and wired into UI deeplinks. |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| DOCS-02 | Done | Per-OS install pages live and end-to-end. |
| DOCS-02 | Done | Error→docs mapping shipped (`backend/core/error_docs_map.py` + `frontend/src/utils/errorDocsMap.ts`) and wired into UI deeplinks. |
🤖 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
@.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md
at line 17, Update the DOCS-02 closure note (the table row labelled "DOCS-02")
so its description reflects the actual scope: replace "Per-OS install pages live
and end-to-end." with wording about implementing error→docs mapping and deeplink
support (e.g., "Error-to-docs mapping and deeplink support implemented and
validated"). Ensure you edit the table cell for DOCS-02 in the SUMMARY.md so it
accurately describes the error→docs/deeplink work.

Comment thread .planning/REQUIREMENTS.md
Comment on lines +221 to +223
| INST-12 | Phase 1 | Done (Wave 2 — Disable torch.compile (Windows) toggle, backend + UI) |
| DOCS-01 | Phase 1 | Done (Wave 2 — troubleshooting.md top-10 entries) |
| DOCS-02 | Phase 1 | Done (Wave 2 — per-OS install pages) |

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix traceability inconsistencies for DOCS-02 and duplicate INST-12.

DOCS-02 is the error→docs map requirement, but its note currently describes per-OS install pages. Also, INST-12 is listed twice with conflicting statuses (Done and Pending).

Proposed correction
-| DOCS-02 | Phase 1 | Done (Wave 2 — per-OS install pages) |
+| DOCS-02 | Phase 1 | Done (Wave 2 — error→docs URL map + contextual deeplink button) |
@@
-| INST-12 | Phase 1 | Pending |

Also applies to: 252-252

🤖 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 @.planning/REQUIREMENTS.md around lines 221 - 223, Update the requirements
table to fix traceability: replace the current note for DOCS-02 so it describes
the "error→docs map" requirement instead of "per-OS install pages" (ensure the
DOCS-02 cell text matches the intended error-to-documentation mapping), and
remove or reconcile the duplicate INST-12 entry so there's a single INST-12 row
with the correct status (choose either Done or Pending as the authoritative
status and delete the other duplicate row or merge notes). Ensure the table
remains syntactically valid after editing.

Comment thread docs/install/linux.md
Comment on lines +106 to +127
## Restricted networks (China / Russia)

If `uv` times out fetching the python-build-standalone tarball or PyPI:

```bash
# Use a faster Python source mirror (China only — verify a current mirror)
export UV_PYTHON_INSTALL_MIRROR=https://ghproxy.com/https://github.com/astral-sh/python-build-standalone/releases/download

# Use a PyPI mirror
export UV_DEFAULT_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple

# Or skip the download entirely if you have a compatible system Python
export UV_PYTHON_PREFERENCE=only-system

# Be tolerant of slow links
export UV_HTTP_TIMEOUT=120
export UV_HTTP_RETRIES=5
```

The Phase 3 install milestone (INST-07..11) ships an OS-level mirror cascade
that picks these defaults automatically; for v0.3 set them by hand.

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add Aliyun fallback and explicit Russia VPN guidance in restricted-network instructions.

Line 106 onward documents UV_PYTHON_INSTALL_MIRROR and Tsinghua, but it doesn’t include the required Aliyun fallback or explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN.

Suggested doc patch
 ## Restricted networks (China / Russia)

 If `uv` times out fetching the python-build-standalone tarball or PyPI:

 ```bash
 # Use a faster Python source mirror (China only — verify a current mirror)
 export UV_PYTHON_INSTALL_MIRROR=https://ghproxy.com/https://github.com/astral-sh/python-build-standalone/releases/download

-# Use a PyPI mirror
+# Use a PyPI mirror (China primary)
 export UV_DEFAULT_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple
+
+# Fallback mirror (China)
+export UV_DEFAULT_INDEX=https://mirrors.aliyun.com/pypi/simple

 # Or skip the download entirely if you have a compatible system Python
 export UV_PYTHON_PREFERENCE=only-system

 # Be tolerant of slow links
 export UV_HTTP_TIMEOUT=120
 export UV_HTTP_RETRIES=5

+For Russia: there is currently no blessed PyPI mirror. Use a VPN/proxy tunnel to
+reach the default PyPI index (or your organization-approved internal mirror).

</details>

As per coding guidelines, "Installation documentation: Document `UV_PYTHON_INSTALL_MIRROR` and region-specific PyPI mirrors (Tsinghua for China, Aliyun fallback) with explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN".

<details>
<summary>🤖 Prompt for AI Agents</summary>

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

In @docs/install/linux.md around lines 106 - 127, Update the Restricted networks
section to include an Aliyun fallback and explicit Russia guidance: add a second
UV_DEFAULT_INDEX example pointing to https://mirrors.aliyun.com/pypi/simple as a
China fallback alongside the existing Tsinghua mirror, keep the
UV_PYTHON_INSTALL_MIRROR, UV_PYTHON_PREFERENCE, UV_HTTP_TIMEOUT and
UV_HTTP_RETRIES lines as-is, and append a short note that Russia currently has
no blessed PyPI mirror and users should tunnel via VPN/proxy (or use an
organization-approved internal mirror) to reach the default PyPI index.


</details>

<!-- fingerprinting:phantom:triton:hawk -->

<!-- This is an auto-generated comment by CodeRabbit -->

Comment thread frontend/src/components/settings/PerformancePanel.test.jsx
Comment thread scripts/validate-install-docs.py
@debpalash
debpalash force-pushed the phase-1-wave-2-docs-settings-ui branch from c071645 to 06b32d7 Compare May 20, 2026 00:24

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

🧹 Nitpick comments (1)
tests/backend/core/test_links.py (1)

55-55: 💤 Low value

Move import to module level.

For consistency with Python conventions, import json at the module level (lines 12-15) rather than inside the test function.

♻️ Suggested refactor

At module level:

 from __future__ import annotations
 
 import importlib
+import json
 import sys

In the test:

     links = _fresh_links_module()
     monkeypatch.setattr(links, "_TAURI_CONF", tmp_path / "tauri.conf.json")
-    import json
     (tmp_path / "tauri.conf.json").write_text(json.dumps(fake_conf), encoding="utf-8")
🤖 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 `@tests/backend/core/test_links.py` at line 55, The test currently imports json
inside a test function in tests/backend/core/test_links.py; move that import to
the module level alongside the other imports at the top of the file (so json is
imported once for the module), and remove the in-function import; this applies
to the test function that contains the inline `import json` statement.
🤖 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 `@docs/engines/cosyvoice.md`:
- Around line 7-21: The CosyVoice install doc only covers the in-app installer
but must also include the manual source-setup steps required by issue `#55`;
update docs/engines/cosyvoice.md to add instructions to clone the CosyVoice repo
with submodules (git clone --recursive), install Python dependencies (pip
install -r requirements.txt), install SoX on the host OS, and document setting
the OMNIVOICE_COSYVOICE_MODEL environment variable (showing both POSIX export
and Windows PowerShell forms) pointing to the
pretrained_models/CosyVoice-300M-Instruct directory so OmniVoice can find the
model.

In `@docs/install/troubleshooting.md`:
- Line 107: The documentation line references an internal planning tag "Plan
01-03" which should be removed or replaced; edit the sentence containing
`window.location.host` and remove "Plan 01-03" (or replace it with the
appropriate public release version such as "v0.3.1") so the troubleshooting text
contains only user-facing information without internal planning references.
- Around line 82-84: The troubleshooting entry currently points to linux.md but
lacks the explicit Russia guidance required by the docs guideline; update the
text around the existing env var note (UV_PYTHON_INSTALL_MIRROR,
UV_HTTP_TIMEOUT, UV_HTTP_RETRIES, UV_PYTHON_PREFERENCE) to add a short inline
sentence stating that Russia has no officially blessed PyPI mirror and users
must tunnel via a VPN to reach mirrors (e.g., use the same env vars as shown) so
readers get immediate, actionable guidance without following the linux.md link.

In `@tests/backend/core/test_links.py`:
- Line 23: Remove the obsolete noqa comment on the re-import line `import
core.links as links  # noqa: WPS433 — needed for re-import` so it becomes a
plain re-import and similarly remove the identical `# noqa: WPS433` comment
found in `backend/tests/test_tts_backend_lifecycle.py`; the re-import is
intentional for cache-clearing tests and Ruff does not use WPS codes, so simply
delete the trailing `# noqa: WPS433` comments.

---

Nitpick comments:
In `@tests/backend/core/test_links.py`:
- Line 55: The test currently imports json inside a test function in
tests/backend/core/test_links.py; move that import to the module level alongside
the other imports at the top of the file (so json is imported once for the
module), and remove the in-function import; this applies to the test function
that contains the inline `import json` statement.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 81bc9199-8612-49ef-9999-f89dc24f6edf

📥 Commits

Reviewing files that changed from the base of the PR and between c071645 and 06b32d7.

📒 Files selected for processing (37)
  • .github/workflows/ci.yml
  • .gitignore
  • .planning/REQUIREMENTS.md
  • .planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md
  • README.md
  • backend/api/routers/settings.py
  • backend/core/error_docs_map.py
  • backend/core/links.py
  • backend/services/engine_env.py
  • backend/services/settings_store.py
  • backend/services/sonitranslate.py
  • docs/engines/cosyvoice.md
  • docs/features/diarization.md
  • docs/install/docker.md
  • docs/install/linux.md
  • docs/install/macos.md
  • docs/install/troubleshooting.md
  • docs/install/windows.md
  • docs/setup/huggingface-token.md
  • frontend/src/components/ErrorBoundary.jsx
  • frontend/src/components/ErrorBoundary.test.jsx
  • frontend/src/components/WaveformErrorBoundary.css
  • frontend/src/components/settings/ApiKeysPanel.css
  • frontend/src/components/settings/ApiKeysPanel.jsx
  • frontend/src/components/settings/ApiKeysPanel.test.jsx
  • frontend/src/components/settings/PerformancePanel.css
  • frontend/src/components/settings/PerformancePanel.jsx
  • frontend/src/components/settings/PerformancePanel.test.jsx
  • frontend/src/pages/Settings.jsx
  • frontend/src/utils/errorDocsMap.test.ts
  • frontend/src/utils/errorDocsMap.ts
  • scripts/validate-install-docs.py
  • tests/backend/core/test_error_docs_map.py
  • tests/backend/core/test_links.py
  • tests/backend/test_perf_settings.py
  • tests/scripts/__init__.py
  • tests/scripts/test_validate_install_docs.py
✅ Files skipped from review due to trivial changes (5)
  • docs/features/diarization.md
  • docs/install/windows.md
  • .planning/REQUIREMENTS.md
  • docs/install/macos.md
  • docs/install/linux.md
🚧 Files skipped from review as they are similar to previous changes (21)
  • .gitignore
  • frontend/src/components/WaveformErrorBoundary.css
  • frontend/src/components/ErrorBoundary.jsx
  • frontend/src/components/ErrorBoundary.test.jsx
  • frontend/src/components/settings/ApiKeysPanel.css
  • .github/workflows/ci.yml
  • frontend/src/components/settings/PerformancePanel.test.jsx
  • frontend/src/pages/Settings.jsx
  • backend/services/engine_env.py
  • docs/setup/huggingface-token.md
  • tests/backend/core/test_error_docs_map.py
  • frontend/src/components/settings/PerformancePanel.jsx
  • frontend/src/utils/errorDocsMap.test.ts
  • tests/backend/test_perf_settings.py
  • backend/core/error_docs_map.py
  • backend/services/settings_store.py
  • frontend/src/components/settings/ApiKeysPanel.jsx
  • frontend/src/utils/errorDocsMap.ts
  • backend/services/sonitranslate.py
  • frontend/src/components/settings/ApiKeysPanel.test.jsx
  • tests/scripts/test_validate_install_docs.py

Comment thread docs/engines/cosyvoice.md
Comment on lines +7 to +21
## Install

CosyVoice is installed *per-engine* from the in-app **Settings → Engines** tab:

1. Open **Settings → Engines**.
2. Click **Install** next to "CosyVoice".
3. The app fetches the engine source, creates a dedicated venv, syncs deps,
and downloads model weights (~2 GB).
4. Once installed, the engine appears in the **Voice Cloning** and
**Voice Design** engine picker dropdowns.

The dedicated venv keeps CosyVoice's transformer pins from clashing with
IndexTTS / ChatterboxTTS / SonicTranslate (see
[troubleshooting.md](../install/troubleshooting.md#10-indextts--cosyvoice--chatterboxtts-clash)).

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing required #55 setup steps in the CosyVoice install doc.

The install section currently documents only the in-app flow, but this PR’s stated objective for #55 requires explicit source-setup steps (git clone --recursive, pip install -r requirements.txt, SoX install, and OMNIVOICE_COSYVOICE_MODEL configuration).

Proposed doc patch
 ## Install

 CosyVoice is installed *per-engine* from the in-app **Settings → Engines** tab:
@@
 4. Once installed, the engine appears in the **Voice Cloning** and
    **Voice Design** engine picker dropdowns.

+### Manual/source setup (Issue `#55` compatibility path)
+
+If you are running OmniVoice from source and need to prepare CosyVoice manually:
+
+```bash
+git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git
+cd CosyVoice
+pip install -r requirements.txt
+```
+
+Install SoX on your OS (required by CosyVoice audio tooling), then point OmniVoice to the model directory:
+
+```bash
+export OMNIVOICE_COSYVOICE_MODEL=/path/to/CosyVoice/pretrained_models/CosyVoice-300M-Instruct
+```
+
+Windows (PowerShell):
+
+```powershell
+$env:OMNIVOICE_COSYVOICE_MODEL="C:\path\to\CosyVoice\pretrained_models\CosyVoice-300M-Instruct"
+```
🤖 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 `@docs/engines/cosyvoice.md` around lines 7 - 21, The CosyVoice install doc
only covers the in-app installer but must also include the manual source-setup
steps required by issue `#55`; update docs/engines/cosyvoice.md to add
instructions to clone the CosyVoice repo with submodules (git clone
--recursive), install Python dependencies (pip install -r requirements.txt),
install SoX on the host OS, and document setting the OMNIVOICE_COSYVOICE_MODEL
environment variable (showing both POSIX export and Windows PowerShell forms)
pointing to the pretrained_models/CosyVoice-300M-Instruct directory so OmniVoice
can find the model.

Comment on lines +82 to +84
**Fix:** see [linux.md#restricted-networks-china--russia](linux.md#restricted-networks-china--russia)
(same env vars work on macOS and Windows — `UV_PYTHON_INSTALL_MIRROR`,
`UV_HTTP_TIMEOUT=120`, `UV_HTTP_RETRIES=5`, `UV_PYTHON_PREFERENCE=only-system`).

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add explicit Russia VPN guidance per coding guidelines.

The guideline for installation documentation requires: "Document UV_PYTHON_INSTALL_MIRROR and region-specific PyPI mirrors (Tsinghua for China, Aliyun fallback) with explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN".

While you reference linux.md for details, this troubleshooting entry should include inline mention that Russia has no blessed mirror and requires VPN tunneling, since users hitting this error need immediate actionable guidance.

As per coding guidelines: Installation documentation must include explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN.

📝 Suggested addition
 **Fix:** see [linux.md#restricted-networks-china--russia](linux.md#restricted-networks-china--russia)
 (same env vars work on macOS and Windows — `UV_PYTHON_INSTALL_MIRROR`,
-`UV_HTTP_TIMEOUT=120`, `UV_HTTP_RETRIES=5`, `UV_PYTHON_PREFERENCE=only-system`).
+`UV_HTTP_TIMEOUT=120`, `UV_HTTP_RETRIES=5`, `UV_PYTHON_PREFERENCE=only-system`).
+**Note:** China can use Tsinghua/Aliyun mirrors; Russia has no blessed PyPI mirror — users should tunnel via VPN.
🤖 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 `@docs/install/troubleshooting.md` around lines 82 - 84, The troubleshooting
entry currently points to linux.md but lacks the explicit Russia guidance
required by the docs guideline; update the text around the existing env var note
(UV_PYTHON_INSTALL_MIRROR, UV_HTTP_TIMEOUT, UV_HTTP_RETRIES,
UV_PYTHON_PREFERENCE) to add a short inline sentence stating that Russia has no
officially blessed PyPI mirror and users must tunnel via a VPN to reach mirrors
(e.g., use the same env vars as shown) so readers get immediate, actionable
guidance without following the linux.md link.

URLs, which is wrong when the UI is reached from a different LAN host.

**Fix:** Plan 01-03 ships a fix that derives the media-preview base from
`window.location.host`. See [docker.md#lan-access](docker.md#lan-access) for the

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove internal planning reference.

"Plan 01-03" is an internal planning reference that will confuse end users reading troubleshooting docs. Either replace with the version number (e.g., "v0.3.1") or simply remove the reference.

📝 Suggested fix
-**Fix:** Plan 01-03 ships a fix that derives the media-preview base from
+**Fix:** v0.3.1 ships a fix that derives the media-preview base from
 `window.location.host`. See [docker.md#lan-access](docker.md#lan-access) for the
 override env var (`VITE_OMNIVOICE_API`) when running behind a reverse proxy.
🤖 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 `@docs/install/troubleshooting.md` at line 107, The documentation line
references an internal planning tag "Plan 01-03" which should be removed or
replaced; edit the sentence containing `window.location.host` and remove "Plan
01-03" (or replace it with the appropriate public release version such as
"v0.3.1") so the troubleshooting text contains only user-facing information
without internal planning references.

for mod in list(sys.modules):
if mod == "core.links":
del sys.modules[mod]
import core.links as links # noqa: WPS433 — needed for re-import

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if wemake-python-styleguide is actually in use
rg -l 'wemake-python-styleguide' pyproject.toml setup.cfg setup.py tox.ini .flake8 || echo "Not found in config files"

# Check Ruff external rules config
rg 'lint\.external|external\s*=' pyproject.toml || echo "No external rules configured"

Repository: debpalash/OmniVoice-Studio

Length of output: 338


🏁 Script executed:

# Check the pyproject.toml for linter configuration
cat pyproject.toml | head -100

Repository: debpalash/OmniVoice-Studio

Length of output: 4410


🏁 Script executed:

# Search for all WPS noqa comments in the codebase
rg 'noqa.*WPS' --no-heading

Repository: debpalash/OmniVoice-Studio

Length of output: 297


🏁 Script executed:

# Verify the exact content at the specified file and line
head -30 tests/backend/core/test_links.py | tail -15

Repository: debpalash/OmniVoice-Studio

Length of output: 574


🏁 Script executed:

# Check for Ruff configuration in pyproject.toml
rg '\[tool\.ruff\]|tool\.ruff' pyproject.toml -A 20

Repository: debpalash/OmniVoice-Studio

Length of output: 52


🏁 Script executed:

# Check if there are any ignore/select rules in pyproject.toml that mention this pattern
rg 'ignore|select|lint' pyproject.toml -B 2 -A 2

Repository: debpalash/OmniVoice-Studio

Length of output: 410


🏁 Script executed:

# Check if there's a .ruff.toml or ruff.toml file
fd -name '*ruff*' --type f

# Also check for flake8, pylint, or other linter configs
fd -name '.flake8|.pylintrc|pylintrc|pyproject.toml|setup.cfg' --type f

Repository: debpalash/OmniVoice-Studio

Length of output: 532


🏁 Script executed:

# Check if Ruff or any linter is listed in dependencies
rg 'ruff|flake8|pylint|wemake' pyproject.toml

Repository: debpalash/OmniVoice-Studio

Length of output: 52


🏁 Script executed:

# Check for linter config files
fd '(ruff|flake8|pylint)' --type f

# And double-check dependencies for linters
grep -i 'ruff\|flake8\|pylint\|wemake\|linter' pyproject.toml || echo "No linters found"

Repository: debpalash/OmniVoice-Studio

Length of output: 97


🏁 Script executed:

# Look at the complete test file to understand the intent of the noqa comment
cat tests/backend/core/test_links.py

Repository: debpalash/OmniVoice-Studio

Length of output: 2876


Remove the outdated noqa comment.

The # noqa: WPS433 references wemake-python-styleguide, which is not a dependency or active linter in this project. Ruff is the active linter (confirmed by ruff.toml), and it does not enforce WPS codes. The re-import pattern itself is intentional and valid for testing module state after cache clearing, so the comment can be safely removed.

Note: A similar WPS433 comment exists in backend/tests/test_tts_backend_lifecycle.py and should also be removed.

🧰 Tools
🪛 Ruff (0.15.13)

[warning] 23-23: Invalid rule code in # noqa: WPS433

Add non-Ruff rule codes to the lint.external configuration option

(RUF102)

🤖 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 `@tests/backend/core/test_links.py` at line 23, Remove the obsolete noqa
comment on the re-import line `import core.links as links  # noqa: WPS433 —
needed for re-import` so it becomes a plain re-import and similarly remove the
identical `# noqa: WPS433` comment found in
`backend/tests/test_tts_backend_lifecycle.py`; the re-import is intentional for
cache-clearing tests and Ruff does not use WPS codes, so simply delete the
trailing `# noqa: WPS433` comments.

debpalash added a commit that referenced this pull request May 20, 2026
…modules (#95)

The smoke test used `os.environ.setdefault()` to point at the frozen
fixture, which silently skipped when a prior test in the suite had
already set the env var. Combined with `core.config` caching `DB_PATH`
at module import time, this left smoke tests pointed at the wrong DB
once Wave 1's services tests pre-imported `main` with their own temp
state.

Exposed by Wave 2's additional tests (PR #94) pushing collection order
past the tipping point, but the underlying pollution existed since Wave
1 merged — Wave 3 CI passed only by collection-order luck.

Fix mirrors the `sys.modules` purge pattern that
`tests/backend/services/conftest.py` already uses.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
debpalash and others added 5 commits May 20, 2026 06:15
Splits the 600-line README install section into self-contained per-OS docs
under docs/install/{macos,windows,linux,docker}.md plus a Top-10
troubleshooting index. Each OS doc is end-to-end: a user opens it and
reaches a working app following only commands inside that file.

Adds:
- docs/install/{macos,windows,linux,docker}.md  (OS-specific install paths)
- docs/install/troubleshooting.md               (top 10 install errors)
- docs/engines/cosyvoice.md                     (closes #55 docs half)
- docs/features/diarization.md                  (pyannote license flow)
- docs/setup/huggingface-token.md               (3-source cascade guide)
- scripts/validate-install-docs.py              (INST-06 docs-drift gate)
- tests/scripts/test_validate_install_docs.py   (B-5: validator self-tests)
- .github/workflows/ci.yml step running the validator on every PR

Implements INST-02 (README routing), INST-03 (macOS Gatekeeper anchor),
INST-12 docs half (Windows torch-compile-oom anchor), DOCS-01..05.

The validator is a one-way diff: every `<!-- validate -->`-tagged line
in docs must appear in scripts/desktop-prod.sh after normalisation
(prompt-prefix strip, CRLF, trailing whitespace, blank-and-comment skip).
A `<!-- validate: skip -->` marker opts out for human-readability blocks.
Its own 10 unit tests catch regressions in the gate itself.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the single source of truth for the project repo URL and the 4-class
error → docs taxonomy that both the in-app ErrorBoundary deeplink button
(Wave 2 Task 3) and the Phase 5 bug reporter will consume.

New:
- backend/core/links.py            — PROJECT_REPO_URL + BLOB_MAIN resolver
                                      (Tauri config first, pyproject fallback)
- backend/core/error_docs_map.py   — lookup(error_class) → docs URL
- frontend/src/utils/errorDocsMap.ts (TS mirror with classifyError helper)
- tests/backend/core/test_links.py + test_error_docs_map.py
- frontend/src/utils/errorDocsMap.test.ts

Resolves checker B-6 (links.py ownership) and Open Question #3 (which fork
the deeplinks resolve to — the Tauri updater endpoint wins, which points
at the desktop app fork debpalash/OmniVoice-Studio).

The TS BASE constant is documented as the second hardcoded URL drift site;
the keys-sync test (`test_keys_match_python_map` equivalent) guards the
4-class taxonomy contract between Python + TS halves.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wave 2 AUTH-03 UI half + ErrorBoundary deeplink wiring.

ErrorBoundary fallback now renders an "Open docs for this error" button
that classifies the thrown Error message (heuristic: pkg_resources → 401 /
HfHubHTTP → WebKit / white screen → quarantine / Gatekeeper) and opens the
matching docs anchor via Tauri shell.open (with a window.open fallback
in browser dev mode).

ApiKeysPanel consumes the Wave 1 resolver state endpoint:
  - 3 source rows (App / Env var / HF CLI) with set/unset indicator,
    masked token preview, whoami username + green check
  - "Active" badge on whichever source is currently serving the cascade
  - App-row only: Save (POST /api/settings/hf-token) +
    Clear (DELETE with optional "also clear HF CLI" confirm dialog)
  - "Test now" button refetches state (invalidates the resolver's
    validation cache via the same endpoint hit)

Panel mounted in the existing Settings → Credentials tab; the legacy
HF_TOKEN row from CREDENTIAL_FIELDS is filtered out so the two paths
don't fight over the same key.

Threat T-02-02: the panel never displays the full token. The masked
value comes from the resolver state endpoint; the full token only
crosses the IPC boundary on Save (POST) and is cleared from local
state on success.

Closes AUTH-03 fully (Wave 1 backend + this Wave 2 UI).

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

Wave 2 Task 4 — full INST-12 delivery per checker B-2/B-7 v0.3.0 fat-release
decision. Both the docs half (windows.md anchor, shipped in earlier commit)
and the runtime toggle are now in Phase 1.

Backend:
- backend/services/settings_store.py: adds get_text/set_text helpers for
  non-secret config (refuses to write to the encrypted hf_token key).
- backend/api/routers/settings.py: GET + PUT
  /api/settings/perf/torch-compile-disabled, both under the existing
  loopback guard (threat T-02-04).
- backend/services/engine_env.py: new `build_engine_env()` helper that
  centralises HF_TOKEN/YOUR_HF_TOKEN injection from the 3-source resolver
  AND injects TORCH_COMPILE_DISABLE=1 when the flag is set on win32.
  Phase 2 SubprocessBackend launchers should adopt the same helper.
- backend/services/sonitranslate.py: migrated to engine_env.build_engine_env()
  while preserving the source-level `env["HF_TOKEN"]` sentinel that
  test_sonitranslate_module_uses_resolver checks.

Frontend:
- frontend/src/components/settings/PerformancePanel.{jsx,css,test.jsx}:
  toggle UI with the explainer for #65; renders disabled with a "not
  applicable" badge on macOS/Linux.
- frontend/src/pages/Settings.jsx: mounts the panel into the Credentials
  tab alongside the API Keys panel.

Tests:
- tests/backend/test_perf_settings.py: 7 backend tests (default state,
  PUT persistence, T-02-04 non-loopback rejection, settings_store round-
  trip, env injection on win32, NO injection on macOS/Linux, NO injection
  when disabled).
- frontend PerformancePanel.test.jsx: 5 tests (renders from GET state,
  PUT on toggle, disabled on non-Windows platforms, pre-enabled state).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- .planning/phases/01.../01-02-SUMMARY.md: full implementation report
  per template (truths, commits, tests, deviations, drift-site
  acknowledgments per W-3, launcher seam name for Phase 2,
  taxonomy keys for Phase 5).
- .planning/REQUIREMENTS.md: flips Wave 2 closures to Done:
    AUTH-03, INST-02, INST-03 (docs half), INST-06, INST-12,
    DOCS-01..05.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@debpalash
debpalash force-pushed the phase-1-wave-2-docs-settings-ui branch from 06b32d7 to c949c44 Compare May 20, 2026 00:45

@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

♻️ Duplicate comments (5)
docs/engines/cosyvoice.md (1)

7-20: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the manual/source setup path required by issue #55.

Line 7 onward only covers in-app installation. The required source path is still missing: git clone --recursive, pip install -r requirements.txt, SoX install, and OMNIVOICE_COSYVOICE_MODEL examples for both POSIX and Windows PowerShell.

Suggested doc patch
 ## Install
 
 CosyVoice is installed *per-engine* from the in-app **Settings → Engines** tab:
@@
 4. Once installed, the engine appears in the **Voice Cloning** and
    **Voice Design** engine picker dropdowns.
+
+### Manual/source setup (Issue `#55` compatibility path)
+
+If you're running OmniVoice from source and need a manual CosyVoice setup:
+
+```bash
+git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git
+cd CosyVoice
+pip install -r requirements.txt
+```
+
+Install SoX on your OS, then point OmniVoice to the model directory:
+
+```bash
+export OMNIVOICE_COSYVOICE_MODEL=/path/to/CosyVoice/pretrained_models/CosyVoice-300M-Instruct
+```
+
+Windows (PowerShell):
+
+```powershell
+$env:OMNIVOICE_COSYVOICE_MODEL="C:\path\to\CosyVoice\pretrained_models\CosyVoice-300M-Instruct"
+```
🤖 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 `@docs/engines/cosyvoice.md` around lines 7 - 20, Add the missing manual/source
install steps to the "Install" section of docs/engines/cosyvoice.md: include git
clone --recursive and cd instructions, pip install -r requirements.txt, a note
to install SoX, and examples showing how to set OMNIVOICE_COSYVOICE_MODEL for
both POSIX (export
OMNIVOICE_COSYVOICE_MODEL=/path/to/CosyVoice/pretrained_models/CosyVoice-300M-Instruct)
and Windows PowerShell
($env:OMNIVOICE_COSYVOICE_MODEL="C:\path\to\CosyVoice\pretrained_models\CosyVoice-300M-Instruct"),
and place these under the existing "Install" heading alongside the in-app
installation steps for clarity.
.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md (1)

17-17: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Correct the DOCS-02 closure note to match the implemented scope.

Line 17 still describes per-OS install pages, but DOCS-02 in this wave is the error→docs mapping/deeplink work.

Suggested wording
-| DOCS-02 | Done | Per-OS install pages live and end-to-end. |
+| DOCS-02 | Done | Error→docs mapping shipped (`backend/core/error_docs_map.py` + `frontend/src/utils/errorDocsMap.ts`) and wired into UI deeplinks. |
🤖 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
@.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md
at line 17, Update the DOCS-02 summary row so its closure note reflects the
implemented scope (error→docs mapping/deeplink) instead of "Per-OS install pages
live and end-to-end"; locate the table row containing the text "| DOCS-02 | Done
| Per-OS install pages live and end-to-end |" and replace the third column with
a concise description like "Error-to-docs mapping and deeplink implementation
completed" (or similar wording that explicitly mentions error→docs
mapping/deeplink).
scripts/validate-install-docs.py (1)

100-108: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix drift line reporting to use the first code line, not the marker line.

Line 100 currently anchors block_start to the marker, so Line 167 reports shifted locations. Capture the first fenced body line number and use it directly in the error formatter.

Suggested patch
-            block_start = pending_marker[0]
             skip = pending_marker[1]
             pending_marker = None
             i += 1
+            block_start = i + 1  # first code line inside the fenced block (1-indexed)
             while i < len(lines) and not _FENCE_CLOSE_RE.match(lines[i]):
                 block_lines.append(lines[i])
                 i += 1
@@
-                        f"{md_path.relative_to(args.root)}:{start_line + 1 + offset}: "
+                        f"{md_path.relative_to(args.root)}:{start_line + offset}: "
                         f"docs line not present in scripts/desktop-prod.sh: {norm!r}"
                     )

Also applies to: 167-168

🤖 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 `@scripts/validate-install-docs.py` around lines 100 - 108, The code currently
sets block_start = pending_marker[0] (the marker line) but should record the
first fenced body line number so reported drift lines point to the actual code,
not the marker; while building the fenced block in the loop inside the parser
that uses pending_marker, compute and store first_body_line = i (or i+0 after
incrementing) before appending lines, and replace block_start with that
first_body_line when appending to blocks (blocks.append((first_body_line,
"\n".join(block_lines), skip))); update any error formatter usage that reads the
tuple to expect the first code line number instead of the marker line.
docs/install/troubleshooting.md (2)

82-84: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add explicit Russia VPN guidance in the restricted-network fix.

Line 82 links the detailed section, but Line 83-84 should also state directly that Russia has no blessed PyPI mirror and users should tunnel via VPN.

Suggested addition
 **Fix:** see [linux.md#restricted-networks-china--russia](linux.md#restricted-networks-china--russia)
 (same env vars work on macOS and Windows — `UV_PYTHON_INSTALL_MIRROR`,
 `UV_HTTP_TIMEOUT=120`, `UV_HTTP_RETRIES=5`, `UV_PYTHON_PREFERENCE=only-system`).
+In Russia, there is no blessed PyPI mirror; use a VPN tunnel to reach the configured mirrors.
As per coding guidelines: Installation documentation: Document `UV_PYTHON_INSTALL_MIRROR` and region-specific PyPI mirrors (Tsinghua for China, Aliyun fallback) with explicit guidance that Russia has no blessed PyPI mirror and users should tunnel via VPN.
🤖 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 `@docs/install/troubleshooting.md` around lines 82 - 84, Update the
troubleshooting note to explicitly state that Russia does not have an endorsed
PyPI mirror and users must tunnel via VPN to access PyPI; mention the
environment variables UV_PYTHON_INSTALL_MIRROR, UV_HTTP_TIMEOUT,
UV_HTTP_RETRIES, and UV_PYTHON_PREFERENCE and document recommended mirrors for
China (Tsinghua, with Aliyun as fallback) while clarifying that for Russia the
only supported workaround is using a VPN or tunnel to reach a public PyPI
mirror; add a short sentence after the existing mirror examples to convey this
region-specific guidance and include the exact env var names shown
(UV_PYTHON_INSTALL_MIRROR etc.) for copy-paste.

106-108: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace internal planning reference with user-facing release wording.

Line 106 mentions “Plan 01-03,” which is internal and unclear in end-user troubleshooting docs.

Suggested wording
-**Fix:** Plan 01-03 ships a fix that derives the media-preview base from
+**Fix:** v0.3 ships a fix that derives the media-preview base from
 `window.location.host`. See [docker.md#lan-access](docker.md#lan-access) for the
 override env var (`VITE_OMNIVOICE_API`) when running behind a reverse proxy.
🤖 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 `@docs/install/troubleshooting.md` around lines 106 - 108, Replace the internal
phrasing "Plan 01-03" with user-facing release wording: update the sentence that
currently reads "Plan 01-03 ships a fix..." to something like "A recent release
fixes..." (or "Version X.Y.Z fixes..." if a version is known) so end users
understand it's a release-level change; keep the rest of the guidance intact
(retain the reference to deriving media-preview base from `window.location.host`
and the override env var `VITE_OMNIVOICE_API` and the link to
docker.md#lan-access) and ensure the term "media-preview" remains unchanged for
clarity.
🤖 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 `@docs/setup/huggingface-token.md`:
- Around line 110-113: Update the wording in the "Settings → API Keys" guidance
so it clarifies that seeing "Env" or "HF CLI" as the active source while the App
row is populated is not always expected — it only happens when the App token
cannot be used (e.g., fails validation or decryption) and the cascade falls back
to Env or HF CLI; otherwise the App source remains highest priority.
Specifically revise the sentence referencing the App row and the active source
("If it's set but the active source is 'Env' or 'HF CLI', that's the cascade
working as intended (App is highest priority).") to explicitly state the
fallback condition (App token invalid/unusable) and that App remains active when
its token is valid.

---

Duplicate comments:
In
@.planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md:
- Line 17: Update the DOCS-02 summary row so its closure note reflects the
implemented scope (error→docs mapping/deeplink) instead of "Per-OS install pages
live and end-to-end"; locate the table row containing the text "| DOCS-02 | Done
| Per-OS install pages live and end-to-end |" and replace the third column with
a concise description like "Error-to-docs mapping and deeplink implementation
completed" (or similar wording that explicitly mentions error→docs
mapping/deeplink).

In `@docs/engines/cosyvoice.md`:
- Around line 7-20: Add the missing manual/source install steps to the "Install"
section of docs/engines/cosyvoice.md: include git clone --recursive and cd
instructions, pip install -r requirements.txt, a note to install SoX, and
examples showing how to set OMNIVOICE_COSYVOICE_MODEL for both POSIX (export
OMNIVOICE_COSYVOICE_MODEL=/path/to/CosyVoice/pretrained_models/CosyVoice-300M-Instruct)
and Windows PowerShell
($env:OMNIVOICE_COSYVOICE_MODEL="C:\path\to\CosyVoice\pretrained_models\CosyVoice-300M-Instruct"),
and place these under the existing "Install" heading alongside the in-app
installation steps for clarity.

In `@docs/install/troubleshooting.md`:
- Around line 82-84: Update the troubleshooting note to explicitly state that
Russia does not have an endorsed PyPI mirror and users must tunnel via VPN to
access PyPI; mention the environment variables UV_PYTHON_INSTALL_MIRROR,
UV_HTTP_TIMEOUT, UV_HTTP_RETRIES, and UV_PYTHON_PREFERENCE and document
recommended mirrors for China (Tsinghua, with Aliyun as fallback) while
clarifying that for Russia the only supported workaround is using a VPN or
tunnel to reach a public PyPI mirror; add a short sentence after the existing
mirror examples to convey this region-specific guidance and include the exact
env var names shown (UV_PYTHON_INSTALL_MIRROR etc.) for copy-paste.
- Around line 106-108: Replace the internal phrasing "Plan 01-03" with
user-facing release wording: update the sentence that currently reads "Plan
01-03 ships a fix..." to something like "A recent release fixes..." (or "Version
X.Y.Z fixes..." if a version is known) so end users understand it's a
release-level change; keep the rest of the guidance intact (retain the reference
to deriving media-preview base from `window.location.host` and the override env
var `VITE_OMNIVOICE_API` and the link to docker.md#lan-access) and ensure the
term "media-preview" remains unchanged for clarity.

In `@scripts/validate-install-docs.py`:
- Around line 100-108: The code currently sets block_start = pending_marker[0]
(the marker line) but should record the first fenced body line number so
reported drift lines point to the actual code, not the marker; while building
the fenced block in the loop inside the parser that uses pending_marker, compute
and store first_body_line = i (or i+0 after incrementing) before appending
lines, and replace block_start with that first_body_line when appending to
blocks (blocks.append((first_body_line, "\n".join(block_lines), skip))); update
any error formatter usage that reads the tuple to expect the first code line
number instead of the marker line.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 44ee38b8-b97f-4c99-87fe-852713584a09

📥 Commits

Reviewing files that changed from the base of the PR and between 06b32d7 and c949c44.

📒 Files selected for processing (37)
  • .github/workflows/ci.yml
  • .gitignore
  • .planning/REQUIREMENTS.md
  • .planning/phases/01-install-token-persistence-docs-scaffolding-error-ux/01-02-SUMMARY.md
  • README.md
  • backend/api/routers/settings.py
  • backend/core/error_docs_map.py
  • backend/core/links.py
  • backend/services/engine_env.py
  • backend/services/settings_store.py
  • backend/services/sonitranslate.py
  • docs/engines/cosyvoice.md
  • docs/features/diarization.md
  • docs/install/docker.md
  • docs/install/linux.md
  • docs/install/macos.md
  • docs/install/troubleshooting.md
  • docs/install/windows.md
  • docs/setup/huggingface-token.md
  • frontend/src/components/ErrorBoundary.jsx
  • frontend/src/components/ErrorBoundary.test.jsx
  • frontend/src/components/WaveformErrorBoundary.css
  • frontend/src/components/settings/ApiKeysPanel.css
  • frontend/src/components/settings/ApiKeysPanel.jsx
  • frontend/src/components/settings/ApiKeysPanel.test.jsx
  • frontend/src/components/settings/PerformancePanel.css
  • frontend/src/components/settings/PerformancePanel.jsx
  • frontend/src/components/settings/PerformancePanel.test.jsx
  • frontend/src/pages/Settings.jsx
  • frontend/src/utils/errorDocsMap.test.ts
  • frontend/src/utils/errorDocsMap.ts
  • scripts/validate-install-docs.py
  • tests/backend/core/test_error_docs_map.py
  • tests/backend/core/test_links.py
  • tests/backend/test_perf_settings.py
  • tests/scripts/__init__.py
  • tests/scripts/test_validate_install_docs.py
✅ Files skipped from review due to trivial changes (5)
  • docs/features/diarization.md
  • docs/install/windows.md
  • .gitignore
  • docs/install/macos.md
  • docs/install/linux.md

Comment on lines +110 to +113
- **Token didn't survive a reboot** — open **Settings → API Keys** and check
the App row. If it's empty, the SQLite store may have been wiped — re-save.
If it's set but the active source is "Env" or "HF CLI", that's the cascade
working as intended (App is highest priority).

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify when Env/HF CLI can be active despite App being set.

Line 112–113 currently reads like this is always expected. It’s only expected when the App token fails validation/decryption; otherwise App should stay active as highest priority.

Suggested wording tweak
-  If it's set but the active source is "Env" or "HF CLI", that's the cascade
-  working as intended (App is highest priority).
+  If it's set but the active source is "Env" or "HF CLI", the App source likely
+  failed `whoami` or decrypt and the cascade fell back (App remains highest
+  priority when valid).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Token didn't survive a reboot** — open **Settings → API Keys** and check
the App row. If it's empty, the SQLite store may have been wiped — re-save.
If it's set but the active source is "Env" or "HF CLI", that's the cascade
working as intended (App is highest priority).
- **Token didn't survive a reboot** — open **Settings → API Keys** and check
the App row. If it's empty, the SQLite store may have been wiped — re-save.
If it's set but the active source is "Env" or "HF CLI", the App source likely
failed `whoami` or decrypt and the cascade fell back (App remains highest
priority when valid).
🤖 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 `@docs/setup/huggingface-token.md` around lines 110 - 113, Update the wording
in the "Settings → API Keys" guidance so it clarifies that seeing "Env" or "HF
CLI" as the active source while the App row is populated is not always expected
— it only happens when the App token cannot be used (e.g., fails validation or
decryption) and the cascade falls back to Env or HF CLI; otherwise the App
source remains highest priority. Specifically revise the sentence referencing
the App row and the active source ("If it's set but the active source is 'Env'
or 'HF CLI', that's the cascade working as intended (App is highest priority).")
to explicitly state the fallback condition (App token invalid/unusable) and that
App remains active when its token is valid.

@debpalash
debpalash merged commit 715766c into main May 20, 2026
8 checks passed
@debpalash
debpalash deleted the phase-1-wave-2-docs-settings-ui branch May 20, 2026 00:52
debpalash added a commit that referenced this pull request May 20, 2026
…ink (closes #78) (#110)

* fix: speaker detection — gated pyannote license surfaces a docs deeplink (closes #78)

Issue #78 ("Speaker detection fails — speakers blend together or aren't
detected correctly") was the user-visible symptom of the dub pipeline
silently falling back to the silence-gap heuristic in
`backend/api/routers/dub_core.py::_diarize`. The heuristic alternates
Speaker 1 ↔ Speaker 2 on >1.2s gaps only, so two real speakers with
similar pacing get merged or swapped — and once the auto-clone step
extracts a reference voice for the wrong label, downstream dubs make
"person A speak like person B" (the reporter's exact phrasing).

The structural cause is that pyannote-3.1 is gated on HuggingFace: a
valid HF_TOKEN by itself isn't enough — the user must also click
"Agree and access repository" on both pyannote/speaker-diarization-3.1
AND pyannote/segmentation-3.0. We can't fix that for the user, but we
CAN make the failure actionable instead of silent.

Changes:

- `backend/services/model_manager.py`: `get_diarization_pipeline()`
  gains an opt-in `return_error=True` shape that returns
  `(pipeline | None, error_sentinel)`. Sentinels distinguish
  NO_TOKEN / PYANNOTE_LICENSE_REQUIRED / LOAD_FAILED. A new
  `_classify_diarization_error()` sniffs the exception's class name +
  message for 401/403/gated/"accept license" signals — kept as a
  string heuristic so it survives huggingface_hub major-version
  churn. Bare-`None` default return preserved for the legacy
  `_transcribe` call site at dub_core.py:781.

- `backend/api/routers/dub_core.py::_diarize`: now emits a structured
  SSE warning `{detail, source, error_class, docs_url}` instead of
  plain `{detail, source}`. The new fields let the front-end render a
  "See docs" button that deeplinks directly to the
  `License acceptance flow` section of `docs/features/diarization.md`
  (landed in PR #94) — the page with the click-by-click instructions
  for fixing this exact failure mode.

- `backend/core/error_docs_map.py` + `frontend/src/utils/errorDocsMap.ts`:
  add a 5th taxonomy class `PYANNOTE_LICENSE_REQUIRED` pointing at the
  diarization docs section. Distinct from `HF_AUTH_FAILED` (which is
  the more general "token missing or invalid" case). The TS
  `classifyError` heuristic also picks up pyannote / gated /
  "speaker diarization" keywords so a thrown error in the boundary
  routes to the right deeplink too.

- `tests/backend/core/test_error_docs_map.py`: bump locked-keys set to
  5 classes; add an explicit assertion that the new class points at
  the `license-acceptance-flow` anchor.

- `frontend/src/utils/errorDocsMap.test.ts`: bump locked-keys set to
  5 classes; add classifier tests for pyannote / gated / accept-license
  keyword routing.

- `tests/test_diarization_error_class.py`: regression test (20 cases)
  covering `_classify_diarization_error`, the new
  `get_diarization_pipeline(return_error=True)` shape, backward-
  compatible bare-`None` return for the legacy call site, and the
  error_docs_map deeplink target. Uses sys.modules patching so
  pyannote / torch are never actually imported.

HF token plumbing: unchanged. The new code continues to route through
`token_resolver.resolve()` per the AUTH-01 contract — no new bare
`os.environ.get("HF_TOKEN")` reads.

Cross-platform: identical behaviour on macOS / Windows / Linux —
the only platform-touching change is a docs URL string, which is
opened via the existing `openExternal()` helper that already abstracts
Tauri's `shell.open` on all three platforms.

Verification:

  .venv/bin/python -m pytest tests/test_diarization_error_class.py \
      tests/backend/core/test_error_docs_map.py -v
  # 20 passed in 0.03s

  bun run test src/utils/errorDocsMap.test.ts
  # 13 passed (1 test file)

  .venv/bin/python -m pytest tests/test_segmentation.py \
      tests/test_dub_transcribe.py \
      tests/backend/services/test_token_resolver.py \
      tests/test_model_manager_preload.py
  # 40 passed, 10 xfailed (pre-existing), 1 xpassed

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

* test: add regression test for diarization error classification (issue #78)

Companion to the fix in d6e6586. 20 test cases covering:

- `_classify_diarization_error` — the string heuristic that buckets
  pyannote/HF exceptions into NO_TOKEN / LICENSE / LOAD sentinels.
  Pinned for 401/403/gated/accept-license/accept-user-conditions
  signals so it survives huggingface_hub major-version churn.
- `get_diarization_pipeline(return_error=True)` — the new 2-tuple
  return shape that lets the dub pipeline's SSE warning carry an
  error_class.
- Backward compatibility — the bare-`None` return on the default
  signature is preserved so dub_core.py:781's legacy `_transcribe`
  call site doesn't break.
- The error_docs_map deeplink — the new PYANNOTE_LICENSE_REQUIRED
  class points at `docs/features/diarization.md#license-acceptance-flow`.

Uses sys.modules patching for pyannote.audio.Pipeline + token_resolver
so the real torch + pyannote + HF API are never imported.

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

* test(diarization): dotted-path monkeypatch to survive Wave 1 sys.modules purge

The new `test_diarization_error_class.py` tests pass in isolation but fail
in the full suite — Wave 1's `fresh_resolver` fixture aggressively purges
all `services.*` and `core.*` modules from `sys.modules` mid-suite. When
this file's tests later did `from services import token_resolver` then
`monkeypatch.setattr(token_resolver, "resolve", ...)`, the local
`token_resolver` reference bound to a stale module identity. The function
under test does `from services import token_resolver` at call time, which
re-resolves through the (post-purge) `sys.modules['services.token_resolver']`
— a different object — so the monkeypatch was applied to one ID and the
function read from another.

Two fixes in this commit:

1. Don't pop `services.token_resolver` in this file's `model_manager`
   fixture — the test body's import and the function's import must agree
   on identity. Popping forces re-import that can create two distinct
   modules.

2. Use the dotted-path form `monkeypatch.setattr("services.token_resolver.resolve", ...)`
   instead of the object-attribute form. Pytest's dotted form re-resolves
   the path through `sys.modules` at setattr time, so the binding is
   always on the live module object regardless of which identity the test
   imported earlier.

Verified: `pytest tests/ -q` → 442 passed, 0 failures (was 1 failed
before this commit on PR #110).

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

Help with installation off (CosyVoice 3)

1 participant