Expediente 0/318: el validador que nunca se ejecutó

Setenta y dos ADRs. Trescientas dieciocho restricciones. Un comando que existe para exigirlas. Y cero ejecuciones completas en toda la historia del repositorio — desde el primer commit

Jesús Pérez
El contrato que habría cazado el defecto estaba escrito, exportado, y ANUNCIADO EN UN COMENTARIO tres líneas encima del campo que debía proteger. No estaba enchufado a nada. Así que convivieron cinco dialectos incompatibles del mismo registro, el ejecutor murió con el primero que se encontró —y se llevó por delante las 318 restricciones de los 72 ADRs—, y `adr validate` no completó una sola ejecución desde el commit inicial. Ninguna restricción Hard fue jamás exigida por el comando que existe para exigirlas. Cuando por fin se ejecutó: 93 fallos, y 39 de ellos eran promesas que no podían pasar en ninguna máquina.
Expediente 0/318: el validador que nunca se ejecutó

🩺 Mostrar historia clínica → 📋 Protocolo de sesión →

Historia clínica · Servicio de Patología del Software

Setenta y dos ADRs. Trescientas dieciocho restricciones, doscientas cuarenta y nueve de ellas marcadas 'Hard. Un comando que existe precisamente para exigirlas: ontoref adr validate. Y cero ejecuciones completas en toda la historia del repositorio. Ni una. Ninguna restricción Hard fue jamás exigida por el comando que existe para exigirlas — y no desde una regresión reciente, sino desde el commit inicial, que git show fef21f4 firma sin discusión. El paciente no empeoró. Nunca estuvo vivo.

Historia Nº 0/318Diagnóstico: ANTI-PAP · EL CONTRATO DESCONECTADOEstado: RESUELTO · CON DEUDA DECLARADA
«Están todas en verde.» En realidad, nadie lo había dicho nunca — y ése es el cuadro. No hubo un check que mintiera, ni un número inflado, ni un acta falsa. Hubo un silencio, y el silencio se leyó como conformidad. Setenta y dos ADRs, cada uno con sus reglas Hard cuidadosamente redactadas, cada una con su check tipado al lado. El comando para ejecutarlas existía, estaba documentado, y moría en el primer fichero. Nadie lo notó porque nadie lo llamaba, y nadie lo llamaba porque moría.
Mostrar cuadro
restricción
Una regla que un ADR declara y que un check debe poder falsar. Lleva una severidad: 'Hard vincula, 'Soft se audita. La severidad dice cuánto obliga la regla. No dice —y aquí está el caso entero— si alguien la comprueba.
contrato
En Nickel, un predicado que se aplica a un campo y rechaza el fichero al exportarlo. Su virtud es que no se puede ignorar: o el dato pasa, o no hay dato. Un contrato escrito y no aplicado no es un contrato a medias: es un comentario.
dialecto
Dos formas de escribir el mismo dato que ningún esquema distingue: `cmd` y `command`, `paths` y `files`, `must_be_empty` y `absent_ok`. Sólo aparecen donde nadie tipa el registro. Y sólo se descubren cuando algo intenta leerlo.
deuda declarada
Una regla que vincula y que nada verifica, que lo DICE. No es verde ni roja: es una tercera palabra que hasta hoy no existía. Sin ella, todo lo que no se podía comprobar simplemente pasaba —o reventaba— y en ambos casos se leía como salud.

Protocolo para declarar, versionar y verificar esto → ontoref.dev

El doble balance — lo que costó, y lo que dejó

Las cifras de la izquierda son el cuadro clínico. Las de la derecha, el alta. Y conviene mirar de frente el cero que las preside: «ejecuciones completas del validador en toda la historia del repositorio: 0». No es un cero pequeño. Es la medida exacta de la distancia entre declarar una regla y exigirla — y esa distancia había sido, hasta hoy, invisible por construcción, porque el sistema no tenía ninguna palabra para nombrarla.

Lo que costó el crimen

  • ADRs en el corpus 72
  • Restricciones que declaran 318 · 249 de ellas 'Hard
  • Ejecuciones completas del validador, en toda la historia del repo 0
  • Erratas que actuaban de interruptor general 2
  • Restricciones que cada una de esas erratas apagaba las 318
  • Commit en el que ya estaban las dos fef21f4 · «init repo»
  • Dialectos incompatibles del mismo registro 5
  • Fallos revelados en la primera ejecución completa 93
  • …que no podían pasar en NINGUNA máquina, nunca 39 de 93
  • Checks que invocaban un alias de shell en vez de un binario 33
  • Tags en el enum que el ejecutor nunca implementó 1 · 'Cargo · 3 restricciones Hard despachadas a nada
  • Ejecutores en la sombra con su propia definición del mismo tag 1 · con 0 llamantes
  • Gates que no podían fallar por construcción 3
  • ADRs con sintaxis bash dentro de un NuCmd 5 · dos los encontró la regla reparada, no yo
  • Violaciones reales bajo todo esto 2

