Skip to content

translator — Changelog

The release history from v0.0.2 on. The canonical entries live in the tool's CONTRIBUTING.md. This page gives the same history in two other shapes: a scannable line per release, and the arcs those releases belong to.

Releases are numbered as pre-releases in the project's own sense — 0.x, then -beta — and from v0.10.1 on each one publishes its container images through the release gate described on Operations.

The four arcs

1 · Getting XML in and out intact (v0.0.2 → v0.4.1). The early releases narrow the problem. v0.0.2 accepts almost anything — txt, pdf, xml — and v0.1.0 adds a draft AMCR path with no line-level logging. v0.2.1 is the first release that says what the tool is for: ALTO and AMCR XML only. v0.3.0 adds paradata logging, v0.4.0 the controlled vocabulary, v0.4.1 the first tests.

2 · Making ALTO output structurally honest (v0.5.0 → v0.8.0). v0.5.0 is the technical centre of the project: the dual-pass reconstruction — translate the block for quality, translate each line as a structural anchor, then realign — together with NMT-safe vocabulary sentinels and the number-agreement guard. v0.6.0 hardens it: XXE-proof XML parsing through an lxml secure parser, TranslationError with exponential back-off instead of logging corrupt output, pinned dependencies, and --fast-align. v0.8.0 moves ALTO translation from per-block to per-page calls, which is where the ~20× call-count reduction comes from.

3 · Backends (v0.6.2 → v0.7.0, and issue #4). A pluggable TranslationBackend protocol replaces the hardcoded LINDAT call, with lindat and openai_compatible registered and a CTranslate2 scaffold alongside. v0.7.0 calls this "finalized in theory (not tested in practice)": the architecture was settled first, and the choice between candidate models was left to a measurement harness, eval/bakeoff.py.

4 · Production readiness (v0.9.0 → v1.1.0-beta). OpenAPI conformance, shared version and licence tests, the atrium_document integration, the hub's reusable workflows at @v1, and then two releases that are about behaviour rather than features: v1.0.0-beta makes five announced-but-inert contracts real, and v1.1.0-beta adds the replace/append switch and fixes three defects that only appeared under real use.

v1.1.0-beta — the replace/append switch

The replace/append switch. --output-mode replace|append — also a config.txt key, an OUTPUT_MODE environment variable and a /translate field — decides whether the source-language field is overwritten or kept beside an xml:lang-marked sibling, the shape AMCR's own thesaurus already uses for heslo / heslo_en. In ALTO mode it labels rather than duplicates: a per-String append would multiply a word-to-box alignment that is manufactured rather than observed. replace stays the default, and its output is byte-identical across all 16 shipped samples.

Three fixes that only real use could find:

  • /translate answered HTTP 200 with the metadata untranslated — a hard-coded empty XPath list. Targets now load from AMCR_FIELDS_PATH, and an unconfigured request is a 422 rather than a successful-looking no-op.
  • Request parameters were read from the query string while callers were sending them in the body. Both are now accepted.
  • The page-batch fallback degraded call count by roughly 20× behind a silent except Exception: pass. It is now counted, categorised (clean batching / line-count mismatch / transport error) and logged as a per-document summary.

v1.0.0-beta — the release where five contracts became real

Prompted by a production-readiness review rather than a filed issue. Each defect lived somewhere the test suite was structurally not looking, and each fix was confirmed by reintroducing the defect and watching the new guard go red.

Defect What was actually happening
The retry policy was not configuration http_retry.py clamped its arguments upward, so LINDAT_MAX_RETRIES and its LLM_* twins were read and discarded. The effective policy was 11 attempts backing off to 2,046 s for one failing chunk — unreachable against a 20-second drain window
413 was unreachable /translate read the whole upload before checking its size, for exactly the inputs the limit existed to refuse
The CLI always exited 0 Every failure path was a bare return. A Kubernetes Job reported success for a run that translated nothing
A failed FastText load was swallowed detect() then answered ("en", 0.0) for every document while the service reported itself healthy — the failure mode of an egress-restricted cluster specifically
The release zip could not start It omitted atrium_document.py and service/atrium_service.py, both imported by the entry points. ModuleNotFoundError on the primary download path for anyone not using the container

Breaking: the batch CLI now exits non-zero on failure.

Every release

Version What changed
v1.1.0-beta The replace/append switch; /translate metadata 422; body and query parameters accepted; batch-fallback instrumentation
v1.0.0-beta Pre-production hardening — five announced-but-inert contracts made real. Breaking: non-zero CLI exit on failure
v0.10.5 Re-vendored atrium_document.py; .coveragerc stops omitting service/* — where a backend-less /translate HTTP 500 had been hiding — floor held at 81 % against a re-measured 82.87 %
v0.10.4 doc_id is inherited, never re-derived. The input is PAGE_ALTO/<doc>/<doc>-1.alto.xml, a page — so the record, the log's file column and the paradata key all take the document's id while per-file outputs keep the per-file name
v0.10.3 End-to-end CI for document-JSON input/output refined against the draft schema
v0.10.2 Workflow references repinned to the hub's @v1 tag
v0.10.1 The release path exercised end to end: version guard, post-publish Trivy digest scan with SARIF, BuildKit SBOM and provenance attestations. No functional change
v0.10.0 First atrium_document integration; paradata template refreshed
v0.9.0 API standardised to OpenAPI rules, aligned with the agent-skill branch
v0.8.1 Shared version-reading and licence tests; LLM review round
v0.8.0 Per-page instead of per-block calls for ALTO — the origin of the ~20× call-count reduction; agent_dev_logs/ introduced
v0.7.0 Multi-backend support finalised in theory, not tested in practice
v0.6.2 Draft multi-backend translation model
v0.6.1 Second LLM review round; Docker CI alignment
v0.6.0 Security: XXE-proof XML parsing via an lxml secure parser. Reliability: TranslationError with exponential back-off instead of logging corrupt output; all dependencies pinned. Performance: --fast-align and the LINDAT_* rate-limit variables
v0.5.1 Docker wrapper; fasttext swapped for fasttext-wheel, removing the compiler requirement
v0.5.0 Dual-pass ALTO reconstruction — block plus line translation with similarity-based token alignment; NMT-safe vocabulary sentinels and the number-agreement guard; per-run licence resolution and paradata
v0.4.1 Pytest for the main functionality
v0.4.0 Controlled vocabulary added
v0.3.0 AMCR samples; paradata logging of outputs
v0.2.1 Narrowed to ALTO and AMCR XML; citation, licence and contribution drafts
v0.1.0 Broad input support with a draft AMCR path; no ALTO line logging yet
v0.0.2 Working draft — txt, pdf, xml, no AMCR XPath configuration

Sources

Read from ufal/atrium-translator at branch master, commit 71feaef (2026-09-23). The arcs are written here, not taken from a source. This table records provenance, not a build instruction.

Source What was taken from it
CONTRIBUTING.md § 📦 Release History every release line and the two release descriptions
agent_dev_logs/DEVLOG.md the v1.0.0-beta defect table, cross-checked
CITATION.cff the current version and its release date