Skip to content

docs+ci: upstream-sync runbook + whisper divergence guard (QIP PR 3)#97

Merged
ogad-tether merged 8 commits into
feat/whisper-subtreefrom
feat/upstream-sync-guard
Jul 21, 2026
Merged

docs+ci: upstream-sync runbook + whisper divergence guard (QIP PR 3)#97
ogad-tether merged 8 commits into
feat/whisper-subtreefrom
feat/upstream-sync-guard

Conversation

@ogad-tether

Copy link
Copy Markdown

What

PR 3 of the repo-reorg QIP (#94) — the enforcement + documentation layer on top of #96. Stacked on #96; retarget as the stack merges.

  • docs/UPSTREAM-SYNC.md — the git subtree pull runbook: conflicts are expected only in the PATCHES.md manifest files; checklist covers bumping UPSTREAM_PIN, re-verifying the manifest, the never-edit-vendored-ggml rule, local sanity commands, and the registry pin-bump coordination.
  • whisper-divergence-guard.yml — the teeth: on any PR touching third_party/whisper.cpp, diff the subtree against the UPSTREAM_PIN tag (tree-to-tree) and fail if anything outside the PATCHES.md manifest differs. ggml divergence gets a dedicated error pointing at qvac-ext-ggml@speech.

Validation

Dry-ran the guard logic locally against the #96 tree: the declared manifest set matches the actual divergence exactly (10 files), guard passes; an undeclared path is surfaced by comm and fails the job. The guard runs on this PR itself (path filter matches its own workflow file).

🤖 Generated with Claude Code

- docs/UPSTREAM-SYNC.md: the git-subtree pull runbook — expected
  conflict surface (only the PATCHES.md files), post-pull checklist
  (bump UPSTREAM_PIN, re-verify the manifest, never resolve into
  vendored ggml), and the coordination steps.
- whisper-divergence-guard.yml: fails any PR where third_party/
  whisper.cpp differs from the UPSTREAM_PIN tag outside the PATCHES.md
  manifest (tree-to-tree diff vs the upstream tag, allowlist parsed
  from the manifest table). ggml/ divergence gets a dedicated error.

Dry-run locally: declared set == actual divergence, guard passes; an
undeclared file makes comm(1) surface it and the job exit 1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ogad-tether
ogad-tether marked this pull request as ready for review July 17, 2026 10:07
@ogad-tether
ogad-tether requested review from a team as code owners July 17, 2026 10:07
@ogad-tether ogad-tether self-assigned this Jul 21, 2026
@ogad-tether
ogad-tether merged commit 72ce9dc into feat/whisper-subtree Jul 21, 2026
5 checks passed
GustavoA1604 pushed a commit that referenced this pull request Jul 22, 2026
…aster (QIP PRs 2+3) (#102)

* ci: add per-engine CI lanes for parakeet-cpp and tts-cpp + repo-reorg QIP (PR 0)

Nothing in this repo's CI built or tested our engines until now — real
verification happened three repos downstream in tetherto/qvac. This adds
path-filtered workflows that, per PR:

- build qvac-ext-ggml@speech (CPU-only, cached by branch-tip SHA — the
  same fork the ggml-speech vcpkg port ships)
- build each engine + all test harnesses against it as system ggml
- run the non-GPU ctest lanes (`-LE 'gpu|perf'`); model-dependent tests
  auto-DISABLE to "Not Run" per the existing harness design

Validated locally on macOS arm64: tts lane 68/68 pass, parakeet lane
green (1 runnable test model-free; parity suites need staged GGUF
fixtures — follow-up documented in the QIP). GPU lanes are stubbed
behind workflow_dispatch until self-hosted GPU runners exist.

docs/QIP-speech-repo-reorg.md is the reorg proposal this is "PR 0" of
(symmetric engines/ layout, upstream vendored as a minimally-divergent
git subtree under third_party/). The workflows land against today's
paths; the reorg PRs only touch the path filters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tts): link backend_selection.cpp into campplus test targets; move QIP to #94

First run of the new tts CI lane caught a real cross-platform bug:
test-campplus and test-campplus-backward-parity compile src/campplus.cpp
(which calls tts_cpp::detail::init_cpu_backend()) without
src/backend_selection.cpp, where that symbol lives. Apple's toolchain
happened to optimize the reference away; GNU ld on Linux fails with an
undefined reference — and Linux-with-tests was never built by any CI
until now. Mirror the source list test-voice-embedding already uses.

Also drop docs/QIP-speech-repo-reorg.md from this branch — the QIP now
has its own approval PR (#94); this PR is CI + fixes only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: export LD_LIBRARY_PATH for the ctest step (transitive ggml .so loads)

On ubuntu the test binaries resolve libqvac-speech-ggml.so via their
build RUNPATH, but RUNPATH is not consulted for that library's own
transitive dependencies (libqvac-speech-ggml-cpu.so.0 et al), so 35 tts
tests failed at exec with "cannot open shared object file". macOS is
unaffected (@rpath resolution walks the executable's rpath stack for
the whole load chain). Point LD_LIBRARY_PATH at the ggml install dir
for the ctest step in both lanes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: add Windows build+test and Android/iOS compile-smoke lanes for the engines

engines-cross-ci.yml: engine x platform matrix complementing the
linux/mac lanes —
- windows-2022: MSVC, static system ggml, full build + non-GPU ctest
- android: NDK arm64-v8a compile smoke (no device to run tests on)
- ios: device arm64 compile smoke, Metal embedded (flags mirror
  build-xcframework.sh)

iOS recipe validated locally (ggml + both engines compile clean against
the iphoneos 26.2 SDK). On-device e2e remains downstream in
tetherto/qvac; these lanes front-load cross-compile/link breaks ahead
of the repo-reorg moves (QIP #94).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor: move parakeet-cpp -> engines/parakeet, tts-cpp -> engines/tts (rename-only)

Pure `git mv` with zero content changes so Git records 100% renames and
`git log --follow` / blame survive. Establishes the symmetric engines/
layout from the repo-reorg QIP (#94, PR 1); path fixups follow in the
next commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: point workflows at engines/parakeet and engines/tts

Path-filter and source-dir fixups for the rename-only move in the
previous commit. No workflow logic changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tts): portable setenv/unsetenv shim for MSVC test builds; skip examples in cross lanes

The new Windows lane's first run caught 9 test files calling POSIX
setenv/unsetenv, which MSVC's CRT doesn't provide — add
test/test_env_portable.h (same-named _putenv_s shims on _MSC_VER,
plain <cstdlib> elsewhere) and include it where used.

Also -DPARAKEET_BUILD_EXAMPLES=OFF in the windows/android/ios lanes:
the live-mic examples hand GCC-style warning flags to cl.exe and use
mic-capture APIs that don't exist on the iOS device SDK; examples are
dev conveniences, not part of the cross-platform surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor: remove the vendored upstream whisper.cpp tree from the repo root

Everything upstream-owned at root (src/ include/ ggml/ examples/
bindings/ cmake/ CMakeLists.txt Makefile media/ models/ samples/
grammars/ tests/ ci/ scripts/ .devops/ .pi/ + upstream workflow files)
goes away; the next commit re-vendors upstream v1.9.1 under
third_party/whisper.cpp as a proper git subtree, and a follow-up
re-applies the QVAC whisper delta there (QIP #94, PR 2).

Kept at root: LICENSE, .gitignore, our workflows (.github/workflows/
{parakeet,tts,engines-cross}-ci.yml, check-approvals, security-baseline),
.github/CODEOWNERS, engines/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tts): portable temp-dir fallback for tests that write scratch GGUFs

test-gguf-stream and test-lavasr-enhancer-ggml consulted only TMPDIR
with a hard "/tmp" fallback — Windows sets TEMP/TMP and has no /tmp, so
both failed on the new Windows lane. Add test_tmpdir() to
test_env_portable.h (TMPDIR -> TEMP -> TMP -> "/tmp") and use it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Squashed 'third_party/whisper.cpp/' content from commit f049fff

git-subtree-dir: third_party/whisper.cpp
git-subtree-split: f049fff

* whisper: re-apply the QVAC delta on the vendored subtree + PATCHES.md manifest

One auditable divergence commit on top of the pristine v1.9.1 subtree:
- src/whisper.cpp + src/whisper-logits-slice.h + include/whisper.h:
  vocab-logits slice and decoder QKV matmul fusion (QVAC-21623)
- CMakeLists.txt / src/CMakeLists.txt / cmake/{git-vars,whisper-config}:
  install-export and tarball-build fixes the vcpkg port relies on

The in-tree ggml delta is intentionally NOT re-applied: every ggml patch
(Android in-APK backend loading, Adreno Vulkan workarounds) was verified
present on qvac-ext-ggml@speech — the ggml-speech port source — which is
the single home for ggml changes from now on. third_party/whisper.cpp/ggml
stays byte-identical to upstream and is never compiled by our builds.

PATCHES.md is the manifest the divergence-guard CI (QIP PR 3) enforces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* whisper(subtree): subproject-safety patches + WHISPER_BUILD_PARAKEET gate + UPSTREAM_PIN

Umbrella integration surfaced three issues, all added to PATCHES.md:
- WHISPER_BUILD_PARAKEET option (default ON = stock upstream): upstream
  ships its own C-API parakeet whose `parakeet`/`parakeet-cli` targets
  collide with engines/parakeet; the umbrella turns it off. Upstreaming
  candidate.
- PROJECT_SOURCE_DIR (not CMAKE_SOURCE_DIR) in the whisper include
  export — CMAKE_SOURCE_DIR points at the umbrella root when built as a
  subdirectory, breaking '#include "whisper.h"'.
- UPSTREAM_PIN: machine-readable upstream tag for the divergence-guard
  CI (QIP PR 3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* engines: rename test-streaming targets engine-scoped for the umbrella build

Both engines defined a ctest target literally named `test-streaming`,
which collides when they configure into one superbuild. Rename to
test-parakeet-streaming / test-tts-streaming (CMake target + ctest name
+ README references only; PROGRESS history docs untouched). No library
or public target names change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* build: root umbrella superbuild + whisper CI lane + repo README

- CMakeLists.txt: feature-gated superbuild (SPEECH_BUILD_{WHISPER,
  PARAKEET,TTS,TESTS,EXECUTABLES}); one find_package(ggml) shared by
  every component via their common `if (NOT TARGET ggml)` guards.
  whisper vars set with CACHE FORCE (its cmake_minimum_required(3.5)
  leaves CMP0077 OLD, so option() would clobber plain set()s).
- whisper-ci.yml: umbrella build on linux+mac (all engines, one ggml,
  full non-GPU ctest) + whisper-cli transcription smoke on jfk.wav with
  a cached ggml-tiny.en — replaces the useful slice of upstream's
  build.yml, which went inert when the upstream tree moved under
  third_party/.
- README.md: repo layout, build quick-start, third_party ground rules.

Validated locally (macOS arm64): fresh umbrella configure+build clean,
69/69 non-GPU tests pass, whisper-cli smoke transcribes jfk.wav.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* whisper(subtree): absorb the registry port's GNUInstallDirs ordering patch

include(GNUInstallDirs) must precede add_subdirectory(src): the whisper
INSTALL_INTERFACE expands ${CMAKE_INSTALL_INCLUDEDIR}, and when unset it
exports a bogus "/whisper" include path that breaks install-tree
find_package(whisper) consumers (the exact failure the registry's
0001-move-gnuinstalldirs patch fixed). Carrying it in the subtree delta
lets the whisper-cpp port drop its patch when it re-pins onto the
reorged tree. Declared in PATCHES.md; upstreaming candidate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: QIP-review feedback — full root README + self-contained PATCHES.md

- README.md: per QIP review, document every engine and supported model
  (whisper GGUFs; Parakeet CTC/TDT/EOU/Sortformer; Chatterbox Turbo/MTL,
  Supertonic, LavaSR), install + build, verified run commands for each
  CLI (flags checked against the engines' docs and the umbrella build
  outputs), and representative cross-platform perf tables sourced from
  the per-engine READMEs (linked for methodology/reproduction).
- PATCHES.md: manifest rows no longer lean on ticket IDs — each row now
  states what the patch does and why on its own, per review feedback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci+fix: address #93 review — exact-SHA ggml fetch, POSIX-faithful setenv shim, GPU flags in gpu stubs

- All ggml provisioning steps now fetch the exact SHA the cache key was
  derived from (git init + fetch --depth 1 <sha> + checkout FETCH_HEAD)
  instead of cloning the branch tip with a swallowed checkout — the tip
  advancing between ls-remote and clone could poison the cache with a
  commit the key never described. Applies to parakeet-ci, tts-ci and
  all three engines-cross-ci jobs.
- test_env_portable.h: the MSVC setenv shim now honors overwrite=0
  (existing variable left untouched, return 0) instead of silently
  diverging from POSIX.
- GPU stub jobs: build ggml with -DGGML_VULKAN=ON (the backend the
  -L gpu suites target; Metal is default-on on Apple hosts) so a
  dispatch run can't falsely pass against a CPU-only ggml; flag set to
  be revisited when the runner fleet exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(whisper): fetch the exact pinned ggml SHA (same #93-review race fix)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* whisper+docs+ci: address #96 review

- Restore the fork files the subtree conversion dropped (the delta
  capture missed upstream-owned paths beyond src/include/cmake):
  tests/test-whisper-logits-slice.cpp, tests/test-vad-streaming.cpp
  (+ tests/CMakeLists.txt wiring) and the Java-binding VAD params
  (WhisperFullParams.java, WhisperVadParams.java). All declared in
  PATCHES.md with self-contained rationale.
- Deliberately NOT restored (documented in PATCHES.md): the fork's
  examples/talk-llama/llama-hparams hunk — it references
  nextn_predict_layers, which doesn't exist in v1.9.1's talk-llama
  snapshot, didn't compile, and was the actual cause of the ubuntu-22
  matrix failures on every master push of the old upstream build.yml.
- Run the restored tests: new SPEECH_BUILD_WHISPER_TESTS umbrella
  option; whisper-ci enables it and widens the ctest exclusion to
  whisper's model-labeled transcription tests (tiny/base/...). Gate
  upstream's parakeet tests behind WHISPER_BUILD_PARAKEET (they link
  the gated target). Local: full umbrella build clean, 73/73.
- whisper-ci model fetch: curl -fL (fail on HTTP errors instead of
  writing the error page into the model), URL pinned to a fixed HF
  revision, sha256 verified (shasum -a 256: portable to macOS runners).
- README perf tables: name the hardware — GPU rows are the
  qvac-ubuntu2204-x64-gpu runner's NVIDIA RTX 4000 SFF Ada (Vulkan),
  Mac rows Mac Studio M3 Ultra; CPU row identified as the same x86-64
  host (its CPU model is not published in any doc we can cite).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: name the benchmark host CPU (Intel Core i5-13500) in the perf tables

The qvac-ubuntu2204-x64-gpu runner's CPU, read from its own job logs;
completes the hardware naming requested in review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci+fix: portable ggml builds for hosted lanes; env shim for Parler sched test

First lane run against master's Parler merge caught two issues:

- 19 tts tests SIGILL'd on ubuntu: the lanes built ggml with the
  default GGML_NATIVE=ON (-march=native) and cached the install keyed
  only by ggml SHA + OS — hosted runner fleets mix CPU generations, so
  a cache built on an AVX-512 machine crashes on one without. Build
  ggml with GGML_NATIVE=OFF in every hosted lane (gpu stubs on
  self-hosted machines keep native) and bust the possibly-poisoned
  caches with a -portable key prefix.
- test/parler/test_sched_equivalence.cpp (new in #92, never built on
  Windows) uses POSIX setenv/unsetenv — include the existing
  test_env_portable.h shim.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(whisper): portable ggml build + cache bust (same fix as engine lanes)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs+ci: upstream-sync runbook and whisper divergence guard (QIP PR 3) (#97)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants