# Objective Guard en TODO_HARNESS

TODO una o dos oraciones: qué harness cubre esta guía y qué herramienta de edición frena. Remitir a [../getting-started.es.md](../getting-started.es.md) para la puesta en marcha inicial en lugar de repetirla. Versión en inglés: [_template.md](_template.es.md).

Antes de completar esto, leé el script de hook propio del harness bajo `src/` y los tests que lo cubren. Reemplazá cada `TODO`. Si una capacidad no está implementada o no está cubierta por un test, eliminá la afirmación o decilo explícitamente — no inventes flags, rutas ni claves de configuración. Conservá los siete headings H2 de abajo, en orden.

## Qué aporta esta integración

De tres a seis bullets. Cada uno declara una capacidad concreta y qué no prueba.

- **Un gate de preflight pre-edición.** TODO qué evento del harness ejecuta `src/pre-edit-gate.mjs` y cómo se ve una denegación en este harness. Prueba que el agente leyó el contrato antes de mutar; no prueba nada sobre si la edición es correcta.
- **Detectores en tiempo de edición.** TODO qué evento ejecuta el hook del harness, cómo se extrae el archivo editado del payload y qué detectores aplican (`weak-test`, `stub-prod`, `new-dep` únicamente sobre `package.json`, sintaxis JS únicamente en `.js`/`.mjs`/`.cjs`). El silencio significa que esos cuatro no encontraron nada en ese archivo.
- **Inyección de prompt de la fase actual.** TODO qué script y qué evento, y qué le dice al agente que corra a continuación. Es un consejo inyectado como contexto; no fuerza nada.
- **Evidencia de ronda.** `oguard align` mide la superficie modificada contra el scope y los key results declarados; `oguard round-end` corre los checks declarados y conserva un registro append-only. Un `pass` significa que los checks en alcance no encontraron violación.
- **Telemetría sanitizada.** Cada decisión agrega harness, hash del repositorio, resultado, código de razón y duración al inventario global. Sin paths, sin prompt, sin contenido de archivos.

## Requisitos

- Node 20 o superior (`package.json#engines` declara `"node": ">=20"`), y `node` resoluble en el `PATH` — los comandos del hook invocan `node` directamente.
- Un repositorio Git. Todo comando resuelve su raíz con `git rev-parse --show-toplevel`.
- TODO las capacidades del harness de las que el código realmente depende: qué eventos de hook, si respeta una decisión de denegación y qué campos del payload lee el hook. Aclarar que no se fija ninguna versión de harness salvo que el código la fije.

## Instalación

TODO si el paquete puede instalarse desde un registry. Al día de hoy `package.json` declara `"private": true`, así que las guías describen un checkout.

```bash
git clone <repository-url> objective-guard
cd objective-guard
node --version            # debe ser >= 20
node src/cli.mjs --help   # imprime la superficie de comandos por stderr y sale con código 2
```

Dentro de este checkout, invocá la CLI como `node src/cli.mjs <cmd>`. `package.json#bin` mapea `oguard` a `./src/cli.mjs`, así que `npm link` pone `oguard` en tu `PATH`; ningún test cubre el paso de linkeo.

La configuración de hooks es TODO **a nivel usuario** o **a nivel proyecto**, en `TODO/ruta/que/lee/el/harness`. Las rutas en `command` deben ser absolutas.

```json
{
  "TODO": "el bloque de configuración real que lee este harness, con el gate pre-edición, el hook post-edición y el script de prompt"
}
```

TODO explicar cualquier variable de entorno que el hook necesite (`OGUARD_HARNESS=<nombre>` etiqueta la telemetría; `OGUARD_HOOK_EXECUTE=1` fuerza el `main()` del hook cuando se lo invoca a través de un wrapper) y cualquier sutileza del matcher.

Después, por repositorio:

```bash
oguard init   # crea solamente oguard.contract.json
```

`oguard init` no instala hooks ni toca la configuración del harness — escribe un contrato placeholder con `objective.id = "O-UNSPECIFIED"` y se niega a sobreescribir uno existente (`test/init-cli.test.mjs`). La instalación del hook es el paso manual de arriba.

## Verificar la integración

```bash
# 1. Preflight. Imprime status ready o action-required; action-required sale con código 1.
node src/cli.mjs task-flow --json

# 2. Pasale al gate el payload que envía este harness, con telemetría aislada.
export OGUARD_INVENTORY_DIR=/tmp/oguard-verify
printf '{"cwd":"%s","tool_name":"TODO","tool_input":{"file_path":"%s/README.md"}}' "$PWD" "$PWD" \
  | OGUARD_HARNESS=TODO node src/pre-edit-gate.mjs
echo "exit=$?"

# 3. Leé la decisión que quedó registrada.
tail -1 "$OGUARD_INVENTORY_DIR/events.jsonl"
```

Un repositorio autorizado no produce stdout y devuelve `exit=0` con `"preflight_reason":"fresh-preflight"`. Uno no autorizado imprime el JSON con `permissionDecision: deny`, sale con código 2 y registra `"preflight_reason":"missing-or-expired-preflight"`. Ambas transiciones están aseveradas en `test/pre-edit-gate.test.mjs`.

