fix(bootstrap): mirror cascade + system-Python fallback for blocked networks (plan-03, closes #60) - #140
Conversation
…etworks (#130) plan-03. First-run bootstrap downloaded managed Python from GitHub with no mirror and a short retry budget, so a GitHub-blocked/unresolvable network killed the install dead-on-arrival (#60). bootstrap.rs (Rust/Tauri): - apply_uv_http_env(): UV_HTTP_TIMEOUT=120 / CONNECT_TIMEOUT=30 / RETRIES=5 on both `uv venv` and `uv sync`. - `uv venv` cascade: default GitHub → gh-proxy mirror (UV_PYTHON_INSTALL_MIRROR) → system Python (UV_PYTHON_PREFERENCE=only-system, only if a system Python >=3.11 is detected). First success wins. - Actionable failure messages (install python.org Python / set a mirror / Clean & Retry) instead of a raw uv exit code. Frontend: BootstrapSplash hint for the GitHub-blocked / can't-download-Python case. Docs: troubleshooting.md restricted-network section (mirror env vars, China PyPI index, honest VPN note) — referenced by the remediation text. Tests: Rust #[cfg(test)] for parse_py_version + apply_uv_http_env (cargo test: 2 passed, crate compiles); docs-drift validator + frontend build green. NOTE: the restricted-network E2E paths (mirror install, only-system fallback) need MANUAL verification on a real GitHub-blocked network — not reproducible in the dev/CI harness. cargo + the unit tests cover compile + the pure helpers only. Closes #60. Addresses #130, #57, #127. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR implements installer bootstrap resilience for restricted networks by adding mirror-cascade strategies, HTTP timeout injection, system-Python fallback, user-facing remediation messaging, and frontend error detection integrated with updated troubleshooting documentation. ChangesInstaller Bootstrap Network Resilience
Sequence DiagramsequenceDiagram
participant Installer as Installer Bootstrap
participant UV as uv Command
participant DefaultHost as GitHub (default)
participant Mirror as gh-proxy Mirror
participant SystemPy as System Python ≥3.11
rect rgba(100, 150, 200, 0.5)
Note over Installer,SystemPy: venv Creation Cascade
Installer->>UV: uv venv (default host)
UV->>DefaultHost: Download python-build-standalone
DefaultHost-->>UV: ✗ Network timeout/DNS error
UV-->>Installer: Failure
Installer->>UV: uv venv (gh-proxy mirror via UV_PYTHON_INSTALL_MIRROR)
UV->>Mirror: Download python-build-standalone
Mirror-->>UV: ✗ Mirror unreachable
UV-->>Installer: Failure
alt System Python ≥3.11 Available
Installer->>UV: uv venv (UV_PYTHON_PREFERENCE=only-system)
UV->>SystemPy: Use system Python
SystemPy-->>UV: ✓ Success
UV-->>Installer: venv ready
else No System Python ≥3.11
Installer->>Installer: Set stage=Failed with remediation message
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
| Filename | Overview |
|---|---|
| frontend/src-tauri/src/bootstrap.rs | Adds mirror cascade (default GitHub → gh-proxy → system Python), apply_uv_http_env for extended timeouts, and actionable error messages; apply_uv_http_env unconditionally overrides user-set env vars, contradicting the docs guidance; the repair-sync path (uvicorn-missing branch) still lacks apply_uv_http_env (previously flagged, still unresolved). |
| frontend/src/components/BootstrapSplash.jsx | Adds a hint detection regex that correctly matches phrases from BOOTSTRAP_REMEDIATION (blocking GitHub, couldn't download Python) and triggers an actionable user hint. |
| docs/install/troubleshooting.md | Adds a restricted-network troubleshooting section covering mirror env vars, China PyPI index, and VPN; item 4 claims users can override the bootstrap's HTTP timeouts via env vars, which is incorrect as written (the bootstrap's apply_uv_http_env overrides them unconditionally). |
| specs/004-installer-network-resilience/plan.md | Spec/plan/tasks documents for this feature; accurately describes the verification gap (E2E restricted-network paths require manual testing). |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[ensure_venv_ready] --> B{Venv exists?}
B -- Yes, uvicorn OK --> C[Return venv_py]
B -- Yes, uvicorn missing --> D[repair_cmd: uv sync\nNO apply_uv_http_env ⚠️]
D --> E{repair success?}
E -- Yes --> C
E -- No --> F[fail: raw error]
B -- No --> G[First-run bootstrap]
G --> H[Attempt 1: default GitHub\napply_uv_http_env ✓]
H --> I{success?}
I -- Yes --> J[uv sync\napply_uv_http_env ✓]
I -- No --> K[Attempt 2: gh-proxy mirror\napply_uv_http_env ✓]
K --> L{success?}
L -- Yes --> J
L -- No --> M{system Python ≥3.11?}
M -- Yes --> N[Attempt 3: only-system\napply_uv_http_env ✓]
N --> O{success?}
O -- Yes --> J
O -- No --> P[fail: BOOTSTRAP_REMEDIATION]
M -- No --> P
J --> Q{sync success?}
Q -- Yes --> C
Q -- No --> R[fail: actionable sync message]
Reviews (2): Last reviewed commit: "fix(bootstrap): drop --python 3.11 pin o..." | Re-trigger Greptile
| if system_python_ge_311() { | ||
| venv_attempts.push(( | ||
| "system-python", | ||
| vec!["venv", "--python", "3.11"], | ||
| vec![("UV_PYTHON_PREFERENCE", "only-system")], | ||
| )); | ||
| } |
There was a problem hiding this comment.
System-Python fallback fails when system Python is 3.12 or 3.13
system_python_ge_311() returns true for any Python ≥ 3.11 (3.12, 3.13, …), so the system-python attempt is added to the cascade. However the args include --python 3.11, which tells uv to look for a Python interpreter matching ==3.11.* exactly. On a machine with only Python 3.12 installed, uv venv --python 3.11 UV_PYTHON_PREFERENCE=only-system will fail because there is no 3.11.x system interpreter, and the user still sees BOOTSTRAP_REMEDIATION despite having a perfectly compatible Python available. Dropping the --python 3.11 pin from the system-Python attempt lets uv resolve any >=3.11 system interpreter automatically.
| if system_python_ge_311() { | |
| venv_attempts.push(( | |
| "system-python", | |
| vec!["venv", "--python", "3.11"], | |
| vec![("UV_PYTHON_PREFERENCE", "only-system")], | |
| )); | |
| } | |
| if system_python_ge_311() { | |
| venv_attempts.push(( | |
| "system-python", | |
| vec!["venv"], | |
| vec![("UV_PYTHON_PREFERENCE", "only-system")], | |
| )); | |
| } |
There was a problem hiding this comment.
Good catch — fixed in the latest commit. Dropped the --python 3.11 pin from the system-Python attempt; with only-system + the project's requires-python = ">=3.11", uv resolves any compatible system interpreter (3.12/3.13 included) instead of demanding 3.11.x exactly.
…ptile #140) system_python_ge_311() accepts 3.12/3.13, but the fallback passed `--python 3.11`, forcing uv to find a 3.11.x interpreter exactly — so a machine with only 3.12/3.13 failed the fallback and wrongly hit the remediation. Drop the pin; `only-system` + the project's `requires-python = ">=3.11"` lets uv resolve any compatible system interpreter. cargo test: 2 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gate (#142) Verification of #140 (driving real uv) found system_python_ge_311() was stricter than uv's own interpreter discovery: it probed only `python3`/`python`, so on a machine where `python3` is the macOS 3.9 but a Homebrew 3.14 exists, the gate returned false and the only-system fallback was skipped — even though `UV_PYTHON_PREFERENCE=only-system uv venv` resolves 3.14 fine. Fix: drop the pre-gate (and the now-unused parse_py_version/system_python_ge_311 helpers + the parse test) and always add the system-python attempt as the last resort. uv's discovery is the authority; with `requires-python = ">=3.11"` it resolves any compatible system interpreter or fails fast → remediation. Verified live: `only-system uv venv` created a venv from system CPython 3.14.5 on this host (no 3.11.x present). cargo test + cargo check clean. Refs #130. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bring the branch up to date with main and resolve 5 conflicts as feature-unions so nothing shipped since #133 was opened regresses: - useTTS.js: take main's #141 validator-safe instruct (buildDesignInstruct); #133 held only the stale pre-#141 dedup logic. - dub_pipeline.py: UNION — keep #133's download-task cancel cleanup AND main's plan-04 logging + structured failure event (build_failure). - dubSlice.ts / useDubWorkflow.js: UNION — keep both #133's dub download-progress state (setDubPrepProgress / setDubCurrentSegId) and main's pipeline-error-transparency state (setDubFailure). - bootstrap.rs: take main's shipped plan-03 network-resilience cascade (#140/#142); #133's region-based mirror approach was the superseded alternative for the same concern. get_effective_region stays live (shared via config.rs, used by tools.rs). Verified: frontend typecheck + build clean; 90 backend tests pass (dub / failure / timing / onboarding / personalities), 0 failures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
plan-03 — Closes #60. Addresses #130, #57, #127.
First-run bootstrap downloaded managed Python from GitHub with no mirror and a short retry budget — a GitHub-blocked/unresolvable network killed the install dead-on-arrival (#60:
uv venv failed, DNS error).Fix (
frontend/src-tauri/src/bootstrap.rs)apply_uv_http_env()—UV_HTTP_TIMEOUT=120/UV_HTTP_CONNECT_TIMEOUT=30/UV_HTTP_RETRIES=5on bothuv venvanduv sync(step 2).uv venvcascade (step 1+3): default GitHub → gh-proxy mirror (UV_PYTHON_INSTALL_MIRROR) → system Python (UV_PYTHON_PREFERENCE=only-system, only when a system Python ≥3.11 is detected). First success wins.uvexit code.BootstrapSplashhint for the GitHub-blocked case.troubleshooting.mdrestricted-network section — mirror env vars, China PyPI index, honest VPN note — referenced by the remediation text.Cross-platform parity
Mirrors/fallbacks only kick in after the default path fails, so an unrestricted network is unchanged.
Tests
Rust
#[cfg(test)]:parse_py_version(real + garbage),apply_uv_http_envsets the three vars —cargo test: 2 passed, crate compiles. Docs-drift validator + frontend build green.This is ~90% Rust in the Tauri bootstrap. The restricted-network E2E paths (mirror install, only-system fallback) depend on real network conditions + a packaged Tauri build and cannot be reproduced in the dev/CI harness —
cargo+ the unit tests cover compile + the pure helpers only. Recommend a manual smoke on a GitHub-blocked network (or a VM with GitHub firewalled) before relying on it in the wild. Also note: CodeRabbit/Greptile/CodeQL give weaker coverage on Rust than on the Python PRs.Spec/plan/tasks in
specs/004-installer-network-resilience/.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests