---
title: "El archivo de bloqueo y la procedencia"
description: "Qué registran verbatra.lock.json y verbatra.provenance.json, cómo se detecta el desfase y por qué debes confirmar ambos archivos."
type: "concept"
---
# El archivo de bloqueo y la procedencia

Qué registran verbatra.lock.json y verbatra.provenance.json, cómo se detecta el desfase y por qué debes confirmar ambos archivos.

`verbatra.lock.json` es la línea base con la que compara cada ejecución, así que una ejecución puede
saltarse lo que está al día y volver a traducir lo que se desfasó. A su lado,
[`verbatra.provenance.json`](#procedencia-quién-escribió-cada-valor) registra quién o qué escribió
cada valor.

## Qué registra [#qué-registra]

Para cada locale de destino, un hash por clave traducida de la entrada de origen detrás de la
traducción actual, más un campo `version`: ni traducciones ni secretos. El hash cubre el valor de
origen junto con su descripción, su significado, su indicador de plural y sus marcadores, así que una
descripción cambiada también deja la clave desfasada. Normaliza Unicode a NFC y los finales de línea
a LF, así que volver a guardar un archivo de origen con finales CRLF no cambia nada.

## Cómo se detecta el desfase [#cómo-se-detecta-el-desfase]

Una clave de origen que el destino no tiene está ausente (missing). Para una que sí tiene, el hash
de origen actual se compara con el registrado: una diferencia significa que el origen cambió y la
clave se vuelve a traducir; una coincidencia significa que nunca se envía, así que una segunda
ejecución sin cambios en el origen no cuesta nada. La canalización completa está en
[Cómo funciona una ejecución](https://verbatra.kreitz-webdev.de/es/docs/how-it-works.md).

### Claves protegidas [#claves-protegidas]

<AvailableFrom version="0.12.0" />

La excepción es una clave cambiada cuyo valor escribió o importó una persona: por defecto está
[protegida](https://verbatra.kreitz-webdev.de/es/docs/protecting-human-translations.md) y sigue desactualizada en lugar de volver a
traducirse.

## Adoptar un proyecto existente [#adoptar-un-proyecto-existente]

Los archivos de locale que ya contienen traducciones revisadas no se vuelven a traducir. En la
primera ejecución no hay archivo de bloqueo, así que nada puede estar desfasado: una clave que el
destino tiene conserva su valor, solo se traducen las que le faltan, y la ejecución registra cada
hash de origen como línea base sin coste de proveedor.

La adopción se basa en la presencia de la clave, nunca en su valor, lo que tiene dos consecuencias:

- **Un valor vacío o sin traducir cuenta como traducido.** Borra la clave (vaciarla no basta) y la
  siguiente ejecución la traduce.
- **Una traducción desfasada se registra como actual.** Corrígela o bórrala antes de la primera
  ejecución.

La misma regla conserva las formas de plural escritas a mano, así que `generatePlurals` es seguro
durante la adopción. Para ver todo esto de antemano, ejecuta [`verbatra diff`](https://verbatra.kreitz-webdev.de/es/docs/cli/diff.md) o
`verbatra translate --dry-run`.

## Cómo se actualiza [#cómo-se-actualiza]

- Una ejecución completa (`translate`, `watch` o una importación) sustituye las entradas de un
  locale por el resultado de la ejecución.
- Una acción de una sola clave, como volver a traducir desde Studio, fusiona solo la entrada de esa
  clave.

En ambos casos, una clave retenida en esta ejecución (una comprobación de integridad o llamada al
proveedor fallida, un origen con ICU no válido) conserva su hash anterior, así que la siguiente
ejecución la reintenta. Las claves huérfanas no tienen entrada, y las claves ordenadas mantienen
pequeños los diffs.

## El bloqueo de escritura [#el-bloqueo-de-escritura]

Dos ejecuciones que tocan el mismo locale a la vez podrían comparar con una línea base desfasada y
pagar dos veces, así que cada escritura toma un bloqueo entre procesos para ese locale en
`.verbatra-local/`. Un segundo escritor espera y luego compara con una línea base que incluye el
resultado del primero. Locales distintos nunca se bloquean entre sí.

Lo que garantiza el bloqueo:

- **Un tiempo de espera agotado no cuesta nada.** `--lock-timeout` acota solo la espera previa a
  cualquier llamada al proveedor, así que un locale que se rinde no ha gastado ni escrito nada;
  registrar un archivo ya escrito espera los diez minutos por defecto.
- **Los bloqueos abandonados no te frenan.** Un bloqueo cuyo proceso ya no existe en esta máquina se
  recupera al instante, y uno sin refrescar durante 30 segundos (quien lo tiene lo refresca cada 10)
  se trata como abandonado.
- **Una interrupción libera los bloqueos.** Ctrl-C o SIGTERM durante `translate` o `import`, y la
  segunda interrupción que detiene `watch` a la fuerza, liberan cada bloqueo antes de que el proceso
  termine.
- **Un bloqueo perdido detiene la escritura.** Cada bloqueo lleva un token aleatorio, que se
  comprueba antes de cada escritura; cuando otra ejecución se ha quedado con el
  bloqueo, la escritura se detiene con [`LOCK_CONTENDED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#lock_contended) y no se
  escribe nada.

Lo que no cubre:

- **Un bloqueo de otra máquina** (una unidad de red compartida) o de un verbatra anterior a 0.12.0
  nunca se recupera automáticamente; [Solución de problemas](https://verbatra.kreitz-webdev.de/es/docs/troubleshooting.md) tiene los
  pasos para quitarlo.
- **Una pausa larga entre la comprobación y la escritura.** Una ejecución pausada justo después de
  comprobar el token (una máquina que se duerme, un proceso detenido) todavía puede escribir una vez
  al reanudarse.
- **Hosts que comparten nombre.** Fuera de Linux, el nombre de host es la única identidad de
  máquina, así que dos contenedores con un mismo nombre de host que comparten `.verbatra-local/`
  pueden tomar el bloqueo vivo del otro por abandonado. Da a cada uno su propio
  nombre de host o su propia copia de trabajo.

## Un código de locale reescrito [#un-código-de-locale-reescrito]

<AvailableFrom version="0.12.0" />

El archivo de bloqueo, la caché y el archivo de procedencia indexan su estado por el código de
locale de tu configuración. Cuando reescribes uno, por ejemplo `pt_BR` como `pt-BR`, la siguiente
ejecución de `translate` o `watch` traslada el estado antiguo una vez e informa
[`LOCALE_STATE_CARRIED_OVER`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#locale_state_carried_over). Un cambio en el origen
hecho antes del cambio de nombre se sigue traduciendo, y las traducciones en caché se siguen
reutilizando.

El traslado solo ocurre sin ambigüedad: `pt-BR` no tiene estado propio, y el archivo
guarda estado bajo exactamente una grafía con guion bajo (o su grafía de gettext, como `sr@latin`
para `sr-Latn`), comparada sin distinguir mayúsculas. El estado que `pt-BR` ya tiene nunca se
sobrescribe. Si el traslado no se puede escribir, ese locale no se ejecuta y falla con
[`LOCALE_STATE_NOT_CARRIED_OVER`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#locale_state_not_carried_over), para que la
siguiente ejecución lo intente de nuevo; los demás locales se ejecutan como siempre.

Hasta entonces, cada lectura trata el estado antiguo como el de `pt-BR` sin escribir, así que una clave desfasada se informa como desfasada. Una escritura de una sola
clave (una edición, una nueva traducción, una decisión de revisión) y `verbatra import` trasladan
antes el estado, del mismo modo. La comprobación `locale-state` de
[`verbatra doctor`](https://verbatra.kreitz-webdev.de/es/docs/cli/doctor.md) nombra cualquier estado que quede atrás.

## Ausente o corrupto [#ausente-o-corrupto]

Un archivo de bloqueo ausente es una [primera ejecución](#adoptar-un-proyecto-existente), no un
error. Uno que no se puede analizar, con una estructura incorrecta, demasiado
grande o con una versión no soportada hace fallar la ejecución con
[`LOCK_FILE_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#lock_file_invalid) en lugar de sobrescribirse, para que
puedas restaurarlo en vez de perder la línea base.

## Procedencia: quién escribió cada valor [#procedencia-quién-escribió-cada-valor]

<AvailableFrom version="0.12.0" />

`verbatra.provenance.json` registra qué vía de escritura produjo cada valor que hay ahora en el
archivo de locale, y si alguien lo revisó. Un verbatra más antiguo, por ejemplo uno fijado en CI, lo
ignora.

| Origen | Lo escribe |
| --- | --- |
| `machine` | una respuesta del proveedor en `translate`, `watch` o una nueva traducción de una sola clave, con el `id` del proveedor y, si se conoce, el modelo |
| `memory` | un acierto exacto de la caché, incluido cada valor que rellena una ejecución solo humana (proveedor `none`) |
| `fuzzy` | un acierto de la [caché difusa](https://verbatra.kreitz-webdev.de/es/docs/the-cache.md#reutilización-difusa) |
| `human` | la edición de una persona a través de `editEntry` del SDK, como hace el diálogo de edición de Studio |
| `agent` | la edición de un agente de IA a través de `editEntry` con `actor: "agent"` |
| `import` | una fila aceptada de `verbatra import` |
| `unknown` | una decisión de revisión sobre un valor sin registro, o un origen que esta versión no conoce |

Al leer se derivan dos más: `unrecorded` es un valor sin registro, como cada clave tras actualizar;
`external` ya no coincide con el hash de su registro porque algo fuera de verbatra lo cambió, como
la pull request de un traductor, un verbatra más antiguo o una fusión. Los campos que devuelve cada lectura están en la
[referencia del SDK](https://verbatra.kreitz-webdev.de/es/docs/sdk/inspect.md#loadprovenance).

Lo que garantiza el archivo:

- **Diffs estables.** Sin texto traducido ni marcas de tiempo, un registro ordenado por línea, así
  que una ejecución que no cambia nada deja el archivo igual. En un conflicto de fusión, quédate con
  el lado que coincide con el archivo de locale que conservas: un registro que no coincide se lee
  como `external`, lo que protege el valor de una nueva traducción.
- **Registros nuevos para valores nuevos.** Una escritura que cambia un valor sustituye su registro
  por uno nuevo y sin revisar; una escritura que deja igual el valor y el origen lo conserva.
- **Ninguna sobrescritura silenciosa.** Un archivo corrupto detiene cada escritura con
  [`PROVENANCE_FILE_INVALID`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#provenance_file_invalid) antes de que cambie ningún
  archivo de locale; los informes omiten en su lugar sus campos de procedencia. Un archivo de un
  verbatra más nuevo se deja intacto, y uno que crecería demasiado para volver a leerlo no se
  escribe ([`PROVENANCE_FILE_TOO_LARGE`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#provenance_file_too_large)).

No es a prueba de manipulaciones; para convertirlo en un informe, consulta
[Registrar evidencia de traducción automática](https://verbatra.kreitz-webdev.de/es/docs/provenance-evidence.md).

### Decisiones de revisión [#decisiones-de-revisión]

<AvailableFrom version="0.12.0" />

Un registro puede llevar una decisión de revisión, `approved` o `rejected`, con un nombre de
`reviewer` opcional. Las escriben la [página Review de Studio](https://verbatra.kreitz-webdev.de/es/docs/review-in-studio.md), las
[funciones de revisión del SDK](https://verbatra.kreitz-webdev.de/es/docs/sdk/review.md) y las
[herramientas MCP de revisión](https://verbatra.kreitz-webdev.de/es/docs/cli/mcp.md); las herramientas MCP transmiten la decisión de una
persona y exigen su nombre. Una decisión se aplica al valor exacto que vio el revisor y se rechaza
si cambió.

- **Una aprobación** solo cambia el archivo de procedencia, y vuelve a leerse como sin revisar en
  cuanto cambia el texto de origen.
- **Un rechazo** quita el valor y su entrada del bloqueo, así que la clave se lee como ausente hasta
  la siguiente ejecución de `translate` o hasta que una persona escribe un valor nuevo. El registro
  guarda un hash del texto quitado y la entrada de caché se descarta, para que una ejecución no vuelva a poner el mismo texto. XLIFF no puede quitar una
  sola traducción, así que ahí un rechazo se deniega con
  [`REVIEW_REJECT_UNSUPPORTED`](https://verbatra.kreitz-webdev.de/es/docs/error-codes.md#review_reject_unsupported).

Solo los valores de clase máquina entran en la cola de revisión y en la puerta `--require-reviewed`. Los contadores `byReviewState` de `check` y `lock.state` cubren cada valor según su decisión registrada, sea cual sea su origen, así que un valor escrito o importado por una persona sin decisión cuenta como `unreviewed` ahí sin estar en la cola; léelos junto con `byOrigin`.

Las decisiones viven en este archivo confirmado, así que la cola de revisión y
[`verbatra check --require-reviewed`](https://verbatra.kreitz-webdev.de/es/docs/cli/check.md#exigir-traducciones-revisadas) ven el mismo
estado en todas partes, y el nombre de `reviewer` es público; verbatra nunca lo rellena.

## Confírmalo [#confírmalo]

Confirma `verbatra.lock.json` y `verbatra.provenance.json` junto a tus archivos de locale, y nunca
los edites a mano: son la línea base con la que comparan tu equipo y tu CI, y lo
que restaura una [reversión](https://verbatra.kreitz-webdev.de/es/docs/recovery-and-rollback.md).
