Revisión 1: Infraestructura y normas

¿Qué norma de AGENTS.md está protegida por una prueba y cuál depende solo de que alguien la lea? Actualizada el 24 de octubre de 2026.

Alcance y método

Revisión de la versión 9.11.0 en la rama dev (commit 170ee03), escrita desde cero sobre el estado actual del código. Desde la revisión anterior (9.2.3, commit 924aef6) hay 238 commits y 39 hitos cerrados (M5 a M43). Sigue el procedimiento docs/audits/AuditFull.md.

El criterio es el de la lección de la 9.0.0: una norma solo se da por cumplida si una prueba falla al infringirla. Cada afirmación indica su procedencia:

  • [test] una prueba automatizada la protege;
  • [cmd] un comando reproducible la comprueba hoy, pero nada impide que deje de cumplirse;
  • [lectura] revisión del código, sin prueba ni comando;
  • [sin prueba] norma escrita que ninguna prueba vigila.

1. Línea base

ComandoResultado
npm run test:all702 casos: 623 de node --test y 79 de unittest; todos correctos y 1 omitido (Job Object, solo en Windows)
npm run test:unit180/180
npm run test:integration273/273
npm run test:infrastructure28/28 de Node y 79 de Python en 12 archivos (1 omitido)
npm run test:architecture39/39 en 14 archivos
npm run test:browser103/103 en Chromium headless
npm run buildSin diferencias en zerochat.py, py/dd-managed-services.py ni los bundles de js/vendor/

Tamaño: 64 módulos JavaScript en js/ (27.963 líneas) y 12 herramientas nativas en js/tools/builtin/ (970 líneas); 13 módulos Python en py/ (4.909 líneas); 14 hojas de estilo (8.367 líneas); 834 claves de traducción en cada idioma; 3 bundles de terceros en js/vendor/. [cmd]

La suite tiene menos casos que en la 9.2.3 (864) aunque cubre más funciones: los hitos M24, M32 y M41 retiraron pruebas triviales, duplicadas o de ausencia y dejaron cada comportamiento probado una vez, en el nivel más bajo que lo observa.

2. Normas y pruebas

Cada fila es una norma de AGENTS.md (por sección) o de un README de subsistema, con la prueba que la protege de forma continua.

NormaProtecciónEstado hoy
§2 Calidad del código
Única fuente por decisión y pruebas que importan esa fuente[test] en los contratos JS–Python: tests/fixtures/mcp/ (estados de servicio, motores, navegadores, nombres públicos de herramientas) la comprueban a la vez las pruebas de Node y de Python; en el resto, [lectura]Cumple
Dependencias con resolveDep o la fábrica UMD[test] test_code_hygiene.jsCumple
Separar dominio, persistencia, adaptadores y presentación[test] test_persistence_boundary.js y test_state_contract.js; zonas modelo, vista y controlador de los diálogos (M38), [lectura]Cumple
Errores explícitos[test] test_error_handling.js (sin catch vacíos) y test_backend_hygiene.js (sin capturas genéricas silenciosas en py/)Cumple
Sin código especulativo ni de compatibilidad hacia atrás[sin prueba] en general; [test] parcial: test_code_hygiene.js detecta funciones que la aplicación no ejecutaRevisión manual de cada diff
Eliminar lo huérfano tras una retirada[test] test_code_hygiene.js (funciones y variables), test_i18n_literals.js (claves sin uso), test_icon_sprite.js (símbolos y glifos), test_style_hygiene.js (selectores y tokens)Cumple
Sin código de producción que solo usan las pruebas[test] test_code_hygiene.jsCumple
§3 Seguridad
Datos externos fuera de innerHTML, lista cerrada de usos[test] test_html_sinks.js (93 usos en 24 archivos) y pruebas de inyección (browser_tool_cards.test.js)Cumple
Comandos, sandbox y datos sensibles con pruebas de límites y autorización[test] py/test_run_command.py, test_tool_security.js, browser_sandbox_security.test.js, py/test_login.pyCumple
Token de sesión obligatorio y escucha en 127.0.0.1[test] test_local_server.js, py/test_token.py, py/test_network.pyCumple
§4 Pruebas
Cada comportamiento se prueba una vez, en el nivel más bajo[lectura] revisiones de M32 y M41Cumple tras la poda de M41
Todo tope probado en N y N+1 con su aviso[test] tope a tope (test_office_parser.js, test_local_server.js con el cuerpo de 1 MiB y el de 4096 bytes sin token, py/test_login.py con los intentos); [sin prueba] que todo tope nuevo la tengaCumple en los topes revisados
§5 Git y versiones
Versiones solo con npm run bump[test] test_versioning.jsCumple
Promoción a master solo desde dev, con bump y suite en verde[sin prueba]: es un procedimientoCumplido en cada versión desde la 9.2.3
§6 Finalización
Español e inglés sincronizados en la interfaz y la ayuda[test] test_i18n.js (mismas claves en los dos idiomas) y test_help_pages.js (traducción, idioma y enlace cruzado de cada página)Cumple: 834/834 claves
sitemap.xml regenerado al añadir o retirar páginas[test] test_help_pages.jsCumple: 50 páginas
Backend recompilado tras cambiar py/[test] test_backend_hygiene.js (zerochat.py igual a la concatenación de py/)Cumple
Memoria de proyecto (.zerochat/) al día[sin prueba]; task.py la actualiza de forma atómicaCumple en M42
README de subsistema
Eventos enlazados una vez en mount() y diálogos de ChatDialogs siempre esperados[test] test_ui_listeners.js y test_code_hygiene.jsCumple
Mensajes inyectados al modelo en inglés y texto visible con ChatI18n[test] test_english_literals.js y test_i18n_literals.jsCumple
Colores en tokens.css, sin respaldo en var(), ocultar con hidden[test] test_style_hygiene.jsCumple
Sin emojis; iconos del sprite y de ChatIcons[test] test_icon_sprite.jsCumple
ChatState solo mediante sus mutadores[test] test_state_contract.jsCumple
Solo las librerías de arranque se cargan con la página y entran en el precache[test] test_vendor_loading.jsCumple
Orden del prompt de sistema para la caché de contexto[test] test_context_cache_architecture.jsCumple
Proveedores que extienden BaseProviderAdapter[test] test_providers.jsCumple
Páginas públicas con título y descripción únicos[test] test_help_pages.jsCumple
Backend: zz-main.py último y paridad de definiciones y manejadores de herramientas[test] test_backend_hygiene.jsCumple
El wheel solo contiene el ejecutable[test] tests/packaging_smoke_test.py en la releaseCumple en la 9.11.0

Recuento: de 29 normas, 23 están protegidas por pruebas, 2 lo están en parte (única fuente por decisión, topes en el borde), 1 se apoya en la lectura de las revisiones de pruebas y 3 no tienen prueba automatizada: la ausencia de código especulativo o de compatibilidad, la promoción a master y la memoria de proyecto. Las dos últimas son procedimientos; la primera solo se vigila revisando los diffs.

3. Seguridad del servidor local

  • Token diario obligatorio en cada petición, solo en cabeceras. Caduca al cambiar el día también con el servidor en marcha: el anterior recibe 401 y se genera el nuevo. [test] test_local_server.js, py/test_token.py
  • Identificación con la cuenta del sistema: sin token solo se atiende la identificación, con un cuerpo de 4096 bytes como máximo. La contraseña se comprueba con PAM (Linux y macOS) o LogonUserW (Windows) y nunca se guarda. Tras 5 fallos seguidos, los intentos se rechazan durante 15 minutos sin comprobarlos. [test] py/test_login.py, test_local_server.js
  • Sin confianza en el proxy inverso: la cabecera con que el proxy enruta no da acceso; detrás de él se exigen igualmente el token y la identificación. [test] test_local_server.js y browser_connection.test.js
  • API solo por POST JSON-RPC, con orígenes CORS de una lista cerrada; GET solo sirve la interfaz en desarrollo. [test] test_local_server.js
  • Firma de cada llamada a herramienta con HMAC, nonce de un solo uso y ventana de 60 s, que tolera ±30 s de desfase de reloj. [test] test_local_server.js
  • Cuerpo HTTP acotado a 1 MiB, salvo la exportación de --prompt --export (64 MB). [test] test_local_server.js
  • Escucha en bucle local por defecto, con aviso al usar un host que no lo es. [test] py/test_network.py
  • Transporte web del servidor con protección anti-SSRF en la URL pedida y en cada redirección, y cuerpo acotado. [test] py/test_network.py
  • Comandos acotados: plazo, terminación del grupo de procesos y limpieza de los huérfanos de sesiones anteriores; en Windows, Job Object. [test] py/test_run_command.py (la prueba del Job Object solo se ejecuta en Windows)
  • Sandbox de JavaScript en un iframe de origen opaco sin red; la ayuda advierte de que no es una barrera de seguridad. [test] browser_sandbox_security.test.js
  • Permisos de herramientas: políticas ask, workspace_trust y allow_all, reglas de directorio y comprobación de traversal. [test] test_tool_security.js

4. Riesgos aceptados

RiesgoSituación
Origen compartido albalday.github.ioOtras páginas del mismo origen podrían leer la cookie de sesión, localStorage e IndexedDB. Aceptado mientras ese origen solo publique páginas propias.
Clave del proxy sin cifrar en el navegadorSe guarda en la configuración local (M42-D17): solo abre la puerta del proxy, y el servidor sigue exigiendo el token diario y la identificación. Solo se envía a la URL configurada.
Bloqueo de cuentas del sistemaSi el equipo usa un bloqueo por intentos (por ejemplo, pam_faillock) con un límite inferior a 5, los fallos desde la web podrían bloquear la cuenta. La ayuda indica cómo evitarlo.
--host no localExpone la ejecución de comandos a la red sin cifrar; el arranque avisa. Para el acceso remoto se documentan el túnel SSH y el proxy inverso con HTTPS.
WebLLM desde CDNEl motor se importa de cdn.jsdelivr.net si se utiliza este proveedor.
Herramientas webLa búsqueda en DuckDuckGo y la lectura de páginas pasan por el servidor local o, sin él, por Jina Reader.
Proveedores remotosCon una API en la nube los mensajes salen hacia el proveedor configurado; con un LLM local no.

5. Hallazgos

IdHallazgoRiesgo y prioridadPropuesta
F-01Las rutas exclusivas de Windows (LogonUserW para la identificación y el Job Object de los comandos) no se ejecutan en ninguna prueba: la CI solo usa ubuntu-latest y la prueba del Job Object se omite.Estabilidad; mediaUn trabajo de CI en windows-latest para las pruebas Python de infraestructura, con un caso de LogonUserW que rechace una contraseña errónea.
F-02La identificación correcta con PAM no tiene prueba automatizada: las pruebas simulan la comprobación y, a mano, solo se ha probado el rechazo de un usuario inexistente y el uso real del responsable del proyecto.Seguridad; bajaEn CI, un usuario temporal con contraseña conocida que ejecute la comprobación de su propia cuenta.
F-03js/app.js (1.020 líneas) y js/mcp.js (1.058) siguen creciendo con la coordinación: la sesión con el backend (fragmento de arranque, conexión e identificación) vive en app.js.Deuda técnica; bajaLlevar la sesión del backend a un módulo de dominio propio cuando cambie de nuevo.

Resuelto en esta versión: una prueba de arranque del navegador dependía de que no hubiera un zerochat real escuchando en 127.0.0.1:6388; con uno en marcha, su 401 abría el diálogo de identificación. Ahora la prueba corta esa dirección.

6. Dictamen

Infraestructura sólida, con la superficie de red rediseñada sin perder protección. Desde la 9.2.3 el servidor local ha pasado a un transporte solo por POST, con token diario que caduca en marcha, identificación con la cuenta del sistema y acceso remoto por túnel o proxy inverso; cada uno de esos cambios llegó con sus pruebas. La suite es más pequeña y más rápida que en la 9.2.3 y cubre más funciones. Lo pendiente es la cobertura de Windows (F-01), que hoy solo se prueba a mano.

Autoría y entorno de verificación

  • Revisión y redacción: Claude Opus 5.5 en Claude Code, a partir de las instrucciones del responsable del proyecto y del procedimiento de docs/audits/AuditFull.md.
  • Entorno: Linux x86_64, Node.js 24.21.0, Python 3.14.8, Playwright 1.62.1 con Chromium headless.
  • Reproducción: los comandos de la línea base.