# Auditar en local y en CI

> Cómo funciona el punto de control que deja init, el hook pre-push y el flujo de GitHub Actions, y cómo correr el detector en otro CI o desde una herramienta.

Tienes el proyecto inicializado y quieres que la entropía documental se mida sola, sin depender de que alguien se acuerde de correr `audit`. `init` deja escrito el punto de control: el mismo detector en dos sitios, con tolerancias distintas.

| Dónde                                  | Cuándo corre                      | Qué lo detiene                       |
| -------------------------------------- | --------------------------------- | ------------------------------------ |
| Hook de git `.githooks/pre-push`       | En cada `git push`, en tu máquina | Sólo un P0                           |
| Flujo `.github/workflows/ai-first.yml` | En cada pull request              | Cualquier hallazgo, con `--estricto` |

## Cuándo usarla

* Acabas de correr `init` y quieres entender qué dejó en el push y en los pull requests.
* Tu CI no es GitHub Actions y necesitas el comando para montarlo.
* Quieres leer el resultado desde otra herramienta, o guardarlo en `AI-FIRST.md`.

Si lo que quieres es evitar un hallazgo concreto, la guía del flujo que lo produce lo explica: [Cambiar algo que ya funciona](https://ai-first.falcux.com/docs/guias/gestionar-un-cambio/) para el alcance, [Cerrar la sesión](https://ai-first.falcux.com/docs/guias/cerrar-la-sesion/) para la fila del ADR.

## Antes de empezar

`init` escribe los dos por defecto. `--sin-hook` y `--sin-ci` los omiten, y `--hook-local` deja el hook en `.git/hooks/`, que no viaja en el clon, en vez de `.githooks/`, que sí viaja y se revisa en un PR.

El hook no baja nada de la red: usa el detector del proyecto, el del `PATH` o el que `npx` ya tenga en su caché. Para que siempre lo encuentre, instálalo como dependencia de desarrollo:

```bash
pnpm add -D @falcux/ai-first
```

## Paso a paso

1. **Corre el detector a mano una vez.** Sin opciones, compara el árbol de trabajo contra `HEAD`:

   ```bash
   npx @falcux/ai-first@latest audit
   ```

   Un repo recién inicializado, sin cambios:

   ```text
   ai-first audit — demo
   árbol de trabajo contra HEAD · 0 archivos tocados


   ✓ Zona Prohibida tocada
   ✓ Decisión sin fila en ADR
   – Alcance excedido — omitido: no hay ninguna spec activa en docs/changes/pending/
   ✓ Artefacto huérfano
   – Inventario de componentes desactualizado — omitido: faltan «artefactos.inventario_componentes» o «artefactos.componentes_dir»


   Entropía: 0 / 100 (0 P0 · 0 P1 · 0 P2)
   ```

   Un check omitido no es un check aprobado: le falta lo que necesita para correr, y la razón lo dice.

2. **Mira qué hace el hook.** `init` lo escribe en `.githooks/pre-push` y apunta `core.hooksPath` a esa carpeta. En cada push, toma como base lo que el remoto ya tiene y corre `audit --base` sobre ese rango; si la rama todavía no existe en el remoto, corre contra el árbol de trabajo. Corre **sin `--estricto`**: un P1 o un P2 se imprimen y el push sigue. Un P0 lo detiene. Así se ve uno, en el mismo repo después de tocar `.env.local`:

   ```text
   ai-first audit — demo
   árbol de trabajo contra HEAD · 2 archivos tocados


   ✗ Zona Prohibida tocada
       P0  Zona Prohibida «.env*» tocada — credenciales
             .env.local
   ✓ Decisión sin fila en ADR
   – Alcance excedido — omitido: no hay ninguna spec activa en docs/changes/pending/
   ✓ Artefacto huérfano
   – Inventario de componentes desactualizado — omitido: faltan «artefactos.inventario_componentes» o «artefactos.componentes_dir»


   Entropía: 40 / 100 (1 P0 · 0 P1 · 0 P2)
   ```

   Si no encuentra `node` o el detector, avisa y deja pasar el push: no encontrarse a sí mismo no es motivo para frenar a nadie.

3. **Sáltalo cuando haga falta.** Si el push tiene que salir igual, lo decides tú:

   ```bash
   git push --no-verify
   ```

   El hook no lo combate. El detector informa; la disciplina es del equipo.

4. **Revisa el flujo de CI.** Es el archivo que escribe `init`, tal cual:

   ```yaml
   # El punto de control de la metodología AI-First, en integración continua.
   #
   # Lo escribe `ai-first init`. A diferencia del hook local, éste corre **con
   # `--estricto`**: acá el corte por P1 y P2 sí se quiere, porque hay un humano
   # revisando y el costo de parar es un rebote, no una interrupción.
   name: ai-first


   on:
     pull_request:


   jobs:
     auditar:
       runs-on: ubuntu-latest
       steps:
         - uses: actions/checkout@v4
           with:
             # El detector compara contra la rama base: sin historia no hay rango.
             fetch-depth: 0
         - uses: actions/setup-node@v4
           with:
             node-version: 22
         - name: Entropía documental
           run: npx --yes @falcux/ai-first audit --base "origin/${{ github.base_ref }}" --estricto
   ```

   Tres cosas sostienen el paso. `fetch-depth: 0` trae la historia: sin ella, la rama base no existe en el checkout y `audit` sale con código 2, avisando que la ref no existe en el repositorio. `--base` compara el rango de la rama base a `HEAD`, que es lo que el pull request agrega. `--estricto` hace que un P1 o un P2 también fallen el paso.

5. **Móntalo en otro CI, si no usas GitHub.** El paso es el mismo comando, con Node 22.12 o superior, la historia completa del repo y la rama base del pull request o merge request:

   ```bash
   npx --yes @falcux/ai-first@latest audit --base "origin/<rama base>" --estricto
   ```

Precaución

Un `core.hooksPath` ya configurado —por husky, lefthook u otro gestor de hooks— no se pisa: el reporte de `init` lo marca como `sugerido` y te dice que muevas el hook a esa carpeta o cambies la configuración. Cambiarlo apagaría los hooks que ya tenías.

### Los códigos de salida

| Código | Cuándo                                                                              |
| ------ | ----------------------------------------------------------------------------------- |
| 0      | Sin hallazgos, o sólo P1 y P2 sin `--estricto`                                      |
| 1      | Cualquier P0, o cualquier hallazgo con `--estricto`                                 |
| 2      | Error de uso: no es un repo git, no hay `AI-FIRST.md`, la ref de `--base` no existe |

### Para una herramienta: `--json`

Con `--json`, la misma información sale en JSON. Es la salida real del ejemplo del P0 de arriba:

```json
{
  "proyecto": "demo",
  "modo": "arbol",
  "cambiados": [
    ".env.local",
    "src/a.ts"
  ],
  "resultados": [
    {
      "check": "zona-prohibida",
      "estado": "hallazgos",
      "hallazgos": [
        {
          "severidad": "P0",
          "ruta": ".env*",
          "mensaje": "Zona Prohibida «.env*» tocada — credenciales",
          "detalle": [
            ".env.local"
          ]
        }
      ]
    },
    {
      "check": "decision-sin-adr",
      "estado": "aprobado"
    },
    {
      "check": "alcance-excedido",
      "estado": "omitido",
      "razon": "no hay ninguna spec activa en docs/changes/pending/"
    },
    {
      "check": "artefacto-huerfano",
      "estado": "aprobado"
    },
    {
      "check": "inventario-componentes",
      "estado": "omitido",
      "razon": "faltan «artefactos.inventario_componentes» o «artefactos.componentes_dir»"
    }
  ],
  "conteo": {
    "p0": 1,
    "p1": 0,
    "p2": 0
  },
  "entropia": 40,
  "codigoDeSalida": 1
}
```

`modo` es `arbol` sin `--base` y `rango` con ella. El código de salida del proceso es el mismo que `codigoDeSalida`.

### Para guardar la lectura: `--registrar`

`--registrar` escribe el resultado en el bloque `auditoria` del frontmatter de `AI-FIRST.md`: la fecha, la entropía y el conteo de P0, P1 y P2. Sólo lo escribe cuando lo pides, y sólo reemplaza ese bloque, sin tocar el resto del frontmatter. Como cualquier cambio del repo, queda en la historia si lo commiteas.

```bash
npx @falcux/ai-first@latest audit --registrar
```

## Qué queda escrito

| Archivo                                | Qué es                                                            |
| -------------------------------------- | ----------------------------------------------------------------- |
| `.githooks/pre-push`                   | El hook, ejecutable; con `--hook-local`, en `.git/hooks/pre-push` |
| `core.hooksPath`                       | La configuración local de git que apunta a `.githooks/`           |
| `.github/workflows/ai-first.yml`       | El flujo de GitHub Actions                                        |
| El bloque `auditoria` de `AI-FIRST.md` | Sólo con `--registrar`                                            |

## Qué vigila el detector

Esta guía es el detector: los cinco checks corren en los dos sitios. Lo que cambia es qué detiene el trabajo. En el hook, sólo **Zona Prohibida tocada (P0)**. En CI, también **Decisión sin fila en ADR** y **Alcance excedido** (P1), y **Artefacto huérfano** e **Inventario de componentes** (P2). El puntaje es `min(100, 40·P0 + 20·P1 + 8·P2)`: más alto es peor. Qué detecta cada uno y cómo se evita está en [Las cinco verificaciones](https://ai-first.falcux.com/docs/referencia/verificaciones/).

## Por qué funciona así

Un hook que bloquea por todo se desinstala, y con él se van los cinco checks. En el push se interrumpe a una persona en medio de su trabajo, y sólo lo justifica un P0; en un pull request hay un humano revisando, y el costo de parar es un rebote. Los instrumentos que el detector verifica están en [Gobierno del contexto](https://ai-first.falcux.com/docs/parte-2/gobierno-del-contexto/); cómo se adopta el método en un equipo, fase por fase, en [Escalar al equipo y costos](https://ai-first.falcux.com/docs/parte-4/escalar-y-costos/).

## Próximos pasos

[ai-first audit](https://ai-first.falcux.com/docs/referencia/audit/)Todas las opciones, el puntaje y los códigos de salida.

[Las cinco verificaciones](https://ai-first.falcux.com/docs/referencia/verificaciones/)Qué detecta cada check y con qué severidad.

[El formato de AI-FIRST.md](https://ai-first.falcux.com/docs/referencia/ai-first-md/)Las claves que el detector lee.
