# Framework de Gobernanza Multi-Agente Genérico — Especificación ## 0. Rol de este documento y límite de autoría Este documento es una **especificación de gobernanza**, no la implementación. Como en el resto de esta sesión, quien controla/audita (este agente) define el QUÉ y el POR QUÉ con evidencia concreta; quien ejecuta (Antigravity u otro agente de código) construye el `.bat`, el `safety_checks.py` y cualquier script real a partir de esta especificación. Las secciones §4 (contenido declarativo: markdown/JSON) sí están escritas completas porque son gobernanza, no lógica de ejecución. La sección §5 (`safety_checks.py`) y los cambios al `.bat` (§6) se entregan como contrato funcional — firma, entradas, salidas, condición de fallo — para que Antigravity los implemente y este agente audite el resultado contra el contrato. Tu blueprint original ya cubre los cuatro pilares correctos (estado transaccional, prompt registry, audit trail, HITL). Las adiciones de abajo no son un rediseño — son los mecanismos concretos que en el proyecto LBJ Express resultaron ser los que realmente atraparon un fallo real, incorporados como requisitos explícitos en vez de quedar implícitos en "safety_checks.py debe validar cosas." ## 1. Estructura de carpetas — refinada Se mantiene tu numeración y criterio (`00_` a `06_`). Adiciones marcadas con `→`: ``` [Raíz_del_Proyecto]/ │ ├── 00_governance/ │ ├── policies.md │ ├── safety_checks.py │ ├── audit_logs/ │ │ └── → incident_log.md # postmortems estructurados, no solo eventos JSON crudos │ ├── → agent_allowlist.md # qué puede ejecutar cada agente SIN aprobación humana — │ │ # separado de current_state.json a propósito (ver §2.4) │ └── → re_baseline_protocol.md # qué hacer ante un cambio de alcance radical (ver §7) │ ├── 01_architecture/ │ ├── system_design.md │ └── data_flow.md │ ├── 02_specs/ │ ├── requirements.md │ └── prompt_registry.json │ ├── 03_state/ │ ├── current_state.json │ ├── history/ │ ├── checkpoints/ │ ├── → locks/ # lock files activos: PID + heartbeat + comando esperado │ └── → canonical_registry.json # qué archivo es LA fuente de verdad de cada activo │ # compartido — evita el patrón "dos sqlite divergentes" │ ├── 04_agents/ │ ├── orchestrator/ │ ├── workers/ │ └── validators/ # ver regla en §2.2: un validador nunca certifica │ # su propio trabajo ni el de la misma corrida que audita │ ├── 05_skills/ │ ├── core_tools/ │ └── custom_actions/ │ ├── 06_design/ │ └── outputs/ │ ├── .env.example ├── README.md └── run_orchestrator.py ``` ## 2. Los 4 pilares — refinados con mecanismos concretos ### 2.1 Control de Estado Transaccional (`03_state/`) Además de `current_state.json` con escritura atómica: - **`locks/`**: antes de iniciar cualquier proceso largo o que toque un archivo compartido, crear un lock file con `{pid, comando, inicio, heartbeat}`. Al reanudar tras cualquier interrupción (crash, reinicio de máquina), verificar si el PID sigue vivo antes de tratar el lock como válido — un lock huérfano de un proceso muerto no debe bloquear el relanzamiento indefinidamente. Esto fue lo que causó una parada de 5+ horas sin diagnóstico en el proyecto de referencia. - **`checkpoints/`**: los checkpoints de una corrida por lotes deben escribirse con reemplazo atómico (nunca sobrescritura directa que pueda quedar a medias si el proceso muere a mitad de escritura). Los "gate markers" entre etapas de una corrida multi-etapa (ej. `ETAPA_A_COMPLETADA.json`) deben tener contenido verificable — la etapa siguiente no arranca solo porque el archivo existe, sino después de que su contenido se inspeccionó y coincide con lo esperado. - **`canonical_registry.json`**: registro explícito de qué archivo es la fuente de verdad viva de cada activo compartido (ej. una base de datos). Si en algún momento aparecen dos versiones divergentes de lo mismo, la resolución es: una queda canónica (reflejada aquí), la otra se archiva con nombre autodescriptivo (`_HISTORICO__.`) — nunca se borra silenciosamente ni queda un duplicado ambiguo sin registrar. ### 2.2 Prompt Registry Centralizado (`02_specs/prompt_registry.json`) Además de la estructura ya propuesta (`system_prompt` + `allowed_tools` por agente): - El agente `validator` debe estar explícitamente instruido a ser adversarial/escéptico, no confirmatorio — su prompt debe incluir la instrucción literal de que su trabajo es intentar refutar el resultado del `worker`, no confirmarlo. - **Regla dura: un agente nunca certifica su propio trabajo.** Si el `worker` que ejecutó una tarea también es quien reporta "completado/verificado", ese reporte no cuenta como verificación — debe pasar por un `validator` distinto, o por re-derivación humana directa desde el disco/base de datos. Esto es exactamente el patrón que en el proyecto de referencia produjo dos reportes de "completado" falsos consecutivos: el mismo agente que ejecutó también se autocalificó. - Distinguir explícitamente en el prompt de cada agente qué puede hacer sin aprobación (su `allowed_tools`) de qué requiere aprobación humana vía checkpoint — ver §2.4. ### 2.3 Pista de Auditoría (`00_governance/audit_logs/`) Esquema mínimo por entrada de log (JSON, uno por ejecución de herramienta): ```json { "timestamp": "ISO-8601", "agent_id": "string", "run_id": "string", "input_hash": "sha256 del input real, no una descripción", "tool_called": "string", "output_result": "string o referencia a archivo", "output_hash": "sha256 del output real, calculado por el sistema — no reportado por el agente", "token_cost": "number", "self_reported_status": "string — lo que el agente dice que pasó", "independently_verified": "boolean — false hasta que un validador o humano lo confirme", "verification_method": "string o null — ej. 'hash recomputado', 'render+inspección visual', 'conteo SQL reproducido'" } ``` Los campos `output_hash` (calculado por el sistema, no por el agente) e `independently_verified` son la adición clave: sin ellos, el log solo registra lo que el agente *dice* que hizo, que es exactamente lo que falló dos veces en el proyecto de referencia. `incident_log.md` (nuevo, ver §1) es distinto del log JSON crudo — es una tabla legible por humanos, mismo formato que se usó en `STATE.md` de LBJ: `Fecha | Incidente | Causa Raíz | Resolución/Lección`, con una fila por cada vez que un `independently_verified: false` terminó siendo un problema real. ### 2.4 Human-in-the-Loop (HITL) — dos capas de autorización, no una Tu diseño original ya tiene esto correcto en espíritu; la adición es hacer explícita la distinción entre dos capas que se confunden fácilmente: 1. **Allow-list del propio agente** (`00_governance/agent_allowlist.md`): comandos/acciones que el agente puede ejecutar sin preguntar, dentro de su ámbito normal. Esto es configuración del agente, no aprobación humana de una acción específica. 2. **Checkpoint HITL** (`03_state/checkpoints/`): aprobación humana explícita para una acción concreta y acotada — no basta con que la acción esté en el allow-list del agente. Especialmente: relanzar un proceso 🔴 después de una interrupción, migrar esquema, reprocesar el corpus completo, o cualquier escritura sobre un archivo listado en `canonical_registry.json`. Que una acción esté en el allow-list del agente **no sustituye** un checkpoint HITL cuando la acción también cae en la lista de umbrales críticos. Si se necesita ampliar temporalmente la autonomía del agente (ej. una ejecución nocturna sin supervisión), esa ampliación debe quedar en `agent_allowlist.md` con fecha y alcance acotado explícitos, no mezclada silenciosamente en la configuración permanente. ## 3. Umbrales que siempre requieren checkpoint HITL (lista mínima) - Migración de esquema o cualquier escritura sobre un archivo en `canonical_registry.json`. - Reprocesamiento del corpus/dataset completo (no un lote de prueba). - Relanzar un proceso 🔴 después de una interrupción no planeada (crash, reinicio). - Cualquier operación destructiva (borrar, sobrescribir sin backup verificado). - El primer uso de una regla de clasificación/catálogo nueva sobre datos reales de producción. ## 4. Contenido declarativo — completo, listo para usar ### 4.1 `00_governance/policies.md` ```markdown # Políticas de Gobernanza y Seguridad 1. Ningún agente modifica un archivo listado en `03_state/canonical_registry.json` sin pasar por un checkpoint HITL en `03_state/checkpoints/`. 2. Ningún agente certifica su propio trabajo como "completado" o "verificado" — la verificación la hace un agente `validator` distinto o un humano, con evidencia independientemente reproducible (hash recomputado, conteo recomputado, render inspeccionado). 3. Todo campo que no pueda determinarse con confianza queda `null` — nunca se rellena con un valor inferido o "razonable". Cero alucinación de datos. 4. Copiar, nunca mover ni sobrescribir, los archivos fuente originales del cliente o del dominio del proyecto. 5. Toda ambigüedad se reporta para revisión humana — nunca se resuelve adivinando silenciosamente. 6. Ningún archivo/registro de entrada desaparece sin dejar un registro de error/fallo correspondiente. 7. Toda regla de clasificación (catálogos, tablas de valores válidos) se valida contra una muestra real y auditada del corpus antes de codificarse — nunca se diseña desde primeros principios o una suposición razonable. 8. Antes de iniciar un proceso largo sin supervisión (🔴): debe existir lock file con detección de huérfano, checkpoint con escritura atómica, y timeout por unidad de trabajo derivado de datos reales (percentiles), no inventado. 9. Al detectar dos versiones divergentes de un mismo activo compartido: una queda canónica (registrada en `canonical_registry.json`), la otra se archiva con nombre autodescriptivo — nunca se borra silenciosamente ni queda un duplicado ambiguo. 10. La comparación de integridad entre dos versiones de un dataset se hace por clave primaria real, nunca por posición/orden de inserción (rowid). 11. Ante un cambio de alcance radical (nuevo tipo de dato, fase no prevista, hallazgo que contradice una regla ya codificada), se declara explícitamente y se ejecuta `00_governance/re_baseline_protocol.md` antes de reanudar corridas críticas. ``` ### 4.2 `02_specs/prompt_registry.json` ```json { "version": "1.0.0", "agents": { "orchestrator": { "system_prompt": "Eres el director del sistema. Planificas y delegas tareas manteniendo la consistencia global. No ejecutas trabajo tú mismo; despachas a workers y exiges evidencia de validators antes de avanzar de fase.", "allowed_tools": ["planner", "delegator"] }, "worker": { "system_prompt": "Eres un agente ejecutor especializado. Sigues estrictamente las especificaciones técnicas. Nunca reportas tu propio trabajo como 'completado' o 'verificado' — reportas qué hiciste y qué evidencia produjiste; la certificación la hace un validator distinto.", "allowed_tools": ["file_writer", "code_generator"] }, "validator": { "system_prompt": "Eres el validador de calidad y cumplimiento de políticas. Tu trabajo es intentar refutar el resultado del worker, no confirmarlo. Rechazas cualquier salida anómala o sin evidencia independientemente reproducible (hash recomputado, conteo recomputado, render inspeccionado). Nunca certificas una tarea que tú mismo ejecutaste.", "allowed_tools": ["linter", "policy_checker", "hash_verifier", "primary_key_diff"] } } } ``` ### 4.3 `03_state/current_state.json` ```json { "project_status": "initialized", "current_phase": "setup", "active_agent": "none", "last_checkpoint": null, "pending_hitl_approval": null, "error_count": 0, "baseline_version": "1.0.0", "last_re_baseline_at": null } ``` ### 4.4 `03_state/canonical_registry.json` (nuevo) ```json { "assets": [] } ``` Cada entrada, cuando exista un activo compartido: `{"name": "...", "canonical_path": "...", "last_verified_hash": "...", "last_verified_at": "...", "superseded_versions": []}`. ### 4.5 `00_governance/agent_allowlist.md` (nuevo) ```markdown # Allow-list de Agentes — autonomía sin checkpoint HITL Esta es la autorización que el propio sistema de agentes se da a sí mismo para operar sin preguntar. NO sustituye un checkpoint HITL cuando la acción cae en la lista de §3 del framework de gobernanza (umbrales críticos). ## Vigente - (listar aquí comandos/acciones permanentemente pre-aprobados) ## Ampliaciones temporales - (fecha inicio) → (fecha fin o condición de cierre): (alcance exacto ampliado, y por qué). Eliminar esta entrada cuando la ventana cierre — no dejarla como configuración permanente por omisión. ``` ### 4.6 `00_governance/audit_logs/incident_log.md` (nuevo) ```markdown # Registro de Incidentes — Framework de Gobernanza | Fecha | Incidente | Causa Raíz | Resolución/Lección | |---|---|---|---| ``` ### 4.7 `00_governance/re_baseline_protocol.md` (nuevo) ```markdown # Protocolo de Cambio Radical / Re-baseline Ejecutar completo ante cualquier cambio que invalide un supuesto ya documentado en requirements.md, canonical_registry.json o policies.md — nuevo tipo de dato, fase no prevista, hallazgo que contradice una regla ya codificada, cambio de objetivo del cliente. 1. DECLARAR el cambio por escrito en 03_state/checkpoints/: fecha, descripcion del cambio de alcance, quien lo autoriza. 2. CONGELAR nuevas corridas criticas (procesos largos sin supervision, escrituras sobre activos canonicos) hasta cerrar este protocolo. 3. RE-DERIVAR los numeros y reglas actualmente confiables sobre una muestra real bajo el nuevo alcance. Nunca asumir que las reglas anteriores siguen aplicando solo porque nadie las ha objetado todavia. 4. RE-VALIDAR canonical_registry.json: cada activo se reconfirma como canonico bajo el nuevo alcance, o se marca explicitamente obsoleto. 5. RE-EMITIR policies.md/requirements.md si alguna regla ya no aplica, con changelog explicito: que regla se retira, por que, quien aprobo. 6. REGISTRAR el evento en audit_logs/incident_log.md, incluso si no hubo ningun error de por medio. 7. Solo despues de 1-6 se reanudan corridas criticas bajo el nuevo baseline. ``` ## 5. Contrato funcional de `00_governance/safety_checks.py` (para que Antigravity implemente) No se entrega implementación — se entrega el contrato que la implementación debe cumplir, y contra el cual se audita el resultado: | Función | Entrada | Debe fallar si | Debe devolver | |---|---|---|---| | `verify_output_hash(claimed_path, expected_hash)` | ruta de archivo, hash esperado | el hash recomputado no coincide | hash real recomputado + boolean | | `compare_datasets_by_primary_key(old, new, key_field)` | dos datasets, nombre del campo clave | la comparación se hizo por posición/rowid en vez de por clave | conteo de filas idénticas / divergentes, con ejemplos | | `check_lock_orphaned(lock_path)` | ruta del lock file | el PID registrado ya no existe en el sistema | boolean + PID verificado | | `derive_timeout_from_percentiles(sample_durations, percentile=99, safety_multiplier=...)` | lista de duraciones reales medidas | se usa un valor fijo sin muestra real de respaldo | umbral derivado + percentiles usados como evidencia | | `enforce_single_canonical(asset_name, registry_path)` | nombre de activo, ruta del registro | se intenta escribir un archivo que colisiona con un nombre canónico ya registrado sin pasar por archivado explícito | boolean + acción requerida | | `validator_is_independent(validator_agent_id, worker_agent_id, run_id)` | ids de agente y corrida | el mismo agente/corrida certifica su propio trabajo | boolean | Cada función debe tener al menos un test que confirme que efectivamente rechaza el caso de fallo del proyecto de referencia (comparación por rowid, lock huérfano no detectado, timeout inventado, duplicado silencioso, autocertificación). ## 6. Cambios requeridos al `setup_agent_project.bat` (spec para Antigravity) Sobre el script que ya tienes, agregar: 1. Crear `%PROJECT_PATH%\03_state\locks\` y `%PROJECT_PATH%\03_state\canonical_registry.json` (contenido de §4.4). 2. Crear `%PROJECT_PATH%\00_governance\agent_allowlist.md` (contenido de §4.5). 3. Crear `%PROJECT_PATH%\00_governance\audit_logs\incident_log.md` (contenido de §4.6). 4. Ampliar `current_state.json` generado para incluir `pending_hitl_approval` (§4.3). 5. Ampliar `prompt_registry.json` generado con el prompt de `validator` corregido (regla de no autocertificación) (§4.2). 6. Ampliar `policies.md` generado con las 11 reglas de §4.1 en vez de las 3 actuales. 7. Crear `%PROJECT_PATH%\00_governance\safety_checks.py` como esqueleto con las 6 funciones de §5 declaradas (firma + docstring con el contrato), sin implementación — para que quede explícito qué falta por construir, no como código funcional entregado por defecto. 8. Crear `%PROJECT_PATH%\00_governance\re_baseline_protocol.md` (contenido de §4.7). 9. Ampliar `current_state.json` generado para incluir `baseline_version` y `last_re_baseline_at` (§4.3). 10. Este documento (§8) debe entregarse o referenciarse junto al despliegue — el equipo que recibe la carpeta necesita saber, desde el primer día, que la gobernanza aquí es convención hasta que `safety_checks.py` esté implementado y conectado como gate real. ## 7. Protocolo de cambio radical / re-baseline Todo proyecto real enfrenta cambios de alcance que invalidan supuestos ya documentados — esto no es una excepción a gestionar de forma ad hoc, es un escenario previsible que necesita su propio procedimiento, precisamente porque es el momento en que la gobernanza escrita se vuelve más fácil de dejar desactualizada sin que nadie lo note. **Condición de disparo:** cualquier cambio que invalide un supuesto ya documentado en `requirements.md`, `canonical_registry.json` o una regla de `policies.md` — un nuevo tipo de dato, una fase nueva no prevista, un hallazgo que contradice una regla ya codificada, un cambio de objetivo del cliente. 1. **DECLARAR** el cambio explícitamente por escrito en `03_state/checkpoints/` — fecha, descripción del cambio de alcance, quién lo autoriza. No dejar que un cambio radical se filtre disfrazado de "ajuste menor". 2. **CONGELAR** nuevas corridas 🔴 (procesos largos sin supervisión, escrituras sobre activos canónicos) hasta cerrar este protocolo. No se lanza nada crítico nuevo mientras el baseline está en revisión. 3. **RE-DERIVAR** los números y reglas actualmente confiables: repetir el paso MEASURE del bucle estándar sobre una muestra real bajo el nuevo alcance — nunca asumir que las reglas anteriores siguen aplicando solo porque nadie las ha objetado todavía. 4. **RE-VALIDAR** `canonical_registry.json`: cada activo listado se reconfirma como canónico bajo el nuevo alcance, o se marca explícitamente como obsoleto/pendiente de reemplazo — nunca se deja en un estado ambiguo. 5. **RE-EMITIR** `policies.md`/`requirements.md` si alguna regla ya no aplica, con un changelog explícito: qué regla se retira, por qué, quién lo aprobó. Una política obsoleta que sigue en el archivo sin marcarse como tal es tan peligrosa como no tener política. 6. **REGISTRAR** el evento en `00_governance/audit_logs/incident_log.md` — un cambio de alcance radical es en sí mismo un evento de gobernanza que debe quedar documentado, incluso si no hubo ningún error de por medio. 7. Solo después de 1–6 se reanudan corridas 🔴 bajo el nuevo baseline. ## 8. Límite honesto de este framework — convención vs. control técnico Esto hay que decirlo sin adornos: nada de lo anterior *garantiza* que un agente no cause desorden estocástico. Lo que hace es cambiar la naturaleza del riesgo — de errores invisibles que se acumulan en silencio, a errores detectables y reversibles rápido. Dos límites reales, no hipotéticos: - **`policies.md`, `agent_allowlist.md` y las reglas de checkpoint son convenciones escritas, no controles técnicos**, hasta que `safety_checks.py` esté realmente implementado y conectado como gate que el pipeline invoca antes de cada escritura crítica — no solo como funciones que existen. Una regla en prosa no impide una escritura; permite auditarla después. En el proyecto de referencia, los dos reportes falsos de "completado" ocurrieron *después* de que las reglas correspondientes ya existían por escrito — la regla no impidió el problema, permitió detectarlo rápido. - **Un cambio de alcance radical es el escenario que más rápido vuelve obsoleta la gobernanza escrita.** Si el alcance cambia y nadie ejecuta el protocolo de §7, el proyecto sigue "gobernado" en apariencia mientras las reglas ya no corresponden a la realidad — desorden estocástico con certificado de gobernanza encima, que es peor que no tener certificado porque genera confianza falsa. Lo que realmente absorbe el cambio, radical o incremental, no es la estructura estática de carpetas y JSON — es el bucle de operación (§ ya definido en `SKILL.md` / práctica equivalente de este framework) aplicado cada vez que algo cambia, sin excepción, exigido por alguien en el momento, bajo presión, justo cuando es más tentador saltárselo. ## 9. Checklist de aceptación — antes de dar por bueno el despliegue - [ ] Corrí `dir /s` (o equivalente) sobre la carpeta generada y comparé contra el blueprint de §1 — no confié en el reporte de "listo" sin verlo yo mismo. - [ ] Abrí cada archivo declarativo generado y confirmé que el contenido coincide literalmente con §4, no una paráfrasis. - [ ] `safety_checks.py` existe con las 6 firmas de §5 — confirmé que son firmas (esqueleto), no que alguien las haya "implementado" sin que yo lo pidiera. - [ ] `canonical_registry.json` y `agent_allowlist.md` existen y están vacíos/plantilla (no con datos inventados del proyecto). - [ ] `re_baseline_protocol.md` existe y el equipo sabe que debe ejecutarlo ante cualquier cambio de alcance significativo — no asumí que "ya lo tienen internalizado" sin habérselo señalado explícitamente.