From 8dc44ae21d9876cc5efd82cba2060297d25571d8 Mon Sep 17 00:00:00 2001 From: Viet Nguyen Date: Fri, 14 Aug 2026 07:07:50 +0000 Subject: [PATCH 1/4] fix(daemon): make the data directory before logging into it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `summo serve --background` on a machine that has never run Summo failed with a bare "No such file or directory": the log file is created inside `~/.summo`, and on a fresh install nothing had made `~/.summo` yet. Found by running the released tarball against an empty home, which is the only situation in which it happens — and the first thing a new user does. --- crates/summo-cli/src/daemon.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/crates/summo-cli/src/daemon.rs b/crates/summo-cli/src/daemon.rs index 37b63af..16824a6 100644 --- a/crates/summo-cli/src/daemon.rs +++ b/crates/summo-cli/src/daemon.rs @@ -117,6 +117,10 @@ pub async fn start_background(paths: &Paths, port: u16, dev: bool) -> Result String { From 1caaad9102de15348033c4faac71701e0c6f39b9 Mon Sep 17 00:00:00 2001 From: Viet Nguyen Date: Fri, 14 Aug 2026 07:20:52 +0000 Subject: [PATCH 2/4] test(e2e): find the native libraries when a warm cache did not copy them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `full-flow` failed with "libsherpa-onnx-c-api.so: cannot open shared object file" on a run whose only change was a one-line fix in the daemon. The binary is linked with an `$ORIGIN` rpath, which is right for the shipped bundle where the libraries sit beside the executable; out of `target/debug` it works only because Cargo copies them there while the build script runs, and on a warm cache the build script does not run. Cargo's own `deps/` always has them, so the harness puts that on the library path. Reproduced by moving the copies out of `target/debug` — the daemon then failed to start exactly as it did on CI, and passed with this. --- apps/web/e2e/daemon.mjs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/web/e2e/daemon.mjs b/apps/web/e2e/daemon.mjs index c733474..bbc1a1c 100644 --- a/apps/web/e2e/daemon.mjs +++ b/apps/web/e2e/daemon.mjs @@ -128,7 +128,26 @@ Họ muốn bản dùng thử. * `port: 0` asks the operating system for a free one, so two suites running at once cannot collide * — which is what a fixed port did the first time this was tried in parallel. */ -export async function boot({ name = "e2e", seed = true, registry = REGISTRY } = {}) { +export /** + * Where the native libraries are, when the build did not leave them beside the binary. + * + * A build with `--features models` links sherpa-onnx, and the binary is linked with an `$ORIGIN` + * rpath — right for the shipped bundle, where the libraries sit beside the executable. Out of + * `target/debug` that only works because Cargo copies them there while the build script *runs*; on + * a machine with a warm cache it does not run, the copy never happens, and the daemon dies with + * "libsherpa-onnx-c-api.so: cannot open shared object file". Cargo's own `deps/` always has them, + * so the harness points at it: the failure has nothing to do with whatever is being tested, which + * is the worst kind of red build. + */ +function libraries() { + const beside = dirname(BINARY); + const key = process.platform === "darwin" ? "DYLD_LIBRARY_PATH" : "LD_LIBRARY_PATH"; + return { + [key]: [beside, join(beside, "deps"), process.env[key]].filter(Boolean).join(":"), + }; +} + +async function boot({ name = "e2e", seed = true, registry = REGISTRY } = {}) { const home = join("/tmp", `summo-${name}-${process.pid}`); rmSync(home, { recursive: true, force: true }); mkdirSync(home, { recursive: true }); @@ -141,7 +160,7 @@ export async function boot({ name = "e2e", seed = true, registry = REGISTRY } = // tests a real registry without depending on a deployed CDN — and so it keeps passing when the // network is not there. A caller can substitute one: `models.mjs` builds a registry whose file // URLs point at a local server, so installing does not reach the public internet either. - env: { ...process.env, SUMMO_REGISTRY: registry }, + env: { ...process.env, SUMMO_REGISTRY: registry, ...libraries() }, }); // Detached from Node's own exit accounting. A suite that forgets `stop()` should end with a // failed assertion, not hang until whatever is running it gives up — which is how a passing From e650151bc8ef5b92a5c2476e31e16cd748bd4ca6 Mon Sep 17 00:00:00 2001 From: Viet Nguyen Date: Fri, 14 Aug 2026 07:31:33 +0000 Subject: [PATCH 3/4] fix(e2e): put the export back on boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit inserted a helper between `export` and `async function boot`, which exported the helper and left `boot" unexported — `assistant.mjs` imports it by name and died on a module error. Caught by running the whole suite rather than the one test the change was about. --- apps/web/e2e/daemon.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/e2e/daemon.mjs b/apps/web/e2e/daemon.mjs index bbc1a1c..e3e3354 100644 --- a/apps/web/e2e/daemon.mjs +++ b/apps/web/e2e/daemon.mjs @@ -128,7 +128,7 @@ Họ muốn bản dùng thử. * `port: 0` asks the operating system for a free one, so two suites running at once cannot collide * — which is what a fixed port did the first time this was tried in parallel. */ -export /** +/** * Where the native libraries are, when the build did not leave them beside the binary. * * A build with `--features models` links sherpa-onnx, and the binary is linked with an `$ORIGIN` @@ -147,7 +147,7 @@ function libraries() { }; } -async function boot({ name = "e2e", seed = true, registry = REGISTRY } = {}) { +export async function boot({ name = "e2e", seed = true, registry = REGISTRY } = {}) { const home = join("/tmp", `summo-${name}-${process.pid}`); rmSync(home, { recursive: true, force: true }); mkdirSync(home, { recursive: true }); From f95ae676b2aa759350519a9fcecfd43ab44555e9 Mon Sep 17 00:00:00 2001 From: Viet Nguyen Date: Fri, 14 Aug 2026 07:44:16 +0000 Subject: [PATCH 4/4] ci: rebuild sherpa-onnx when the cache skipped the step that copies it `full-flow` has been failing with "libsherpa-onnx-c-api.so: cannot open shared object file" on runs that changed nothing near it. The library is put beside the binary by the crate's build script; a warm cargo cache skips the build script, and the `$ORIGIN` rpath then points at a directory with nothing in it. The harness now also puts `target/debug` and its `deps` on the library path, which covers the local case, and this covers the one where the file is not in the target directory at all. --- .github/workflows/ci.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 171b2d3..c2f3b4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -379,6 +379,22 @@ jobs: # `bundled,models` is a heavier build — it links sherpa-onnx — so it is a second step rather # than a change to the one above: the ten fast suites should not wait for it to fail. - run: cargo build --bin summo-engine --features bundled,models + # sherpa-onnx ships as a shared library, and it is the crate's *build script* that puts it + # beside the binary — so a cache hit, which skips the build script, produces a binary linked + # with an `$ORIGIN` rpath and nothing at `$ORIGIN` to find. The daemon then dies with + # "libsherpa-onnx-c-api.so: cannot open shared object file" and the harness reports it as + # "the daemon did not come up", which is a long way from the cause. + # + # Rebuilding just that crate is the cheapest way to make the copy happen again, and it only + # costs anything on the runs where it was missing. + - name: The speech libraries, beside the binary + run: | + ls -l target/debug/libsherpa* 2>/dev/null || echo "not beside the binary" + if [ ! -e target/debug/libsherpa-onnx-c-api.so ]; then + cargo clean -p sherpa-rs-sys + cargo build --bin summo-engine --features bundled,models + ls -l target/debug/libsherpa* + fi - run: pnpm -C apps/web e2e:full-flow env: SUMMO_REGISTRY_DIR: ${{ github.workspace }}/.registry