Compliance pack (v0.71.35)
Ship a regulated fine-tune with the paperwork it needs: start from a regulation-shaped config, publish a provenance-carrying model card, and gate every future change in CI.
1. Start from a compliance template
soup init --template hipaa # Protected Health Information
soup init --template soc2 # SOC 2 Trust Services Criteria
soup init --template eu-ai-act # EU AI Act Annex XI/XII
soup init --template sr-11-7 # SR 11-7 Model Risk ManagementBe clear about what a template is, because the honest constraint shaped the design: Soup's compliance controls are CLI flags and commands, not config keys. There is no audit_log: or bom: key in the schema, so a template cannot "pre-wire audit-log on" as YAML, and pretending otherwise would be a lie in a document meant to prove things.
Each template is therefore a valid, immediately trainable config on a license-clean Apache-2.0 base, plus header comments naming the exact commands for that regime: PHI scrubbing and air-gap for HIPAA, BOM / attest / sign for SOC 2, Annex XI plus energy tracking for the EU AI Act, repro-receipt plus diagnose and ship for SR 11-7. Built-in templates went from 17 to 21.
2. The provenance path
soup data pii ./data/train.jsonl # flag emails / phones / SSNs / MRNs
soup data decontaminate ./data/train.jsonl # drop public-benchmark overlap
soup train --config soup.yaml --repro-receipt receipt.json
# EU AI Act: Annex XI/XII docs + measured energy
soup train --config soup.yaml --annex-xi annex_xi.md \
--track-energy --energy-country DEU --energy-out energy.json
soup registry push --run-id <run-id> --name my-model --tag v1
soup bom emit --name my-model --base-sha <hex> --config-sha <hex> \
--energy energy.json --format both # CycloneDX + SPDX
soup attest emit --stage train --subject my-model --sha <hex> \
--sign ed25519 --key key.pem # in-toto + SLSA-3The audit log records every command automatically (soup audit-log tail, soup audit-log rotate).
3. Model card autogen
soup card my-model:v1 -o MODELCARD.md
# or override the auto-generated card when uploading:
soup push --model ./output --repo you/my-model --card my-model:v1soup card turns a registry entry into a publishable Hugging Face card carrying base model, the real training config, an eval scorecard, config and data sha256 hashes, lineage (ancestors), and a table of every registered artifact.
Adapter versus full model is inferred from the registered artifacts and falls back to the training config's LoRA rank, with Spectrum and LISA full fine-tunes correctly treated as dense. This is not a detail: the live smoke caught a real LoRA run with no attached artifacts rendering Type | Full model and library_name: transformers, a false claim in a provenance document that 90 green tests had missed.
soup push --card is Hugging Face only (it warns and ignores on other hubs), and a bad ref fails fast before any network call.
4. Gate future changes in CI
soup ci init --data data/train.jsonl --suite expectations.yaml --evidence ship_evidence.json
# writes .github/workflows/soup-gate.ymlThe generated job runs, in order:
soup data validate <data> # dataset format compliance
soup expect <data> <suite> # PII / token-length / refusal / judge expectations
soup ship --evidence <ev.json> # SHIP / DON'T-SHIP (exit 2 blocks the merge)Flags: --branch main, --python 3.11, --force. Every interpolated path is validated to stay under the repo root and shell-quoted, the branch and Python version are regex-gated so they cannot break out of their YAML context, and the write is atomic, symlink-rejecting, and refuses to clobber an existing workflow without --force.
GGUF export now works on Windows
The same release validated soup export --format gguf end to end on Windows for the first time (llama.cpp built CPU-only with VS2022 BuildTools, SmolLM2-135M exported to q4_0, q4_k_m, q8_0 and f16, then soup deploy ollama, then live inference). Doing so surfaced four real bugs, each independently fatal:
| Bug | Effect |
|---|---|
SOUP_DIR used relatively, not anchored to ~ | ~/.soup/llama.cpp was never found, so a fresh ~200 MB checkout landed in whatever directory you ran from |
The auto-clone pip-installed llama.cpp's requirements.txt | It pins torch~=2.2.1 against the CPU wheel index: torch 2.5.1+cu became 2.2.2+cpu, so CUDA was gone, and transformers 4.57 dropped to 4.46. Your first GGUF export silently destroyed your training setup. Soup now installs only the convert script's extra dependencies, unpinned, never touching torch |
| MSVC is a multi-config generator | It emits build/bin/Release/llama-quantize.exe, but only the flat layout was searched, so a correctly built llama.cpp was "not found" |
soup deploy ollama on a relative GGUF path | Ollama resolves FROM against the Modelfile's directory and Soup writes it to a temp dir, so it failed with "pull model manifest: file does not exist". The Modelfile now emits an absolute path |
That is the argument for validating a feature on real hardware rather than trusting a green suite: 361 export and ollama tests were passing throughout.
Security
Model-card injection was hardened, and the hole was pre-existing in soup push's own auto-card rather than new: the Training section interpolated base, task, scheduler and recipe unescaped into a card destined for the public Hub, and since base and scheduler have no charset validator, a crafted-but-schema-valid config could smuggle raw HTML, or a backtick that breaks out of the surrounding code span. All values now go through the markdown escaper, which also neutralises backticks and strips C0/ESC control bytes.
See also
- Governance & provenance — BOM, attestations, audit log, air-gap.
- Supply-chain security — ed25519 signing, scan gates, license conflicts.
- soup ship — the verdict the CI gate blocks a merge on.
- Model export — GGUF, AWQ, GPTQ, ONNX, TensorRT.