8 min de lectura

La configuración regional remota en pruebas de agentes

La configuración regional remota altera fechas, orden, decimales y texto. Fija el entorno, regístralo y prueba variaciones deliberadas.

La configuración regional remota en pruebas de agentes

Un agente puede ejecutar el mismo comando, con los mismos argumentos y archivos, y obtener otro resultado en un host remoto. La entrada que falta suele ser la configuración regional del proceso. Esta cambia la forma en que las herramientas habituales clasifican texto, ordenan nombres, presentan números, imprimen fechas, eligen una codificación y redactan sus errores.

Trata la configuración regional como datos de prueba, no como decoración de la máquina. Fíjala cuando una prueba espera un protocolo estable, cámbiala cuando el código promete manejar convenciones humanas y regístrala cuando un agente cruza el límite de un proceso o de SSH. De lo contrario, una prueba local correcta puede ocultar un error de análisis remoto hasta que el agente actúe sobre la fila, la cantidad o la fecha equivocadas.

Esto no significa imponer el inglés en todas partes. Una interfaz para máquinas y una interfaz para personas cumplen funciones distintas. La salida estable para máquinas necesita un formato y un entorno explícitos. La salida para usuarios merece una localización deliberada. Al mezclar ambas, un diagnóstico traducido termina interpretado como estado o una coma decimal se convierte sin aviso en el valor equivocado.

El proceso remoto determina el resultado

La configuración regional efectiva pertenece al proceso que ejecuta el comando. La configuración de tu portátil no controla un programa que se ejecuta mediante SSH salvo que algo reenvíe o establezca esas variables de forma deliberada. Una shell remota interactiva tampoco tiene por qué coincidir con una sesión de comandos no interactiva.

POSIX.1-2024 define con claridad la precedencia. Un LC_ALL no vacío reemplaza todas las categorías. Si no existe, una variable de categoría como LC_TIME o LC_COLLATE prevalece en esa categoría. LANG aporta el valor predeterminado a las categorías que siguen sin definir. Por eso LANG=C no hace nada si todavía está presente un LC_ALL=de_DE.UTF-8 heredado.

OpenSSH añade otro límite. Su manual del cliente dice que SendEnv selecciona variables locales para enviarlas, pero el servidor debe aceptarlas. El cliente no envía ninguna de forma predeterminada. SetEnv puede solicitar valores explícitos, sujetos a la misma aceptación del servidor. Un desarrollador puede tener SendEnv LANG LC_* en su configuración personal de SSH, mientras que el auxiliar SSH sin estado del agente no usa esa configuración, o al contrario. No conviene presuponer ninguno de los dos resultados.

Los archivos de inicio de sesión complican más el cuadro. Una distribución puede establecer LANG mediante PAM o la configuración del sistema. El perfil del usuario puede cambiarlo para un inicio interactivo. Un comando remoto suele ejecutarse sin pasar por la misma ruta de inicio. Un contenedor lanzado por ese comando puede introducir su propio conjunto regional, y una imagen mínima quizá ni siquiera tenga instalado el locale solicitado.

La solución consiste en definir el entorno previsto en el punto final de ejecución. No dependas del reenvío cuando el comando necesita una configuración estable. Coloca la asignación junto a la herramienta:

ssh buildbox 'env LC_ALL=C.UTF-8 TZ=UTC command-to-test --format=plain'

Así queda visible el contrato de la prueba. También se produce un fallo informativo si C.UTF-8 no está disponible, en vez de heredar en silencio lo que haya elegido el host. Cuando no puedas contar con ese nombre, detecta los locales compatibles durante el aprovisionamiento y usa una alternativa documentada.

Registra el entorno antes de interpretar la salida

Un informe de fallo remoto necesita las categorías efectivas, la codificación, la zona horaria, la identidad de la herramienta y los bytes originales. Registrar solo LANG resulta insuficiente porque LC_ALL o una variable de categoría pueden reemplazarlo. Guardar únicamente texto ya decodificado puede borrar la prueba de un fallo de codificación.

Ejecuta una pequeña sonda antes del comando investigado:

env | LC_ALL=C sort | sed -n '/^LANG=/p;/^LC_/p;/^TZ=/p'
printf 'charmap='; locale charmap
printf 'decimal='; locale -k decimal_point 2>/dev/null || true
printf 'date='; date +'%Y-%m-%dT%H:%M:%S%z'
printf 'tool='; command -v sort
sort --version 2>/dev/null | sed -n '1p'

Un resultado típico de Linux podría tener esta forma:

LANG=de_DE.UTF-8
LC_NUMERIC=de_DE.UTF-8
TZ=Europe/Berlin
charmap=UTF-8
decimal=decimal_point="," 
date=2026-07-24T143105+0200
tool=/usr/bin/sort
sort (GNU coreutils) 9.5

No conviertas esa muestra en un valor esperado. Lo que importa es el conjunto de campos. Algunas implementaciones de locale presentan de otra manera la salida de palabras clave y otras herramientas quizá no admitan --version. Captura el código de salida y el error estándar de cada sonda para que una función ausente no parezca un valor vacío.

En los fallos de codificación, conserva los bytes antes de decodificar. Un ejecutor puede escribir la salida y el error estándar en archivos distintos, calcular sumas de comprobación y después decodificar una copia con la codificación declarada. Un volcado hexadecimal alrededor del primer byte no válido aporta mucho más que un carácter de sustitución insertado por la capa de registro.

Registra también el transporte exacto del comando. ssh host command, ssh host sh -lc command, una terminal interactiva y un proceso lanzado mediante una herramienta de agente son rutas de ejecución distintas. Pueden elegir shells, archivos de inicio, seudoterminales y filtros de entorno diferentes. Si la ruta que falla usa una acción del agente, reproduce esa ruta en lugar de demostrar que un inicio escrito a mano funciona bien.

Este conjunto de diagnóstico debe acompañar al artefacto de prueba siempre que los resultados difieran. Convierte «el sort remoto falla a veces» en una comparación de entradas concretas.

Fija un locale para protocolos, no para personas

Usa una configuración fija cuando la salida de un comando alimente un analizador, una instantánea, una diferencia, una clave de caché, una decisión de despliegue u otro programa. Usa el locale humano solicitado cuando la salida vaya dirigida a una persona. Son interfaces distintas aunque hoy un solo comando produzca ambas.

El consejo habitual de establecer LC_ALL=C en todas partes es popular porque vuelve previsibles muchas herramientas de Unix y existe en sistemas POSIX. Como regla universal, es equivocado. Según el sistema y el entorno de ejecución, el locale C puede implicar un modelo de caracteres orientado a ASCII. Un programa que lea nombres como Málaga podría rechazar o tratar mal sus bytes aunque el orden ya sea estable.

C.UTF-8 combina una ordenación sencilla con UTF-8 en muchos sistemas Unix actuales, por lo que resulta práctico para pruebas. Sin embargo, POSIX no exige ese nombre exacto. macOS, las distribuciones Linux, los contenedores y los entornos de los lenguajes no exponen catálogos idénticos. locale -a muestra lo que ofrece el host, y las imágenes de prueba aprovisionadas deben declarar el nombre que garantizan.

Conviene mantener clara otra distinción: la estabilidad del locale no equivale a la estabilidad del formato de salida. Fijar LC_ALL no promete que dos versiones de una herramienta impriman las mismas columnas, espacios, advertencias o campos JSON. Si ofrece JSON, delimitadores NUL, segundos desde la época o una cadena de formato explícita, elige también esa interfaz. Controlar el locale elimina una variable, pero no congela el programa.

Un buen envoltorio elimina posibles reemplazos y añade solo lo necesario:

run_stable() {
  env -u LANGUAGE -u LC_COLLATE -u LC_CTYPE -u LC_MESSAGES \
      -u LC_MONETARY -u LC_NUMERIC -u LC_TIME \
      LC_ALL=C.UTF-8 TZ=UTC "$@"
}
run_stable sort input.txt

