Saltar al contenido
disensor.devv0.9.4

CLI · GitHub Action · artefacto JSON

Tu IA escribió el código. Otra IA lo revisó.

Lo que pasó en esa revisión termina como un archivo JSON en tu repo, al lado del código que juzga. disensor es el CLI y la GitHub Action que lo revisan: contra el esquema, contra sus reglas y contra el cambio que el pull request realmente hace.

Instalación

pip install disensor

init escribe cuatro cosas en tu repo. Un archivo de config, un workflow de CI y, para Claude Code, una skill y una instrucción, así el registro se escribe al cerrar cada ronda. Cualquier otro agente recibe la misma guía con disensor guide. El gate no corre ningún modelo ni pide claves de API: valida lo que ya está en el repositorio. La ronda sí corre uno, y elegís cuál: disensor round ejecuta el revisor que tengas instalado y ancla lo que salió de ahí. En los dos casos hace falta un árbitro humano: sin él el artefacto no valida.

§ 01

Ese archivo se llama declaración de residuo. Lista residuo en lugar de cobertura. La página del método explica qué significa eso en la práctica, y por qué no se parece en nada a un badge verde.

Qué es el desacuerdo controlado

§ 02

Desacuerdo controlado

Dentro de un evento el ciclo es lineal: el revisor ataca una vez. disensor se queda afuera de ese ciclo. Define el artefacto con el que termina, y lo revisa.

01familia A

Genera

el plan o el diff

Un modelo produce el plan o el diff que se va a mergear.

02otra familia

Ataca

uno o más revisores (R4)

Un modelo de otra familia lo revisa con una consigna adversarial. Dos modelos del mismo linaje fallan en los mismos lugares, y por eso la familia tiene que cambiar.

03familia A

Verifica

contra el repositorio o la ejecución

El generador contrasta cada hallazgo contra el repositorio o la ejecución y lo lleva a un estado terminal: incorporado, deuda registrada, decisión del dueño, refutado o escalado.

04

Declara

cierra el ciclo, no el problema

El ciclo cierra cuando todo hallazgo llegó a un estado terminal. Lo que no cerró queda escrito y viaja versionado con el commit. Ese archivo lo escribe tu asistente, no vos.

escalated_open, refuted_interpretive

Árbitro humano

Requerido en todo evento. Sin él la declaración no cumple el protocolo.

R0
fix_verification: pending_in_diff_gateSi lo revisado fue el plan, la corrección todavía no existe y no hay dónde verificarla. Queda pendiente para el evento del diff, que tiene su propia declaración.

§ 03

El artefacto

Un JSON versionado en el repositorio, junto al código que juzga. Registra los actores, su familia y cuán independiente fue realmente el revisor, cada hallazgo con su estado terminal y las métricas del evento. Una ronda que no pudo llegar a otra familia de modelo queda registrada como el modo degradado que es, y arrastra su propio ítem de residuo.

El bloque para leer es residue. En este evento real, los 3 hallazgos llegaron todos a un estado terminal, y aun así dejaron 3 ítems de residuo, uno por cada clase. Residuo es todo lo que descansa sobre el juicio de alguien, incluidos los hallazgos que cerraron.

El gate no corre ningún modelo ni pide claves de API: valida un archivo que ya está versionado. Correr la revisión es un paso aparte, y ese sí le entrega tu diff a un modelo de otra familia; desde la 0.9 lo orquesta disensor round con el revisor que tengas instalado.

Los conteos cierran. El residuo, igual, tiene 3 ítems.
total_findings3
incorporated1
debt_recorded0
owner_decision0
refuted_verifiable1
refuted_interpretive0
escalated_open1
residue.items3
spec/examples/example_2_diff_gate.jsonv0.9.4
"residue": {
  "items": [
    {
      "id": "r1",
      "class": "escalation_without_decision",
      "finding_ref": "h2",
      "requires_human_attention": true,
      "description": "El limite de filas de la exportacion quedo escalado a producto y sin resolver al cierre del ciclo."
    },
    {
      "id": "r2",
      "class": "principal_refutation",
      "finding_ref": "h3",
      "refutation_type": "verifiable",
      "requires_human_attention": false,
      "description": "Refutacion con enlace al objeto de consulta compartido, para que el revisor humano pueda no darla por buena.",
      "evidence": {
        "text": "La validacion vive en el objeto de consulta compartido reutilizado por la exportacion.",
        "link": "src/consultas/RangoFechas.cs#L41-L58"
      }
    },
    {
      "id": "r3",
      "class": "execution_gap",
      "requires_human_attention": true,
      "gap_reason": "environment_not_reproducible",
      "description": "El comportamiento bajo concurrencia real no se probo porque el entorno de desarrollo no la reproduce."
    }
  ]
}
Extracto de un evento real, anonimizado. Es el ejemplo que viene con la herramienta. Ver el artefacto completo

§ 04

Qué hace cumplir el gate

Una GitHub Action que valida las declaraciones que el PR agrega, aplica la política de alcance del repositorio y publica el resultado como comentario.

Falla cerrado
Si el gate no puede resolver el rango del PR, no da verde: no pudo leer el cambio, así que no tiene nada que aprobar.
La evidencia es de solo agregar
Un PR no puede modificar, borrar ni renombrar declaraciones que ya estaban, ni reutilizar un identificador de evento.
Una declaración rancia no cubre nada
Si la ruta cambió después del commit revisado, la declaración deja de cubrirla. Revisar y seguir escribiendo no alcanza.
Todo sale de git
El alcance se deriva de los objetos del rango revisado, nunca del working tree: leer del disco clasificaría un árbol y validaría otro.

§ 05

Lo que no detecta

El validador detecta el campo vacío y el marcador genérico. No detecta la declaración falsa, y ninguna herramienta puede. Alguien tiene que abrir PR ya mergeados al azar y leerlos.

Tampoco protege contra un workflow modificado, salteado o sustituido. Esa parte la resuelve la plataforma: required checks estrictos, CODEOWNERS y el pin de la Action por SHA.

Qué exige el artefacto y qué todavía no puede verificar cambia con cada versión del esquema. Los límites conocidos se declaran en la referencia.

Probalo sin tocar tu CI

El gate corre igual en tu máquina y dice exactamente lo mismo que diría en CI. Recién cuando quieras que haga cumplir, se escribe el workflow.

pip install disensor && disensor init --no-workflow