---
title: "How a run works"
description: "The translation pipeline end to end, from reading the source locale and finding changed keys to writing the translations and updating the lock file."
type: "concept"
---
# How a run works

The translation pipeline end to end, from reading the source locale and finding changed keys to writing the translations and updating the lock file.

A run is a pipeline: read the source locale, diff each target against the lock file, send only what
needs work to the provider, check what comes back, write, and record the result. The pipeline is
the same whether the run came from the CLI, the SDK, or `watch`.

<DiffPanel />

## Read the source locale [#read-the-source-locale]

The format adapter reads the source file into a neutral set of keyed entries, so every later step
works the same for every format. A source key whose value is invalid for the format's message
syntax (invalid ICU) is set aside and reported rather than sent to the provider in a broken state.
A source file that is missing or cannot be parsed fails the run; see
[`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#source_unreadable) and
[`SOURCE_INVALID`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#source_invalid).

## Diff against the lock baseline [#diff-against-the-lock-baseline]

The diff is what makes a run incremental. verbatra reads the existing target file (an absent file
counts as empty, though `xliff` and `apple-xcstrings` writers refuse a missing target) and compares each source key against [the lock file](https://verbatra.kreitz-webdev.de/docs/the-lock-file.md), the
record of what was translated before:

| Bucket | Meaning | What the run does |
| --- | --- | --- |
| missing | the target does not have the key | translates it |
| changed | the source no longer matches the recorded hash | translates it |
| unchanged | the source still matches the recorded hash | leaves it alone |
| orphaned | the key is in the target but not in the source | reports it; removes it only with `--prune` or `prune: true` |

### Held-back keys [#held-back-keys]

<AvailableFrom version="0.12.0" />

Two kinds of candidate are held back. A changed key whose current value a person wrote or imported
is protected by default (`humanEdits`), and a key matching `pinnedKeys` is never machine-translated.
Both stay stale until a person resolves them; see
[Protecting human translations](https://verbatra.kreitz-webdev.de/docs/protecting-human-translations.md).

## Batch to the provider [#batch-to-the-provider]

Every candidate is first looked up in the [translation cache](https://verbatra.kreitz-webdev.de/docs/the-cache.md). A hit is reused and
never reaches the provider. Of the misses, keys with the same source content are grouped, so that
text costs one request per locale rather than one per key.

The groups go to your provider in sequential sub-batches of at most `maxBatchSize` (default 50),
each carrying the entries, the glossary terms of that locale and your `tone`. If a sub-batch fails
(a rate limit, a timeout, a revoked key), its keys are withheld for this run while the other
sub-batches keep going. [Providers](https://verbatra.kreitz-webdev.de/docs/providers.md) describes how each provider applies these
inputs.

## Validate the response [#validate-the-response]

Provider output is data, never free text. For the LLM providers the response must match a fixed
schema:

- A malformed response, or one that contains a key that was never requested, fails the whole
  sub-batch.
- A requested key that comes back missing or duplicated is requested once more.
- A key still unresolved after that is not translated this run.

The machine-translation providers have no response schema, but their results go through the same
integrity gate.

## Run the integrity gate [#run-the-integrity-gate]

A schema-valid translation can still be broken, so verbatra decides from the candidate value itself
whether to accept it and never trusts the provider's own report. A candidate that loses a
placeholder, breaks an ICU message or its markup, comes back empty, or degenerates is withheld
instead of written. The checks are on [Translation safety](https://verbatra.kreitz-webdev.de/docs/translation-safety.md#the-integrity-gate).

## Write through the adapter [#write-through-the-adapter]

Accepted translations are merged into the target and written by the format adapter, atomically and
in a stable key order: a key already in the target keeps its position, and new keys are appended
after the existing ones, in source order. An interrupted write never leaves a half-written file, and reviewers see small,
stable diffs.

## Update the lock [#update-the-lock]

After a locale is written, its lock entries are refreshed with the current source hashes. A key
withheld this run keeps its previous hash, so the next run still sees it as needing work. Each
locale is written under a cross-process [write lock](https://verbatra.kreitz-webdev.de/docs/the-lock-file.md#the-write-lock), so two
overlapping runs never diff against a stale baseline or pay twice for the same call.

## One locale at a time, failures as data [#one-locale-at-a-time-failures-as-data]

Each target locale runs on its own, and one locale failing does not stop the others. The run
returns a summary per locale: translated, unchanged, orphaned, withheld, flagged for review, and
notices. What each field holds is on [RunSummary](https://verbatra.kreitz-webdev.de/docs/sdk/run-summary.md).

What this design guarantees:

- A second run with no source edits calls the provider for nothing.
- Nothing a check rejected is ever written, and nothing withheld is recorded as done.
- A dry run (`--dry-run`) stops after the diff and returns the same summary shape, without building
  a provider or writing a file.

What it does not do: it never judges whether a translation is good. That is what
[review flags](https://verbatra.kreitz-webdev.de/docs/translation-safety.md#review-flags) and a person are for.

## Related [#related]

- [`verbatra translate`](https://verbatra.kreitz-webdev.de/docs/cli/translate.md): flags, output and exit codes of a run.
- [The lock file and provenance](https://verbatra.kreitz-webdev.de/docs/the-lock-file.md): what the baseline records.
- [The translation cache](https://verbatra.kreitz-webdev.de/docs/the-cache.md): how reuse is keyed.
- [Translation safety](https://verbatra.kreitz-webdev.de/docs/translation-safety.md): the integrity gate and review flags.
- [Error codes](https://verbatra.kreitz-webdev.de/docs/error-codes.md): every code a run can report.