Lo que el caso dejó

  • La regla un contrato que no se aplica no es un contrato: es un comentario
  • El interruptor un check inservible es un HALLAZGO sobre su ADR, jamás un crash
  • La tercera palabra ⊘ vincula, y nada lo verifica — ni verde ni rojo: deuda
  • El precio de confesar gate_source: nombra lo que la saldaría, o no se acepta
  • El caso negativo, escrito 14 aserciones · una por cada defecto desenterrado
  • …y en la cadena just test-adr-contract · just ci-adrs
  • El validador, hoy 169 Hard ✓ · 35 ✗ · 22 ⊘ · 60 Soft auditadas

El punto de abandono — lo que no sale en la tabla

El punto de abandono estuvo aquí, y estuvo cerca. Con el validador ya arrancando y noventa y tres fallos en pantalla, la salida cómoda era evidente: son fallos viejos, son de layout, son de entorno, el repositorio se movió, ya se mirarán. Es decir: dejar el número en noventa y tres y no preguntar de qué está hecho. Y de haberlo hecho, se habría perdido lo único que importa del caso — porque treinta y nueve de esos noventa y tres no son fallos. Son restricciones que no podían pasar en ninguna máquina, nunca, y que llevaban meses leyéndose como enforcement. La tentación no era ignorar el problema: era contarlo sin desmenuzarlo. Un noventa y tres es un número; un treinta y nueve infalsable es un diagnóstico.

Diagnóstico diferencial — lo que se descartó

Las dos erratas“«Fueron dos erratas.» Lo fueron: `command =` donde el ejecutor lee `cmd`, y `paths =` donde leía `path`. Pero una errata que rompe SU restricción es una errata. Una errata que rompe LAS OTRAS 317 es un interruptor general, y eso ya no es la errata: es que el ejecutor moría con `column_not_found` en vez de decir «este check no sé leerlo». La errata fue el disparador. El arma estaba cargada desde antes.”descartado — es el disparador, no el arma
El ejecutor frágil“«El ejecutor estaba mal escrito.» Lo estaba, y aun así es el síntoma. Reventaba porque se encontraba formas que no esperaba — y se las encontraba porque NADIE TIPABA EL REGISTRO. El `check` era un record abierto: `command`, `files`, `absent_ok`, un `Grep` con vocabulario de `FileExists`. Cinco dialectos, todos Nickel legal. Endurecer el ejecutor sin cerrar el contrato es enseñar al paciente a sobrevivir a la infección.”descartado — es el síntoma
Nadie ejecutaba el validador“«Es que nadie ejecutaba el validador.» Casi. Nadie lo ejecutaba PORQUE NO PODÍA COMPLETARSE — moría en el primer ADR malformado y devolvía un error de columna que no dice nada. Un comando que revienta no se convierte en costumbre. Pero el hallazgo real está debajo: nada en la cadena de CI lo llamaba, así que su muerte no le dolía a nadie. Un gate fuera de la cadena es un ritual privado.”descartado — y ahí asoma el hallazgo
«'Hard significa que está garantizado»“«'Hard significa que está garantizado.» CULPABLE, y es el diagnóstico. `'Hard` dice cuánto OBLIGA la regla. No dice —no decía— si alguien la comprueba. Treinta y nueve restricciones marcadas Hard no podían pasar en ninguna máquina, nunca: treinta llamaban a validadores que jamás se construyeron, seis no llevaban check ninguno, tres usaban un tag sin ejecutor. Se leían como enforcement. Eran deseos con severidad. El sistema no tenía una palabra para «vincula y nada lo verifica», y todo lo que no tiene palabra se lee como salud.”CULPABLE — y no es de nadie: es del vocabulario

Etiología — la causa — adr-schema.ncl — un contrato anunciado en un comentario y enchufado a nada

// adr-schema.ncl

// Required fields per tag (validated by EachCheckWellFormed in adr-constraints.ncl):
//   'Grep -> pattern : String, paths : Array String, must_be_empty : Bool
//   'NuCmd -> cmd : String, expect_exit : Number
let constraint_check_type = {
  tag | check_tag_type,
  ..                      // ← record ABIERTO: cualquier campo vale
} in

...

constraints | Array constraint_type
            | c.NonEmptyConstraints
            | c.EachConstraintHasCheck
            //  ↑ y EachCheckWellFormed NO está aquí

// El contrato existe. Está exportado. Está anunciado en el comentario
// de arriba. No está enchufado a nada.

