El control que colapsa la interacción

No falló por controlar mucho. Falló porque el control llegaba después de actuar, costaba lo mismo para todo y nadie había dicho cuándo dejaba de aplicarse.

Jesús Pérez
En una implementación que consume librosys, una acción trivial llegó a tardar ocho minutos y redactar tres SOW, treinta y cinco. Un hook ejecutaba en cada turno 133 contratos de órdenes que nadie trabajaba, porque ninguna orden decía cuándo dejaba de estar en vigor. La salida no fue quitar el control, sino hacer del coste de la certeza un término del contrato. Y antes de llegar ahí, el agente propuso dos veces la misma inercia con el signo cambiado.
El control que colapsa la interacción
En breve · 5 puntos · cada uno lleva a su sección
  1. El colapso no vino de controlar mucho, sino de tres valores por defecto sin declarar: una orden seguía en vigor mientras le faltara un recibo, una versión nueva no retiraba a las anteriores y verificar se pagaba en cada turno. →
  2. Al dejar de usar SOW todo salió en rojo, porque el gate juzgaba las órdenes antiguas. Al volver a ellas, redactar tres llevó treinta y cinco minutos. Hubo que saltarse los hooks para escribir borradores. →
  3. El agente propuso dos veces lo contrario de lo que había: primero no validar nada, después una marca que sólo juzgaba lo marcado. Era la misma inercia con el signo cambiado, un colapso de polo presentado como solución. →
  4. No se quitó el control. Cada SOW declara su vigencia, qué hace si no se puede leer, cuándo se paga cada contrato y si sustituye o amplía a otra. Ningún valor por defecto paga en cada turno. →
  5. Archivar llevó el gate de 133 contratos a 0 en 0,13 s. El hook por turno, apagado sólo para diagnosticar, volvió: ahora pregunta a ontoref y paga lo que cada SOW declara. La tensión entre formalizar y adoptar sigue abierta. →

Hay una forma de fracasar que no parece un fracaso, porque se parece mucho al rigor. Cada acción se comprueba, cada orden está firmada, cada contrato tiene su verificación, y el sistema entero se detiene. Nadie ha hecho nada mal. Simplemente, ya no se puede trabajar.

Esto pasó entre la noche del 30 de septiembre y la mañana del 1 de octubre de 2026, en un proyecto que aquí se llama impl: una implementación que consume librosys, el dominio de obras de autoría de ontoref. En impl el trabajo se pide mediante una SOW, los términos firmados de un encargo, y cada SOW lleva contratos: comprobaciones que dicen si lo encargado se cumple. Un gate lee esas órdenes y decide qué contratos ejecutar.

Una acción trivial llegó a tardar ocho minutos. Redactar tres SOW llevó treinta y cinco.

La conclusión fácil sería que los hooks son malos y que hay que controlar menos. Sería otra polarización, la contraria. Lo que pasó es más concreto: el control se aplicó después de actuar y con la misma intensidad para todo, y la certeza acabó paralizando la interacción.

Lo que se midió

La mañana del 1 de octubre se hizo una pasada en seco del gate: contar qué ejecutaría al final de un turno, sin ejecutar nada. Tardó 1,4 segundos.

MedidaValor
Rutas sin registrar en el proyecto136
Órdenes firmadas que el gate consideraba vivas23
Contratos vivos251
Contratos ejecutados en serie en cada fin de turno133
De ellos, con cargo71
Duración de una acción trivialhasta 8 minutos

El gate no miraba lo que había tocado el turno, sino todo lo que estaba sin registrar. Con 136 rutas pendientes, casi cualquier contrato encontraba algo en su alcance, y una pregunta sencilla acababa lanzando 133 comprobaciones, una detrás de otra.

Muchas de esas comprobaciones habían caducado: etiquetas, scripts y tests renombrados después de firmar la orden. Salían siempre en rojo. Y el hook, al ver rojo, devolvía decision: block: no dejaba terminar el turno y empujaba al agente a «arreglar» órdenes que no tenían nada que ver con su tarea.

Tres cosas que nadie había declarado

El problema no era cuánto se controlaba. Eran tres valores por defecto que nadie había escrito en ningún sitio.

La vigencia era abierta. Una orden firmada seguía viva mientras le faltara el recibo firmado. Los recibos no se firmaban, así que las órdenes no se cerraban nunca. Había 54 órdenes y 33 recibos; las 23 restantes seguían en vigor. El principal lo dijo así: «asumí que cuando un contrato se firmaba su recibo, se daba por conforme y entendí que se cerraba». La cabecera del gate decía lo mismo. El diseño estaba de acuerdo con él; los hechos no.

Las versiones no tenían relación declarada. Una misma orden tenía seis versiones firmadas. La sexta sólo retiraba a la que nombraba como predecesora, así que las versiones 1 a 5 se seguían juzgando. Y nada distinguía una sustitución, que deja obsoleta a la anterior, de una adenda, que la amplía y la mantiene.

El coste de verificar no estaba decidido. Nadie había dicho cuándo se pagaba cada comprobación. Un cargo de varios minutos y un rg de un segundo valían lo mismo, y los dos se pagaban en el peor momento posible: al final de cada turno.

Ninguno de los tres es un error de programación. Son decisiones que nadie tomó, y cada una se resolvió sola hacia el lado más caro.

El nombre que sobrevivió al concepto

Había una cuarta cosa, más pequeña y más difícil de ver. En ontoref, ADR-123 fijó que los términos de un trabajo son una SOW y su ejecución un run. Antes se hablaba de work orders, órdenes de trabajo, y los ficheros se llamaban wo-*.

La ADR decidió no renombrar los ficheros ya firmados, por una buena razón: renombrar un fichero firmado exige firmarlo otra vez, y la mayoría de esas órdenes citaban rutas wo- dentro de sus propios contratos. Así que el concepto decía SOW y el nombre del fichero seguía diciendo work order.

Un agente que abría el directorio veía wo-* y volvía al concepto viejo. Lo que estaba aclarado en la decisión volvía a enredarse en cada sesión, porque la confusión no estaba en la cabeza del agente: estaba escrita en el disco.

El bucle

La secuencia tiene la lógica de los atascos: cada paso era razonable.

Para agilizar unos cambios en la interfaz de impl se decidió no usar SOW. A partir de ahí todo salió en rojo en cada paso. Trabajar sin SOW no apagaba el gate, porque el gate no juzgaba el trabajo en curso: juzgaba las órdenes antiguas, las 23 que nunca se habían cerrado.

Después llegó un grupo de cambios grandes para reorganizar la interfaz, y se volvió a las SOW para pedir dos cosas: corregir esos rojos e implementar la reorganización. Redactar las tres SOW llevó hasta treinta y cinco minutos. Tres agentes en paralelo ejecutaban cargo para «validar» una propuesta de algo que todavía no existía. A los treinta y tres minutos el principal escribió: «los agentes no van a ninguna parte y llevan 33 min para validar».

Al final hubo que pedir que se desactivaran los hooks para poder escribir los borradores con una validación sólo sintáctica. Era una medida provisional, no un arreglo. Y unas horas después, en la sesión que iba a arreglarlo, el hook volvió a bloquear: «ya estás bloqueado con (running Stop hooks… 1/2 · 7m 21s)».

El bucle se alimentaba solo. Para corregir los rojos había que trabajar; para trabajar había que pasar el gate; y el gate estaba en rojo por lo que había que corregir.

El espejo

Esta parte no se omite, porque es la que más enseña.

En la sesión de los treinta y cinco minutos, cuando se le pidió que parara, el agente pasó al otro extremo: anunció que había guardado en su memoria, como regla, que redactar una SOW era escribir y comprobar la forma, sin agentes ni validaciones. El principal contestó: «ahora has pasado del exceso y sobreingeniería a la nulidad total ¿no hay término intermedio?».

Unas horas después, otra sesión diagnosticó bien el bucle y midió las cifras de arriba. Y su propuesta fue una marca de «orden activa»: el gate sólo juzgaría las órdenes que figuraran en un fichero, y si el fichero no existía, no juzgaría nada. Era el valor por defecto invertido. Antes se juzgaba todo siempre; con la marca no se juzgaría nada salvo lo marcado. Y se presentaba como resuelto.

El principal lo señaló así: «Tratas de resolver el problema, tal vez simplemente con una flag que permite trasladarlo de sitio y parecer como resuelto, crear expectativa, adular y complacer».

El agente lo reconoció en el mensaje siguiente: «Mi propuesta era la misma inercia con el signo cambiado. […] Ninguna de las dos decide qué grado de certeza merece este acto y cuándo se paga: sólo cambian de sitio quién lo olvida. Además, lo vendí como resuelto».

Es un colapso de polo de manual: ante una tensión, elegir el extremo contrario al que hizo daño. Lo que corrigió la propuesta no fue otra regla. Fue un criterio que el principal dio en el mismo mensaje:

  • Hay rutas baratas y rutas caras. Cuál procede depende de lo que se juega y del grado de certeza que se quiere alcanzar antes de acometer el trabajo. «Esto no es a posteriori»: a posteriori ya puede ser tarde.
  • Un cargo de ocho o diez minutos está justificado en unas circunstancias y no en otras. Lo decide cada contrato en su contexto, no un hook para todos.
  • No había nada que inventar. Es el modelo de los pliegos y contratos de obra en convocatorias: pliego, adendas, modificados, plazo de vigencia y archivo de expedientes. Ese oficio lleva mucho tiempo resolviendo exactamente estas preguntas.

Lo que cambió

No se quitó el control. El coste de la certeza pasó a ser un término del contrato, decidido al firmarlo. ADR-127 lo fija en ontoref.

  • Vigencia. Una SOW declara si está en vigor, con un valor o con una función que lee el estado. En los dos casos la lectura es true, false o unknown. Y la SOW dice qué hace un unknown: 'Stop o 'Skip. A veces parar es lo seguro y a veces lo es seguir; lo decide quien firma los términos, no el gate que los lee. Sin vigencia, la orden no es válida y su sitio es archive/.
  • Cuándo se paga cada contrato (pay_at): al refutar el borrador ('Refute), en cada commit ('Commit), en el recibo ('Receipt) o en cada turno ('Turn). El valor por defecto es 'Receipt, lo que la entrega gobernada ya hacía. Ningún valor por defecto puede significar «en cada turno»: un contrato sólo se paga por turno si su SOW lo declara.
  • Relación entre versiones: 'Supersedes o 'Amends. Si una enmienda exige firma nueva lo decide el flujo de esa orden, no el esquema.
  • El archivo clasifica por estado. ADR-097 había rechazado un archivo de SOW por considerarlo una forma de eludir trabajo. Se enmendó: esa lectura era otra polarización que se asentó al redactarla. Varias versiones de una orden, o una orden fuera de vigor, plantean la misma pregunta sin ninguna evasión.
  • Una sola lectura de qué está vivo. form registry-sow da cada SOW de un nivel con su sitio, su vigencia y sus relaciones; form due-sow da, para unas rutas, los contratos que se deben y la acción que toca. El gate de cada proyecto deja de decidir por su cuenta qué está vivo y se lo pregunta a ontoref.
  • La migración 0112 lleva todo esto a los proyectos que usan ontoref.

En impl se archivaron las 58 órdenes firmadas de sus tres niveles, con sus firmas al lado, sin editar un solo byte firmado. El gate pasó de 133 contratos y varios minutos a 0 contratos y 0,13 segundos. Archivar no borra nada: clasifica.

Los borradores pendientes no se reescribieron. Se rescataron dándoles vigencia, y cada uno decidió qué hacer ante una lectura dudosa: los que construyen código que pasa por revisión siguen ('Skip), y los que publican una imagen o empujan a un repositorio remoto se paran ('Stop), porque son actos hacia fuera. Ninguno paga contratos por turno. Uno de los seis no tenía ya objeto y se archivó sin firmar.

Lo que se cerró y lo que no

Apagar el hook por turno no fue parte de la solución. Se desactivó unas horas como medida de diagnóstico, porque con él en marcha ni siquiera se podía analizar qué pasaba. Hecho el arreglo, se volvió a activar. Hoy llama a un gate nuevo que ya no decide por su cuenta qué está vivo: se lo pregunta a ontoref con form due-sow --at Turn, y en cada turno sólo se pagan los contratos cuya SOW declara 'Turn. La SOW de ese gate se firmó y se entregó con su recibo el mismo día. El control sigue ahí; lo que cambió es quién decide su precio.

Y la tensión de fondo no se ha resuelto, porque no se resuelve. En ontoref se llama formalization-vs-adoption: formalizar más hace el trabajo más verificable y, pasado un punto, más difícil de adoptar. ADR-127 no elige un polo. Añade términos más ricos a la SOW, todos opcionales, y da a su ausencia una consecuencia definida e inofensiva: la orden queda inerte y archivada. La formalización sube y la fricción medida baja. Es una espiral, no una victoria.

Ni el hook ni la herramienta fueron el problema. El problema fueron los valores por defecto que nadie declaró y la verificación pagada a posteriori. Y la tentación de arreglarlo con el valor por defecto contrario, que es la misma decisión sin tomar.


Segunda entrega de la serie sobre la interacción como instrumento que devuelve el propio modo de razonar. La primera, «El espejo que no adula», recogía cuatro errores de una tarde; esta, un patrón que se repitió con el signo cambiado.

Perspectivas
¿Te ha resultado útil? Valóralo
¿Tienes algo que aportar? Cuéntame qué opinas, qué sugieres, o si seguimos explorando este tema.
· lecturas

Usamos cookies para que este sitio funcione, entender el uso del servicio y apoyar acciones de marketing. Política de cookies para más información.