Alpamys
ed5fc3a8b3
feat(precision,rollout): live fp8/nvfp4 + vLLM sleep + openenv rollout + apple-adapter + delinearize-llama4 (v0.71.21)
...
Closes #141 , #124 , #125 , #228 , #97 .
- #141 : apply_fp8_attention (torchao float8 on attention projections, Hopper
gate) + apply_nvfp4 (NVFP4Config, Blackwell gate); partial-conversion honesty;
wired into the v0.28 speed/memory pipeline with yellow-advisory degrade.
- #124 : vllm_sleep_mode live - create_vllm_engine(sleep_mode=True) +
vllm_sleep_cycle ctx (wake in finally) + TRL GRPOConfig hook probe.
- #125 : openenv rollout fully live via training.rollout_func module:fn
resolver; rows replace the prompt dataset; art/ruler/nemo_gym honest dep
gates + _EXTERNAL_ROLLOUT_RUNNERS seam. Real GRPO train on SmolLM2-135M.
- #228 : convert_apple_adapter live - PEFT LoRA <-> mlx-lm (both matrices
transpose, bf16 upcast, adapters.safetensors + num_layers, npz legacy read,
np.ascontiguousarray fix for safetensors non-contiguous mangling);
*-to-apple upstream-gated exit 3.
- #97 : delinearize-llama4 live - [E*din,dout] -> [E,din,dout] per shard,
config.json expert-count probe + --num-experts, sidecar copy, atomic writes.
Review waves: 3 HIGH + ~8 MEDIUM + ~12 LOW fixed.
Tests: 13874 -> 14084 (+210 in tests/test_v07121.py).
Full suite: 13967 passed, 117 skipped. ruff clean.
2026-06-10 16:29:52 +05:00
Alpamys
a4dfbb308c
feat(trainer): live TTS / BitNet / MoE-expert-quant trainers (v0.71.20)
...
Lift three v0.52.0 schema-only NotImplementedError stubs to real code.
- #131 TTS: TTSTrainerWrapper(SFTTrainerWrapper) — TTS fine-tune = next-token
CE over [text][audio-codec-token] chat; per-family emotion templating
(Orpheus/Oute) + codec special-token registration. Pre-encoded chat path
live-validated on SmolLM2-135M-Instruct; live-codec (data.format=audio)
hardware-gated per family.
- #134 BitNet: BitNetTrainerWrapper gated on onebitllms; export --format
bitnet|tq1_0 runs real llama.cpp TQ1_0 ternary GGUF export.
- #136 MoE: apply_moe_expert_quant swaps fused-MoE experts to bnb Linear4bit/
Linear8bitLt (pre-LoRA); train_router_only freezes experts (post-LoRA).
Live-validated on RTX 3050 (dequant err 0.0155).
Review fixes: H1 explicit Params4bit/Int8Params weight-carry; H2 quant
pre-LoRA / freeze post-LoRA + skip PEFT-wrapped modules; M4 device-aware
placement.
Tests 13807 -> 13874 (+69 in test_v07120.py, -2 lifted stubs in test_v0520.py).
2026-06-10 12:37:14 +05:00
Alpamys
70fd5ee9f3
feat(distill,agent,cloud): on-policy MiniLLM + aligned ULD + agent sandbox eval + Modal cloud (v0.71.18)
...
Closes #257 , #258 , #110 , #16 .
- #257 MiniLLM true on-policy rollout: minillm_on_policy_rollout (Gu et al. §3.1
autoregressive teacher-mixed rollout, reverse-KL on full distributions,
grad-to-student-only) + on_policy_term + training.minillm_on_policy /
minillm_rollout_length, wired into DistillTrainer.compute_loss.
- #258 cross-tokenizer ULD wasserstein_aligned: align_token_sequences (difflib
char-span) + aggregate_aligned_logits + uld_aligned_loss for fully-disjoint
tokenizers, wired into DistillTrainer.
- #110 soup agent eval --sandbox: build_eval_stub (base64-embed-as-data) +
run_eval_in_sandbox (v0.25 RLVR isolation + SANDBOX_NETWORK_GUARD) +
classify_sandbox_outcome (ok/tool_error/timeout/arg_error).
- #16 soup train --cloud modal: render a Modal app from soup.yaml (config
base64-embedded), plan-only default, --cloud-submit token-gated; [modal] extra.
+114 tests (tests/test_v07118.py); 13656 -> 13770. Step-6 smoke on real input
(Windows + RTX 3050): Modal stub render, real subprocess sandbox scorecard,
on-policy distill (tiny-gpt2), cross-tokenizer aligned ULD (GPT-2 + Llama).
2026-06-08 23:49:14 +05:00
Alpamys
0d55ba9e46
feat(serve): serve-time MoLE + per-request vector banks + epoch RAFT shuffle (v0.71.17)
...
Closes #259 (soup serve --mole: load base + N frozen task LoRAs + mole_gate.pt,
blend per-token at decode; train writes mole_manifest.json).
Closes #260 (soup serve --bank active user per-request via contextvars.ContextVar,
no cross-request leak; streaming path re-selects in-context).
Closes #253 (data.raft_epoch_shuffle: re-permute golden/distractor docs each epoch;
epoch=0 == legacy order).
Closes #254 (soup diagnose --citation-style / --shuffle-seed into the live probe).
Fix: MoLE train() returns initial_loss/final_loss/total_steps/duration_secs so
task=moe_lora_routing completes cleanly (surfaced by the #259 smoke).
Validated live on SmolLM2-135M (RTX 3050). 13595 -> 13656 tests.
2026-06-08 20:06:43 +05:00
Alpamys
28a2d8cf82
feat(edit): GPT-2 Conv1D edits, covariance ROME, atomic governor, Mixtral LongLoRA (v0.71.16)
...
Knowledge edit depth — 4-issue patch (validated on real gpt2 + SmolLM2-135M, RTX 3050).
- #251 GPT-2 (transformer.h / mlp.c_proj Conv1D) support in ROME/MEMIT/AlphaEdit:
transpose-aware _rank1_update + _alphaedit_project + MEMIT dim-check + PEFT unwrap.
- #250 covariance-preconditioned ROME via --cov-corpus (estimate_key_covariance +
C^-1 k* solve; fail-loud reject for non-rome; cwd-contained O_NOFOLLOW loader).
- #252 atomic EditGovernor increment: save_state merges this run's delta under the
cross-process lock (baseline-delta, mirrors namespace_pin).
- #147 Mixtral in the LongLoRA allowlist (is_mixtral_model + MixtralAttention
forward override + _SEPARATE_QKV_FAMILIES).
Tests: 13511 -> 13595 (+81 in tests/test_v07116.py). Full suite green; ruff clean.
2026-06-07 16:11:56 +05:00
Alpamys
d5f98c67d5
fix(loop): config-render, cmaes base-reuse, cost gate, energy hand-off, rank guard (v0.71.15)
...
#261 iterative_dpo._default_train_fn rendered output as a {dir: ...} mapping
that SoupConfig rejected; render it flat so the spawned soup train succeeds.
#246 CMA-ES merge now loads the base model once and reuses it across the
candidate population (_CachedBaseScorer) instead of reloading per candidate.
#245 soup loop estimate_cost wires run_cost.estimate_run_cost_usd off the last
completed run instead of a 0.0 placeholder; never crashes the daemon.
#244 soup train --track-energy --energy-out persists the measurement JSON so
soup bom emit --energy can attach it to an ML-BOM.
#170 --diagnose-gate is RANK-aware: gate once per cluster (RANK==0), not per node.
Tests: 13476 -> 13511 (+35 in tests/test_v07115.py). Validated end-to-end on
SmolLM2-135M / RTX 3050.
2026-06-07 13:58:18 +05:00
Alpamys
6ec36b5ff6
feat: live FSDP-shard consolidation + serve KV-cache type + ONNX QA (v0.71.14)
...
Close the doable tail of the export-QA + deferred-stub family.
- #96 consolidate_shards: lazy-torch safetensors merge, TOCTOU-hardened
(enforce_under_cwd_and_no_symlink, weights_only=True, atomic_write_bytes),
16 GiB/shard cap, dup-key shape-conflict reject. --plan-only flag.
- #140 apply_kv_cache_type -> KvCacheRuntime; soup serve --kv-cache-type
(bf16/f16 dtype, q8_0 quantized cache + hqq probe, fp8 Hopper-gated).
- #71 ONNX export QA: tiny-GPT2 PASS, TinyLlama host-RAM-bound (qa doc).
- #70/#72/#144/#74/#79 deferred to INFRA-BLOCKED tail (kept open).
Tests 13430 -> 13476 (+46). ruff clean. Suite green, 78.52% cov.
2026-06-05 13:39:36 +05:00
Alpamys
f528da5328
feat(prompt-compile): live soup compile / distill-prompt / compile-tools / local-rl train (v0.71.13)
...
Lift the v0.68.0 deferred-stub family to live (closes #225 , #226 , #227 , #229 ):
- #229 local-rl train --once: harvest thumbs -> DPO/KTO/ORPO train via a
soup train subprocess (argv list, no shell); state table tracks last_train_at
(skip-on-no-new-thumbs + skip-on-insufficient-pairs); no --once renders a
systemd/launchd nightly scheduler scaffold. New local_rl_scheduler.py.
- #226 distill-prompt: call the teacher once per trace (Ollama/Anthropic/vLLM)
and write a real dataset (sft/kl -> messages; preference -> chosen/rejected).
- #225 compile / #227 compile-tools: live DSPy/GEPA/TextGrad dispatch behind the
new [compile] extra with a friendly ImportError when absent; injectable seams.
Security: reject \n/\r in the model id + shell-quote ExecStart args (systemd
injection defence). Fix: render train output as a plain string (schema-valid),
with a regression test against SoupConfig.
Tests 13329 -> 13424. Smoked end-to-end: real DPO train on SmolLM2-135M (RTX 3050)
+ real Ollama teacher distillation.
2026-06-04 22:14:43 +05:00
Alpamys
a66e4b9ebe
feat: architecture + distill + adapter-train live wiring (v0.71.12)
...
Lift seven schema-only stubs to live, validated on tiny models:
- #145 distill_mode token|sequence — sequence-level teacher-continuation KD
- #146 classifier LoRA — frozen encoder + adapter (classifier/reranker/cross_encoder)
- #148 LLaMA Pro block expansion — per-arch (Llama/Qwen/Mistral) zero-init blocks
- #158 LongLoRA S2 — shifted-sparse attention on Q/K projections (Llama/Mistral/Qwen/Phi)
- #84 Mixture-of-Depths — per-layer top-k token router (use_mod; Llama/Qwen/Mistral)
- #221 VeRA/VB-LoRA serving — soup serve --bank, per-user delta via X-User-Id header
- #222 MoLE — task=moe_lora_routing, per-token gate over N frozen task LoRAs (gate-only)
Tests 13203 -> 13329 (+126; tests/test_v07112.py). ruff clean, coverage 78.49%.
2026-06-04 19:36:04 +05:00
Alpamys
f316d334bc
feat(rl): live GRPO/RL callbacks — reward-hack, echo-trap, RL ckpt, ULD, MiniLLM, iterative-DPO (v0.71.11)
...
Lifts the v0.70.0 schema-only build_*_callback / build_uld_projection /
run_iterative_dpo stubs. Validated end-to-end on SmolLM2-135M.
Closes #235 , #236 , #237 , #238 , #239 , #240 , #159 , #160
- #235 RewardHackCallback: info_rm cluster-sep / rm_ensemble divergence,
OK/WARN/HACK, halt on HACK. Shared thread-safe RLSignalBuffer captures
per-step rewards by wrapping the reward fns (no TRL monkeypatching).
- #236 ULD: Wasserstein-1 / top-k aligned distill loss in DistillTrainer.
- #237 MiniLLM: teacher-mixed length-normalised reverse-KL + pretrain anchor.
- #238 RLCheckpointCallback: adapter + optimizer.pt + manifest + keep_last prune.
- #239 run_iterative_dpo: sample -> RM-score -> build-pairs -> DPO-train per round.
- #240 EchoTrapCallback: n-gram repetition OK/WARN/TRAP, halt on TRAP.
- #159 one-shot WARNING when a GRPO variant compute_loss falls back to super().
- #160 in-place ref-model EMA (no state_dict round-trip) + 0-overlap warning.
Tests 13142 -> 13203 (+62 in tests/test_v07111.py).
2026-06-04 17:14:08 +05:00
Alpamys
a2287dd6a5
feat(rag): RAFT span-mask trainer + RA-DIT auto-link + live steering + eval citation (v0.71.10)
...
Lifts the v0.62.0 RAG-family schema-only stubs to live, validated on SmolLM2-135M:
- #199 RAFT: data.format=raft trains answer-only (prompt span masked to -100,
[doc-N] citation ids, deterministic doc shuffle by raft_shuffle_seed); rows
whose prompt fills max_length are dropped with a warning. New utils/raft.py +
trainer/raft.py (RaftDataCollator + weighted-CE _RaftTrainer).
- #200 soup ra-dit: one-shot two-stage orchestrator (train retriever -> record
it as the generator's paired retriever -> train generator); a generator-stage
`soup train` with no retriever set auto-links the latest RA-DIT retriever from
the Registry. New utils/ra_dit_run.py + commands/ra_dit.py.
- #201 soup steer train/apply + soup serve --steer: live CAA/ITI/RepE fit from
{positive, negative} pairs + decode-time forward hook (transformers backend).
Lifts the steering.py apply_steering/build_steering_vector stubs.
- #202 soup eval citation + citation-span per-token loss boost + 7th `citation`
failure mode in soup diagnose. New commands/_eval_v07110.py +
diagnose/citation.py.
Review fixes (3 agents, all CRITICAL->LOW): markup-escaped autolink advisory;
shared enforce_under_cwd_and_no_symlink + O_NOFOLLOW on every new file read;
steering-artifact containment; honest RA-DIT docs (records pairing, no weight
fusion); public validate_ra_dit_config_path + render_raft_prompt; repe/iti
require >=2 pairs; eval citation --shuffle-seed.
Full suite: 13034 passed, 106 skipped (13142 collected). ruff clean.
2026-06-03 19:28:45 +05:00
Alpamys
96c339f184
feat(edit): live ROME/MEMIT/AlphaEdit + GRACE + NPO/SimNPO/RMU unlearn (v0.71.9)
...
Closes #193 , #194 , #196 , #197 , #203 .
- #194 utils/edit_kernels.py: covariance-free rank-1 ROME/MEMIT/AlphaEdit;
apply_edit live (load -> optimise residual -> rank-1 update -> save);
edit diff live before/after generation.
- #196 EditGovernorStore SQLite persistence + cross-process lock.
- #197 apply_edit consults the governor (check_can_edit before, record after).
- #203 GraceCodebook + apply_grace_edit + install_grace_hook + Registry kinds.
- #193 utils/unlearn_kernels.py (NPO/SimNPO/RMU) + live UnlearnTrainerWrapper
+ soup train --task unlearn.
Validated on SmolLM2-135M: ROME 0.0016->0.96, NPO/SimNPO forget loss down.
+81 tests (tests/test_v0719.py). 2 review waves, all findings fixed.
2026-06-03 17:04:03 +05:00
Alpamys
823456c1a5
feat(probe): real probe weights, SAE auto-download, truth/harm, interference --measure, capture-activations (v0.71.8)
...
Closes #216 , #217 , #218 , #219 . Partial #215 (calibrated vectors upstream-gated).
- #215 probe_kernel.py: compute_contrast_probe + load_probe_weights
(.npz/.npy/.safetensors, O_NOFOLLOW, allow_pickle=False, cwd-contained);
soup probe sleeper --weights. Synthetic seed fallback retained.
- #216 hubs.snapshot_download (SSRF-hardened, home/cwd/tmp cache, TOFU gate)
+ sae_diff.download_sae (allowlist-before-network + symlink-escape guard);
soup probe sae-diff --auto-download.
- #217 truth_probe.py + harm_probe.py over probe_kernel; soup probe truth/harm;
probe pack ships truth+harm per base.
- #218 interference_live.measure_interference_losses (live PEFT multi-adapter,
add_weighted_adapter cat off-diagonal); soup probe interference --measure.
- #219 live_eval.extract_layer_activations + resolve_layer_module PEFT-fallback;
soup train --capture-activations writes <output>/activations/activations.json.
Test count 12771 -> 12917 (+146 in tests/test_v0718.py). Step-6 smoke on
SmolLM2-135M (RTX 3050) green; caught + fixed a PEFT-wrapper layer-resolution bug.
2026-06-03 15:00:27 +05:00
Alpamys
f097528ac0
feat(eval): live eval runners — advise/tunability/capability/behavior/diagnose (v0.71.7)
...
Closes #161 , #162 , #208 , #211 , #212 , #165 .
New utils/live_eval.py shared model-loading layer (lazy torch/transformers/peft):
load_model_and_tokenizer, make_generator/make_multi_generator, compute_eval_loss,
lora_probe, measure_logit_agreement, token_f1.
- #161 soup advise --probe-model: live zero/few-shot token-F1 + LoRA probe
- #162 base_model_proximity via held-out logit agreement
- #208 soup tunability --live: per-candidate LoRA probe
- #211 soup eval capability --live --model: lm-eval-harness per task (per-task isolation)
- #212 soup eval behavior --base-model: live pre/post battery diff
- #165 soup diagnose --base-model: utils/diagnose/live.py runs all 6 probes live
Heuristic/neutral paths preserved when no model is supplied. Both new JSONL
readers open with O_NOFOLLOW after cwd-containment (TOCTOU close). +68 tests
(12703 -> 12771). Smoked end-to-end on SmolLM2-135M (RTX 3050).
2026-06-03 00:05:36 +05:00
Alpamys
a1463bf716
feat(v0.71.6): live build runner + Magpie generator + 2PL/3PL IRT + augment fix
...
Lift the v0.69.0 deferred stubs to live + extend IRT + fix a real bug:
- #231 soup build materialises (5 built-in transforms, table/view/incremental
with SQLite-tracked config-fingerprint cache key, atomic JSONL, --output-dir)
- #232 soup data gen-magpie live (ollama/vllm raw-completion harvest; anthropic
rejected; optional --quality-filter; dedup-before-response)
- #167 tokenizer-aware memorization probe (sub-word/BPE overlap, library-only)
- #213 soup eval irt-subset --model 2pl|3pl (joint coordinate-ascent MLE)
- #75 fix soup data augment --provider ollama|vllm ImportError + QA log
Security: validate_ollama_url/validate_vllm_url reject 0.0.0.0; augment output
containment+symlink reject; magpie response-body cap.
Tests 12581 -> 12703 (+122 in tests/test_v0716.py). Full suite green, ruff clean.
2026-06-02 22:06:12 +05:00
Alpamys
1f63393421
feat(v0.71.5): ingest/data/prompt/drift polish
...
Closes #157 , #205 , #207 , #149 , #164 , #163 . Defers #204 (live SaaS pull —
paid accounts, infra-blocked, kept open).
- #164 : get_metric_series falls back to eval_results when metrics is empty
- #163 : build_verdict confidence biased by advise_history (same project+choice,
>=3 precedents); decision never changes
- #207 : shared utils/webhooks.py (SSRF-hardened) + --slack-url/--discord-url on
ingest/prune-prompt/ab/active-sample; ab fires only on a decision
- #205 : soup prune-prompt --tokenizer (token-prefix detect + decode remainder,
boundary-safe)
- #149 : DynamicCurriculumCallback buckets by loss/perplexity percentile;
length keeps round-robin
- #157 : soup data push/forge --hub modelscope|modelers (data score N/A)
107 new tests in tests/test_v0715.py (12474 -> 12581). ruff clean.
2026-06-02 14:34:36 +05:00
Alpamys
5652215d4a
feat(adapters,loop): v0.71.4 — live canary verdict + cmaes merge + PR push + pre-wired loop + can lineage + branch↔registry
...
Closes #172 , #173 , #176 , #177 , #220 , #223 .
- #172 soup adapters merge --canary/--strict-verdict: live OK/MINOR/MAJOR verdict (was UNKNOWN stub)
- #220 soup adapters merge --strategy cmaes: live merge→score→write-best loop (was plan-only)
- #223 soup adapters pr --push owner/repo#N: post PR comment via gh api
- #176 soup loop --pre-wired: real traces→DPO→eval-gate→canary stages
- #177 soup loop --pack-cans / replay --extract: iterations as Soup Cans + Registry lineage DAG
- #173 soup adapters branch --from-registry / --attach-to-registry
Security: backdoor-scan + license gates now run for ALL merge strategies (incl cmaes);
loop canary deploy restricted to loopback/RFC1918; gh child env from allowlist;
canary read uses O_NOFOLLOW+fstat (TOCTOU); pack-entry failure rolls back registry entry.
Tests: 12342 → 12474 (+130 in tests/test_v0714.py).
2026-06-02 12:25:01 +05:00
Alpamys
21a2bf8e8c
feat(governance,energy): v0.71.3 — annex PDF, audit auto-log, energy hook, can v3, airgap receipt
...
Closes #180 #181 #182 #183 #184 #188 .
- #180 EnergyTracker (codecarbon offline) + `soup train --track-energy`; [carbon] extra
- #181 PDF Annex XI/XII (reportlab) + paths.atomic_write_bytes; [pdf] extra
- #182 Soup Can manifest v3 + attestations field + `can pack --attest`
- #183 per-command audit-log auto-instrumentation (--no-audit-log / SOUP_NO_AUDIT_LOG)
- #184 auto-populate Annex top_domains from the training JSONL
- #188 embed repro-receipt into `soup airgap-bundle`
New [pdf]+[carbon] extras (reportlab also in [dev]). +83 tests (12259 -> 12342),
79.10% coverage. Reviewed (security/code/python/tdd): security M1 raw-size gate on
--attest before parse, python H1/H2 type hints, +22 negative tests.
2026-06-01 19:12:24 +05:00
Alpamys
9300ee3412
feat(governance,sign): v0.71.2 — ed25519 signing + supply-chain gates
...
ed25519 signing (#179/#185 ed25519 half): new utils/signing.py + [sign]
extra. `soup adapters sign/verify --backend ed25519` (--key/--generate-key/
--public-key) and `soup attest emit --sign ed25519` + new `soup attest
verify`. Sigstore keyless stays infra-blocked (OIDC/Fulcio/Rekor network).
#186 namespace-pin gate wired into download_repo (anti-AI-Jacking; fail-open)
#187 adapters merge auto-detects each adapter's license
#190 license-override reason recorded to the audit log
#191 NamespacePinStore WAL + busy_timeout + cross-process lock
#192 merge refuses scan-FAIL inputs unless --allow-unscanned
+106 tests (12153 -> 12259); full suite 79.07% cov. cryptography added to
[dev] for CI. 5 review waves, all findings fixed.
2026-06-01 17:17:44 +05:00
Alpamys
514761c89a
feat(env,lock,serve,eval): v0.71.1 — quick wins + wiring (7 closures)
...
Closes #195 #210 #214 #224 #230 #233 #209 .
- soup env fix: print-only install-plan renderer from soup-env.lock
(uv-pip / requirements; non-pip entries surfaced as comments). (#209 )
- soup lock write --env-lock: auto-derive --env-hash from soup-env.lock
via new compute_env_hash (excludes created_at). (#224 )
- soup serve --record-thumbs <db>: capture thumbs-up/down into the
local-RL SQLite + POST /v1/thumbs (transformers backend). (#230 )
- Judge-calibration persistence: JudgeCalibrationReport.to_dict +
write/load_judge_calibration + judge_calibration registry kind; load
re-validates the frozen dataclass with cwd/symlink containment. (#214 )
- soup completions: introspect a base model's real LoRA target modules
(config-only AutoConfig, local_files_only, never networks/raises). (#210 )
- Bundled MUSE + WMDP unlearning eval fixtures; WMDP forget rows ship
REDACTED (Soup never bundles verbatim hazardous content). (#195 )
- build_dag.validate_build_source: cwd-containment + symlink rejection. (#233 )
Review-fix hardening (consolidated python+code+security+tdd, 0 CRIT/0 HIGH):
load_judge_calibration containment + friendly missing-field ValueError;
serve thumbs success-print escape; env_fix --output Optional[str];
empty --env-hash auto-derives; render_install_plan PEP 440 docstring note.
Tests: 12071 -> 12134 (12044 passed, 90 skipped, 2 deselected).
2026-06-01 14:12:30 +05:00
Alpamys
7724353ac6
docs: trim README to a 238-line front door; move feature reference to docs/
...
The README had grown to 5046 lines (195 sections) — roughly one deep-dive per
feature accreted over 70 releases. Split it into a concise front door plus a
public docs/ tree:
- README (5046 -> 238 lines): hero, why, quickstart, config, a Documentation
map, data formats, common commands, models, Docker, requirements, dev.
- docs/*.md: all 185 feature sections preserved verbatim, grouped into 10 themed
guides + an index. Every original line is accounted for (content-conservation
checked); all 235 internal links + anchors verified to resolve.
- un-gitignore docs/ (it was empty); fix a pre-existing dangling
docs/QUANTIZATION.md link; correct the stale `ruff check soup_cli/` ->
`src/soup_cli/` reference in the Development section.
No version bump: docs-only — rides into the 0.71.0 deps-split release.
2026-05-31 20:10:59 +05:00