Si la portabilidad incluye sistemas cuyo env no tiene -u, construye un entorno mínimo. Especifica PATH y conserva solo las variables que necesita la aplicación. No copies todo el entorno padre para corregir luego LANG, pues quedarían variables de categoría activas.

Las pruebas del comportamiento destinado a usuarios deben hacer lo contrario. Tienen que seleccionar de forma deliberada un locale compatible y comprobar la convención pertinente. Una prueba de informe en alemán puede esperar una coma decimal y nombres de meses alemanes. El analizador que hay detrás del informe debe seguir intercambiando internamente números y fechas normalizados.

Las fechas necesitan formato y zona horaria

El locale y la zona horaria provocan fallos distintos en las fechas. LC_TIME controla nombres y representaciones convencionales. TZ controla qué hora civil corresponde a un instante. Fijar uno no fija el otro.

GNU Coreutils advierte que la salida de date no siempre se puede analizar después. Su manual recomienda para los datos generados un formato independiente del idioma, una representación gregoriana y una zona inequívoca como UTC o Z. Ese consejo tiene más peso que una instantánea que pasa por casualidad con ajustes en inglés.

Para un protocolo de prueba, elige una representación explícita:

env LC_ALL=C.UTF-8 TZ=UTC date +'%Y-%m-%dT%H:%M:%SZ'

La salida tiene la forma 2026-07-24T12:31:05Z. Si la prueba necesita un instante fijo y no el reloj actual, pásalo mediante una opción compatible de la herramienta o inyecta un reloj en la aplicación. Controlar el locale no detiene el tiempo.

Evita %c, %x, %X, %a y %b en datos que analizará otro programa. Esos especificadores piden a propósito convenciones regionales o nombres traducidos. Incluso los especificadores numéricos pueden incluir detalles de calendario en algunos sistemas. El manual de GNU documenta locales que emplean calendarios alternativos para ciertas directivas, por lo que un año aparentemente numérico no constituye una promesa universal salvo que el formato y el locale elegido lo definan.

Los números de semana son otra trampa. El año natural, el año ISO basado en semanas y las convenciones locales responden a preguntas distintas cerca de Año Nuevo. Declara cuál usa la regla de negocio y prueba fechas limítrofes. Fijar el locale no corrige una combinación errónea de %Y-%V.

Los informes para personas deben dar formato a las fechas en el borde del sistema. Conserva el instante almacenado o transmitido en una forma estable y aplica después el locale y la zona del lector para mostrarlo. Si un agente debe comparar marcas temporales de varios hosts, haz que solicite valores de época o cadenas con estilo RFC 3339 y desplazamiento. No le pidas inferir si 03/04/26 significa 4 de marzo o 3 de abril.

Una matriz útil de fechas incluye un locale con nombres de meses en inglés, otro con nombres diferentes, UTC, una zona con transiciones de horario de verano y fechas cercanas a un cambio de hora y al límite de año. No se trata de enumerar el planeta, sino de revelar código que asumió las convenciones del desarrollador.

El orden debe corresponder al consumidor

Conserva resultados, no secretos
Sallyport devuelve el resultado remoto mientras la credencial permanece en su bóveda cifrada.

El texto no tiene un único orden natural. El orden de bytes, el de puntos de código Unicode y la intercalación lingüística producen secuencias distintas. Las pruebas fallan cuando esperan una e invocan otra.

El manual de GNU sort indica que las comparaciones suelen usar la secuencia seleccionada por LC_COLLATE. Recomienda expresamente LC_ALL=C cuando un script requiere el orden tradicional. También señala que establecer solo LC_COLLATE es arriesgado si LC_ALL lo reemplaza o si las categorías de caracteres emplean codificaciones incompatibles.

Considera este fixture:

Zebra
apple
zebra
Ångström
ábaco

Un locale de estilo C suele ordenar por bytes codificados, con las mayúsculas ASCII antes que las minúsculas y las secuencias UTF-8 fuera de ASCII después. Un locale lingüístico puede comparar mayúsculas o acentos en distintos niveles. No pegues un orden supuesto en una prueba o un artículo multiplataforma. Ejecuta el locale compatible real y comprueba la propiedad semántica que necesitas.

