# Subtitle generator licence gate — 2026-09-30

Selected: **Xenova/whisper-base and Xenova/whisper-tiny.en, q8 ONNX**, **transformers.js 3.8.1 (Apache-2.0)**. Gate PASS before implementation, route **(a)**: the conversion repositories themselves state a compatible licence. No local export or quantisation.

## Separate code and weights findings

- Original Whisper code and weights: **MIT**. [OpenAI Whisper v20250625 LICENSE](https://github.com/openai/whisper/blob/v20250625/LICENSE) says “MIT License” and “Permission is hereby granted, free of charge”. The [upstream README](https://github.com/openai/whisper/blob/v20250625/README.md#license) explicitly applies MIT to code and model weights. The full unmodified MIT text is retained in LICENSE-OpenAI.txt.
- Official HF checkpoints: both [openai/whisper-base](https://huggingface.co/openai/whisper-base/blob/e37978b90ca9030d5170a5c07aadb050351a65bb/README.md) and [openai/whisper-tiny.en](https://huggingface.co/openai/whisper-tiny.en/blob/87c7102498dcde7456f24cfd30239ca606ed9063/README.md) state `license: apache-2.0`. This is their own card declaration; it differs from the MIT upstream release.
- Selected converted weights: **Apache-2.0**. [Xenova/whisper-base immutable card](https://huggingface.co/Xenova/whisper-base/blob/64da57285918e20ea79ea5c88eed7197933abaa8/README.md) and [Xenova/whisper-tiny.en immutable card](https://huggingface.co/Xenova/whisper-tiny.en/blob/79fb389fc764e7c395bd330e9531d9d32ada7049/README.md) both state `license: apache-2.0` and identify the official OpenAI checkpoints as `base_model`. The declaration applies to these repositories, including their ONNX conversions. Apache-2.0 permits redistribution of these MIT-derived weights; the original MIT notice and full Apache text are retained. This is a redistribution licence finding, not a training-data warranty.
- JS runtime: **Apache-2.0**, [@huggingface/transformers 3.8.1 pinned metadata](https://registry.npmjs.org/@huggingface/transformers/3.8.1). Only its unmodified browser ESM build and full licence are vendored. Browser decode and resampling APIs are provided by the browser.

## Rejected candidate and verified measurements

onnx-community/whisper-base at `1846881b6b3a3024392c1eea3ad983695bc23925` and whisper-tiny.en at `2575352d61be1bf7225cf8f8b268a4678025fc58` have **no licence field**. Their q8 encoder/merged decoder sizes were verified from immutable LFS metadata: base **23,201,314 + 53,693,315** bytes; tiny.en **10,124,993 + 30,718,858** bytes. Those bytes differ from Xenova's, so we do not infer that a parent licence covers unidentified altered bytes. REJECTED in favour of explicitly licensed Xenova conversions. The selected totals are **76,908,389 bytes (77 MB)** and **40,852,295 bytes (41 MB)**, decimal MB.

## Immutable asset inventory

All model files are unmodified, with exact pinned URLs below. Config, tokenizer and both encoders are under 25 MB and retained in the tree; each decoder is explicitly gitignored and fetched with scripts/fetch_models.py, which verifies size/hash before atomic replacement. `--check` is offline. assets.json supplies the browser's hash-keyed Cache API inventory. No Hugging Face or CDN request is allowed at runtime.

| Asset | Exact pinned URL | SHA-256 | Bytes | Licence / verdict |
| --- | --- | --- | ---: | --- |
| whisper-base/config.json | https://huggingface.co/Xenova/whisper-base/resolve/64da57285918e20ea79ea5c88eed7197933abaa8/config.json | `d1d347fdb422e6347c2f843a90d375aa67ea3f4b3e20d2c3075f9a9f6243685b` | 2,248 | Apache-2.0 PASS |
| whisper-base/generation_config.json | https://huggingface.co/Xenova/whisper-base/resolve/64da57285918e20ea79ea5c88eed7197933abaa8/generation_config.json | `3bba359e33fdd6dc1c10f71846a477d339b0242f462f70ea1dd73274caa38d05` | 3,776 | Apache-2.0 PASS |
| whisper-base/onnx/decoder_model_merged_quantized.onnx | https://huggingface.co/Xenova/whisper-base/resolve/64da57285918e20ea79ea5c88eed7197933abaa8/onnx/decoder_model_merged_quantized.onnx | `a6beb6baabb66f00b6a686d828c95ffca6146d51900cbad0266cad38f64cf861` | 53,707,539 | Apache-2.0 PASS |
| whisper-base/onnx/encoder_model_quantized.onnx | https://huggingface.co/Xenova/whisper-base/resolve/64da57285918e20ea79ea5c88eed7197933abaa8/onnx/encoder_model_quantized.onnx | `3e345e977b55620a37c0c2b2af0644e019afdfad562dcf71eb929bb7274285f9` | 23,200,850 | Apache-2.0 PASS |
| whisper-base/preprocessor_config.json | https://huggingface.co/Xenova/whisper-base/resolve/64da57285918e20ea79ea5c88eed7197933abaa8/preprocessor_config.json | `a6a76d28c93edb273669eb9e0b0636a2bddbb1272c3261e47b7ca6dfdbac1b8d` | 339 | Apache-2.0 PASS |
| whisper-base/special_tokens_map.json | https://huggingface.co/Xenova/whisper-base/resolve/64da57285918e20ea79ea5c88eed7197933abaa8/special_tokens_map.json | `e67ae3a0aaa99abcd9f187138e12db1f65c16a14761c50ef10eef2c174a7a691` | 2,194 | Apache-2.0 PASS |
| whisper-base/tokenizer.json | https://huggingface.co/Xenova/whisper-base/resolve/64da57285918e20ea79ea5c88eed7197933abaa8/tokenizer.json | `27fc476bfe7f17299480be2273fc0608e4d5a99aba2ab5dec5374b4482d1a566` | 2,480,466 | Apache-2.0 PASS |
| whisper-base/tokenizer_config.json | https://huggingface.co/Xenova/whisper-base/resolve/64da57285918e20ea79ea5c88eed7197933abaa8/tokenizer_config.json | `2a4c4281cf9f51ac6ccc406fdc711a087afe6530f671fa7b80953edc498275ce` | 282,683 | Apache-2.0 PASS |
| whisper-tiny.en/config.json | https://huggingface.co/Xenova/whisper-tiny.en/resolve/79fb389fc764e7c395bd330e9531d9d32ada7049/config.json | `37a1073be00d19118c06557896c7c148598f4d8277edc0f5bc07c9f5554839f1` | 2,202 | Apache-2.0 PASS |
| whisper-tiny.en/generation_config.json | https://huggingface.co/Xenova/whisper-tiny.en/resolve/79fb389fc764e7c395bd330e9531d9d32ada7049/generation_config.json | `132c95ba9db45f4498f2eab3fea7c1d6a174005010f8f6b7d20cfd5e9795996b` | 1,590 | Apache-2.0 PASS |
| whisper-tiny.en/onnx/decoder_model_merged_quantized.onnx | https://huggingface.co/Xenova/whisper-tiny.en/resolve/79fb389fc764e7c395bd330e9531d9d32ada7049/onnx/decoder_model_merged_quantized.onnx | `dbb2e063b7fbc41d9803b9698f93ecb035c50cbb3fb87b56cb131e4a5eb99059` | 30,727,382 | Apache-2.0 PASS |
| whisper-tiny.en/onnx/encoder_model_quantized.onnx | https://huggingface.co/Xenova/whisper-tiny.en/resolve/79fb389fc764e7c395bd330e9531d9d32ada7049/onnx/encoder_model_quantized.onnx | `8cc3c6f8563d1b3fbd2c5af9f64c2bed8b020bc593c402d1ef53b9f08fbf1b90` | 10,124,913 | Apache-2.0 PASS |
| whisper-tiny.en/preprocessor_config.json | https://huggingface.co/Xenova/whisper-tiny.en/resolve/79fb389fc764e7c395bd330e9531d9d32ada7049/preprocessor_config.json | `a6a76d28c93edb273669eb9e0b0636a2bddbb1272c3261e47b7ca6dfdbac1b8d` | 339 | Apache-2.0 PASS |
| whisper-tiny.en/special_tokens_map.json | https://huggingface.co/Xenova/whisper-tiny.en/resolve/79fb389fc764e7c395bd330e9531d9d32ada7049/special_tokens_map.json | `7da611d517fe29e77335b8d8384e71795fb7b37cbf95bdc3b5252fa7e09dd1f8` | 1,717 | Apache-2.0 PASS |
| whisper-tiny.en/tokenizer.json | https://huggingface.co/Xenova/whisper-tiny.en/resolve/79fb389fc764e7c395bd330e9531d9d32ada7049/tokenizer.json | `c6ee8f089220a5b1188f6426456772572671c6141ae007eecb83c6a8349f5deb` | 2,128,494 | Apache-2.0 PASS |
| whisper-tiny.en/tokenizer_config.json | https://huggingface.co/Xenova/whisper-tiny.en/resolve/79fb389fc764e7c395bd330e9531d9d32ada7049/tokenizer_config.json | `e082c1ad251541bf277967a703252cddd4bb37a71a43737e03d050c22ec08238` | 835 | Apache-2.0 PASS |

## Runtime finding

Transformers.js 3.8.1 embeds ONNX Runtime Web JS **1.22.0-dev.20250409-89f8206ba4**, pinned in its npm dependencies. A directory-only wasmPaths would select its JSEP filenames, which the existing stable folder does not contain. A real Chromium worker probe instead supplied both explicit `mjs` and `wasm` paths to the **existing plain onnxruntime-web 1.22.0 companions**. Pipeline creation and actual inference succeeded. The final fixture tests exercise this combination on both models. Therefore the existing stable files are reused without modification; no additional ORT build ships. Execution uses WASM, one thread, no WebGPU provider. Microsoft ORT is **MIT**; its full licence is in ../onnxruntime-1.22.0/LICENSE. A JSEP build downloaded during investigation was removed.

| Runtime asset | Pinned source | SHA-256 | Bytes | Licence |
| --- | --- | --- | ---: | --- |
| transformers/transformers.min.js | https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.8.1.tgz#member=package/dist/transformers.min.js | `aa5002b70e789798da263f5f99c62bd3e8fcd0c119258a493c40c180648365fa` | 888,173 | Apache-2.0 |
| transformers/LICENSE | https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.8.1.tgz#member=package/LICENSE | `cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30` | 11,358 | Apache-2.0 |
| reused onnxruntime-1.22.0/ort-wasm-simd-threaded.mjs | https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.22.0.tgz#member=package/dist/ort-wasm-simd-threaded.mjs | `30dd851d9c00622940500f71ddd2ff8820c5cb65270816080175b958705385a8` | 20,856 | MIT |
| reused onnxruntime-1.22.0/ort-wasm-simd-threaded.wasm | https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.22.0.tgz#member=package/dist/ort-wasm-simd-threaded.wasm | `71aef04959c5c1b6de461b6538e2058e306610034a85aad2742d0c7fd4533fe4` | 11,210,254 | MIT |

Transformers tarball SHA-256: `207714c36765b87accfd9b7b0672c3505805af97140990e0d9f8ac6e3cd5471e` (10,482,401 bytes). Reused stable ORT tarball SHA-256: `e293551f9d36d003e293d0f2937fee7b3dfdcef76d71d1449b55e2d4157c7aea` (20,387,966 bytes). No source map or node bundle ships. Runtime settings disable remote models, point localModelPath at /vendor/whisper/, and set both wasmPaths URLs to the existing stable ORT folder. MP4Box 2.4.1 fallback imports the existing unmodified vendor modules, BSD-3; see ../VIDEO-ENGINE.md. No existing tool code is copied.

## Verification and practical limits

Before Make subtitles, no model or inference runtime is loaded. A worker verifies selected model assets against this inventory before inference and uses Cache API by hash when available. Cancellation terminates the worker, including active inference. Inputs are capped at 60 minutes; browser memory and speed can limit long jobs, especially on phones. Whisper does not supply speaker labels. Timing within a timestamped phrase is estimated when shaping smaller cues; users can edit every cue and audition it. Real Chromium fixtures test both models, the MP4 fallback, exports, cancellation, cache reuse and request origins.

The video editor caption-core.js serialises SRT but has no VTT serialiser. Importing it would add runtime requests outside this tool and /vendor/, so this tool uses original serializers and tests both formats by round-trip through its parser. No video editor code is copied or edited.
