Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: setuptools pin, Linux/Russia troubleshooting (#58, #56, #60) - #62

Merged
debpalash merged 1 commit into
mainfrom
fix/wave1-quick-wins
May 16, 2026
Merged

fix: setuptools pin, Linux/Russia troubleshooting (#58, #56, #60)#62
debpalash merged 1 commit into
mainfrom
fix/wave1-quick-wins

Conversation

@debpalash

@debpalash debpalash commented May 16, 2026

Copy link
Copy Markdown
Owner

Wave 1 Quick Wins

Changes

  • Pin setuptools>=75.0 in pyproject.toml — ensures pkg_resources is available on Python 3.12+ where it's no longer bundled by default. Fixes the No module named 'pkg_resources' error during transcription.
  • Linux white-screen workaround — documents WEBKIT_DISABLE_COMPOSITING_MODE=1 for Fedora 44 and Ubuntu 24.04.
  • Russia/CIS install guide — documents UV_PYTHON_PREFERENCE=system and PyPI mirror options for users behind firewalls that block GitHub CDN.

Issues Addressed

Also in this batch

Summary by CodeRabbit

  • Documentation

    • Added comprehensive architecture documentation for system design and component interactions.
    • Added coding conventions guide for Python and frontend development standards.
    • Added integrations and runtime configuration reference covering external services and setup.
    • Added technology stack documentation detailing frameworks and dependencies.
    • Enhanced Linux setup instructions with troubleshooting for white screen and firewall issues.
  • Chores

    • Updated setuptools dependency version requirement.

Review Change Stack

- Pin setuptools>=75.0 in pyproject.toml to ensure pkg_resources is
  available on Python 3.12+ (fixes #58)
- Add Linux white-screen workaround for Fedora 44 / Ubuntu 24.04 (#56)
- Add firewall/Russia install guide for uv venv failures (#60, #57)

Closes #58
@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR adds comprehensive planning and reference documentation for the OmniVoice codebase, addressing architecture clarity, development conventions, integration points, and technology stack. It also pins setuptools to fix a missing pkg_resources error and enhances README with troubleshooting guidance for Linux users.

Changes

Documentation and Configuration

Layer / File(s) Summary
Architecture and system design
.planning/codebase/ARCHITECTURE.md
System overview (Tauri desktop shell, React SPA, FastAPI backend, model package, SQLite + outputs), component responsibilities, layered patterns, TTS/dubbing data flows, bootstrap sequence, state management abstractions (TaskManager, EventBus, PluginSDK, AppStore), entry points for backend/desktop/frontend/MCP, explicit constraints (threading, global state, circular imports, port binding, runtime directories), anti-patterns (router imports, direct inference in handlers, sibling stores), error handling strategy, and cross-cutting concerns (logging, validation, CORS).
Development conventions and technology stack
.planning/codebase/CONVENTIONS.md, .planning/codebase/STACK.md
Naming conventions for files, functions, variables, and types; code formatting and linting (Ruff, ESLint); import organization; error-handling patterns; logging conventions; docstring and comment guidelines; function and module design rules; export/barrel-file preferences; enumeration of languages, runtimes, frameworks (FastAPI, React, Tauri), ML/audio dependencies with version pins, infrastructure components, configuration directories, build/test tools, and platform requirements.
External integrations and configuration guide
.planning/codebase/INTEGRATIONS.md
LLM/AI translation configuration (env vars, base URLs, model selection, timeouts), HuggingFace Hub auth/cache, yt-dlp video downloading, translation provider registry (offline/online/API-key-required engines), SQLite persistence and migration, local file storage and Docker volumes, caching behavior, authentication model (none) and CORS defaults, AI model backends (TTS, ASR, diarization, watermarking, voice conversion, separation), real-time endpoints (WebSocket ASR capture, SSE progress with durable replay), OpenAI-compatible API routes and MCP server exposure, FFmpeg resolution, observability logging (local crash logs, rotating logs), CI/CD workflows, webhook/callback sources, and environment variable configuration including gated features and secrets locations.
Installation troubleshooting and setuptools dependency
README.md, pyproject.toml
README additions for WebKit compositing workarounds on Fedora 44/Ubuntu 24.04, and firewall/mirror configuration steps for installation failures; setuptools dependency pinned to ≥75.0 to ensure pkg_resources availability for whisperx/faster-whisper on Python 3.12+.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

In the warren of code, a map now unfolds,
Architecture and conventions in tales newly told,
Integrations and stacks, all documented clear,
A setuptools fix brings pkg_resources near! 🐰📚✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: setuptools pin and Linux/Russia troubleshooting, with specific issue numbers referenced.
Description check ✅ Passed The description follows the template structure with Summary, Changes, Issues Addressed sections, providing clear context for all modifications.
Linked Issues check ✅ Passed All linked issue requirements are met: #58 is resolved via setuptools>=75.0 pin, #56 and #60 are addressed via documentation and troubleshooting guides.
Out of Scope Changes check ✅ Passed All changes are in-scope: setuptools pin targets #58, README updates address #56 and #60, and architectural/convention docs support maintainability.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/wave1-quick-wins

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

🤖 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 `@pyproject.toml`:
- Around line 43-46: The dependency pin "setuptools>=75.0" is too loose and
allows setuptools 82.x which removes pkg_resources; update the requirement to
add an upper bound so pkg_resources remains available (change "setuptools>=75.0"
to "setuptools>=75.0,<82.0") or alternatively migrate code that relies on
pkg_resources to importlib.resources/importlib.metadata; locate the setuptools
entry in pyproject.toml and apply the pin change.

In `@README.md`:
- Around line 190-199: Summary: The README currently instructs "Install Python
3.11 manually" but pyproject.toml's requires-python = ">=3.11" allows 3.11 or
newer; update the README to reflect this. Fix: Edit the README.md text inside
the "Installation fails behind a firewall / in Russia" details block to say
"Install Python 3.11 or newer from python.org" (retain the python.org link), and
ensure the environment variable instructions (UV_PYTHON_PREFERENCE and
UV_INDEX_URL) remain unchanged; reference the pyproject.toml requires-python =
">=3.11" note to validate the wording.
🪄 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: a6bf6774-4cdd-42a8-8e81-3ae55a9fea67

📥 Commits

Reviewing files that changed from the base of the PR and between ba4cf6a and 878c873.

📒 Files selected for processing (6)
  • .planning/codebase/ARCHITECTURE.md
  • .planning/codebase/CONVENTIONS.md
  • .planning/codebase/INTEGRATIONS.md
  • .planning/codebase/STACK.md
  • README.md
  • pyproject.toml

Comment thread pyproject.toml
Comment on lines +43 to +46
# pkg_resources is used by whisperx/faster-whisper at runtime.
# On Python 3.12+ it's no longer bundled by default — pin a modern
# setuptools to guarantee it's present (fixes #58).
"setuptools>=75.0",

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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify setuptools 75.0 exists on PyPI and check pkg_resources availability

# Check PyPI for setuptools versions
echo "=== Checking setuptools versions on PyPI ==="
curl -s https://pypi.org/pypi/setuptools/json | jq -r '.releases | keys[]' | grep -E '^75\.' | head -10

# Check if pkg_resources is included in modern setuptools
echo -e "\n=== Checking setuptools 75.x documentation ==="
curl -s https://pypi.org/pypi/setuptools/json | jq -r '.info.version'

# Check for security advisories
echo -e "\n=== Checking for setuptools security advisories ==="
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: PIP, package: "setuptools") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Repository: debpalash/OmniVoice-Studio

Length of output: 1282


🌐 Web query:

setuptools 75.0 pkg_resources Python 3.12

💡 Result:

In setuptools version 75.0.0 and later, the pkg_resources module is deprecated and has been removed as of setuptools version 82.0.0 [1][2]. Key points regarding pkg_resources, setuptools, and Python 3.12: 1. Removal of pkg_resources: As of setuptools v82.0.0 (released February 2026), the pkg_resources module is no longer included in the package [1][3]. Projects that still rely on pkg_resources must either migrate to modern alternatives or pin their setuptools dependency to a version earlier than 82.0.0 (e.g., setuptools<82) [4][1]. 2. Recommended Replacements: The Python Packaging Authority (PyPA) advises migrating to the following standard library modules or maintained packages [1][2]: - Resource access: Use importlib.resources (or the importlib_resources backport) [1][2]. - Distribution metadata and entry points: Use importlib.metadata (or the importlib_metadata backport) [1][2]. - Requirement and version parsing: Use the packaging library [1][2]. 3. Python 3.12 Context: Python 3.12 does not include setuptools by default [5]. If your environment or application requires setuptools (or specifically the legacy pkg_resources), you must explicitly install it [5]. Because pkg_resources has been removed from recent versions of setuptools, users on Python 3.12 who encounter "No module named pkg_resources" errors should check their setuptools version and either update their code to use the recommended importlib-based alternatives or pin setuptools to an older version [4][5]. 4. Deprecation History: The pkg_resources module was officially deprecated in setuptools v67.5.0 [1][2]. Throughout the v75.x release series, it remained available but emitted deprecation warnings to encourage migration [1][6]. By the time v82.0.0 was released, it was fully removed [1][3].

Citations:


The setuptools pin requires an upper bound to prevent breakage with setuptools 82.0+, which has removed pkg_resources.

While setuptools 75.0 does exist and includes pkg_resources, the pin setuptools>=75.0 is insufficient. Setuptools 82.0.0 (released February 2026) completely removed pkg_resources, and version 82.0.1 is now current as of May 2026. This means the dependency pin will fail in environments with up-to-date setuptools. Update to setuptools>=75.0,<82.0 to ensure pkg_resources remains available, or migrate the codebase to use importlib.resources and importlib.metadata as replacements.

🤖 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 `@pyproject.toml` around lines 43 - 46, The dependency pin "setuptools>=75.0"
is too loose and allows setuptools 82.x which removes pkg_resources; update the
requirement to add an upper bound so pkg_resources remains available (change
"setuptools>=75.0" to "setuptools>=75.0,<82.0") or alternatively migrate code
that relies on pkg_resources to importlib.resources/importlib.metadata; locate
the setuptools entry in pyproject.toml and apply the pin change.

Comment thread README.md
Comment on lines +190 to +199
<details>
<summary><b>Installation fails behind a firewall / in Russia</b></summary>
<br/>

The desktop app downloads Python from GitHub during first launch. If your network blocks GitHub:

1. Install Python 3.11 manually from [python.org](https://python.org/downloads/)
2. Set `UV_PYTHON_PREFERENCE=system` before launching, or run from source with `bun run dev`
3. For PyPI mirrors: set `UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/`
</details>

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 Python version requirement.

Line 196 says "Install Python 3.11 manually" but pyproject.toml specifies requires-python = ">=3.11", meaning Python 3.11 or newer is acceptable.

📝 Proposed fix
-1. Install Python 3.11 manually from [python.org](https://python.org/downloads/)
+1. Install Python 3.11 or newer manually from [python.org](https://python.org/downloads/)
📝 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
<details>
<summary><b>Installation fails behind a firewall / in Russia</b></summary>
<br/>
The desktop app downloads Python from GitHub during first launch. If your network blocks GitHub:
1. Install Python 3.11 manually from [python.org](https://python.org/downloads/)
2. Set `UV_PYTHON_PREFERENCE=system` before launching, or run from source with `bun run dev`
3. For PyPI mirrors: set `UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/`
</details>
<details>
<summary><b>Installation fails behind a firewall / in Russia</b></summary>
<br/>
The desktop app downloads Python from GitHub during first launch. If your network blocks GitHub:
1. Install Python 3.11 or newer manually from [python.org](https://python.org/downloads/)
2. Set `UV_PYTHON_PREFERENCE=system` before launching, or run from source with `bun run dev`
3. For PyPI mirrors: set `UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/`
</details>
🤖 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 `@README.md` around lines 190 - 199, Summary: The README currently instructs
"Install Python 3.11 manually" but pyproject.toml's requires-python = ">=3.11"
allows 3.11 or newer; update the README to reflect this. Fix: Edit the README.md
text inside the "Installation fails behind a firewall / in Russia" details block
to say "Install Python 3.11 or newer from python.org" (retain the python.org
link), and ensure the environment variable instructions (UV_PYTHON_PREFERENCE
and UV_INDEX_URL) remain unchanged; reference the pyproject.toml requires-python
= ">=3.11" note to validate the wording.

@debpalash
debpalash merged commit 2d0f0e7 into main May 16, 2026
5 checks passed
@debpalash
debpalash deleted the fix/wave1-quick-wins branch May 16, 2026 19:03
debpalash added a commit that referenced this pull request May 16, 2026
… OOS deferrals

- GATE-06: mark #53 + #61 merged (2026-05-16); add #62 (Wave 1 quick wins) to gate set
- INST-01: note PR #62 implements setuptools pin (closes #58)
- INST-04: note PR #62 lands README docs for #56 workaround
- INST-12: new requirement for #65 Windows Triton/torch.compile OOM (filed post-planning)
- Out of Scope: defer #67/PR #68 (audio effects), #64 (custom model dir),
  PR #66 zh-CN (i18n milestone), #63 (empty-template bug)

PR #62 is the user's own Wave 1 work landed as a separate PR while
GSD planning ran in parallel. Merging it eliminates duplicate work
in Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
debpalash added a commit that referenced this pull request May 17, 2026
…ase smoke (#71)

* docs: initialize OmniVoice stabilization milestone project

* chore: add project config (yolo + balanced)

* docs: domain research for stabilization milestone

* docs: define v1 requirements for stabilization milestone

* docs: add GGUF + singing engine spike requirements (Phase 4 new)

* docs: roadmap revision + CLAUDE.md (7 phases, 62 reqs, +GGUF/SING spikes)

* docs(phase-0): add Gates phase RESEARCH.md

Phase 0 research synthesizes the cross-platform CI matrix, frozen
omnivoice_data fixture, installer post-build smoke, SHA-256 checksum
publishing, and PR-template extension into copy-paste-ready YAML and
Python snippets composed entirely from existing in-repo patterns.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* docs(phase-0): add Gates phase CONTEXT, PATTERNS, and PLAN

Phase 0 — Gates is the hard pre-condition for v0.3.x stabilization.
Lays cross-platform CI matrix (macos-14/windows-2022/ubuntu-22.04),
regression fixture (≤200 KB), installer smoke on tag push, SHA-256
checksums in release body + per-OS SHA256SUMS-*.txt assets, PR
template with RC cadence + fixture line, and the open-PR landing
for #51.

Plan covers GATE-01..06; structured into 7 slices (A–G) with explicit
Slice C → Slice G dependency reordering so the new smoke-matrix lands
on main before PR #51 (CONTEXT.md L86 interleave decision).

Plan-checker iteration 2: APPROVED — all 3 BLOCKERs + 3 MAJORs from
iteration 1 resolved (file truncation/Slice-G missing, GATE-06 sibling
PR verification, Slice C ordering, Truth #5 wording, macOS Tauri
WebView avoidance per Pitfall #5, Windows taskkill per Pitfall #2).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* test(00-gates): seed regression fixture (GATE-01)

- scripts/seed-test-fixture.py — deterministic builder for tests/fixtures/omnivoice_data/
  - wipes + rebuilds; fixed created_at=1700000000.0; all-zero PCM for byte-deterministic diffs
  - calls backend.core.db.init_db() directly (alembic versions/ is empty — see CONTEXT.md)
  - checkpoints WAL → DELETE on close so no -shm/-wal sidecars pollute git status
  - exits non-zero if fixture > 200 KB
- tests/fixtures/omnivoice_data/{omnivoice.db, README.md} — 8-table empty DB + 1 voice_profiles row
- tests/fixtures/omnivoice_data/voices/test-voice/{profile.json, sample.wav} — 1-sec 24 kHz mono silence
- .gitignore — explicit allow-list (!tests/fixtures/omnivoice_data/**) so the existing
  omnivoice_data/, *.db, *.wav patterns don't hide the fixture from git

Verifies: du = 144 KB on disk; sqlite_master lists 8 init_db tables + sqlite_sequence;
voice_profiles has exactly 1 row id='test-voice'; 0 rows in generation_history.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* test(00-gates): add tests/smoke/test_boot_smoke.py (GATE-01)

- tests/smoke/__init__.py — package marker so pytest treats tests/smoke/ as a module
- tests/smoke/test_boot_smoke.py — 4 in-process FastAPI TestClient smoke tests:
    * test_health_returns_ok — /health returns 200 + {status:ok, device:...}
    * test_profiles_endpoint_lists_fixture_voice — /profiles surfaces the seeded
      test-voice row (validates OMNIVOICE_DATA_DIR wiring → DB_PATH → init_db schema)
    * test_system_info_includes_data_dir — /system/info resolves data_dir
    * test_history_endpoint_empty — /history reaches DB and returns []
  Test isolation env vars (OMNIVOICE_MODEL=test, OMNIVOICE_DISABLE_FILE_LOG=1)
  set at module top BEFORE any backend import — pattern from tests/test_router_smoke.py.
  Fixture is copied to a per-session temp dir so the test never mutates the
  checked-in artifact (SQLite file-change counter + runtime subdirs like dub_jobs/
  would otherwise dirty `git status` after every run).
  Failure mode: if tests/fixtures/omnivoice_data/ is missing, pytest.fail at
  import time with the regenerate command.
- .gitignore — tighten the GATE-01 allow-list to ONLY the seed-produced files
  (README.md, omnivoice.db, voices/test-voice/profile.json, sample.wav).
  Prevents future runtime subdirs the backend may create under the fixture
  from being accidentally committed.

Verifies: `uv run pytest tests/smoke/ -q --tb=short` → 4 passed in 1.31 s
(target was < 30 s). `git status` clean after a test run.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* docs(triage): record post-planning GitHub state — PR #62, new issues, OOS deferrals

- GATE-06: mark #53 + #61 merged (2026-05-16); add #62 (Wave 1 quick wins) to gate set
- INST-01: note PR #62 implements setuptools pin (closes #58)
- INST-04: note PR #62 lands README docs for #56 workaround
- INST-12: new requirement for #65 Windows Triton/torch.compile OOM (filed post-planning)
- Out of Scope: defer #67/PR #68 (audio effects), #64 (custom model dir),
  PR #66 zh-CN (i18n milestone), #63 (empty-template bug)

PR #62 is the user's own Wave 1 work landed as a separate PR while
GSD planning ran in parallel. Merging it eliminates duplicate work
in Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* ci(00-gates): add cross-platform smoke matrix (GATE-02)

- New smoke-matrix job on macos-14, windows-2022, ubuntu-22.04
- needs: test, fail-fast: false, timeout-minutes: 10
- Pinned actions: checkout@v4, setup-python@v5, setup-uv@v3 (cache enabled)
- Per-OS ffmpeg + libsndfile install (brew/choco/apt via awalsh128 cache)
- UV_HTTP_TIMEOUT=120, UV_HTTP_RETRIES=5 for restricted-network resilience
- Narrow scope: uv run pytest tests/smoke/ -q --tb=short
- Existing `test` and `tauri-cross-platform` jobs untouched

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* ci: add workflow_dispatch to ci.yml so smoke-matrix can run on feature branches

* feat(00-gates): add --health-check CLI flag to backend entrypoint (GATE-03)

- argparse on __main__ block; --health-check boots uvicorn in a daemon
  thread and polls http://127.0.0.1:3900/health every 5s for up to 60s.
- Prints 'OK — /health responded 200 after Ns' and exits 0 on first 200.
- Prints 'FAIL — /health did not respond 200 within 60s' to stderr and
  exits 1 on timeout. Default invocation behavior unchanged.
- No new deps (stdlib argparse/threading/time/urllib.request/sys + uvicorn).
- Consumed by per-OS installer-smoke step in .github/workflows/release.yml.

Verified locally: exits 0 in 5s against tests/fixtures/omnivoice_data/.

* ci(00-gates): add per-OS installer smoke to release.yml (GATE-03)

Adds three matrix-leg-specific steps after 'Build + release (Tauri)',
each gated by runner.os with timeout-minutes: 5:

- macOS (macos-14): hdiutil attach DMG → locate bundled Python backend
  inside *.app/Contents (NOT the Tauri WebView shell — RESEARCH Pitfall
  #5: WebView hangs on headless runners) → invoke --health-check →
  hdiutil detach. Falls back to *.app/Contents/Resources and hard-fails
  with a directory listing if no backend binary found.

- Windows (windows-2022): msiexec /quiet install → find backend.exe
  under 'C:/Program Files/OmniVoice Studio' → invoke --health-check in
  background, wait, then taskkill //F //T //PID to cleanup orphaned
  PyInstaller child processes on port 3900 (RESEARCH Pitfall #2).

- Linux (ubuntu-22.04): --appimage-extract (no FUSE on GH runners),
  locate binary or AppRun, run under xvfb-run -a.

Bundle-only regressions (PyInstaller missing-module, Tauri sidecar
path mismatch) are invisible to ci.yml's in-process smoke matrix —
this step closes that gap before any release is published.

Verified: YAML parses; all three steps present; gating + timeout
correct; Pitfall #2/#5 mitigations preserved.

* ci(00-gates): publish SHA-256 checksums in release body + as asset (GATE-05)

- Add 'Compute SHA-256 checksums' step writing SHA256SUMS-<label>.txt
  per matrix leg using native shasum/sha256sum (Git Bash on Windows).
- Add 'Append checksums to release + attach SHA256SUMS file' step using
  softprops/action-gh-release@v2 with append_body: true so the hashes
  land in the release body alongside tauri-action's content (not
  replacing it) and the file is uploaded as a release asset for
  'shasum -c SHA256SUMS-<label>.txt' verification.
- Both steps gated by 'github.event_name == push && refs/tags/v*' so
  workflow_dispatch dry-runs do not attempt to attach to a non-existent
  release (per CONTEXT.md L70 + RESEARCH Pitfall #7 deferral of any
  aggregate cross-leg SHA256SUMS job).
- fail_on_unmatched_files: true to surface path-resolution errors loudly.

* docs(00-gates): document RC cadence + regression-fixture check in PR template (GATE-04)

* docs(setup): add HF token persistence guide for macOS/Windows/Linux (DOCS-05)

Covers two persistent paths:
- Method A — canonical ~/.cache/huggingface/token via huggingface-cli login
- Method B — shell env var (~/.zshrc / ~/.bashrc / Windows User scope)

Documents the v0.2.7 "session only" in-app behavior + notes that
Phase 1 AUTH-03 will make in-app pastes write to the canonical file.

Bundled with Phase 0 PR per user request. Strictly DOCS-05 scope —
zero code changes, no engine touches.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* spec(auth): redesign HF token resolution as 3-source cascade with fallback (AUTH-01..06)

Replaces the env_store.py file-based design with a SQLite-backed app
store + cascade resolver that checks app → env var → ~/.cache/huggingface/token
in priority order, with automatic fallback to next source on HTTP 401.

User-explicit design decision:
- App-stored token (SQLite settings table, AES-GCM encrypted) wins
- Env var ($HF_TOKEN) second
- Global huggingface-cli login file third
- All three sources visible in Settings → API Keys with "Active" badge
- Save action populates BOTH app store AND canonical HF file (defense in depth)

New requirement:
- AUTH-06 — on 401, auto-retry next source in cascade before erroring

Also: traceability count corrected (62 → 74 — undercount at planning +
INST-12 + AUTH-06 added post-planning). All 74 v1 reqs mapped.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* fix(auth): backend recognizes HF token from canonical file, not just env var

Two call sites were only checking $HF_TOKEN env var, missing the canonical
~/.cache/huggingface/token file written by `huggingface-cli login` (or the
app's future Save action):

- system.py `/system/info` `has_hf_token` flag — UI showed "No HF token"
  even when `huggingface-cli login` had populated the file.
- model_manager.get_diarization_pipeline — pyannote diarization silently
  returned None when only the canonical file was set. This is the bug
  behind issue #35 (speaker diarization setup failure).

Both fixes use the same pattern: env var > huggingface_hub.get_token()
(which reads the canonical file). Adds a local _has_hf_token() helper
to system.py with a comment marking it as prelude to the AUTH-01..06
cascade (Phase 1 token_resolver.py will layer SQLite app-store on top).

Closes #35 sub-issue (canonical token invisible to diarization).
Cross-cuts AUTH-02 + AUTH-06 design for Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* feat(dictation): make pill-widget mode reachable from GUI + scripts (INST-13)

The dictation widget infrastructure shipped in PR #40 but was only reachable
via the undocumented --pill CLI flag. Adds three discovery paths:

1. Tray menu: "Switch to Dictation Widget" (studio mode) — saves
   launch_as_widget=true to config, relaunches with --pill, exits current.
   Mirrors the existing "Open Studio" path in pill-mode tray.

2. Persistent config: AppConfig.launch_as_widget (bool, default false). Read
   at startup via load_config_pre_app() (uses dirs-next, no AppHandle
   required). CLI --pill still takes precedence when explicitly passed.

3. Tauri commands: get_launch_as_widget / set_launch_as_widget for the
   Phase 2 Settings UI to bind a checkbox to.

4. Scripts: bun desktop-prod:pill / desktop-prod:run:pill — forward --pill
   to the bundled app launch. macOS uses `open -n --args` to spawn fresh
   instance with the flag.

Closes the GUI half of INST-13. Phase 2 closes the Settings UI half.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* fix(dictation): show widget unconditionally on pill-mode launch + visible Suspense fallback

Before: pill mode set up correctly but the widget window stayed hidden
until ⌘⇧Space was pressed. New users saw absolutely nothing on launch
(no main window, no dock icon, hidden widget) and assumed the app
failed. If global-shortcut Accessibility permission wasn't granted,
they had no path to discover the widget at all.

Two changes:

1. lib.rs: in pill_mode_setup, explicitly show + position + focus the
   widget window after hiding main. With per-call error logging so we
   can diagnose failures (and a clear error log if widget window
   wasn't created at all — points at tauri.conf.json regression).

2. main-app.jsx: Suspense fallback was `null`, which combined with
   widget's transparent+decorations:false config made any lazy-import
   delay or failure invisible. Now renders a dark pill saying
   "Loading dictation…" so even if CaptureWidget lazy-import stalls,
   the user sees the window exists.

Studio mode behavior unchanged — widget stays hidden until hotkey
or tray click triggers it (existing show() call in the shortcut/
menu handlers is preserved).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* fix(dictation): create widget window programmatically; Tauri 2 silently dropped config-array creation

Root cause: declaring the widget window in tauri.conf.json's app.windows[]
silently failed in Tauri 2 — get_webview_window("widget") returned None
even though the config was syntactically valid. Probable culprit was the
transparent + decorations:false + visible:false combo, but Tauri offered
no error message either at startup or via webview_windows() enumeration.

Diagnosed by adding webview_windows() enumeration logging at setup start
(only ["main"] ever appeared) and a programmatic WebviewWindowBuilder
fallback that surfaces real Result errors.

Fix:
- tauri.conf.json: widget entry now has `create: false` to make the
  config-vs-programmatic handoff explicit.
- lib.rs setup(): call WebviewWindowBuilder::new(app, "widget", ...).build()
  with the exact same surface attributes the config used to declare.
- capabilities/default.json: include "widget" in windows array so the new
  window inherits the same Tauri permissions as main.
- tauri.conf.json: remove the invalid `"url": "/?window=widget"` field —
  WebviewUrl::App takes a path only, query strings aren't supported.
  Both windows now load index.html.
- main-app.jsx: replace URL-query-based widget detection with
  getCurrentWindow().label === 'widget' via @tauri-apps/api/window. This
  is the Tauri 2-recommended pattern for multi-window apps and works
  regardless of URL routing.

Closes the immediate UX bug behind the dictation widget being invisible.
Builds cleanly + manually verified: pill widget visible on screen at
top-center after `bun desktop-prod:pill`.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
debpalash added a commit that referenced this pull request May 20, 2026
…eeper probe (closes #54, #56, #76, #80) (#93)

* fix(appimage): conditional WEBKIT_DISABLE_COMPOSITING_MODE launcher (#56)

WebKitGTK 2.44.x and 2.46.x have a compositing-path regression on Wayland
that blanks the AppImage's first paint on Fedora 44 / Ubuntu 24.04. Setting
WEBKIT_DISABLE_COMPOSITING_MODE=1 forces the software fallback that works,
but blindly setting it on healthy WebKit versions (2.48+) regresses those.

This wave adds a conditional AppRun launcher that detects the WebKit
version via pkg-config and only sets the env var on the broken ranges
(plus a fail-safe when pkg-config is absent or the version is unknown).
The launcher is injected into Tauri's AppImage staging dir via a
beforeBundleCommand hook — see .planning/decisions/apprun-strategy.md for
the spike outcome and rationale (Strategy B chosen).

Phase 1 Wave 3 — Plan 01-03 Task 1. Closes #56 frontend half.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* fix(deb): relocate bundled ffprobe out of /usr/bin to avoid conflicts (#76)

Prior versions placed the bundled ffprobe at /usr/bin/ffprobe via Tauri's
externalBin, which overwrites the system ffprobe on Ubuntu 26.04 and
collides with apt-installed media-package ffprobe.

Relocate the .deb-bundled ffprobe to /usr/lib/omnivoice-studio/bin/ffprobe
via bundle.linux.deb.files, plus defensive maintainer scripts:
  - preinst:  ensure target dir exists for upgrade flows
  - postinst: remove legacy /usr/bin/ffprobe ONLY when dpkg confirms our
              package owns it (never touches a user's distro ffprobe)
  - postrm:   clean up the relocated path tree on purge/remove

Rust side (tools.rs::resolve_ffprobe) now probes the new path on Linux,
and backend spawn (backend.rs) carries both FFPROBE_PATH (legacy alias)
and OMNIVOICE_FFPROBE_PATH (canonical) into the backend env. Python side
(ffmpeg_utils.resolve_ffprobe) reads OMNIVOICE_FFPROBE_PATH first, falls
back to FFPROBE_PATH, then to shutil.which("ffprobe").

6 new unit tests cover the env-cascade resolution.

Phase 1 Wave 3 — Plan 01-03 Task 2. Closes #76.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* fix(frontend): centralised apiBase resolver for Docker LAN access (#80)

Docker / LAN browser users hit the preview API at the LAN host's IP, not
their local machine — the prior frontend/src/utils/media.js:20 hardcoded
http://localhost:3900, which from a LAN client resolved to the client
machine itself.

Centralise via frontend/src/utils/apiBase.ts:
  1. VITE_OMNIVOICE_API override (Docker compose / dev) always wins.
  2. Tauri webview → http://localhost:3900 (unchanged behaviour).
  3. Plain browser → ${window.location.protocol}//${window.location.hostname}:3900
     (follows the page's origin — closes #80).
  4. SSR / no-window → http://localhost:3900 (safe fallback).

Grep-sweep confirmed media.js:20 was the only hardcode site (Assumption
A4 in 01-RESEARCH.md verified). 6 new vitest cases cover the resolver.

Phase 1 Wave 3 — Plan 01-03 Task 3. Closes #80 frontend half.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* feat(backend): macOS Gatekeeper quarantine probe + INST-01 guard (#54)

Adds backend/core/gatekeeper_detect.py which walks up from sys.executable
to find the .app bundle and runs `xattr -l` to check for the quarantine
extended attribute (com.apple.quarantine). On detection, the lifespan
startup probe logs a structured warning and emits a system_error event
through the existing event bus with error_class="GATEKEEPER_QUARANTINE",
which Wave 2's React ErrorBoundary turns into a docs deeplink.

Detection is informational only — we never auto-run `xattr -cr` (the app
itself is quarantined and cannot fix its own state per Anti-Pattern in
01-RESEARCH.md). Users get a clear pointer to the workaround docs.

GET /system/quarantine-status exposes the structured payload so the
frontend can poll on first load.

INST-01 (setuptools>=75.0 pin from PR #62) gains a PR-time guard in
tests/backend/test_pyproject.py + a user-observable smoke check in
scripts/smoke-test.sh (pkg_resources + whisperx import).

7 gatekeeper tests + 1 pyproject test added — all pass.

Phase 1 Wave 3 — Plan 01-03 Task 4. Closes #54 backend half (Wave 2 owns
the docs page + ErrorBoundary deeplink wiring).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
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.

[Bug] Transcription produced no segments. No module named 'pkg_resources' [Feature] Support importing .srt files for custom subtitles

1 participant