Para un manifiesto reproducible o un archivo de referencia, normalmente corresponde el orden por bytes. Usa LC_ALL=C si todas las rutas se limitan al conjunto portátil, o usa un locale UTF-8 verificado y define la función de orden en el programa. Para una lista que verán lectores españoles, suecos o alemanes, el orden binario se comporta mal. Usa una biblioteca de intercalación regional con una versión de datos fijada, porque los datos de orden del sistema operativo pueden cambiar sin que cambie tu código.

El orden y la unión deben compartir reglas. GNU Coreutils pide ejecutar sort y join con locales y opciones coherentes. Un archivo ordenado con una intercalación puede parecer desordenado a join bajo otra, lo que causa coincidencias perdidas o diagnósticos. Lo mismo ocurre con comm, la eliminación de duplicados, las fusiones y cualquier canalización que suponga que los valores iguales quedan juntos.

Prefiere comprobaciones que expresen la intención. Si el orden no importa, compara conjuntos o mapas en lugar de guardar una instantánea incidental. Si el protocolo exige orden de bytes, calcúlalo en la prueba y etiquétalo. Si la función es el orden localizado, incluye fixtures con acentos, variaciones de mayúsculas y puntuación que lo distingan del orden binario.

Un agente puede agravar el problema usando un sort exploratorio y tratando la primera línea como el elemento «menor» o «siguiente». Especifica la regla de orden en su contrato de acción. «Selecciona la primera versión según orden semántico» no significa «selecciona el primer nombre bajo el locale remoto».

Las comas decimales rompen canalizaciones en silencio

LC_NUMERIC define el signo decimal y las convenciones de agrupación que usan las funciones regionales y algunas opciones de comandos. Un valor mostrado como 1,25 puede ser correcto para una persona e inválido para un analizador que espera 1.25. Peor aún, un analizador permisivo puede aceptar solo el prefijo y devolver 1 sin un error claro.

GNU sort -n usa el separador de millares y el signo decimal del locale cuando reconoce prefijos numéricos. locale.format_string, locale.atof y otras funciones de Python también siguen LC_NUMERIC. El float() normal de Python y muchos formatos de datos no lo hacen. Pasar texto entre ambas familias sin una frontera definida crea un fallo que aparece solo con ciertos ajustes.

Mantén normalizados los números del protocolo. Los números JSON usan un punto, las opciones de comandos suelen documentar una gramática fija y los formatos de base de datos definen su propia representación. Aplica comas o agrupación solo para mostrar, una vez terminados el cálculo y la serialización.

Prueba los analizadores con valores que hagan visible el truncamiento silencioso:

0.5
1.25
1234.75
-0.125

Después ejecuta la misma operación con un locale que use coma decimal. Si la herramienta acepta deliberadamente entradas localizadas, aporta fixtures equivalentes con coma y rechaza agrupaciones ambiguas. Si promete una gramática fija, establece el locale del comando y comprueba que la entrada con coma falle con claridad.

No «arregles» una salida arbitraria cambiando todas las comas por puntos. Una coma puede separar campos, agrupar millares o formar parte del texto. Usa un modo de salida estructurado o un analizador que conozca el locale declarado. Si el productor no publica una gramática, considera su salida humana inadecuada para automatización.

La aritmética de shell también da una falsa confianza. La shell puede usar una sintaxis fija mientras awk, printf, un conversor de hojas de cálculo o el entorno de un lenguaje aplica el locale en ciertas operaciones. Prueba la canalización completa bajo un entorno en vez de probar cada comando por separado en tu shell de inicio.

El dinero exige aún más rigor. Guarda unidades menores o un tipo decimal con moneda explícita, y localiza solo el valor mostrado. Un agente que decide si una cantidad supera un límite debe recibir el valor numérico normalizado, no extraerlo de un informe pensado para una persona.

Los errores de codificación empiezan antes de decodificar

Controla SSH en el límite
El auxiliar sp-ssh ejecuta comandos remotos sin colocar claves SSH en el contexto del agente.