```bash
node --test test/pre-edit-gate.test.mjs test/hooks-e2e.test.mjs test/claude-hook.test.mjs
```

TODO nombrar el test que cubre el cableado propio de este harness y qué asevera. Si ningún test lo cubre, decilo claramente.

## El loop en la práctica

```bash
oguard init
oguard intent --objective-id O-1 --objective "TODO objetivo" --task-type bugfix --scope "src/**,test/**"
oguard intent-scan
oguard start --from-intent --round-id R-1 --round "TODO ronda" --kr-id KR-1 --kr "TODO key result"
git add oguard.contract.json && git commit -m "open round R-1"
oguard task-flow --json
# ... ediciones, cada una frenada e inspeccionada por los hooks de arriba
oguard check --file TODO/ruta.mjs
oguard align --json
oguard round-end --mode final
```

`init` escribe el contrato placeholder una vez por repositorio. `intent` registra un borrador local y revisable de objetivo, tipo de tarea y scope candidato en `.oguard/intent.json`; todavía no hay nada congelado. `intent-scan` resuelve sólo archivos observables por Git que coinciden con esos globs — evidencia estructural, nunca prueba semántica. `start --from-intent` copia el borrador revisado al contrato congelado y ancla el baseline; después de esto, cambiar de dirección exige una ronda sucesora. Commiteá `oguard.contract.json` para que el contrato congelado quede versionado con el trabajo. `task-flow --json` debe devolver `ready` antes de la primera edición material; es lo que concede la autorización que busca el gate. Cada edición queda entonces frenada e inspeccionada automáticamente. `check --file` corre los mismos cuatro detectores a demanda. `align` compara la superficie modificada con el scope y los key results declarados. `round-end --mode final` corre los checks declarados y bloquea si un criterio requerido sigue en `unknown`; `--mode fast` conserva esa incertidumbre. Para el próximo trabajo, abrí una sucesora con `oguard next-round ...`, que exige árbol limpio.

## Qué no puede ver el harness

Conservá todos los límites de abajo que apliquen y agregá los específicos de este harness.

- El gate sólo inspecciona payloads estructurados de herramientas. TODO nombrar los campos que lee acá. Una escritura hecha dentro de un comando de shell — `sed -i`, `tee`, una redirección, `git apply`, un script que reescribe archivos — no queda frenada ni clasificada.
- Un repositorio sin `oguard.contract.json` nunca queda bloqueado: `allow` con razón `no-contract`; un archivo fuera de la raíz del contrato devuelve `allow` con razón `file-outside-contract`. La ausencia de una denegación no es evidencia de gobernanza.
- La autorización `ready` es cacheada, no continua. Vive en `.oguard/state.json` contra el hash del contrato y el hash de la política de KPIs versionada, y expira una hora después de otorgada. Editar cualquiera de los dos la invalida de inmediato.
- El detector post-edición es informativo: corre después de la mutación y devuelve contexto, nunca un rechazo. Su alcance son cuatro checks por archivo.
- La inyección de prompt no es enforcement. Sólo el gate pre-edición produce una denegación.
- La telemetría prueba uso, no beneficio; `oguard inventory dashboard --json` reporta `causal_effect: not-evaluable`.
- TODO todo lo que este harness oculte específicamente: eventos no soportados, payloads sin ruta de archivo, nombres de herramienta que el matcher no captura.

## Resolución de problemas

| Síntoma | Causa probable | Comando que muestra la verdad |
| --- | --- | --- |
| Toda edición queda denegada | No hay autorización vigente, o el contrato o la política de KPIs cambió | `node src/cli.mjs task-flow --json` |
| La denegación nombra una raíz de contrato inesperada | Un directorio padre tiene `oguard.contract.json` | `printf '{"cwd":"%s","tool_input":{"file_path":"%s/file.mjs"}}' "$PWD" "$PWD" \| node src/pre-edit-gate.mjs` |
| `task-flow` devuelve `action-required` | Falta contrato, mismatch de baseline, finding de gobernanza o violación bloqueante de KPIs — el array `actions` dice cuál | `node src/cli.mjs task-flow --json` |
| Nunca se deniega nada | No hay contrato en ese repositorio, o los hooks no están instalados para este harness | `ls oguard.contract.json` y revisar TODO la ruta de configuración del harness |
| No aparecen findings tras una edición mala | El hook se salteó, o el cambio está fuera de los cuatro detectores | TODO el switch de debug de este harness, luego `node src/cli.mjs check --file <ruta> --json` |
| El inventario queda vacío o muestra `tool: "unknown"` | `OGUARD_INVENTORY_DIR` apunta a otro lugar, o falta `OGUARD_HARNESS` en el comando | `tail -3 ~/.oguard/inventory/events.jsonl` |
| `round-end` bloquea por criterios `unknown` | La ronda no declaró un check reproducible para un criterio requerido | `node src/cli.mjs round-end --mode fast --json` |
