Files
buzz/crates/buzz-mesh-smoke/examples/mesh_stack_smoke.rs
Mic Neale 4544ba1713 chore(mesh): upgrade MeshLLM to 0.76.2 (#7559)
## Summary

Upgrade Buzz from MeshLLM `v0.76.0-rc9` to the latest stable [v0.76.2
release](https://github.com/Mesh-LLM/mesh-llm/releases/tag/v0.76.2) (via
v0.76.1).

- Update all eight Mesh git dependencies across desktop and relay smoke
examples; both lockfiles resolve all 47 Mesh packages to
`a0c1e66b0ac037dd56544b9e2d94969ea43d694f` (tag `v0.76.2`). All non-Mesh
lock records are unchanged by the 0.76.1 → 0.76.2 bump.
- Match Mesh's `ed25519-dalek = 3.0.0` and `rusqlite = 0.40`
dependencies.
- Explicitly enable rusqlite's `fallible_uint` feature, preserving
Buzz's existing `u64` SQL conversions when **mesh is disabled**.
Mesh-enabled builds previously supplied this transitively, so testing
both configurations matters.
- Temporarily pin **only** the optional `sqlx-sqlite` package to the
merged upstream compatibility fix
[transact-rs/sqlx#4402](https://github.com/transact-rs/sqlx/pull/4402),
revision `94aafe3a68884d923b0798a767c8d7f6cfda89d2`. SQLx 0.9.0 caps
`libsqlite3-sys` below 0.38, while Mesh 0.76 requires 0.38. Cargo
resolves the conflict even with SQLite disabled. The fix raises that
upper bound; remove the patch once released. Buzz's active PostgreSQL
driver stays on crates.io SQLx 0.9.0.
- Preserve the explicit Linux keyring 3 `crypto-rust` feature so Secret
Service sessions retain DH encryption independently of Mesh keyring 4.
- Preserve the dedicated examples-only `buzz-mesh-smoke` crate and
lifecycle workflow wiring, keeping Mesh/native-runtime dev dependencies
out of relay CI builds.
- v0.76.1 → v0.76.2 upstream delta: self-updater fix for composed
product-v2 bundles (Mesh-LLM/mesh-llm#1844) plus release plumbing — no
API changes affecting Buzz.
- Merged `origin/main` (`7c789dee0`) without rewriting shared PR
history.

### Validation at `ae4adba15` (local macOS ARM64, Hermit toolchain)

- **Passed:** `cargo test --locked -p buzz-mesh-smoke --all-targets`
(all six example harnesses compile; no live harness execution).
- **Passed:** desktop Tauri workspace tests, both default and
`--features mesh-llm` graphs (3,296 tests with mesh enabled, 0
failures).
- **Passed:** `just desktop-tauri-clippy` (both feature graphs, `-D
warnings`), root workspace clippy `-D warnings`, `cargo fmt --all
--check`.
- **Passed:** `--locked` metadata resolution for both workspaces;
lockfile diff audited to touch only Mesh package records.
- **Passed:** full pre-push hook suite on the final push (branch-skew,
rust-tests, desktop-tauri-checks, file-size-check) — no hooks bypassed.
- **Not run:** live Mesh inference/admission smoke or installed-app UI
exercise. CI lifecycle smoke coverage applies.

Originating Buzz conversation:
buzz://message?channel=dffbc117-845a-4c02-bc3f-eaeeefc4deaa&id=670f9c262e1ec0a4df5600b3173a0c5de2abe17e08ba9ccfdd8eff109fadf1a8

---------

Signed-off-by: Thinker <75d8a808fa21bb8d1812e080cf471db601c6e8e6a62dcd516d37531e83a7bb77@meshllm.communities.buzz.xyz>
Signed-off-by: Michael Neale <michael.neale@gmail.com>
Co-authored-by: Thinker <75d8a808fa21bb8d1812e080cf471db601c6e8e6a62dcd516d37531e83a7bb77@meshllm.communities.buzz.xyz>
Co-authored-by: Michael Neale <michael.neale@gmail.com>
Co-authored-by: Galadriel <b81c841ed20a8e17caf4e6fac2f6f3bc61d304c84b8394720f6d00f37538c47e@meshllm.communities.buzz.xyz>
Co-authored-by: Gu <gu@buzz>
2026-09-24 07:32:07 -06:00

122 lines
4.8 KiB
Rust

//! Tokio worker stack-size smoke — reproduces and verifies the fix for the
//! mesh-llm model-download stack overflow (SIGABRT via stack guard).
//!
//! Crash report (2026-07-08, buzz-desktop 0.3.46): enabling Share compute
//! aborted the app on a `tokio-rt-worker` thread inside
//! `mesh_llm_host_runtime::models::resolve::download_model_ref_with_progress_details`
//! — Rust's stack-overflow signal handler fired on tokio's default 2 MiB
//! worker stack. Upstream mesh-llm runs its own binary on 8 MiB worker
//! stacks for exactly this reason (`DEFAULT_WORKER_STACK_SIZE` in mesh-llm
//! `main.rs`), as does mesh-console.
//!
//! This harness polls the same future as a spawned task (matching how Tauri
//! polls command futures on worker threads) in two subprocess legs:
//!
//! 1. 2 MiB worker stacks (tokio default) — expected to DIE from the
//! stack guard (signal, no exit code). Proves we reproduced the crash.
//! 2. 8 MiB worker stacks (the fix installed in desktop `lib.rs` via
//! `tauri::async_runtime::set`) — expected to complete the download.
//!
//! Each leg gets a fresh HF_HOME so the download really runs (a cache hit
//! never reaches the deep code path). Network required; downloads a ~100 MB
//! GGUF twice at most (leg 1 usually dies early). Not CI — run manually:
//!
//! cargo run -p buzz-relay --example mesh_stack_smoke
use std::process::{Command, Stdio};
/// Small real model, same one the admission smoke uses.
const MODEL: &str = "jc-builds/SmolLM2-135M-Instruct-Q4_K_M-GGUF:Q4_K_M";
const TOKIO_DEFAULT_STACK: usize = 2 * 1024 * 1024;
/// Must match `buzz_lib::mesh_llm::MESH_WORKER_STACK_SIZE` (desktop crate is
/// not a dependency of buzz-relay, so the value is duplicated here).
const FIXED_STACK: usize = 8 * 1024 * 1024;
fn main() -> anyhow::Result<()> {
match std::env::var("MESH_STACK_ROLE").ok().as_deref() {
Some("download") => role_download(),
_ => orchestrate(),
}
}
/// Subprocess: poll the download future as a spawned task on a worker
/// thread with the requested stack size — the exact shape of a Tauri
/// command future.
fn role_download() -> anyhow::Result<()> {
let stack: usize = std::env::var("MESH_STACK_SIZE")?.parse()?;
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_stack_size(stack)
.build()?;
runtime.block_on(async {
tokio::spawn(async {
mesh_llm_host_runtime::models::download_model_ref_with_progress_details(MODEL, true)
.await
.map(|_| ())
.map_err(|error| anyhow::anyhow!("download failed: {error}"))
})
.await?
})?;
println!("DOWNLOAD_OK");
// Skip destructors (ggml teardown abort, mesh-console issue #8).
std::process::exit(0);
}
fn run_leg(stack: usize, hf_home: &std::path::Path) -> anyhow::Result<(bool, Option<i32>)> {
let exe = std::env::current_exe()?;
let status = Command::new(exe)
.env("MESH_STACK_ROLE", "download")
.env("MESH_STACK_SIZE", stack.to_string())
.env("HF_HOME", hf_home)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()?;
Ok((status.success(), status.code()))
}
fn orchestrate() -> anyhow::Result<()> {
let scratch = std::env::temp_dir().join(format!("mesh-stack-smoke-{}", std::process::id()));
println!(
"=== leg 1: {} MiB worker stacks (tokio default) — expecting stack-guard death ===",
TOKIO_DEFAULT_STACK / (1024 * 1024)
);
let hf1 = scratch.join("hf-2mb");
std::fs::create_dir_all(&hf1)?;
let (ok_2mb, code_2mb) = run_leg(TOKIO_DEFAULT_STACK, &hf1)?;
println!(
"=== leg 2: {} MiB worker stacks (the fix) — expecting success ===",
FIXED_STACK / (1024 * 1024)
);
let hf2 = scratch.join("hf-8mb");
std::fs::create_dir_all(&hf2)?;
let (ok_8mb, code_8mb) = run_leg(FIXED_STACK, &hf2)?;
let _ = std::fs::remove_dir_all(&scratch);
println!();
println!(
"leg 1 (2 MiB): success={ok_2mb} exit_code={code_2mb:?} (None = killed by signal, i.e. stack guard)"
);
println!("leg 2 (8 MiB): success={ok_8mb} exit_code={code_8mb:?}");
// Leg 2 is the hard gate: the fix must work.
if !ok_8mb {
anyhow::bail!("FAIL: download did not complete on 8 MiB worker stacks — fix is broken");
}
// Leg 1 documents the repro. If it *succeeds*, the overflow needs deeper
// nesting than this harness provides — flag loudly but do not fail, the
// fix leg is still proven.
if ok_2mb {
println!(
"WARNING: 2 MiB leg did not crash here; overflow requires the app's extra \
tauri/ipc nesting. Fix leg still verified."
);
} else {
println!("repro confirmed: 2 MiB worker stack dies, matching the crash report");
}
println!("PASS");
Ok(())
}