El locale puede indicar a un proceso cómo interpretar secuencias de bytes como caracteres. LC_CTYPE afecta a la clasificación y suele estar unido a una codificación. Esto importa a las herramientas que dividen texto, buscan clases de caracteres, cambian mayúsculas, calculan anchuras o convierten entre bytes y cadenas.

Que ambas máquinas usen UTF-8 no demuestra que todos sus procesos lo usen. Un servicio remoto puede arrancar en el locale C, un contenedor mínimo puede carecer de datos regionales generados o un entorno de lenguaje puede activar su propio modo UTF-8. La documentación de Python lo dice sin rodeos: en algunos sistemas la codificación preferida solo es una estimación, y Python UTF-8 Mode puede ignorar la codificación regional en esa consulta.

Decodifica de forma explícita en los límites. Si el contrato del comando dice UTF-8, lee bytes y decodifícalos como UTF-8 con una política estricta de errores. No invoques el decodificador predeterminado de la plataforma y confíes en el resultado. Si Unix admite nombres de archivo arbitrarios, recuerda que en el límite del sistema son secuencias de bytes. Forzarlos a texto común puede perder información. Usa la codificación de sistema de archivos y la estrategia reversible del entorno cuando estén disponibles.

Sustituir errores ayuda al mostrar, pero resulta peligroso para decidir. Dos secuencias no válidas pueden reducirse al mismo carácter visible. Una prueba debe fallar indicando el desplazamiento del byte, conservar la salida original y mostrar una pequeña ventana hexadecimal. Esa evidencia permite distinguir si el productor emitió una codificación antigua, cortó una secuencia o devolvió datos binarios por un canal de texto.

Las clases de caracteres merecen fixtures directos. Con diferentes locales, [[:alpha:]], la conversión de mayúsculas y el reconocimiento de espacios pueden incluir caracteres distintos. POSIX explica que LC_CTYPE determina cómo las secuencias de bytes se convierten en caracteres y qué caracteres pertenecen a cada clase. Un script que limpia nombres con un rango dependiente del locale puede aceptar o eliminar otro texto de forma remota.

Usa código de aplicación que entienda Unicode para texto humano y reglas ASCII explícitas para identificadores de protocolo. No dejes que el locale ambiente decida qué vale como nombre de variable, token o campo del protocolo. Tampoco apliques a un nombre personal un filtro limitado a ASCII y llames validación al resultado.

Un conjunto compacto de pruebas de codificación debe incluir ASCII simple, texto acentuado precompuesto, el mismo texto visible con marcas combinadas, otro sistema de escritura y una secuencia de bytes inválida donde la interfaz admita bytes originales. Comprueba bytes en los límites del protocolo y caracteres después de decodificar. Esa separación vuelve comprensible el fallo.

Una matriz pequeña descubre las suposiciones

Verifica el rastro del comando
El registro cifrado forma una cadena hash que sp audit verify comprueba sin conexión.

Ejecuta la mayoría de las pruebas deterministas con un locale fijado y después una serie menor de variaciones elegidas para romper suposiciones. Probar todos los locales instalados consume tiempo y mantiene una cobertura débil, porque muchos comparten las mismas convenciones pertinentes.

Elige variantes por comportamiento:

  1. Usa C para el comportamiento portátil de bytes y los diagnósticos traducidos que no deben analizarse.
  2. Usa un locale UTF-8 disponible con punto decimal y una intercalación no trivial.
  3. Usa otro con coma decimal y nombres de fechas diferentes.
  4. Añade un locale o modo de ejecución que revele suposiciones de codificación si el producto lo admite.
  5. Combina los casos de fechas con UTC y una zona que tenga horario de verano.

Aprovisiona esos locales en la imagen de prueba. Una prueba omitida porque el ejecutor no tiene datos regionales no es un éxito. Imprime locale -a cuando falle la preparación e incluye el catálogo necesario en la definición de la imagen.

Mantén la matriz cerca del lanzamiento del proceso. En Python, pasa una copia del entorno a subprocess.run en lugar de cambiar el locale global dentro de un ejecutor con hilos:

import os
import subprocess

def run_case(locale_name):
    child_env = os.environ.copy()
    child_env.update({"LC_ALL": locale_name, "TZ": "UTC"})
    return subprocess.run(
        ["./agent-command", "inspect", "fixtures/names.txt"],
        env=child_env,
        check=False,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )

El manual de Python dice que setlocale() no es seguro entre hilos en la mayoría de sistemas y cambia una propiedad de todo el programa. Modificarlo entre pruebas puede hacer que los casos paralelos se afecten. Un entorno hijo aísla el comando y reproduce mejor la ejecución remota.

Las comprobaciones deben separar código de salida, bytes de salida estándar, bytes de error y significado analizado. LC_MESSAGES puede cambiar el idioma del diagnóstico sin cambiar el fallo. Una prueba que busca la frase inglesa «No such file» está probando un catálogo de traducción, no la condición de error. Prefiere códigos de salida, campos estructurados o identificadores estables.

Cuando falle una variación, reduce por categoría. Empieza con LC_ALL vacío y establece después LANG y categorías individuales para averiguar si cambió el tiempo, la intercalación, los números, los mensajes o los caracteres. Las variables de categoría son buenas herramientas de diagnóstico aunque producción use un solo LC_ALL.

Ejecuta la matriz menor en solicitudes que cambien análisis, lanzamiento de procesos, SSH, informes o fixtures. Una ejecución programada puede abarcar más sistemas operativos y versiones. Guarda la sonda de entorno junto a cada fallo para que la repetición no dependa de la memoria.

Las acciones del agente necesitan un contrato

Un agente autónomo amplifica la ambigüedad del locale porque puede encadenar una salida plausible con una acción que tenga consecuencias. Si una lista cambia de orden, puede elegir otro archivo. Si un analizador trunca un decimal, puede comparar el límite equivocado. Si una fecha cruza una zona, puede actuar sobre el registro del día incorrecto.

Da a las herramientas remotas un contrato explícito con cuatro partes: el entorno que establecen, los bytes o datos estructurados que devuelven, la información de salida que conservan y la semántica de shell que usan. Incluye versiones o sondas cuando la salida cambie entre implementaciones. Un prompt no puede reparar un límite de proceso sin especificar.

Define el éxito antes de que el agente vea la salida. Un estado cero puede significar que terminó el comando, no que encontró un registro. Algunas herramientas entregan resultados parciales con una advertencia y otras escriben progreso en el error aun al tener éxito. Conserva los tres canales y deja que un analizador con gramática declarada decida si el resultado sirve. No pidas a un modelo que deduzca el éxito por el tono de un mensaje localizado.

Haz que los locales no compatibles provoquen un error de preparación, no una sorpresa durante la acción. Si un comando arranca con LC_ALL=fr_FR.UTF-8 en un host que no lo tiene, la shell o el entorno pueden advertir y volver a otro valor, o el programa puede fallar. El ejecutor debe confirmar primero el locale mediante locale -a o una comprobación de capacidad, registrar el nombre y detenerse si no puede ejercer el comportamiento requerido. Una alternativa elegida al aprovisionar está controlada; otra elegida a mitad de una acción es estado oculto.

Revisa también las capas de intérprete por separado. El proceso local construye un argumento SSH, el servicio remoto inicia la shell del usuario y esa shell analiza la cadena antes de que el programa lea sus argumentos. Las asignaciones y las comillas pueden cambiar en cualquier capa. Prefiere una API remota basada en argumentos cuando exista. Si solo hay una cadena de shell, prueba el comando serializado exacto e incluye espacios, una comilla simple, un salto de línea y texto fuera de ASCII. Fijar el locale no corrige las comillas, pero un error de comillas puede aplicar el locale al comando equivocado.

Trata la salida que se analiza con frecuencia como un pequeño protocolo con versión. Guarda un fixture de bytes, documenta el locale y la familia de herramienta esperados y rechaza formas desconocidas. Cuando una actualización cambie la forma, actualiza juntos el analizador y el fixture. Resulta menos vistoso que hacer que el agente «entienda» otra salida humana, y es mucho más seguro para comandos que llevan a escrituras.

