Documentación
La tesis en una línea: una regla en markdown casi nunca se cumple, una regla en CI se cumple siempre. Lo que sigue es lo que sostiene esa frase.
El problema, medido
En un análisis forense de 161 commits en seis repositorios, los tres sin CI eran exactamente los tres con el lint roto en ese momento. El repositorio con más documentos de gobernanza — un AGENTS.md estricto, SECURITY.md, GOVERNANCE.md, CONTRIBUTING.md — tenía 35 errores de lint y un script de verificación que nada ejecutaba nunca.
- Repositorios sin CI: 3 de 6
- Esos mismos 3 con el lint roto ahora
- Commits con coautoría de IA: 41 de 161
- Repositorio con más gobernanza: 35 errores de lint
Si una regla puede bajar de nivel, debe bajar
Los niveles van de N0 a N7. N0 es el compilador, N1 el análisis estático, N4 el CI, N5 el hook. Por encima de N5 es una máquina; por debajo es una petición. Toda regla que vive en una petición y cabría en una máquina es deuda, y la cuenta es medible: cien líneas de reglas siempre presentes, en treinta sesiones por semana durante un año, pasan de dos millones de tokens.
- N0 compilador — falla como "no compila"
- N1 análisis estático — "no pasa el lint"
- N4 CI — "no entra en la principal"
- N5 hook — "la acción no ocurre"
- N6 instrucción para la IA — depende de leerla y obedecerla
Toda regla nace con dos casos
Cada regla tiene un repositorio en miniatura que reprueba y otro que aprueba, montados en un directorio temporal con su propio git. Nunca se escribe en el repositorio vivo. El lado que aprueba lleva a propósito los falsos positivos previstos: el ejemplo dentro de un comentario, el archivo de ejemplo que es el arreglo y no el fallo, el pre-hash legítimo al lado de bcrypt.
- Leer solo el código de salida no bastaba: pasó y no aplica salen los dos como cero
- Aflojar la regla tiene que pintar de rojo el lado que aprueba en la primera vuelta
- Un par imposible de montar es una regla que no entra
Lo que no se convierte en regla, y por qué
Ocho clases de fallo quedaron fuera por honestidad: en ellas, dos árboles idénticos en el disco reciben veredictos opuestos. El rate limit vive en Cloudflare, la autorización vive en una policy, RLS puede estar activada desde el panel. Cada una se convirtió en una pregunta escrita, respondida con una ruta de archivo, en lugar de un marcador inventado.
- IDOR y autorización por objeto
- Rate limit y fuerza bruta
- La IP tratada como identidad
- RLS activada fuera del repositorio
Códigos de salida
El 127 domina al 1, y eso no es un detalle: no se acusa a un repositorio con una raya que se rompió. Una excepción dentro de una regla es un defecto de la herramienta y nunca entra en la nota del objetivo.
- 0 — todo lo que aplica pasó
- 1 — falló, violación real
- 2 — objetivo inválido o invocación equivocada
- 127 — se rompió, defecto de la herramienta
Lo que todavía no está probado
rebar se impone en dos repositorios. Una regla sigue solo avisando porque cerca del doce por ciento de lo que señala es ruido de vocabulario de interfaz. Y la lección más cara del árbol: el portón estuvo verde durante seis commits mientras el generador estaba muerto, porque ningún paso generaba un proyecto. Toda la cobertura estaba en la herramienta y ninguna en lo que se entrega.
- El generador ganó su propio paso después de eso, probado por mutación
- El rastreador de secretos no tenía prueba alguna hasta que una auditoría externa encontró una fuga en UTF-16