From ac49c61f21a14f169d158b23bf60a1788f977534 Mon Sep 17 00:00:00 2001 From: Stuart Cameron Date: Mon, 8 Jun 2026 18:59:59 +1000 Subject: [PATCH 1/3] Add Linux whisper-cli entries to whisper-addon.json Point the app at the self-built linux-x64/arm64 whisper-cli tarballs published to the whisper-v1.8.3 release (format: tar, extracted to whisper/bin/whisper-cli). This lets Linux users download the whisper subtitle add-on at runtime, matching macOS (Homebrew bottle) and Windows (upstream release zip). Also fix build-whisper.yml: the build jobs don't check out the repo, so gh release commands had no git remote to infer from ("not a git repository"). Set GH_REPO explicitly so future runs publish correctly. (The v1.8.3 release was created manually from this run's artifacts.) Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/build-whisper.yml | 3 +++ app/assets/whisper-addon.json | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/.github/workflows/build-whisper.yml b/.github/workflows/build-whisper.yml index 3ded36b..40f8813 100644 --- a/.github/workflows/build-whisper.yml +++ b/.github/workflows/build-whisper.yml @@ -81,6 +81,9 @@ jobs: if: inputs.release_tag != '' env: GH_TOKEN: ${{ github.token }} + # These jobs do not check out the repo, so gh has no git remote to + # infer the repo from — set it explicitly. + GH_REPO: ${{ github.repository }} run: | # Create the release if it does not exist (|| true tolerates a race # with the sibling arch job creating it concurrently). diff --git a/app/assets/whisper-addon.json b/app/assets/whisper-addon.json index 8e215d5..f0bbe56 100644 --- a/app/assets/whisper-addon.json +++ b/app/assets/whisper-addon.json @@ -22,6 +22,20 @@ "format": "zip", "executable": "whisper-cli.exe", "size": 3968674 + }, + "linux-x64": { + "url": "https://github.com/StuartCameronCode/VapourBox/releases/download/whisper-v1.8.3/whisper-cli-linux-x64.tar.gz", + "format": "tar", + "executable": "whisper-cli", + "size": 1573360, + "sha256": "4ea12345281a210937ce900984721d650adf834e308d03e520c506923ec4c8e6" + }, + "linux-arm64": { + "url": "https://github.com/StuartCameronCode/VapourBox/releases/download/whisper-v1.8.3/whisper-cli-linux-arm64.tar.gz", + "format": "tar", + "executable": "whisper-cli", + "size": 1527325, + "sha256": "2ffb99a5432bb6153b2a6e29ce7034465358f2fb5b98dad99c69663f6305c1c4" } } }, From f2b40f3d0a781c1e5a623aebb85b6db90759dd14 Mon Sep 17 00:00:00 2001 From: Stuart Cameron Date: Mon, 8 Jun 2026 19:10:56 +1000 Subject: [PATCH 2/3] CI: download published whisper-cli for the Linux test, don't build it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Linux test job built whisper.cpp from source, but the app never does that — it downloads the prebuilt whisper-cli add-on at runtime. Now that whisper-addon.json has a linux-x64 source, the test downloads that same published tarball (URL read from the JSON so it can't drift), exercising the real artifact + tar layout. Mirrors the Windows job, which curls its release zip. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci-test.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml index b81df66..596d22c 100644 --- a/.github/workflows/ci-test.yml +++ b/.github/workflows/ci-test.yml @@ -230,15 +230,14 @@ jobs: curl -L -o .whisper-cache/ggml-small.bin "$WHISPER_MODEL_URL" fi cp .whisper-cache/ggml-small.bin addons/whisper/models/ggml-small.bin - # No prebuilt Linux whisper-cli is published (macOS uses a Homebrew - # bottle, Windows a release zip), so build whisper.cpp from source. - # Static build (BUILD_SHARED_LIBS=OFF) => a self-contained whisper-cli - # with no lib/ dir to manage; GGML_NATIVE=OFF for runner portability. - git clone --depth 1 -b v1.8.3 https://github.com/ggml-org/whisper.cpp /tmp/whisper.cpp - cmake -S /tmp/whisper.cpp -B /tmp/whisper.cpp/build \ - -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DGGML_NATIVE=OFF - cmake --build /tmp/whisper.cpp/build --config Release -j"$(nproc)" - cp "$(find /tmp/whisper.cpp/build -name whisper-cli -type f | head -1)" addons/whisper/bin/whisper-cli + # Download the same published whisper-cli the app fetches at runtime + # (the linux-x64 source in whisper-addon.json), so the test exercises + # the real add-on artifact + tar layout instead of building from + # source. Mirrors the Windows job, which curls its release zip. + WHISPER_URL=$(python3 -c "import json;print(json.load(open('app/assets/whisper-addon.json'))['binary']['platforms']['linux-x64']['url'])") + echo "whisper-cli: $WHISPER_URL" + curl -L -o /tmp/whisper-cli.tar.gz "$WHISPER_URL" + tar xzf /tmp/whisper-cli.tar.gz -C addons/whisper # => addons/whisper/bin/whisper-cli chmod +x addons/whisper/bin/whisper-cli ls -la addons/whisper/bin addons/whisper/models From eb3f8ac66c68bac357c8487810389703780ca8d4 Mon Sep 17 00:00:00 2001 From: Stuart Cameron Date: Mon, 8 Jun 2026 20:27:07 +1000 Subject: [PATCH 3/3] docs: detail the three test suites in CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Distinguish the Rust worker tests (cargo test), the Flutter test/ suite (the CI gate), and the Flutter integration_test/ suite (local-only, not in CI — Flutter routes it through the device launcher, and it has drifted out of sync with the models). Update the CI gate description to include the Linux x64 job and the per-platform whisper-cli provisioning. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 79e6010..8e9c72d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -410,25 +410,74 @@ The most important parameters: ## Testing +VapourBox has **three distinct test suites**. Know which is which before adding +or changing tests — they live in different places and run differently. + +### 1. Rust worker tests — `worker/tests/`, run by `cargo test` + ```bash -# Rust tests cd worker && cargo test +cd worker && cargo test --test subtitle_integration_test -- --nocapture +``` + +- `filter_integration_test.rs` — **every filter/parameter change must add a + numbered test here** (see "Adding a New Filter"). It generates `.vpy` scripts + and, via `run_job`, runs the `vspipe | ffmpeg` pipeline, so it needs `deps/`. +- `subtitle_integration_test.rs` — runs `whisper-cli` on + `Tests/TestResources/small_clip.mp4`; needs the whisper add-on + ffmpeg. +- In **debug** builds `DependencyLocator` finds repo-root `deps/`/`addons/` by + searching upward — **except Linux**, which only reads + `~/.local/share/VapourBox/` (no upward search), so CI symlinks those there. -# Flutter tests +### 2. Flutter `test/` suite — `app/test/`, run by `flutter test` ← the CI gate + +```bash cd app && flutter test +``` -# Test worker standalone +Headless Dart-VM tests. A mix of pure unit tests (`dynamic_parameters`, +`filter_schema`, `parameter_converter`, `widget_test`, `scan_type_detection`) +and integration-style tests that shell out to the bundled binaries +(`vapoursynth_integration_test`, `schema_converter_integration_test`); the latter +need the per-arch `deps/` and (for whisper) `addons/`. **This is the Flutter +suite CI runs** — put new shell-out Dart tests here so CI covers them. + +### 3. Flutter `integration_test/` suite — `app/integration_test/`, NOT in CI + +```bash +cd app && flutter test integration_test # separate invocation; needs a display/device +``` + +- Flutter routes **anything** under `integration_test/` through the device + launcher (even plain `package:test` files), so it can't be combined with the + `test/` suite in one `flutter test` call and won't run on a headless CI runner + without a display (e.g. `xvfb`). These are **local/manual** tests. +- **Not maintained by CI, so they drift.** As of this writing + `filter_pipeline_test.dart` is stale and does not compile — it references a + removed API (`EncodingSettings.audioCopy`, now the `AudioMode` enum; + `ChromaFixParameters.vinverseScl`, now `vinverseSstr`/`vinverseAmnt`). Fix or + delete before relying on it; prefer adding shell-out tests to suite #2 instead. + +```bash +# Run the worker standalone (no test harness) cd worker && cargo run --release -- --config test_job.json ``` -**CI test gate** (`.github/workflows/ci-test.yml`): runs on push to `main` + PRs. It -pulls the published deps bundle and the whisper add-on (binary + small model), -then runs the full Rust + Flutter suites — including the subtitle integration -test — on macOS **arm64** (`macos-15`) and **x64** (`macos-15-intel`) and Windows x64. The -subtitle test needs `addons/whisper/{bin/whisper-cli,models/ggml-small.bin}` and -ffmpeg from `deps/`; the scan-type/vapoursynth Flutter tests need the per-arch -`deps/` dir. The `small_clip.mp4` + telecine/interlaced fixtures are committed -under `Tests/TestResources/`. +### CI test gate (`.github/workflows/ci-test.yml`) + +Runs on push to `main` + PRs (skipped for doc-only changes via `paths-ignore`). +Each job pulls the published deps bundle + the whisper add-on, then runs +**suite #1 (`cargo test`) and suite #2 (`flutter test`)** — including the subtitle +integration test. Matrix: macOS **arm64** (`macos-15`), macOS **x64** +(`macos-15-intel`), **Windows x64**, **Linux x64** (`ubuntu-22.04`). Notes: + +- whisper-cli is provisioned from the **same source the app uses at runtime** + (`app/assets/whisper-addon.json`): macOS via a Homebrew bottle, Windows/Linux + by downloading the published release zip/tarball (Linux from `whisper-vX.Y.Z`, + built by `build-whisper.yml`). +- Fixtures (`small_clip.mp4`, telecine/interlaced clips) are committed under + `Tests/TestResources/`. +- Suite #3 (`integration_test/`) is **not** part of this gate (see above). ## Code Style