Para SSH, prefiere un comando que establezca el entorno remoto en vez de confiar en el reenvío. Cita en la capa correcta y prueba valores con espacios, comillas y texto fuera de ASCII. No añadas una shell de inicio solo para heredar el locale, pues también importará alias, scripts y otro estado.

Conserva los resultados originales para revisarlos. Sallyport puede ejecutar acciones SSH mediante su auxiliar incluido sp-ssh mientras guarda las claves SSH en su bóveda cifrada, y el diario Activity registra las llamadas individuales. Eso no independiza la salida del locale, pero conserva una frontera útil: el agente recibe resultados sin recibir la credencial utilizada.

Cuando una acción pueda cambiar estado externo, valida el valor analizado antes de escribir. Exige un formato explícito al comando de lectura, rechaza bytes que no se puedan decodificar y adjunta el locale registrado a la acción propuesta. La aprobación humana solo tiene sentido si la tarjeta muestra el valor que el sistema analizó de verdad.

La primera reparación de una suite existente es concreta. Encuentra cada comando remoto cuya salida se analice o guarde. Añade la sonda a los fallos, fija locale y zona en el proceso remoto e introduce un locale con coma decimal y otro con diferente intercalación como casos adversos. Los fallos sorprendentes son las suposiciones que tu shell local llevaba tiempo ocultando.

FAQ

¿Puede SSH copiar automáticamente mi locale al host remoto?

Solo si el cliente envía las variables seleccionadas y el servidor las acepta. OpenSSH no envía variables de entorno por defecto, así que establece el locale necesario en el comando remoto en vez de presuponer el reenvío.

¿Las pruebas deben usar LC_ALL=C o C.UTF-8?

Usa C cuando la entrada se limite a ASCII portátil y el contrato sea el orden por bytes. Prefiere un locale de estilo C.UTF-8 disponible cuando debas manejar UTF-8, pero comprueba el nombre al aprovisionar porque POSIX no lo exige.

¿Por qué LANG=C no vuelve estable la salida?

Un LC_ALL no vacío reemplaza LANG y las variables de categoría pueden reemplazar su propio comportamiento. Elimina variables en conflicto o establece LC_ALL en el proceso que realmente lanzas.

¿Qué variables afectan al orden y a los números?

LC_COLLATE controla la intercalación y LC_NUMERIC las convenciones decimales y de agrupación en operaciones regionales. LC_CTYPE también importa porque la herramienta debe interpretar caracteres antes de compararlos.

¿Fijar el locale también corrige las zonas horarias?

No. Establece TZ por separado y elige un formato de fecha explícito. Una prueba estable suele necesitar tanto un locale como C.UTF-8 como una zona como UTC.

¿Cómo pruebo locales que no están en la imagen de CI?

Aprovisiona el catálogo exacto en la imagen y haz fallar la preparación si falta. Imprimir locale -a ayuda a diagnosticar, pero omitir el caso en silencio solo esconde el riesgo.

¿La salida JSON siempre es independiente del locale?

La gramática JSON usa puntuación fija, pero el productor puede poner fechas o números localizados en campos de texto. Prueba el contrato de campos y el analizador, no solo las llaves.

¿Por qué hay que guardar los bytes originales?

Un decodificador puede sustituir o descartar secuencias antes de escribir los registros. La salida y el error originales conservan la prueba necesaria para encontrar el primer byte incorrecto e identificar la codificación.

¿Puedo cambiar el locale del proceso en pruebas paralelas?

Evítalo. Muchos entornos lo tratan como estado global y Python documenta que setlocale() no es seguro entre hilos en la mayoría de sistemas. Da un entorno propio a cada proceso hijo.

¿Cuántas variantes regionales debe ejecutar una suite?

Ejecuta la suite principal con un locale fijo y elige una matriz pequeña por comportamiento, como orden de bytes, coma decimal, otros nombres de fecha y UTF-8. Más nombres no ayudan si prueban el mismo supuesto.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov