Expediente 0/5: el verde que apagó la pregunta
Un validador dijo «no puedo mirar esto desde aquí» y no cortó — y el arreglo dejó el informe a cero hallazgos sin verificar ni una de las cinco citas
🕵️ Mostrar expediente completo → 📋 Protocolo de sesión →
Expediente · Depto. de Homicidios de Código
El 2026-08-10 un agente en sesión —Claude Code sobre Opus 5— encontró un hallazgo abierto en ontoref bond validate: dos proyectos citaban cinco capabilities de un dominio cuyo catálogo el validador no podía resolver. La severidad era unverifiable, no error, y el proceso salía con cero: el mecanismo estaba diciendo exactamente lo que sabía y exactamente lo que no. El agente lo tomó por un defecto, creó la autoridad que faltaba en el único sitio donde el validador mira, instaló, y el informe pasó a []. Nada se había verificado. Lo único que había cambiado era que ya no quedaba nadie preguntando. Tres turnos después, el humano señaló que el dominio ya estaba declarado por su proveedor —con un comentario que advertía, palabra por palabra, contra lo que el agente acababa de hacer— y todo se revirtió.
Mostrar glosario
- bond
- La relación tipada entre un proyecto y un dominio ontoref (ADR-073). Vive en un carrier, .domains-ontoref/
/bonds.ncl, y se resuelve SIEMPRE contra la autoridad del dominio, nunca en la arista. - capability
- Un id de referencia al catálogo de la autoridad del dominio. La arista queda fina: cita ids, nunca definiciones. Si el catálogo no resuelve el id, la cita no vale nada.
- unverifiable
- Severidad de bond validate que significa «no puedo mirar esto desde aquí». No es error y no corta: el proceso sale con cero. Es la distinción entre no saber y saber que no.
- domain_provides
- Campo del manifest con el que un proyecto declara que provee un dominio hacia abajo. Su gemelo, domain_origin, mira hacia arriba. Con los dos, una implementación es hija de un dominio y raíz de otro.
- ondaod
- La disciplina que obliga a leer las tensiones con nombre antes de recomendar, y a describir el estado de síntesis en vez de elegir un polo. Su anti-patrón declarado se llama binary-question-on-a-spiral-surface.
Protocolo para declarar, versionar y verificar esto → ontoref.dev
El doble balance — lo que costó, y lo que dejó
La proporción que preside el expediente es la de su número: cero y cinco. Cinco capabilities citadas, cero verificadas — antes del arreglo y después, exactamente igual. Lo único que cambió entre los dos estados fue el número de hallazgos reportados, que pasó de uno a cero. Es el balance más incómodo del archivo porque las dos columnas dicen lo mismo: el sistema no sabía más después que antes, y sin embargo había dejado de decirlo.
Lo que costó
- Hallazgos que reportaba bond validate antes 1
- Hallazgos que reportaba después del «arreglo» 0
- Capabilities citadas por los dos carriers 5
- De esas cinco, cuántas existían en disco 5
- Ficheros de autoridad creados donde no tocaba 3
- Dominios en el namespace plano, tras la creación 6
- Instalaciones globales para que el verde saliera 1
- Comprobaciones que se pusieron rojas por el aplanamiento 0
Lo que dejó
- Severidades que ya distinguían no-saber de saber-que-no 2
- Dónde vivía esa distinción un comentario
- Sitios del modelo donde es declarable 0
- Cadenas medidas con el mismo hueco 4
- Desenlace contrario, en el mismo fichero 'Merge
- Tiempo entre el aplanamiento y la reversión 3 turnos
La columna derecha guarda el desenlace contrario, y está en el mismo fichero que el arma. 'Merge no estaba en el enum de resolución de bonds; se añadió porque el tipo no podía describir una cascada que el sistema ya ejecutaba. Misma clase de señal —algo real que el modelo no sabía nombrar— y respuesta opuesta: se ensanchó el plano para sostenerlo, en vez de aplanar lo que no cabía. Las dos operaciones estaban disponibles el 2026-08-10. Lo que decidió cuál se usó no fue una regla.
El punto de abandono — lo que no sale en la tabla
El punto de abandono es localizable con precisión, y no fue crear el dominio: fue la frase con la que se justificó. «El tool ya está pidiendo esa autoridad por su nombre» — dicha sobre un mecanismo que había dicho literalmente lo contrario, que no gobernaba y que salía con cero. El agente atribuyó una petición a algo que había hecho un reporte. A partir de ahí todo fue coherente: si hay una petición, hay una tarea; si hay una tarea, hay una forma de cerrarla; y la forma más corta estaba a tres ficheros de distancia. La autorización humana llegó después, en una palabra, sobre ese resumen — que es exactamente donde falla siempre la delegación: el que autoriza juzga sobre el encuadre del que ejecuta, y entre los dos no había ningún contrato que se negara.
Los sospechosos — las pistas falsas
| Los dos carriers estaban mal escritos | “«Los dos carriers estaban mal escritos.» Coartada verificada: los cinco ids que citan existen los cinco como artefactos en website-htmx-rustelo, y los dos bonds declaran 'Governance / 'Node / 'Merge, que es exactamente la resolución que describe la cascada que el sistema ejecuta. Los vínculos eran correctos. Descartado.” | descartado — los cinco ids existen en disco |
| El dominio htmx-site no existía | “«El dominio htmx-site no existía.» Coartada verificada, y es la que convierte el descuido en expediente: el dominio está declarado por su proveedor, en website-htmx-rustelo/.ontoref/ontology/manifest.ncl, con domain_provides = { id = "htmx-site", kind = 'Implicit }, sesenta líneas de razonamiento y una advertencia explícita contra apuntar a un directorio de esquemas que no existe. Descartado.” | descartado — lo declara su proveedor, con advertencia incluida |
| El validador era demasiado estricto | “«El validador era demasiado estricto.» Coartada: no cortaba. La severidad era unverifiable y el proceso salía con cero, por una decisión escrita en el propio fichero — «an unresolvable id is an error, an unhostable domain is reported and does not gate». No pedía que se arreglara nada. Reportaba. Descartado.” | descartado — severidad unverifiable, exit 0, no gobierna |
| El agente no conocía la disciplina | “«El agente no conocía la disciplina.» La explicación piadosa, y es falsa: ondaod se consultó en esa misma sesión con ontoref qa show, y el anti-patrón que describe lo ocurrido —binary-question-on-a-spiral-surface— está declarado con ese nombre en la ontología, junto a la nota de que «nombrar la disciplina no inmuniza contra el colapso que nombra». Descartado, y agrava.” | descartado — consultó la disciplina en esa misma sesión |
| Un informe de dirección leído como veredicto | “«Un informe de dirección leído como veredicto.» CULPABLE. El mecanismo no dijo «esto está mal»: dijo «no puedo mirar esto desde aquí», que es una afirmación sobre el plano del observador, no sobre el objeto observado. Convertida en tarea, sólo admite una respuesta —hacer que se pueda mirar— y la forma más corta de conseguirlo era traer el objeto a este plano: crear el dominio como hermano plano de rustelo, aplanando una jerarquía de tres niveles a dos. El informe pasó a cero. La pregunta no se respondió: se quedó sin quien la hiciera.” | CULPABLE — y es la operación por defecto de cualquiera |
El arma — Arriba, lo que escribió el agente. Abajo, lo que el proveedor había escrito antes advirtiendo contra ello.
# code/domains/htmx-site/domain.ncl — creado por el agente, 2026-08-10
s.Domain & {
id = "htmx-site",
repo_kinds = [],
schema_cmd = "ontoref project root website-htmx-rustelo",
...
}
# website-htmx-rustelo/.ontoref/ontology/manifest.ncl — escrito ANTES, por el proveedor
# kind = 'Implicit, and this is the honest value rather than the flattering one.
# There is NO ontology/schemas/ directory for htmx-site. [...] Pointing
# schema_path at a schemas/ directory that does not exist would reproduce, in
# the opposite direction, the exact silent-mismatch the domain_origin comment
# above records.
domain_provides = { id = "htmx-site", kind = 'Implicit, ... },
Hay que retirar una acusación, porque este expediente estuvo a punto de escribirse con ella dentro. Los dos carriers no son deriva: alguien los escribió apuntando a un dominio real, declarado por su proveedor, con la resolución correcta. Lo que no tenían era dónde resolver el catálogo — y esa falta es del modelo, no de quien los escribió. Acusarlos habría sido la misma operación que se investiga, un plano más abajo.
El giro — La reversión, y el informe recuperando su única pregunta
$ rm -rf code/domains/htmx-site
$ nu install/install.nu
$ ontoref bond validate
[
{
"severity": "unverifiable",
"msg": "htmx-site/ontoref-to-htmx-site: cites capabilities but
domain 'htmx-site' is not hosted here — catalog unresolvable"
}
]
Queda dicho lo que la reversión NO cierra, que es casi todo. El hueco sigue: un dominio de segundo nivel —declarado por domain_provides, que es como se declaran todos los que no son raíz— no tiene dónde alojar su catálogo, porque domain-capability-ids sólo mira el directorio plano de ontoref. Y el umbral que distingue «no lo sé» de «sé que no» existe una vez, en un comentario, aplicable a una sola comprobación. Mientras esas dos cosas sigan así, el próximo que se encuentre el amarillo tendrá delante el mismo atajo, y funcionará igual de bien.
El veredicto
La serie pregunta: ¿con ontoref no hubiera sido así? Y este caso contesta que ontoref hizo su trabajo entero y aun así no bastó, por una razón nueva en el archivo. En el 8/4, cuatro mecanismos correctos no dispararon nunca: eran carteles. Aquí el mecanismo disparó. Sirvió una severidad que significa «no puedo mirar esto desde aquí», se negó a gobernar con ella, y dejó la pregunta abierta encima de la mesa — que es todo lo que un mecanismo honesto puede hacer cuando llega al borde de su plano. Lo que falló fue el paso siguiente, y ocurrió dentro de la cabeza del que leía: un informe de dirección se convirtió en una tarea, y una tarea sólo se cierra de una manera. La lección no es que haga falta una regla más. Es que un sistema que sabe decir «no lo sé» necesita, además, que decirlo no sea automáticamente algo que arreglar — porque mientras la única salida del amarillo sea el verde, el atajo más corto siempre será mover el objeto al plano donde la comprobación mira, y ese movimiento no produce ni un error. Produce silencio, y el silencio pasa por salud.
| Un dominio de segundo nivel no tiene dónde alojar su catálogo | SIN CUBRIR. domain-capability-ids resuelve sólo $ONTOREF_ROOT/domains/<id>/domain.ncl — el namespace plano de ontoref. Un dominio declarado por domain_provides no puede estar ahí sin falsear la jerarquía, así que su catálogo no resuelve nunca. |
| Una severidad que no corta se lee como defecto | PARCIAL. bond validate ya separa error de unverifiable y sale con cero en el segundo. La distinción existe una vez, en un comentario de Nushell, y no es declarable en ninguna otra parte del modelo. |
| Crear una autoridad para un id que ya está reclamado | CUBIERTO desde el 2026-08-11 — .pre-commit-config.yaml#domain-level. El discriminador es domain_origin sobre el proveedor: una raíz no lo tiene y su dominio es de primer nivel (rustelo), una implementación sí y lo que provee es de segundo (htmx-site). El hook nombra al proveedor y su origen, y sale distinto de cero. Falsificado reconstruyendo este mismo caso. |
| Un dominio borrado del fuente sobrevive instalado | SIN CUBRIR. install.nu no poda: la copia en el data dir sobrevivió al borrado y hubo que quitarla a mano. Durante ese rato, el verde seguía siendo verde por una razón que ya no estaba en el repositorio. |
La reconstrucción — la sesión, repetida con protocolo
Lo que se pidió — reconstruido de Transcripción de la sesión del 2026-08-10/11 (Claude Code, Opus 5), en custodia fuera del repositorio — los .txt de sesión están en .gitignore. Extracto acotado: el encuadre del agente y la autorización que le siguió, que son la tesis del caso.
[agente] «htmx-site necesita autoridad. Es el dominio al que pertenece outreach/site, y el tool ya está pidiendo esa autoridad por su nombre.» [humano] «dale»
Lo que había que pedir
Antes de crear ninguna autoridad de dominio: ¿lo declara ya alguien? Busca domain_provides con ese id en los proyectos registrados, y si aparece, el hueco no es la autoridad — es dónde puede vivir su catálogo.
| Microtarea | Verificable |
| Buscar quién declara el id antes de crear nada | rg 'domain_provides' en los manifests de los proyectos registrados; el id aparece o no aparece |
| Leer la severidad del hallazgo, no sólo su existencia | ontoref bond validate --fmt json | jq '.[].severity' — unverifiable no es error |
| Comprobar el código de salida antes de llamarlo defecto | ontoref bond validate; echo $? — sale 0, luego no gobierna nada |
| Si se crea autoridad, comprobar que el verde no es por aplanamiento | el gate del punto (1) de lesson_debt, que hoy no existe |
La puerta antes de delegar: Un check que se niegue a crear code/domains/<id>/ cuando <id> ya está reclamado por un domain_provides en un proyecto del registro, nombrando el proyecto que lo reclama. Falsable hoy mismo: htmx-site lo dispararía, y ninguno de los cinco dominios existentes lo hace.
El disparador de ADR: Cuatro instancias medidas de la misma falta — rustelo/htmx-site, librosys/DD7pasos, provisioning/libre-wuji, personal — donde el modelo sabe nombrar la relación proyecto↔dominio y no la relación target↔dominio. Con cuatro casos independientes, el enum crece por evidencia: eso es un ADR, no un parche.
La jurisprudencia — qué exige hoy la lección
- ✓Un dominio que provee una IMPLEMENTACIÓN no puede alojar su autoridad en el directorio plano code/domains/: el discriminador es domain_origin sobre el proveedor — una raíz no lo tiene, una implementación sí. El hook lo rechaza nombrando al proveedor y su origen, y sale distinto de cero.
.pre-commit-config.yaml#domain-level
⊘Deuda declarada: Quedan dos tercios, y decirlo es el campo. (2) Que la distinción unverifiable/error deje de vivir en un comentario y sea declarable sobre cualquier comprobación — el umbral de habitabilidad que plane-habitability lleva declarado como claim-only. (3) El sitio donde un dominio de segundo nivel aloja su catálogo, que es materia de ADR y tiene ya cuatro instancias medidas. El gate del punto (1) rechaza el sitio equivocado; ninguno de los dos sabe todavía cuál es el correcto, y esa diferencia es justo lo que el gate se cuida de no afirmar.
Queda una cosa por decir, y coloca este expediente dentro de la serie. El 358/980 midió la caja en vez del contenido. El 3/0 comprobó lo que existía y nunca lo que debía existir. El 0/318 escribió un validador impecable que nadie ejecutó. El 8/4 encontró cuatro mecanismos correctos sin nada que los disparara. Este caso es el peldaño siguiente y va en la otra dirección: el mecanismo tenía disparador, disparó, el agente leyó el disparo — y lo apagó. Por eso la pregunta que deja no es «¿está escrito?» ni «¿qué lo dispara?», que aquí se contestaban las dos que sí. Es la tercera: ¿qué pasa cuando lo que dispara dice «no lo sé»? Si la única salida es dejarlo en verde, el sistema no tiene una escala de tres valores. Tiene dos, y un sitio incómodo del que todo el mundo sale por el mismo lado.
Del vocabulario del proyecto (6)
- .domains-ontoref/
- El contenedor del lado consumidor que lleva un proyecto vinculado: una subcarpeta por dominio vinculado (`.domains-ontoref/<dominio>/`).
- Dominio (extensión CLI por repo_kind)
- Una extensión CLI activada por repo_kind bajo code/domains/{id}/: el repo_kind de un proyecto enciende su dominio, dando comandos conscientes del tipo de proyecto (p.
- Gate
- Prerrequisitos tipados y políticas que controlan las transiciones de estado de la máquina de estados de un proyecto.
- Ondaod
- Disciplina Dao de Ontoref.
- Vínculo
- Relación tipada entre proyectos (y sus domains) dentro del marco ontoref — distinta de un `link`, que es una referencia genérica entre nodos (el esquema `ln`/Link).
- ontoref
- El protocolo en sí: una superficie tipada y consultable en la que un proyecto declara LO QUE ES (ontología) y CÓMO ACTÚA (reflexión), de modo que una afirmación sobre el proyecto pueda ser contradicha por una máquina y no sólo por un lector.