mirror of https://github.com/razor-ai/soup.git
34 KiB
34 KiB
Changelog
All notable changes to Soup CLI are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Detailed, per-release notes for every published version live on the GitHub Releases page. This file tracks unreleased changes and links out for historical detail rather than reproducing 70+ versions of notes.
Unreleased
[0.71.13] - 2026-06-04
Added
- Prompt-compile family — live wiring (closes #225, #226, #227, #229). Four
soupcommands that shipped as deferred-stubNotImplementedErrorin v0.68.0 are now real, validated end-to-end (real DPO train on SmolLM2-135M + real Ollama teacher distillation on RTX 3050). soup local-rl trainruns a real nightly DPO/KTO/ORPO train (#229).--onceharvests the latest thumbs-up/down DPO pairs from the local-RL SQLite and trains them via asoup trainsubprocess (argv list, no shell); astatetable trackslast_train_atso a re-run with no new feedback skips, and a run with fewer than--min-pairs(default 10) skips. Without--onceit renders a systemd.service/.timer+ launchd.plistscheduler scaffold into--scheduler-dirfor the user to install. New flags:--once,--min-pairs,--output/-o,--scheduler-dir,--hour,--minute.soup distill-promptprepares a real distillation dataset (#226). For each prompt in the traces JSONL the teacher is called once via the v0.20 provider helpers (Ollama / Anthropic / vLLM);sft/klemit{messages:[user, assistant=teacher]}andpreferenceemits{prompt, chosen=teacher, rejected=student}. New flags:--provider,--base-url,--temperature,--max-rows.soup compileruns DSPy / GEPA / TextGrad prompt-program optimisation (#225) andsoup compile-toolsruns the TextGrad / GEPA tool-schema optimiser (#227), both lazy-importing the optimiser libraries behind the new[compile]extra (pip install 'soup-cli[compile]') with a friendlyImportErrornaming the extra when absent.--plan-onlystill renders the plan and exits 0.
Security
- systemd / launchd injection defence (#229).
local-rland the scheduler renderers reject\n/\rin the model id and shell-quote everyExecStartargument, so a crafted model id cannot inject extra unit directives.
Fixed
local-rltrain config renderedoutputas a mapping (#229). The nightlysoup trainYAML now emitsoutput: <dir>(a plain string the schema accepts) instead ofoutput: {dir: <dir>}; a regression test validates the rendered config againstSoupConfig.
[0.71.12] - 2026-06-04
Added
- Architecture + distillation + adapter-training — live wiring (closes #145, #146, #148, #158, #84, #221, #222). Seven surfaces that shipped schema-only in earlier releases are now real, validated end-to-end on tiny models (SmolLM2-135M / a locally-built tiny Llama).
- Sequence-level knowledge distillation is live (#145).
task: distillnow acceptsdistill_mode: token|sequence; sequence mode trains the student on the teacher's generated continuations (cross-tokenizer-friendly hard-label KD) instead of per-token logit matching.sequencemode is mutually exclusive with the v0.70 cross-tokenizer ULD logit path. - Classifier LoRA is live (#146).
task: classifier|reranker|cross_encodernow attaches a LoRA adapter to the sequence-classification head whenlorais configured, so a frozen encoder + small adapter can be trained instead of the full model. - LLaMA Pro block expansion is per-architecture (#148).
expand_layersnow interleaves zero-initialised identity blocks for Llama / Qwen / Mistral decoder stacks (was Llama-shaped only), withfreeze_trainable_layersfreezing the original blocks so only the new ones train. - LongLoRA S² shifted-sparse attention is live (#158).
use_longlora: truenow installs the shifted-sparse-attention forward override on the Q/K projections (Llama / Mistral / Qwen / Phi), restoring the patched forwards on context exit. - Mixture-of-Depths is live (#84).
use_mod: trueattaches a per-layer top-k token router (mod_capacity_factor) so only a subset of tokens receive each block's residual update. Architecture allowlist: Llama / Qwen / Mistral; unsupported bases warn and skip. - VeRA / VB-LoRA multi-tenant serving is live (#221).
soup serve --bank <bank.json> [--bank-strength S]reconstructs the shared projection + per-user scaling vectors and installs a decode-time forward hook; the active user is selected per request via theX-User-Idheader (an unknown/absent id is a zero-delta no-op, so there is no cross-request leak). Serves N personas at ~KB-per-user instead of a full LoRA each. - MoLE per-token adapter routing is live (#222).
task: moe_lora_routingwithmole_task_adapters: [...]trains a per-token gating network that blends N frozen task LoRAs (mole_top_k/mole_temperature); only the router trains. The gate is saved asmole_gate.ptalongside the run.
Changed
apply_bank_to_serve(#221) andbuild_gating_kernel(#222) now return live objects (aLoadedVectorBankand atorch.nn.Modulerouter) instead of the v0.67.0 deferred-stubNotImplementedError.
[0.71.11] - 2026-06-04
Added
- GRPO / RL callbacks — live wiring (closes #235, #236, #237, #238, #239, #240, #159, #160). The reward-hacking, cross-tokenizer distillation, MiniLLM, mid-epoch RL checkpoint, iterative-DPO and echo-trap surfaces that shipped schema-only in v0.70.0 are now real, validated end-to-end on SmolLM2-135M.
- Reward-hacking detector is live (#235).
--reward-hack-detector info_rm|rm_ensemblenow installs a GRPOTrainerCallbackthat reads the per-step rewards (via a shared, thread-safe reward-fn capture buffer), computes an InfoRM cluster-separation drop (info_rm) or RM-ensemble divergence (rm_ensemble), classifies OK/WARN/HACK, logs the verdict tostate.log_history, and halts training on HACK when--reward-hack-haltis set.rm_ensemblerequires ≥2 reward functions. - Cross-tokenizer ULD distillation is live (#236).
task: distillwith--uld-strategy wasserstein|topk_alignnow computes a real Wasserstein-1 (sorted-CDF) or top-k-aligned distillation loss inside the distill trainer, handling student/teacher vocab-size mismatch by clamping teacher ids to the teacher vocab. - MiniLLM reverse-KL distillation is live (#237).
--minillm-enabledadds a teacher-mixed, length-normalised reverse-KL term plus an optional pretrain-anchor SFT term (--minillm-pretrain-anchor-path/--minillm-pretrain-anchor-weight) that keeps the student near coherent language. The anchor corpus reader is cwd-contained + symlink-rejecting with a per-line byte cap. - Mid-epoch RL checkpoint is live (#238).
--rl-checkpoint-save-every-steps Nwrites a real adapter + optimizer state + JSON manifest every N steps during PPO/GRPO and prunes to--rl-checkpoint-keep-last, so a long RL run survives a crash without losing the optimizer momentum. soup iterative-dpoorchestrator is live (#239). Runs the full sample → reward-score → build-pairs → DPO-train loop across rounds: each round samples completions from the previous round's adapter, the next round trains a fresh LoRA from the base on that round's harvested pairs.--plan-onlystill renders the plan without running.- Echo-trap detector is live (#240).
--echo-trap-enabledinstalls a GRPO callback that scores per-trajectory n-gram repetition, classifies OK/WARN/TRAP against--echo-trap-threshold, logs the verdict, and halts on TRAP when--echo-trap-haltis set (catches RAGEN-style degenerate repetition in multi-turn agent RL). - GRPO variant fallback now warns once (#159). When a
--grpo-variantcustomcompute_lossfalls back to the base trainer (because the installed TRL renamed the loss inputs), the trainer logs a one-shot WARNING instead of silently degrading to the default objective.
Changed
- GRPO reference-model EMA no longer materialises full state dicts (#160).
--ref-model-ema-alphanow updates the reference model in place by iteratingnamed_parameters()(ref = (1-α)·ref + α·policy), eliminating the three model-sized allocations per step the v0.53.11 path made. A total name/shape-mismatch (0 shared parameters) logs a one-shot WARNING so a misconfigured EMA can't silently no-op.
[0.71.10] - 2026-06-03
Added
- RAG family — live wiring (closes #199, #200, #201, #202). The four retrieval / steering surfaces that shipped schema-only in v0.62.0 are now real, validated on SmolLM2-135M.
- RAFT span-mask training is live (#199).
data.format: raftrows ({query, golden_doc, distractor_docs, answer}) now train answer-only: the prompt span is masked to-100and each document is labelled[doc-N]so the model learns to cite the supporting document. Documents are shuffled reproducibly (data.raft_shuffle_seed). Rows whose prompt fillsmax_length(answer fully truncated) are dropped with a warning rather than silently shrinking the effective dataset. soup ra-dit— one-shot two-stage orchestrator (#200). Trains the retriever (stage 1, embedding/contrastive) then the generator (stage 2, RAFT-SFT) in a single command, recording the trained retriever as the generator's paired retriever. Asoup trainof a generator-stage config with no retriever model set now auto-links the most-recent RA-DIT retriever run from the Registry.--plan-onlyvalidates both configs without training;--retriever-modeloverrides the auto-link.soup steer train/apply+soup serve --steerare live (#201). Fit a CAA (contrastive activation addition), ITI (inference-time intervention) or RepE (representation-engineering PCA) control vector from{positive, negative}contrastive pairs, persist it as a safetensors + config artifact, and apply it at decode time via a forward hook (soup serve --steer <name> --steer-strength <s>).soup eval citation+ citation-span loss boost are live (#202). Score citation precision / recall / F1 over{predicted, expected_ids}or RAFT rows (--shuffle-seedaligns the golden[doc-N]id with what the model saw at train time). Whencitation_faithful: true, bracketed[doc-id]spans in the answer get a boosted per-token loss weight. A newcitationfailure mode is available insoup diagnose.
[0.71.9] - 2026-06-03
Added
- Knowledge edit + unlearn — live wiring (closes #193, #194, #196, #197, #203). The v0.61.0 / v0.62.0 schema-only stubs are now live, validated on SmolLM2-135M.
soup edit set(ROME / MEMIT / AlphaEdit) is live (#194). Newsoup_cli/utils/edit_kernels.pyships covariance-free rank-1 weight-edit kernels: ROME (single-layerW += δ·kᵀ/‖k‖²), MEMIT (residual distributed across a layer band), AlphaEdit (ROME update projected orthogonal to the down-proj's top singular direction).apply_editloads the model, optimises the target residual, applies the rank-1 update, and optionally saves with cwd-containment + symlink rejection.--output,--device,--governor/ --no-governorflags added. On a tiny model a ROME edit movedP("Lyon" | "The capital of France is")from 0.0016 → 0.96.soup edit difflive before/after generation (#194). Pass--before-model+--after-model(+--probes) to generate completions through both models and surface the probes whose output changed.- EditGovernor SQLite persistence + cross-process locking (#196). New
EditGovernorStore(mirrorsnamespace_pin.NamespacePinStore— $HOME/$CWD/$TMPDIR containment, TOCTOU symlink rejection, WAL + busy_timeout,fcntl/msvcrtsidecar lock, POSIX 0600).save_governor/load_governor/default_governor_db_path(env overrideSOUP_EDIT_GOVERNOR_DB) persist per-base-model edit-count + verdict across separatesoup edit setruns. apply_editconsults the EditGovernor automatically (#197). When a governor is supplied,check_can_edit()runs BEFORE the model load (refusing on norm blowup / edit cap) andrecord_edit()runs AFTER with the measured Frobenius delta.- Live GRACE codebook (#203).
GraceCodebook(epsilon-ball nearest-key lookup),apply_grace_edit(captures a residual key + optimises a value + appends to a codebook sidecar),save_codebook/load_codebook(atomic, cwd-contained, symlink-rejected),install_grace_hook(decode-time residual substitution). Newedited_model/grace_codebookRegistry artifact kinds. soup train --task unlearnis live (NPO / SimNPO / RMU) (#193). Newsoup_cli/utils/unlearn_kernels.py(NPO(2/β)·mean(-logσ(-β(πlp-reflp))), length-normalised SimNPO, RMU representation steering) + a self-containedUnlearnTrainerWrapperloop loading a LoRA policy, a frozen reference (NPO/RMU), and forget/retain JSONL datasets. NPO/SimNPO forget loss decreased on the tiny-model smoke. Warns when run without a retain set.
Security
_save_edited_model/UnlearnTrainerWrapperoutput dirs +save_codebook/load_codebook+_load_unlearn_rowsenforce cwd-containment, raw-path symlink rejection (TOCTOU), null-byte rejection, and file-size / per-line caps.apply_grace_edithonours the governor for direct callers.
[0.71.8] - 2026-06-03
Added
- Probes & SAE — real weights + live downloads (closes #215, #216, #217,
#218, #219). A new shared
soup_cli/utils/probe_kernel.pyprovides the linear-probe math (contrast-pair derivation, apply, flag-rate, verdict bands, operator-supplied weight loading, deterministic synthetic fallback); every heavy import (numpy/torch/safetensors) is lazy. soup probe sleeper --weights <w.npz|.npy|.safetensors>(#215) — load a real calibrated probe direction instead of the synthetic fallback. Weights are cwd-contained, symlink-rejected,O_NOFOLLOW-opened,allow_pickle=False, and size-capped.compute_contrast_probe(positive, negative)derives a probe from contrast-pair activations.soup probe sae-diff <repo> --auto-download(#216) — fetch an allowlisted SAE from the HF Hub into~/.soup/sae-cache/(validated againstHF_HUB_ALLOWLISTBEFORE any network call) via a new SSRF-hardenedsoup_cli.utils.hubs.snapshot_download(repo-id shape + home/cwd/tmp cache containment + namespace-pin TOFU gate).soup probe truth/soup probe harm(#217) — TruthfulQA-style honesty and HarmBench-style misuse activation probes (6 bundled bases each, 5% / 20% verdict bands,--weightsto skip the allowlist with a real probe). The probe pack now ships truth + harm entries per base.soup probe interference --measure <eval_suite> --base-model <m> --adapter name=path ...(#218) — auto-measure the N×N interference matrix by actually loading the base + each LoRA adapter (PEFT multi-adapter), measuring loss for each adapter alone (diagonal) and each co-loaded pair (add_weighted_adapter(combination_type="cat"), off-diagonal). Exit 2 on a MAJOR worst-pair.soup train --capture-activations <layer> --capture-prompts <jsonl>(#219) — a post-training hook writes an SAE-diff-ready per-token activation snapshot to<output>/activations/activations.json.resolve_layer_moduleresolves the samemodel.layers.Npath whether or not a LoRA adapter is loaded (PEFT-wrapper fallback).
Security
- Probe / SAE / capture file I/O is cwd-contained +
O_NOFOLLOW(TOCTOU close)- size-capped; SAE weight loads use
allow_pickle=False. SAE auto-download validates the allowlist before any network call and rejects a glob result that resolves outside the snapshot dir (symlink-escape guard).
- size-capped; SAE weight loads use
Notes
- #215 is partial: the operator-supplied / contrast-pair / synthetic paths ship now, but the 6 large-base Anthropic-calibrated probe vectors remain upstream-gated (no public calibrated artifact exists). Documented as a known limitation.
[0.71.7] - 2026-06-02
Added
- Eval live runners — six probe surfaces that previously emitted heuristic
/ neutral stubs now load a real model and run live (closes #161, #162, #208,
#211, #212, #165). New shared
soup_cli/utils/live_eval.pyprovides the model-loading primitives (generator / multi-generator closures, masked cross-entropy eval-loss, a short-LoRA probe, and held-out logit agreement); every heavy import (torch/transformers/peft/lm_eval) is lazy. soup advise --probe-model <id>— runs a LIVE ROI probe: zero/few-shot token-F1 baselines, a short LoRA probe (relative held-out-loss improvement + real wall-clock), and base-model proximity (held-out logit agreement) folded into the dataset profile. Without--probe-model,--probestays the offline heuristic.soup tunability --live— replaces the offline heuristic with a real per-candidate LoRA probe (loads eachrepo_id, trains--probe-stepson a held-out-excluded slice, reports the held-out-loss drop).soup eval capability --live --model <id>— invokes lm-eval-harness per resolved task (or a--tasksoverride) with--limit/--device, isolating per-task failures and surfacing a no-metric result as an explicit error.soup eval behavior --base-model <id> [--adapter <path>]— generates pre/post responses on the bundled behaviour battery and scores the live diff.soup diagnose --base-model <id> [--adapter <path>] [--dataset <jsonl>] [--tokenizer <id>]— runs all six failure-mode probes (forgetting / refusal / format / mode_collapse / memorization / contamination) live viasoup_cli.utils.diagnose.live.run_live_diagnose; falls back to neutral OK or--evidenceJSON when no model is supplied.
Security
- The two new JSONL dataset readers (
diagnose.live._load_dataset_rows,tunability._load_jsonl_rows) open withO_NOFOLLOWafter the cwd-containment check, closing the check→open TOCTOU window (matches the v0.65 / v0.67 reader policy).
[0.71.6] - 2026-06-02
Added
soup buildlive runner — the dbt-for-SFT DAG (soup build <manifest>) now materialises datasets instead of only dry-running the plan. Five built-in transforms ship live (identity,drop_empty,lowercase,strip,dedup_exact);tablerebuilds from scratch,viewre-derives on every run, andincrementalre-transforms only the rows whose content hash changed (tracked in a SQLite state store, keyed by row hash and the model's transform+config fingerprint so a transform change re-runs everything). Custom transforms are passed per-run via the Python API'stransforms=map. Outputs are written atomically; the--output-diris symlink-checked before any directory is created.soup data gen-magpielive generator — the Magpie synthetic generator (Xu et al. 2024) now actually generates. It feeds an aligned model its chat-template prefix (chatml / llama3 / gemma / mistral families auto-detected) and harvests the self-generated user instruction + assistant response via raw completion. Live providers:ollama(/api/generateraw) andvllm(/v1/completions) — both SSRF-hardened (loopback-only HTTP);anthropicis rejected (no raw-completion endpoint). Optional--quality-filterdrops low-quality rows via the v0.47 toxicity/educational scorers; exact-duplicate instructions are de-duplicated.soup eval irt-subset --model {1pl,2pl,3pl}— the IRT eval-cost optimiser gained 2PL (per-item discrimination) and 3PL (+guessing floor) joint coordinate-ascent MLE fits alongside the existing 1PL Rasch.1plkeeps the closed-form path for back-compat;2pl/3plroute through the newfit_irt.- Tokenizer-aware memorization probe —
score_memorization(..., tokenizer=...)andsplit_prefix(..., tokenizer=...)(used bysoup diagnose) now split the prefix/suffix on real token-id boundaries and measure echo-overlap over sub-word tokens when a tokenizer (HF id / path / duck-typed object) is supplied, catching BPE-level memorization that whitespace tokenisation misses. Default (no tokenizer) keeps the whitespace behaviour.
Fixed
soup data augment --provider ollama|vllmno longer crashes — the command imported a non-existentOllamaProvidersymbol and raisedImportErroron every non-OpenAI provider. It now routes through the shared, SSRF-hardened provider factory;--model/--base-urlare honoured, the output path is containment- and symlink-checked, and the write is atomic.
Security
- Ollama / vLLM provider URLs reject
0.0.0.0—validate_ollama_url/validate_vllm_urldropped the bind-any wildcard from their loopback allow-set (nowlocalhost/127.0.0.1/::1only), matching the newervalidate_hub_endpoint/validate_webhook_urlSSRF validators. Reachable now that Magpie threads a user-supplied--base-urlthrough these providers.
[0.71.5] - 2026-06-02
Added
soup eval againstnow reads eval metrics —ExperimentTracker.get_metric_seriesfalls back to theeval_resultstable when the metric is not a per-step training column (loss/lr/grad_norm/speed/gpu_mem). Sosoup eval against <base> --candidate <run> --metric task_accuracyreturns a real score series (benchmark scores live ineval_results, notmetrics) instead of "Empty series". Per-step columns still read frommetrics— no regression for existing callers.soup adviselearns from past project outcomes —soup advisenow reads this project's accepted-verdict history (~/.soup/advise_history.jsonl) and biases the rubric: 3+ successful SFT precedents flip a marginal RAG call to SFT; 3+ negative GRPO outcomes suppress GRPO in favour of SFT-on-traces; an encouraged choice gets a small confidence nudge. Scoped per-project (one project's record never biases another). No history → identical to before.- Slack/Discord webhooks on four more commands —
--slack-url/--discord-url(SSRF-hardened, loopback-only HTTP, RFC1918 rejected, never crashes the command) now ship onsoup ingest,soup prune-prompt,soup ab(fires only on areject_h0/accept_h0decision, notcontinue), andsoup data active-sample— not justsoup drift-alarm. The validator + sender moved to a sharedsoup_cli/utils/webhooks.py. - Tokenizer-aware
soup prune-prompt—--tokenizer <model_or_path>detects and strips the shared system-prompt prefix on token boundaries instead of characters, so a multi-byte UTF-8 prefix can never be split mid-code-point. Default (no--tokenizer) keeps the whitespace-character behaviour. - Curriculum bucketing by loss percentile —
DynamicCurriculumCallbacknow buckets samples by the percentile rank of the live loss (or perplexity) signal within a rolling window whendata.curriculum_metricisloss/perplexity, so a consistently-hard sample is routed to the same difficulty bucket across recomputes.lengthand warm-up still use round-robin. --hubonsoup data pushandsoup data forge—soup data push --hub modelscope|modelersuploads a dataset via the matching SDK (repo_type=dataset, commit message sanitised);soup data forge --hub <non-hf> --teacher owner/namepre-fetches the teacher model from that hub (and warns when the teacher is not a repo id so--hubis never silently ignored). HF stays the default.
Notes
- Live SaaS pull adapters for
soup ingest(Langfuse / LangSmith / Helicone / OpenPipe / OpenAI SDKs, issue #204) remain deferred: they need credentialed vendor accounts with populated trace data to validate honestly. Tracked as an open,infra-blocked(external-account) item.soup ingestcontinues to parse the JSONL export you pull from your dashboard.
[0.71.4] - 2026-06-02
Added
- Live canary verdict for
soup adapters merge—--canary <suite.json>scores the merged adapter against the first input and classifies OK / MINOR / MAJOR using the Quant-Lobotomy taxonomy (drop <2% OK, <5% MINOR, else MAJOR).--strict-verdictexits 2 on MAJOR. Pre-scored{"baseline_scores","candidate_scores"}suites run with no model load; a{"tasks":[...]}suite uses an injectable scorer. Replaces the v0.57UNKNOWNstub. - Live evolutionary merge —
soup adapters merge --strategy cmaes --eval <suite> --budget <t>now runs the full CMA-ES loop: each candidate is merged, materialised, scored against the eval suite, and the best-weighted merge is written to--output. Replaces the v0.67 plan-only stub. - Publish an adapter PR to GitHub —
soup adapters pr <title> --base-sha <hex> --adapter <path> --push owner/repo#Nposts the rendered PR Markdown as a GitHub PR comment viagh api(argv-list, body over JSON stdin; no shell). Token resolves fromGITHUB_TOKEN/GH_TOKEN. - Pre-wired
soup loopproduction stages —soup loop init --pre-wired(orsoup loop watch --pre-wired) swaps the v0.58 no-op stage stubs for real harvest (traces → preference pairs) → DPO train → eval-gate → canary-deploy callables.soup loop statusnow shows thepre_wiredflag. - Loop iterations as Soup Cans + Registry lineage —
soup loop watch --pack-canspacks each successful iteration as a v0.26 Soup Can and appends a Registry entry (tagloop-iter), chaining a real lineage DAG across iterations visible throughsoup history. `soup loop replay --extract ` unpacks a recorded iteration. - Branch pointers into the Registry —
soup adapters branch <name> --attach-to-registry <id>links a branch snapshot to a Registry entry (shown as abranchesnode insoup history);soup adapters branch <name> --from-registry <id>derives a fresh snapshot's config + base from an entry.
Security
- The backdoor-scan gate (v0.71.2 #192) and license-conflict gate (v0.60 Part E)
now run for all merge strategies, including
--strategy cmaes(previously bypassed because cmaes returned before the gates). soup loopcanary deploy restrictsSOUP_LOOP_SERVE_ENDPOINTto loopback / RFC1918-private hosts (a serve endpoint is the operator's own box/LAN), beyond the general webhook SSRF policy which permits any HTTPS host.soup adapters pr --pushbuilds theghchild environment from an allowlist so unrelated secrets (HF_TOKEN/OPENAI_API_KEY/ …) never reach the subprocess.- The canary-suite JSON read uses
O_NOFOLLOW+os.fstat(size cap enforced on the same fd) to close the symlink/size-cap TOCTOU window.
[0.71.3] - 2026-06-01
Added
- Energy & CO2 measurement for training —
soup train --track-energywraps the training window in a codecarbon offline tracker (no IP-geolocation network call) and reports kWh / CO2 / grid intensity, feeding those numbers into--annex-xi. NewEnergyTrackercontext manager; graceful no-op when codecarbon is absent (pip install soup-cli[carbon]).--energy-countrypicks the ISO-3166 alpha-3 grid for the CO2 estimate (defaultUSA). - PDF Annex XI/XII documents —
soup train --annex-xi report.pdfnow renders a reportlab PDF (a.mdpath still renders markdown).pip install soup-cli[pdf]. - Auto-populated training-corpus domains in Annex XI/XII — the top crawled domains (with shares) are now extracted from the training JSONL and listed in the EU AI Act docs, replacing the previous empty placeholder.
- Soup Can manifest v3 with embedded attestations —
soup can pack --attest <statement.json>(repeatable) embeds in-toto Statements into a v3 can manifest; v1/v2 cans still load. Each statement is shape- and size-validated. - Local audit log auto-instrumentation — every
soupcommand now appends one HIPAA/SOC2-shaped record to~/.soup/audit.jsonl(secrets redacted, args capped). Opt out per-invocation with--no-audit-logor globally withSOUP_NO_AUDIT_LOG=1. Tail/rotate withsoup audit-log. - Reproducibility receipt in airgap bundles —
soup airgap-bundle --repro-receipt <receipt.json>embeds an SR 11-7 receipt asrepro-receipt.json; auto-detected from<model>/repro-receipt.jsonwhen not supplied.
Security
soup can pack --attestnow rejects oversize attestation files by their raw size before parsing them into memory (defence against memory-exhaustion).- The new file-loading paths (attestation JSON, airgap receipt, training-corpus
scan, PDF write) are all cwd-contained + TOCTOU symlink-rejected and
size-capped; the audit auto-log redacts
hf_/sk-/Bearertokens and never crashes the CLI on a broken log.
[0.71.2] - 2026-06-01
Added
- ed25519 signing for
soup adapters sign/soup attest— real detached signatures (over the adapter Merkle root / the in-toto statement) via a new[sign]extra (pip install soup-cli[sign], pullingcryptography).soup adapters sign --backend ed25519 --key <priv.pem>(or--generate-key <out.pem>, orSOUP_SIGNING_KEY);soup adapters verify [--public-key <trusted.pem>]does a cryptographic verify and, with a trusted key, genuine authentication.soup attest emit --sign ed25519 --key <priv.pem>writes a<output>.sigsidecar; newsoup attest verify <statement> --signature <sig>verifies it (canonical-JSON, so it's platform/newline-independent). Sigstore keyless signing stays infra-blocked (needs an OIDC provider + Fulcio/Rekor network — can't be honestly validated offline). - Anti-AI-Jacking namespace pin on Hub downloads — HF model fetches now
consult a trust-on-first-use pin store: a repo whose author changes (or whose
created_atjumps backward) is refused unless the namespace shift is explicitly allowed. Fails open when repo metadata is unavailable. - License auto-detection at
soup adapters merge— when--licenseisn't given, the license is read from each adapter'sadapter_config.json/config.json/ model-card frontmatter (HFllama3.1-style ids mapped to canonical) and the conflict gate runs automatically. - Backdoor-scan gate at
soup adapters merge— refuses to merge any input whosesoup adapters scanreturns FAIL (or can't be scanned) unless--allow-unscannedis passed; WARN is advisory.
Changed
- License-conflict overrides (
--license-override <reason>) are now recorded to the audit log for legal review. - The namespace-pin store now uses SQLite WAL + busy-timeout and a cross-process file lock around its get+insert, so concurrent writers don't lose the trust anchor.
Security
- ed25519 verification fails closed (any tamper / wrong key / missing key ⇒
invalid). Signing keys + trusted public keys are symlink-rejected and
size-capped via a shared reader (no cwd-containment — keys live outside the
project).
--generate-keyrefuses to overwrite any existing path.
[0.71.1] - 2026-06-01
Added
soup env fix— render a reproducible install plan fromsoup-env.lock. Emits copy/pasteuv pip installcommands (--format uv-pip, default) or arequirements.txtbody (--format requirements);--outputoptionally writes arequirements.txtunder cwd. Print-only by design — never shells out to a package manager.soup lock write --env-lock <path>— auto-derive--env-hashfrom asoup-env.lockso operators who ransoup env lockdon't copy the hash by hand.--env-hashstill wins when passed explicitly.soup serve --record-thumbs <db>— capture thumbs-up/down feedback into a local-RL SQLite at startup, plus a newPOST /v1/thumbsendpoint (transformers backend). Returns 404 when the flag isn't set.- Judge-calibration persistence:
JudgeCalibrationReport.to_dict,write_judge_calibration, andload_judge_calibration, backed by a newjudge_calibrationregistry artifact kind. Loading re-validates the report so a corrupt on-disk field is rejected. - Bundled MUSE and WMDP unlearning eval fixtures so
soup eval unlearning --benchmark muse|wmdpruns out of the box. WMDP forget-set probes ship redacted (placeholder prompts +REFUSEDresponses) — Soup never ships verbatim hazardous content.
Changed
soup completionsnow introspects a cached base model's actual LoRA target modules (config-onlyAutoConfigload,local_files_only=True, never networks or raises) and falls back to the canonical default shape when the base isn't cached locally.build_dagexposes avalidate_build_sourcehelper (cwd-containment + symlink rejection) for build-manifest source paths.
0.71.0 - 2026-06-01
Changed
- Breaking — install split. The heavy training stack (
torch,transformers,peft,trl,datasets,bitsandbytes,accelerate) moved out of the core install into a new[train]extra.pip install soup-cliis now a light CLI + data-tools install with no PyTorch; runpip install 'soup-cli[train]'(or[all]) to fine-tune. Existing users who train must reinstall with[train]. Version pins are unchanged. - Trimmed
README.mdto a ~238-line front door; the full feature reference now lives underdocs/(one topic page per area, indexed from the README). - Raised the pytest coverage gate from 50% to 77% (
--cov-fail-under=77). - Migrated to a
src/layout (src/soup_cli/) for cleaner packaging and to stop tests accidentally importing the in-tree package.
Added
[train]and[all]optional-dependency extras ([all]pullstrain,serve,ui,data).[dev]self-references[train]so CI and contributors still get the full stack frompip install -e ".[dev]".- Friendly error mapping: a missing heavy dependency (
torch,transformers,peft,trl,datasets,bitsandbytes,accelerate) now surfaces "Training needs the [train] extra. Run: pip install 'soup-cli[train]'". py.typedmarker (PEP 561) so downstream type checkers pick up Soup's inline type hints..pre-commit-config.yamlwith ruff (lint + format) and standard file-hygiene hooks.- Lenient
mypyconfiguration and a non-blockingtype-checkCI job. - This
CHANGELOG.md.
Removed
- The historical, per-version security-fix log that had grown inside
SECURITY.md(~220 KB).SECURITY.mdis now a concise security policy; the detailed hardening notes remain in git history and the GitHub Releases notes.