El detector
Las cinco verificaciones
audit corre cinco verificaciones, siempre en el mismo orden. Todas son código puro —git, sistema de archivos y expresiones regulares—, sin modelo, sin conexión y sin API key: la misma entrada da el mismo resultado. Cada una lee una parte de AI-FIRST.md, y si esa parte falta se reporta omitida, nunca aprobada.
Resumen
Sección titulada «Resumen»| # | Verificación | Sev. | Qué detecta | Por qué importa | Lee de AI-FIRST.md |
|---|---|---|---|---|---|
| 1 | Zona Prohibida tocada | P0 | Se tocó una ruta declarada como Zona Prohibida | Es lo único que corta el flujo aun sin --estricto |
zonas_prohibidas |
| 2 | Decisión sin fila en ADR | P1 | Señales de decisión arquitectónica sin fila nueva en el ADR | La decisión existe en el código y no en el registro | superficies_de_decision, artefactos.adr |
| 3 | Alcance excedido | P1 | Más archivos tocados de los que declara la spec activa | El alcance creció y nadie lo midió | alcance.spec, alcance.tolerancia |
| 4 | Artefacto huérfano | P2 | Un documento declarado, o una ruta que menciona, no existe | Un documento apunta a algo que ya nadie mantiene | artefactos |
| 5 | Inventario de componentes desactualizado | P2 | Componentes en disco que el inventario no nombra, o al revés | El inventario empezó a mentir | artefactos.inventario_componentes, artefactos.componentes_dir |
Cuatro de las cinco son deterministas y no admiten discusión: una ruta cambió o no cambió, un archivo referenciado existe o no existe, un componente aparece en el inventario o no aparece. La segunda no lo es, porque «se tomó una decisión arquitectónica» no cabe en una expresión regular: se resuelve declarando dónde un cambio se presume decisión, produce falsos positivos y por eso se puede silenciar. Una verificación que no se puede silenciar termina desactivada entera, que es peor que tenerla ruidosa.
Los patrones de ruta que usan las verificaciones 1, 2 y 3 siguen las reglas de Patrones de ruta. Qué es «tocado» depende del modo, árbol o rango: ver Modos.
Zona Prohibida tocada
Sección titulada «Zona Prohibida tocada»Severidad: P0 · Identificador: zona-prohibida
Compara cada archivo tocado contra los patrones de zonas_prohibidas. Un hallazgo por zona, no por archivo: tocar tres migraciones es una Zona Prohibida tocada, con los tres archivos en el detalle. Si la zona declara razon, el mensaje la incluye.
- Lee:
zonas_prohibidas[].rutayzonas_prohibidas[].razon. - Se omite si no hay ninguna zona declarada:
no hay «zonas_prohibidas» declaradas. - No se silencia. Una Zona Prohibida no impide el cambio, lo hace visible: el hallazgo existe para que un humano decida. Si el cambio estaba aprobado, se publica igual; lo que no se hace es quitar la zona para que el detector calle.
✗ Zona Prohibida tocada P0 Zona Prohibida «.env*» tocada — credenciales .env.localPor qué y cómo se eligen las zonas está en Gobierno del contexto.
Decisión sin fila en ADR
Sección titulada «Decisión sin fila en ADR»Severidad: P1 · Identificador: decision-sin-adr
Busca dos señales de que se tomó una decisión arquitectónica:
- Cambió un archivo que coincide con
superficies_de_decision. - Un
package.json, en cualquier carpeta, ganó o perdió una dependencia de producción. Se comparan las claves dedependencies;devDependenciesno cuenta. Esta señal no hay que declararla.
Si hay alguna señal y el archivo de artefactos.adr no ganó una fila en el mismo tramo, emite un P1. Una fila es una línea agregada que empieza con un encabezado de nivel 2 o 3 seguido de ADR- y un número, como ## ADR-007 — La cola de trabajos pasa a SQS.
- Lee:
superficies_de_decisionyartefactos.adr. - Se omite si no hay
artefactos.adr:no hay «artefactos.adr» declarado. Sin superficies declaradas, igual corre: le queda la señal de las dependencias. - Se silencia de dos formas:
-
Agregando la fila al ADR, si de verdad era una decisión.
-
Con la anotación en el cuerpo de un commit del rango, si no lo era, por ejemplo subir un timeout en un
*.config.*:<!-- ai-first: sin-decision -->La anotación sólo se lee en modo rango, con
--base: en modo árbol no hay commits cuyo cuerpo leer. Ahí el P1 queda como advertencia y no corta salvo con--estricto. El hookpre-pushcorre en modo rango cuando la rama ya existe en el remoto, y el flujo de CI siempre.
-
✗ Decisión sin fila en ADR P1 Hay señales de decisión arquitectónica y ADR.md no ganó ninguna fila vite.config.ts (superficie «**/*.config.*») Silenciar: agregar la fila al ADR, o «<!-- ai-first: sin-decision -->» en el cuerpo del commit.Una dependencia aparece en el detalle como package.json: +nombre o package.json: -nombre. Qué merece una fila y qué no está en Gobierno del contexto.
Alcance excedido
Sección titulada «Alcance excedido»Severidad: P1 · Identificador: alcance-excedido
Compara los archivos tocados contra los que declara la spec activa. Si los que quedan fuera superan tolerancia, emite un solo P1 con la lista.
La spec activa es alcance.spec: un archivo, o una carpeta, y entonces cuenta cada .md o .mdx que haya dentro y no empiece por punto. init la apunta a docs/changes/pending/, donde vive el CHG del cambio en curso.
Cómo declara archivos una spec: en una sección cuyo encabezado empiece por «Archivos» o «Alcance», de cualquier nivel y sin importar mayúsculas, con cada ruta entre acentos graves. Se admiten patrones. La sección llega hasta el siguiente encabezado de igual o mayor nivel, y lo que esté dentro de un bloque de código no cuenta.
## Archivos
- `src/lib/cola.ts`- `src/lib/cola.test.ts`- `docs/specs/cola.md`En la 0.5.1, una ruta declarada tiene que llevar una barra o una extensión conocida, como .ts, .md, .json o .yml. Un archivo sin carpeta y sin extensión reconocida —.npmrc, LICENSE, Makefile— no se puede declarar: si lo tocas, cuenta fuera del alcance y sólo lo cubre la tolerancia.
Nunca cuentan como fuera de alcance: AI-FIRST.md, la propia spec o su carpeta, y cualquier archivo declarado en artefactos. Actualizar el registro de sesión al cerrar es parte del protocolo, no un desvío.
- Lee:
alcance.specyalcance.tolerancia. Sin tolerancia declarada vale 0. - Se omite si:
- no hay
alcance.spec:no hay «alcance.spec» declarado; - no hay ninguna spec en esa ruta:
no hay ninguna spec activa en docs/changes/pending/. Es el caso normal cuando no hay un cambio abierto: no hay alcance que exceder; - las specs no listan archivos:
las specs en … no listan archivos (sección «Archivos» o «Alcance» con rutas entre acentos graves).
- no hay
- Se silencia declarando en la spec lo que de verdad entró en el cambio, o subiendo
toleranciasi el proyecto acepta cierto margen.
✗ Alcance excedido P1 3 archivos fuera del alcance declarado (tolerancia: 0) src/b.ts src/c.ts vite.config.tsArtefacto huérfano
Sección titulada «Artefacto huérfano»Severidad: P2 · Identificador: artefacto-huerfano
Verifica que existan los documentos declarados en artefactos y que las rutas que mencionan resuelvan. Dos cosas cuentan como huérfano:
- Un artefacto declarado que no existe. Una clave que apunta a una carpeta sólo tiene que existir; un archivo, además, se recorre.
- Una ruta mencionada dentro de un artefacto que no existe, sea en un enlace
[texto](ruta)o entre acentos graves.
Qué cuenta como mención de ruta: un token con barra o con una extensión conocida, sin espacios. No cuentan las URL, lo que empieza con /, @, - o ~, las refs de git como origin/main, los patrones con * y los marcadores como CHG-XXX o docs/…. Lo que está dentro de un bloque de código tampoco: ahí las rutas son ejemplos.
Cómo resuelve, en orden:
- Desde la raíz del repo y desde la carpeta del documento. Lo que
.gitignorecubre, comodist/o.env, cuenta como existente: está ausente a propósito. - Un nombre sin carpeta, como
cola.ts, se busca por nombre en todo el repo: la prosa nombra archivos, no siempre los ubica. - Una ruta con carpeta cuyo primer segmento no existe en la raíz se asume de otro árbol —otro proyecto, un ejemplo, un repo externo— y no se reporta. Un check que no puede verificar algo no lo cuenta como fallo.
- Lee: todas las claves de
artefactos, las conocidas y las que agregues. - Se omite si no hay ningún artefacto declarado:
no hay «artefactos» declarados. Trasinitnunca pasa, porque declaraadryagents. - Se silencia corrigiendo la ruta o quitando la mención. Si la ruta es de otro repositorio, escríbela con su carpeta o sin acentos graves; si es un ejemplo, dentro de un bloque de código.
✗ Artefacto huérfano P2 docs/ARQUITECTURA.md menciona src/lib/queue.ts, que no existeUn artefacto que no existe se reporta como «artefactos.clave» apunta a ruta, que no existe. En JSON, la ruta del hallazgo lleva el número de línea: docs/ARQUITECTURA.md:3.
Inventario de componentes desactualizado
Sección titulada «Inventario de componentes desactualizado»Severidad: P2 · Identificador: inventario-componentes
Compara los componentes que hay en componentes_dir con lo que nombra el documento de inventario_componentes. Es por nombre, así que un renombre sin actualizar el inventario también lo caza. Mira en las dos direcciones:
- Un componente en disco que el inventario no menciona. Basta con que el nombre aparezca como palabra entera en cualquier parte del documento.
- Un encabezado del inventario que nombra un componente que ya no existe. Sólo cuentan los encabezados de nivel 2 o más con forma de componente: entre acentos graves o ángulos, como
`Boton`o<Boton>, o con mayúscula interna, comoBotonPrimario. Una palabra capitalizada suelta, como «Formularios», es un título de sección y se deja pasar.
Qué cuenta como componente: cada archivo .astro, .tsx, .jsx, .vue, .svelte, .ts o .js dentro de la carpeta, a cualquier profundidad. Boton/index.tsx es el componente Boton; un index en la raíz de la carpeta es el barril de exportación y no cuenta. Se ignoran los archivos de prueba, de stories y de declaración de tipos, lo que empieza por . o _, y node_modules.
- Lee:
artefactos.inventario_componentesyartefactos.componentes_dir. Hacen falta las dos. - Se omite si:
- falta alguna de las dos claves:
faltan «artefactos.inventario_componentes» o «artefactos.componentes_dir». Es lo que pasa en un repo recién iniciado:initlas deja comentadas; - la carpeta no existe o no es una carpeta;
- el inventario no existe. Eso ya lo reporta la verificación de artefactos huérfanos.
- falta alguna de las dos claves:
- Se silencia agregando el componente al inventario, o quitando el encabezado del que ya se borró.
✗ Inventario de componentes desactualizado P2 Tarjeta existe en src/components/ y no aparece en COMPONENTES.md P2 COMPONENTES.md documenta Modal, que ya no existe en src/components/