Release v2.7.0 — Transformers v5 upgrade + ML architecture unification¶
Release Date: 2026-07-05 Type: Minor release (major dependency bump, backwards-compatible public API) Last Updated: 2026-07-05
Summary¶
v2.7.0 raises the transformers floor from 4.57.6 to >=5.0.0,<6.0.0
and unifies the local ML architecture behind two shared backends
(HFEvidenceBackend, HFSeq2SeqBackend). Public APIs preserved — no
config changes, no schema changes, no operator action required.
Delivered as one epic PR closing GitHub issue #382.
Highlights¶
- transformers v5.13.0 replacing 4.57.6. Picks up the CVE-2026-1839
fix (Trainer
torch.loadweights_only, fixed in 5.0.0rc3+) and the eight PYSEC-2025-211..218 transformers-4.x deserialization advisories that had no fix in the 4.x line. - sentence-transformers 5.6.0 (from 5.5.1) — silent causal-LM reranker scoring bug fixed; TSDAE restored on transformers v5.
pipeline()retired for all local ML tasks:pipeline("summarization")→AutoModelForSeq2SeqLM.generate()+transformers.GenerationConfigpipeline("text2text-generation")(hybrid tier-1 reduce) → samepipeline("question-answering")(extractive QA, removed in v5) →AutoModelForQuestionAnswering.forwardwith pipeline-parity post-processing (overflow chunking, top-k logit walk, softmax over aggregated candidates)- Two new shared backends replace three parallel loader idioms:
HFEvidenceBackend(providers/ml/hf_evidence_backend.py) — QA / NLI / embedding. Owns device resolution (with per-subclassmps_supportedflag), the standardfrom_pretrainedkwargs (local_files_only,low_cpu_mem_usage=False,trust_remote_code=False), and a per-subclass instance cache with a threading lock.HFSeq2SeqBackend(providers/ml/hf_seq2seq_backend.py) — one loader/generator for BART / LED / Pegasus / LongT5 / FLAN-T5.SummaryModel(map profile) andTransformersReduceBackend(reduce profile) both delegate through it. Snapshot-first checkpoint discovery + retry hook + model-family class override.- Download helper collapse: three
_download_*_for_cachehelpers inproviders/ml/model_loader.pycollapsed into a single_download_hf_evidence_model(kind, model_id)with aLiteralkind discriminator;preload_evidence_modelsiterates one list of(kind, aliases)pairs instead of three parallel loops.
Behavior parity — measured¶
Frozen artifacts under data/eval/:
- Summarizer (BART+LED,
curated_5feeds_smoke_v1): min ROUGE-L = 1.0000, mean = 1.0000. Byte-identical output pre-vs-post migration on all 5 episodes. Seedata/eval/baselines/baseline_ml_bart_authority_smoke_v5_pre/and..._v5_post/, comparison indata/eval/runs/v5_parity_2026-07-05.json. - Extractive QA (
deepset/roberta-base-squad2, 8 fixture pairs): answer-text match 7/8 (87.5 %), offset match 6/8 (75 %). The one divergent pair is a legitimate algorithmic difference: our v5 post-processing softmaxes over aggregated top-k candidates across chunks, where the removed v4 pipeline used its own aggregation. Both answers are correct extractive spans.
Full parity report: data/eval/runs/v5_parity_2026-07-05.json.
Independent data-quality validation (data/eval/runs/v5_data_quality_recheck_2026-07-05.json,
run via scripts/eval/data_quality_recheck_2026-07-05.py):
| Comparison | Metric | Result |
|---|---|---|
v5-post vs shipped baseline_ml_bart_authority_smoke_v1 (April 2026) |
ROUGE-L / R-1 / R-2 | 1.0000 / 1.0000 / 1.0000 across all 5 episodes — byte-identical |
v5-post vs silver_opus47_smoke_v1 (Claude Opus 4.7 reference) |
mean ROUGE-L / R-1 / R-2 | 0.2175 / 0.4003 / 0.2391 |
| Historical anchor: shipped_v1 vs same silver | mean ROUGE-L / R-1 / R-2 | 0.2175 / 0.4003 / 0.2391 — identical to row 2 |
Rows 2 and 3 being identical is the strongest possible cross-check: v5 achieves the same quality score against the semantic ground truth as v4 did. No quality regression measured across three orthogonal comparisons.
Broader uniform data-quality coverage (post-audit expansion): every ML surface #382 touched now has a captured baseline + regression guard, matching the summarizer path's validation bar.
| Surface | Frozen reference | Bar |
|---|---|---|
| Summarizer smoke (BART+LED, 5 eps) | baselines/baseline_ml_bart_authority_smoke_v5_post/ |
byte-identical vs shipped_v1 |
| Summarizer benchmark (BART+LED, 10 eps) | baselines/baseline_ml_bart_authority_benchmark_v5/ |
1.0000 vs smoke on shared IDs |
| Extractive QA (roberta-squad2, 8 pairs) | references/qa_baseline_v5_post.jsonl |
answer-text identity |
| NLI (deberta-v3-base, 12 pairs) | references/nli_baseline_v5.jsonl |
entailment score ±0.01 |
| Embedding (MiniLM-L6-v2, 10 inputs) | references/embedding_baseline_v5.jsonl |
dim + L2 + first-8 dims ±1e-4 |
| FLAN-T5 reduce (hybrid tier-1, 4 prompts) | references/flant5_reduce_baseline_v5.jsonl |
output-text identity |
One-shot regression via scripts/eval/full_ml_recheck.py --json-report ...;
enforced by the nightly e2e test
tests/e2e/test_v5_parity_regression.py::test_full_ml_surface_recheck_no_regressions.
Absolute quality anchors (v5-post scored against semantic silvers):
| Baseline | Reference | Scope | mean ROUGE-L / R-1 / R-2 |
|---|---|---|---|
| smoke_v5_post | silver_opus47_smoke_v1 | 5 eps | 0.2175 / 0.4003 / 0.2391 |
| shipped_v1 (historical, v4-pipeline) | silver_opus47_smoke_v1 | 5 eps | 0.2175 / 0.4003 / 0.2391 (same) |
| benchmark_v5 | silver_sonnet46_benchmark_v1 | 10 eps | 0.1906 / 0.3790 / 0.1520 |
| smoke_v5_post (subset) | silver_sonnet46_benchmark_v1 | 5 eps | 0.1975 / 0.4015 / 0.1700 |
Determinism across dataset scope: benchmark_v5 vs smoke_v5_post on the 5 shared episode IDs = 1.0000 ROUGE-L identical output — the same transcript produces the same summary whether it's part of a 5-episode smoke run or a 10-episode benchmark run. No batch-size drift.
Dependency deltas¶
- "transformers>=4.57.6,<5.0.0",
+ "transformers>=5.0.0,<6.0.0",
- "sentence-transformers>=5.4.1,<6.0.0",
+ "sentence-transformers>=5.6.0,<6.0.0",
Transitively pulled in: huggingface-hub 1.22.0 (v5 requires >=1.0).
torch, accelerate, tokenizers, numpy, protobuf, spacy —
unchanged.
Makefile / CI cleanup¶
Nine pip-audit --ignore-vuln entries removed:
- CVE-2026-1839 (transformers Trainer
torch.loadw/oweights_only) - PYSEC-2025-211, -212, -213, -214, -215, -216, -217, -218 (transformers 4.x conversion-script / X-CLIP / Trainer deserialization RCE)
Fixed a shell-syntax bug in run-promote (# comment inside a \
line-continuation block, silently eating the trailing \) so
make baseline-create auto-promotes correctly.
Test infrastructure¶
- New:
tests/unit/podcast_scraper/providers/ml/test_hf_evidence_backend.py(15 tests): device matrix, cache-hit-once, subclass-cache-isolation, concurrent get_or_load thread safety, ABC contract enforcement. - New:
tests/unit/podcast_scraper/providers/ml/test_hf_seq2seq_backend.py(19 tests): default-safetensors matrix, device auto-detect fallback, guards, snapshot-fallback path, generate-config wiring. - Killed seven dead
@patch("transformers.pipeline", create=True)decorators intests/unit/podcast_scraper/test_summarizer.py— transformers_LazyModulerenderscreate=Trueno-ops (issue #677). - Bulk-migrated 34 pipeline-mock references in
test_summarizer.pyto the class-method seam (_generate_summary). - New docs:
docs/guides/testing-strategy-ml.mddocuments where to mock and why.
Compatibility¶
Public API preserved:
extractive_qa.answer/answer_candidates/answer_multi/clear_qa_model_cache(renamed fromclear_qa_pipeline_cache; no alias, only internal callers) /QASpan— unchanged.extractive_qa.get_qa_model/load_qa_model— NEW canonical names for what were previouslyget_qa_pipeline/load_qa_pipeline. Both old names are retained as deprecation aliases (emitDeprecationWarningon call,stacklevel=2); they proxy to the new names verbatim. Migrate at your leisure; aliases stay until v3.0.0.nli_loader.entailment_score/entailment_scores_batch/get_nli_model/load_nli_model/predict_output_to_entailment_scores— unchanged.embedding_loader.encode/cosine_similarity/get_embedding_model/load_embedding_model— unchanged.SummaryModel.summarize/SummaryModel(model_name, device, cache_dir, revision)constructor — unchanged. Internalself.pipelinefield type changed fromOptional[Pipeline]tobool(loaded sentinel); external code should not have depended on thePipelinetype.hybrid_ml_provider.TransformersReduceBackend.reduce()shape andHybridReduceResult— unchanged.SummarizationProviderProtocol (initialize/summarize/cleanup) — unchanged.
Config: no changes required. Schemas: no changes. Registry: no revision-hash changes; all pinned checkpoints verified resolvable under transformers 5.13.0.
Known follow-ups (separate from this release)¶
- Bundled-inference dedup across cloud providers — tracked in
#1142. The
summarize_bundled/summarize_extraction_bundled/summarize_mega_bundledtrio on OpenAI / Gemini / Anthropic / Mistral totals ~1460 LOC across the four providers with a shared flow (chunking → LLM call → JSON-parse retry → cost tracking → result-shape assembly) but SDK-specific request/response shapes. Orthogonal to transformers v5; ships in its own PR when scheduled. Full measurement + API proposal + test plan lives in the audit doc and the issue.
Related¶
- Testing strategy:
docs/guides/testing-strategy-ml.md - Post-impl notes:
docs/adr/ADR-068-bart-led-as-ml-production-baseline.md(§ Post-Implementation Notes — #382) - Parity report:
data/eval/runs/v5_parity_2026-07-05.json - Closes: GitHub issue #382