Y no es sólo el check. 'Cargo llevaba en el enum de tags desde el primer commit y el ejecutor no lo implementó nunca — mientras un SEGUNDO run-check, escondido en adr.nu, definía el mismo tag de otra forma incompatible. Dos significados de una palabra, en dos ficheros, sin saber el uno del otro. Las tres restricciones Hard que usan la forma del esquema respondían «Cargo: cmd is empty» desde siempre. Comprobé los dos dialectos privados de adr.nu contra los 72 ADRs: ningún ADR usa ninguno. Se mantenían para cero llamantes, y el precio era secuestrar el tag de los tres que sí existen.

Tratamiento — Enchufar la tubería, desarmar el interruptor, y darle al sistema la palabra que le faltaba

# 1. El contrato, enchufado. Lo que era legal deja de serlo, al exportar.

constraints | Array constraint_type
            | c.NonEmptyConstraints
            | c.EachConstraintHasCheck
            | c.EachCheckWellFormed     # ← la tubería que faltaba

# 2. El interruptor, desarmado. Un check que el ejecutor no sabe leer
#    es un hallazgo CONTRA SU ADR — y los otros 264 siguen corriendo.

  UNRUNNABLE CHECK — NuCmd check has no `cmd` (has: command, expect_exit).
  This constraint has never been enforced.

# 3. La tercera palabra. Y confesar CUESTA:

  'Hard + gateable      →  exigida. Rojo = el código está mal.
  'Hard + NO gateable   →  VINCULA Y NADA LA VERIFICA. No es verde.
                           `gate_source` nombra lo que la saldaría,
                           y sin él el contrato RECHAZA el fichero.
                           Con un check, también: un check que se admite
                           que no gatea nada es teatro.

Y hay una confesión que va en el expediente porque es la prueba, no la anécdota: el mecanismo gateable/gate_source lo declara obligatorio el ADR-071 —«una regla que el checker no puede falsar DEBE marcarse inverificable EN EL DATO»— y no existía. Ni un campo. Su check corría el test de otro oráculo, así que pasaba en verde sobre un mecanismo que nunca se construyó. Y el ADR-072 lo citó como precedente. Una promesa en tiempo futuro, citada como jurisprudencia, dentro de los dos ADRs que denuncian esa clase. Ahora existe, y confesar cuesta: sin gate_source el contrato rechaza el fichero.

Pronóstico

La serie pregunta: ¿con ontoref no hubiera sido así? Y este caso obliga a responder con incomodidad, porque el mecanismo no es que faltara: es que estaba escrito y desconectado. El contrato que habría cazado las cinco formas ilegibles llevaba desde el primer commit en el repositorio, exportado, con su nombre, anunciado en un comentario tres líneas encima del campo que debía proteger. Nadie lo escribió mal. Nadie lo borró. Sencillamente, no se conectó — y un contrato que no se aplica no es un contrato a medias: es un comentario. El resto cae solo. Cinco dialectos del mismo registro se vuelven legales. El ejecutor muere con el primero que se encuentra, y muere de la peor manera: no reportando que no sabe leerlo, sino reventando y llevándose las trescientas dieciocho por delante. Y como ninguna receta de CI lo llamaba, su muerte no le dolió a nadie. Setenta y dos ADRs siguieron declarando reglas Hard durante meses, y las reglas eran ciertas, y estaban bien escritas, y no las comprobaba nada. Lo que hace que este caso valga —lo que lo separa de una anécdota de tubería mal conectada— es lo que apareció debajo cuando el validador por fin arrancó: treinta y nueve restricciones Hard que no podían pasar en ninguna máquina, nunca. Treinta llamaban a validadores que jamás se construyeron. Seis no llevaban check ninguno. Tres usaban un tag que el ejecutor no implementa. No estaban rotas: estaban escritas en tiempo futuro, y marcadas con la palabra que se lee como una garantía. El protocolo no tenía forma de distinguir «esto lo comprueba una puerta» de «esto lo comprobará alguien algún día». Y todo lo que un sistema no puede nombrar, lo cuenta como salud.

