[agent]
Agent: Claude Code (claude-sonnet-4-6) — caro-qa-agent
Problem
Any command that triggers the embedded model download (caro -p "...", caro ai --once, etc.) hangs indefinitely without any user-visible feedback in environments where the model binary download stalls at the network layer. The process blocks silently until killed. In v1.3.0, the same condition produced "Failed to download model after 3 attempts" and returned control to the user; v1.5.0 hangs forever.
Reproduction
# Build without remote-backends
cargo build --release --features embedded-cpu
# Run a prompt that is not handled by the static_matcher
# (no model pre-downloaded, network stalls on binary blob)
./target/release/caro -p 'list files in current directory' --dry-run
# Process hangs indefinitely — Ctrl-C required
# $ RUST_LOG=debug ./target/release/caro -p 'list files' --dry-run # still no output
# Same for conversational mode
./target/release/caro ai --once 'list files'
# Process hangs indefinitely — zero output, no error, no ETA
Expected vs Actual
Expected: Either (a) a timeout fires and caro exits with a clear error ("Model download timed out after 30s. Check caro doctor for setup."), or (b) the v1.3.0 retry-with-backoff behavior ("Failed to download model after 3 attempts") is restored.
Actual: Process enters a sleeping state (6 threads, state S) and remains there indefinitely — no stdout, no stderr, no indicatif progress (indicatif suppresses output in non-TTY environments). No HTTP timeout is configured on the reqwest client so the stalled TCP connection is never detected.
Environment
- caro version:
caro 1.5.0 (be07b22 2026-07-18)
- OS: Linux 6.18.44 x86_64 (remote sandbox)
- Test date: 2026-09-06
- Backend: embedded (no model pre-downloaded)
- Network:
huggingface.co HTTP 200 reachable; binary blob download stalls (proxy blocks large transfers)
Investigation
Root cause — src/cache/http_client.rs:42:
// HfHubClient::new()
let client = Client::builder().user_agent("caro/1.0").build()?;
No .timeout() or .connect_timeout() is passed to the builder. When the HEAD request or binary GET request stalls, reqwest never fires a timeout error, so is_timeout() at src/cache/mod.rs:63 never matches.
Regression evidence — qa-known-flakes.md FLAKE-001 (filed 2026-05-07 under v1.3.0) documents "Backend is not available: Failed to download model after 3 retries (2s, 4s backoff)". The retry-with-backoff path is no longer reachable because the blocking I/O never returns an error.
Why indicatif doesn't help: src/cache/progress.rs uses indicatif::ProgressBar without a TTY check. In non-TTY environments (CI, pipes, remote sandbox), indicatif silently suppresses all progress output. Users get a blank terminal.
Fix direction:
- Add timeout to the reqwest client in
src/cache/http_client.rs:
let client = Client::builder()
.user_agent("caro/1.0")
.connect_timeout(Duration::from_secs(15))
.timeout(Duration::from_secs(300)) // 5-min cap on full download
.build()?;
- Restore or add download retry logic with backoff (was present in v1.3.0).
- Add a plain-text
eprintln! fallback in src/cache/download.rs for non-TTY environments so users always see "Downloading model…" regardless of indicatif rendering.
Severity
P1 — Regression. The embedded backend is the primary backend for offline/local users. Any first-run in a network-constrained environment (proxy, air-gapped node, CI) now hangs permanently instead of failing gracefully. caro doctor correctly reports "No ready backend" but caro -p "..." and caro ai --once bypass that check and attempt the download silently.
Prompt used to generate this comment
caro QA agent — daily rotation slot A+B+C, scheduled remote run 2026-09-06
[agent]Agent: Claude Code (
claude-sonnet-4-6) — caro-qa-agentProblem
Any command that triggers the embedded model download (
caro -p "...",caro ai --once, etc.) hangs indefinitely without any user-visible feedback in environments where the model binary download stalls at the network layer. The process blocks silently until killed. In v1.3.0, the same condition produced "Failed to download model after 3 attempts" and returned control to the user; v1.5.0 hangs forever.Reproduction
Expected vs Actual
Expected: Either (a) a timeout fires and caro exits with a clear error ("Model download timed out after 30s. Check
caro doctorfor setup."), or (b) the v1.3.0 retry-with-backoff behavior ("Failed to download model after 3 attempts") is restored.Actual: Process enters a sleeping state (6 threads, state S) and remains there indefinitely — no stdout, no stderr, no indicatif progress (indicatif suppresses output in non-TTY environments). No HTTP timeout is configured on the reqwest client so the stalled TCP connection is never detected.
Environment
caro 1.5.0 (be07b22 2026-07-18)huggingface.coHTTP 200 reachable; binary blob download stalls (proxy blocks large transfers)Investigation
Root cause —
src/cache/http_client.rs:42:No
.timeout()or.connect_timeout()is passed to the builder. When the HEAD request or binary GET request stalls,reqwestnever fires a timeout error, sois_timeout()atsrc/cache/mod.rs:63never matches.Regression evidence —
qa-known-flakes.mdFLAKE-001 (filed 2026-05-07 under v1.3.0) documents "Backend is not available: Failed to download model after 3 retries (2s, 4s backoff)". The retry-with-backoff path is no longer reachable because the blocking I/O never returns an error.Why indicatif doesn't help:
src/cache/progress.rsusesindicatif::ProgressBarwithout a TTY check. In non-TTY environments (CI, pipes, remote sandbox), indicatif silently suppresses all progress output. Users get a blank terminal.Fix direction:
src/cache/http_client.rs:eprintln!fallback insrc/cache/download.rsfor non-TTY environments so users always see "Downloading model…" regardless of indicatif rendering.Severity
P1 — Regression. The embedded backend is the primary backend for offline/local users. Any first-run in a network-constrained environment (proxy, air-gapped node, CI) now hangs permanently instead of failing gracefully.
caro doctorcorrectly reports "No ready backend" butcaro -p "..."andcaro ai --oncebypass that check and attempt the download silently.Prompt used to generate this comment