Le pediste a Claude Code que añadiera un estado de carga al formulario de inicio de sesión. El estado de carga funciona. El botón ahora dice «Log in» en vez de «Sign in», el mensaje de error suena más amable, y un encabezado pasó a sentence case de repente. Nadie pidió nada de eso, todos los tests pasan y, a menos que alguien lea el diff entero palabra por palabra, se despliega.
Este artículo trata sobre ese fallo específico: copy existente y aprobado que un agente de codificación con IA reescribe en silencio, y el flujo de trabajo que lo evita. Las cadenas que los agentes crean codificadas y sin clave son otro problema distinto, cubierto en por qué las herramientas de codificación con IA siguen añadiendo cadenas codificadas. Dónde debería vivir el copy de producto en general es la pregunta de arquitectura, cubierta en copy de producto nativo en código. Este artículo se centra en el incidente: la mañana de lunes en la que el texto cambió y nadie decidió que debía cambiar. globalize.now es un sistema de gestión de copy nativo en código con localización integrada, y este incidente es una de las razones por las que existe.
¿Por qué los agentes de codificación con IA reescriben el copy de UI?
Los agentes de codificación con IA reescriben el copy de UI porque ven prosa colocada dentro de componentes; una vez que ese copy vive detrás de claves en un archivo de locale fuente, cambiarlo se convierte en una edición explícita y revisable en lugar de un efecto secundario de otra tarea.
Dentro de un componente, «Sign in» no tiene ningún estatus especial. Es un literal de cadena en un atributo JSX, indistinguible de un className o un test id. El agente se entrenó con millones de diffs donde mejorar el código cercano era buena práctica, y para un modelo, hacer una etiqueta «más clara» es el mismo movimiento que renombrar una variable. No hay un error de tipos esperando, ni un test que falle, ni ninguna anotación de propiedad sobre las palabras. Reescribir no le cuesta nada al agente.
El cambio sobrevive la revisión por la misma razón. Los revisores leen lógica. Un cambio de texto queda en medio de un diff que legítimamente trata sobre un estado de carga, compila, se renderiza y, si un test de snapshot se queja, la respuesta habitual es actualizar el snapshot, lo que registra el nuevo texto como si estuviera aprobado.
¿De verdad los archivos de reglas como AGENTS.md lo evitan?
Los archivos de reglas del agente reducen la frecuencia; no hacen que el copy de UI sea inmodificable. La arquitectura es lo que hace visible la edición.
Ten el archivo de reglas de todos modos: es la capa más barata y funciona lo suficiente como para valer treinta segundos. Este bloque funciona en AGENTS.md, CLAUDE.md y en las reglas de Cursor (.cursorrules o .cursor/rules/):
## UI copy policy — do not modify user-facing text
- Never change user-visible strings (button labels, headings, empty states,
error messages, tooltips, placeholder text) unless the task explicitly
asks for a copy change.
- User-visible text lives in the source locale file (e.g. locales/en.json).
Reference it by key. Never inline a new user-facing string in a component.
- If a task needs new user-facing text, add a key to the source locale file,
reference it, and list the new key in your summary for copy review.
- Any diff to the source locale file is a copy change. Call it out
separately — it needs its own approval, apart from code review.
Ahora la parte honesta. Una regla es contexto, y el contexto compite. En una tarea larga, la instrucción es una línea entre miles de tokens de código, y a veces pierde: ante una compactación, ante un subagente que nunca la vio, ante un patrón fuerte en el archivo circundante. Peor aún, el agente que rompe la regla no lo anuncia. No recibes ninguna notificación de que tu texto cambió; recibes un diff en el que resulta que ha cambiado. Una convención no es una comprobación.
Así que el archivo de reglas es la primera capa, y la capa en la que no deberías confiar por sí sola.
¿Cómo haces que una edición de copy sea visible en vez de silenciosa?
Mueve cada cadena visible para el usuario fuera de los componentes y ponla detrás de claves en un archivo de locale fuente. Después de eso, un agente que quiera cambiar tu texto tiene que editar un archivo cuyo único propósito es el texto.
Este es el paso que el archivo de reglas no puede dar, y el mecanismo es sencillo. Cuando los componentes referencian t('auth.signIn') en lugar de repetir «Sign in», dos cosas cambian a la vez. Los diffs de componentes dejan de contener copy, así que el agente que trabaja en tu estado de carga no tiene nada que reescribir donde está trabajando. Y cada cambio de copy, sea de agente o humano, llega a un único archivo, donde una línea modificada es el evento que te importa, no ruido alrededor. Escanear el diff de un archivo de locale toma segundos. Revertir un mal reescrito es una sola línea.
Para ser precisos sobre lo que esto aporta: el agente todavía puede editar el archivo de locale. El punto no es que las palabras se vuelvan intocables, sino que tocarlas deja de ser un efecto secundario y se convierte en un acto legible y revisable. Esa es la diferencia entre enterarte por el diff y enterarte por un cliente.
El argumento completo a favor de mantener la fuente de verdad en el codebase —en lugar de en una herramienta de diseño que se sincroniza con él— es el pilar copy de producto nativo en código. Este artículo solo necesita una consecuencia: el copy con claves es lo que convierte tu archivo de reglas de una petición en algo verificable.
¿Cómo es la puerta de revisión?
Trata cualquier diff al archivo de locale fuente como un cambio de copy, y enrútalo a quien sea responsable de las palabras.
En concreto: pon el directorio de locales en CODEOWNERS para que se solicite la revisión de una persona responsable del copy en cualquier cambio a él. Añade una línea a la plantilla del PR: «¿este PR cambia texto de cara al usuario, y era esa la tarea?». Y mantén el requisito del archivo de reglas de que el agente liste las claves modificadas en su resumen; cuando lo cumple, la revisión es instantánea, y cuando no, el hook de CODEOWNERS lo atrapa de todos modos.
En un equipo pequeño esto pesa menos de lo que parece. El diff de locale es corto, se lee en lenguaje llano, y «¿debería este botón decir ahora Log in?» es una decisión que alguien puede tomar en cinco segundos, siempre que la pregunta realmente se le ponga delante, que es el trabajo entero de la puerta de revisión.
¿Y si el agente ya reescribió tu copy?
Restaura primero el texto aprobado, luego pon en clave las cadenas para que el próximo reescrito aparezca como un diff.
Encontrar el daño es un ejercicio de git: compara los componentes afectados contra el último commit en el que confías y lee solo los literales de cadena. Restaura lo que cambió. Si no puedes decir con confianza cuál era el texto aprobado —el botón dice «Log in», la página de marketing dice «Sign in», y ningún artefacto registra cuál es el correcto—, has topado con el estado más profundo que alimenta este incidente. El copy drift es texto visible para el usuario que diverge de su fuente aprobada entre superficies y a lo largo del tiempo, sin una única fuente de verdad de la que divergir. Ese término, qué lo causa y qué provoca después, es su propio artículo: qué es el copy drift.
Luego pon en clave lo que restauraste, empezando por las cadenas que el agente tocó. Son, demostrablemente, las que están en la línea de fuego.
¿Dónde encaja la localización?
Un reescrito silencioso es una molestia en un idioma y un pasivo en diez: cada traducción derivada del texto anterior queda obsoleta, y nada te avisa de que hay que retraducir.
Aquí es donde el incidente del agente se agrava. Despliegas el texto en inglés reescrito y tu alemán, japonés y español todavía dicen lo de antes: ahora las superficies discrepan entre idiomas, no solo entre pantallas. Que los catálogos se desincronicen es su propio modo de fallo con sus propias soluciones, cubierto en archivos de traducción desincronizados.
El copy con claves también cierra este bucle, porque una cadena fuente modificada es un evento visible del que dependen sus traducciones, en lugar de un literal que se movió en silencio. Ese es el diseño detrás de globalize.now: el copy vive en el codebase, con una única fuente detrás de claves, y la localización es la misma operación en lugar de un añadido — conectas un repositorio y cada idioma se deriva de esa única fuente. Los equipos que despliegan con herramientas de codificación con IA se topan con esto antes que nadie, por eso escribimos para desarrolladores y para quienes construyen con herramientas de IA.
La próxima vez que un agente esté en tus componentes, la pregunta es si una etiqueta modificada aparece como una decisión o como una sorpresa. globalize.now centraliza tus cadenas visibles para el usuario en el repositorio que conectas, y deriva cada idioma de ese único copy.
globalize.now convierte el texto codificado de tu app en archivos de traducción listos para localizar y los mantiene actualizados en cada despliegue.
Prueba globalize.now gratis