Un contrato escrito y no aplicadoSe enchufa. EachCheckWellFormed estaba escrito, exportado y anunciado en un comentario tres líneas encima del campo que debía proteger. Un comentario no se consulta, no se verifica y no puede contradecir a nadie.
Un check malformado que revienta al ejecutorSe reporta como UNRUNNABLE contra el ADR que lo escribió, y los demás siguen corriendo. Un check que no puede mirar y además anula la mirada de todos los demás es peor que la lista vacía: es un interruptor general.
Una regla que vincula y que nada verificagateable = false + gate_source. Ni verde ni roja: deuda declarada, con la dirección de quien la salda. Y la confesión no es gratis, o sería una puerta trasera para poner cualquier gate rojo en verde.
Un check cuyo oráculo vive en el perfil de tu shellore y onre son alias, no binarios. El ejecutor corre nu --no-config-file; CI tampoco tiene alias. Una restricción que sólo puede pasar en el portátil de su autor no es una restricción.
Un tag que el contrato admite y el ejecutor no implementaSe implementa, o se saca del enum. 'Cargo llevaba desde el primer commit en el enum, sin ejecutor — y un segundo run-check en la sombra lo definía de otra forma incompatible. Tres restricciones Hard despachaban a nada.
Una falsificación hecha a mano se evaporaSe escribe. Cada reparación de esta autopsia se falsó a mano, y una falsificación a mano no deja nada que rechace el mismo defecto mañana. Catorce aserciones, en la cadena.

La pauta — la sesión, repetida con protocolo

Lo que se pidió — reconstruido de outreach/.coder/2026-07_12_spanish_terms_complete_done.md

lee .coder/2026-07_12_spanish_terms_done.md
completa el ADR que quedó pendiente al final

Lo que había que pedir

Completa el ADR-072 que quedó pendiente al final de .coder/2026-07_12_spanish_terms_done.md.

Antes de tocar la prosa:
1. Ejecuta `ontoref adr validate` sobre el corpus ENTERO y pega el resultado —
   la ejecución completa o el error exacto con que muere. Un ADR sobre cobertura
   no se completa encima de un validador que no corre.
2. Cada afirmación que añadas nombra su verificable: el comando que hoy la falsa,
   o gateable = false + gate_source con la dirección de quien la saldará.
3. Si una microtarea descubre un contrato sin decidir —un campo que un ADR promete
   y no existe—, PARA y repórtalo. No lo cites como precedente.

Al cierre: adr? — evalúa si la sesión deja decisiones con peso arquitectónico.
MicrotareaVerificable
Ejecutar el validador completo antes de leer o escribir prosaontoref adr validate termina — el contador de ejecuciones completas deja de ser 0
Desmenuzar cada fallo: ¿viola el código, o la restricción es infalsable?cada uno de los 93 clasificado —violación real, check inservible o promesa sin oráculo— con su cuenta
Construir el primitivo que falta ANTES de usarlonickel export rechaza un gateable = false sin gate_source — visto rechazar, no supuesto
Marcar las 22 infalsables por script, nunca a manolos 72 ADRs satisfacen el contrato y just test-adr-contract pasa
Dejar el caso negativo de cada defecto desenterrado14 aserciones en just ci-adrs, una por defecto — una falsificación a mano se evapora

La puerta antes de delegar: El contrato y su test existen ANTES de soltar al agente sobre los 72 ADRs: adr-constraints.ncl exporta y just test-adr-contract corre. Sin la puerta cerrada, el agente improvisa el contrato que le falta — y lo cita como jurisprudencia. Pasó: ADR-072 citó como precedente un mecanismo de ADR-071 que nunca se construyó.

El disparador de ADR: La tercera palabra —vincula, y nada lo verifica— cambia el vocabulario del protocolo y revertirla tocaría los 72 ADRs: adr? da fuerte en los cinco criterios. Quedó en ADR-071/072.

La profilaxis — qué exige hoy la lección

  • Una regla que vincula y que nada verifica se declara en el dato — ni verde ni roja: deudacontract:.ontoref/adrs/adr-constraints.ncl#gateable-gate_source
  • La puerta declara lo que no puede comprobaradr:071/the-gate-declares-what-it-cannot-check
  • Un check extendido debe ser VISTO rechazar el modo de fallo que cubreadr:072/falsify-against-the-new-capability
  • Las catorce aserciones del caso negativo, en la cadenagate:just test-adr-contract · just ci-adrs
  • La pasada del validador COMPLETA sobre el corpus entero como condición de aceptación — un check inservible es hallazgo, nunca crashmode:validate-adrs/run-checks

Alta y profilaxis

El alta se firma con dos hechos que se sostienen solos. El primero: al enchufar el contrato, nickel export cazó un ADR malformado que yo no había encontrado leyendo con cuidado — la tubería, recién conectada, vio antes que su fontanero. El segundo: al apuntar la regla de ADR-010 al corpus donde de verdad aplica, encontró cinco ADRs con bash dentro de un NuCmd, y dos de ellos tampoco los había encontrado yo. Ésa es la diferencia entre revisar y exigir. Revisar es un acto que depende de quien revisa, y se agota con él. Un contrato enchufado no se cansa, no se distrae, y no se acuerda de nada — porque no le hace falta.

Glosario

¿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.