Expediente 18/0: el verbo que informó un alta
Tres superficies decían que la tarea estaba creada. Ninguna de las tres había mirado el fichero — y el fichero no había cambiado en veintiséis días
🕵️ Mostrar expediente completo → 📋 Protocolo de sesión →
Expediente · Depto. de Homicidios de Código
Le pedí al proyecto que registrase una tarea. El comando respondió «New backlog item: bl-044», con su identificador, su título y su prioridad. El log de acciones lo anotó como escritura. El manual, desde el primer día del repositorio, prometía «create new item». Escribí el identificador en un registro gobernado que ya apuntaba a él. Y solo mucho después, redactando otra cosa, pregunté al almacén cuál era su último elemento. Contestó bl-043. Ejecuté git diff --stat sobre el fichero: cero líneas. El alta no existía, no había existido nunca, y tres superficies distintas me habían confirmado que sí.
Mostrar glosario
- verbo
- Un subcomando de la CLI que muta estado: `add`, `done` o `cancel` sobre la cartera de pendientes, `qa add` sobre el almacén de preguntas. Es la superficie por la que una persona o un agente muta el estado declarado del proyecto. A diferencia de un paso de un mode, nadie le pedía nunca que demostrase su efecto.
- verificación derivada
- La regla de ADR-066: un paso que declara un `verify` no decide si funcionó — lo decide el código de salida de la comprobación, y un auto-informe que la contradiga se rechaza. Existía, estaba aceptada, y alcanzaba a los pasos de un mode. No a los verbos.
- log de acciones
- El registro de auditoría de la CLI: cada verbo declara si su acto es de lectura o de escritura. Es la superficie a la que se acude para saber qué tocó una sesión. Su valor entero depende de que lo declarado coincida con lo ocurrido.
- validar antes de sustituir
- Escribir el candidato al lado del fichero real, exportarlo con Nickel y solo entonces moverlo encima. Si el contrato lo rechaza, el almacén no llega a enterarse. Lo contrario —escribir y luego comprobar— deja el fichero roto en el disco mientras se decide qué hacer.
Protocolo para declarar, versionar y verificar esto → ontoref.dev
El doble balance — lo que costó, y lo que dejó
Lo que costó el crimen
- Superficies que afirmaban el alta 3
- …que hubieran mirado el fichero 0
- Sentencias
printenbacklog add18 - Escrituras en
backlog add0 - Primer commit del repo en el que ya era así fef21f4 · 2026-07-10
- Días demostrables en los que las tres superficies coincidieron 26
- Commits que tocaron el fichero en esa ventana 2
- …que cambiaran esto 0
- Opciones aceptadas por la firma del comando 3
- …emitidas en el registro que imprimía 0
- Verbos del despachador que declaran
write65 - …que no escriben, hallados al auditarlos 2
- Identificador anunciado por el comando bl-044
- Identificador presente en el almacén tras anunciarlo ninguno
- Lo que lo delató
git diff --stat· 0 líneas - Tamaño del arreglo 129+ / 28− en 3 ficheros
Lo que el caso dejó
- La regla un verbo que declara una escritura no es un verbo que escriba
- El cerrojo escribe, RELEE el almacén, y refusa si el identificador no vuelve
- El segundo cerrojo valida el candidato con Nickel antes de sustituir el fichero
- El escape que no existe
%{no tiene escape en cadena Nickel normal — se rechaza por nombre - El hermano correcto
qa addya escribía, y ya refusaba la entrada malformada - El tercer verbo
backlog promoteanotaba escritura y solo imprime — corregido - El resto, con dirección el resto declarado — nada audita los otros 63
Los sospechosos — las pistas falsas
| «El alta la escribió el daemon en otro sitio» | “«El alta la escribió el daemon en otro sitio.» Razonable: este proyecto tiene un daemon que cachea exportaciones y varias raíces posibles según la variable de entorno. Se descarta buscando el identificador en el árbol entero: cero coincidencias, en cualquier fichero, bajo cualquier raíz. Y `git status` no reportaba ningún fichero tocado.” | descartado — cero coincidencias en el árbol |
| «Faltaba una confirmación explícita» | “«Faltaba una confirmación explícita.» También razonable: mutar una superficie gobernada sin pedir permiso sería lo contrario de lo que este proyecto predica, así que un `--write` explícito hubiera sido una decisión defendible. Se descarta leyendo el comando entero: no había ninguna rama que escribiese, ni con opción ni sin ella. No faltaba el permiso. Faltaba la escritura.” | descartado — no faltaba permiso, faltaba escritura |
| «Es el diseño: imprime para pegar a mano» | “«Es el diseño: imprime un registro para pegar a mano.» Esta era la buena hipótesis, y estuvo viva un rato — hasta que miré a sus hermanos. `backlog done` y `backlog cancel`, en el mismo módulo, parchean el fichero. `qa add`, en otro, escribe y además refusa por nombre la entrada malformada. Si imprimir fuese el diseño, sería el diseño de uno solo de los cuatro. No era una convención: era una anomalía con veintiséis días.” | descartado — sus tres hermanos sí escriben |
| «Si el comando dice creado y el log dice escritura, está creado» | “«Si el comando dice creado y el log dice escritura, está creado.» CULPABLE. Y no es de nadie: es la creencia por defecto. Lo que hace de esto un caso y no una errata es que las tres superficies eran COHERENTES ENTRE SÍ. Contrastar el mensaje contra el log confirmaba el alta. Contrastar el log contra el manual, también. La deriva no era contradictoria: era consistente, y por eso resistía cualquier contraste que no fuese contra el fichero. La única pregunta que la rompía es la que nadie hace después de un mensaje de éxito.” | CULPABLE — y coherente consigo misma |
El arma — Dieciocho sentencias que imprimen, y dos superficies más repitiéndolo.
# modules/backlog.nu — el final de `backlog add`, tal como estaba. # Dieciocho sentencias. Todas print. Ninguna toca el disco. print $"New backlog item: ($new_id)" print "Add to reflection/backlog.ncl:" print $" id = \"($new_id)\"," ... # Y las otras dos superficies, que decían lo mismo sin haber mirado tampoco: bin/ontoref.nu:916 log-action $"backlog add ($title)" "write" nulib/help.nu:140 "create new item" # El hermano de al lado, en el mismo módulo, SÍ escribía: modules/backlog.nu:268 def backlog-set-status ← done y cancel parchean el fichero # Tres afirmaciones coincidentes. Cero lecturas del almacén. # Un agente que contrastara cualquiera de las tres contra otra quedaba igual de convencido.
El identificador se calculaba como el máximo más uno sobre los existentes. Sin escritura, dos sesiones seguidas reciben el mismo. El comando no solo no creaba: repartía el mismo número a quien lo pidiese.
El giro — Escribe, y después se somete al almacén.
# 1. Escribe. Y después NO se cree a sí mismo: relee el almacén y exige verse en él.
# Es adr-066 —la comprobación decide, nunca quien informa— aplicada a un verbo
# en vez de a un paso de un mode.
let landed = (backlog-load | where id == $new_id)
if ($landed | is-empty) {
error make {
msg: $"backlog add: se escribió ($file) y ($new_id) NO está al releerlo —
me niego a informar de un alta que el almacén no confirma"
}
}
# 2. Y antes de sustituir, el contrato del propio almacén decide:
$patched | save -f $candidate # al lado, nunca encima
let check = (do { ^nickel export $candidate } | complete)
if $check.exit_code != 0 {
rm -f $candidate # el almacén no se entera
error make { msg: $"...no se escribió NADA. nickel dijo: ($check.stderr)" }
}
mv -f $candidate $file
# El log de acciones recibe ahora el acto que de verdad ocurre, no el que se pretendía.
Los rechazos se probaron contra lo que deben rechazar, no solo contra lo que deben aceptar: un kind fuera del enum y un título con %{. En los dos, el fichero quedó intacto, con el mismo digest, y sin candidatos huérfanos.
El veredicto
La serie pregunta: ¿con ontoref no hubiera sido así? Y este caso responde que la regla ya existía y ya se ejecutaba. ADR-066 dice, con severidad Hard, que un paso que declara una comprobación no decide su propio estado: lo decide el código de salida, y un auto-informe que lo contradiga se rechaza. Está aceptada, tiene su comprobación tipada, y corre sobre cada paso de cada mode de este proyecto. Lo que este expediente encuentra no es una ausencia: es una frontera. La regla empieza cuando un mode arranca, y un agente teclea verbos mucho antes de eso. Al otro lado de esa frontera, el verbo se certificaba a sí mismo con la misma naturalidad con la que, dentro, tenía prohibido hacerlo. Y hay algo peor que una superficie que miente, que es tres que se corroboran: el mensaje, el registro de auditoría y el manual decían lo mismo desde el primer commit del repositorio, así que cualquier contraste entre ellas devolvía coherencia. La deriva no era detectable comparando declaraciones. Solo lo era preguntando al almacén — que es exactamente lo que un mensaje de éxito consigue que nadie haga.
| El verbo se certificaba a sí mismo | ADR-066 ya lo prohibía: la comprobación decide, y un auto-informe que la contradiga se rechaza. Alcanzaba a los pasos de un mode y no a los verbos de la CLI. El arreglo extiende la misma regla: escribe, relee el almacén, y refusa si su efecto no vuelve. |
| Tres superficies afirmando lo mismo sin haber mirado ninguna | Una verdad en tres sitios, casada a mano: exactamente la enfermedad que el propio manual de esta serie declara sobre sí mismo. Ahora el log recibe el acto que ocurre y el help dice que escribe el fichero. Las tres siguen siendo tres, y ninguna es ya la fuente. |
| Tres opciones aceptadas y descartadas en silencio | --adr, --mode y --dim se recogían y no se emitían. Una opción de línea de comandos que se toma y se tira es peor que una que no existe: quien llama no tiene forma de notarlo. Ahora se emiten bajo los nombres del esquema. |
| Un texto con comillas podía romper el almacén | El título y el detalle se interpolaban crudos en una cadena Nickel. Ahora se escapan; y %{, que abre interpolación y no tiene escape —comprobado en las tres formas—, se rechaza por nombre en vez de maquillarse. Sobre todo ello, validar antes de sustituir. |
| El verbo 64 que haga lo mismo mañana | SIN CUBRIR, y declarado: nada compara un verbo que dice escribir con si escribe. Los dos hallados se corrigieron a mano. La forma es la de ADR-072 —cobertura afirmada y jamás contrastada con el alcance— y tiene dirección en bl-045. |
La reconstrucción — la sesión, repetida con protocolo
Lo que se pidió — reconstruido de refs:sessions/2026-08-05-assess-signal-y-el-verbo — extracto acotado en custodia. NO es el prompt de apertura de la sesión: es el que abrió el trabajo donde ocurrió la deriva, que es lo que el replay reconstruye. Con sus erratas: una cita corregida deja de ser cotejable. Sesión identificada por el trabajo — 71 menciones de `backlog add`.
además el backlog add noe es del todos correcto, tiene carencias ¿ no ¿
Lo que había que pedir
Un verbo dice que escribe. Antes de creerle, mira el fichero. 1. Contrasta contra el ARTEFACTO, no contra otra superficie. Tres superficies coherentes entre sí no son tres confirmaciones: pueden ser un solo error repetido. 2. Un verbo que declara escribir se comprueba con `git diff` o con la mtime del fichero, nunca con su propio mensaje de salida. 3. Si el sistema tiene un registro de acciones, pregunta quién lo EMITE: una entrada escrita AL LADO de la escritura puede registrar una mutación que no ocurrió. 4. Y cuando encuentres uno, no lo arregles solo: cuenta cuántos verbos declaran lo mismo. Uno es una errata; el número dice si es un caso.
| Microtarea | Verificable |
| Comprobar el efecto contra el fichero, no contra la salida | git diff --stat .ontoref/reflection/backlog.ncl tras ejecutar el verbo — cero líneas es el hallazgo |
| Desconfiar de superficies que se confirman entre sí | mensaje, registro y manual coincidían; el fichero no. La coincidencia de tres no es prueba |
| Preguntar quién EMITE la entrada del registro | rg -n 'log_action' code/crates --type rust — la entrada va al lado de la escritura, no la emite ella |
| Contar el resto antes de dar por cerrado el arreglo | 233 llamadas al registro, 65 declaran escritura; auditar las 65 y no solo la que se cayó |
La puerta antes de delegar: Antes de aceptar «hecho» de un verbo que declara escribir, tiene que estar escrito con qué comando se comprueba el FICHERO. Aquí no lo estaba, y la deriva sobrevivió justo por eso: no era contradictoria, era consistente — mensaje, registro y manual decían lo mismo, y ninguno había mirado el disco. Un contraste entre superficies que se derivan unas de otras no es un testigo: es el mismo error citado tres veces.
El disparador de ADR: Sí, y sigue sin declararse como restricción: que la entrada del registro de acciones la EMITA la escritura en vez de ir a su lado. Mientras vayan separadas, una mutación que no ocurre se puede registrar igual — y eso es este caso, no su anécdota. Dirección: bl-045.
La jurisprudencia — qué exige hoy la lección
- ✓Quien ejecuta no certifica: el estado lo decide la comprobación, y un auto-informe que la contradiga se rechaza
adr:066/check-decides-never-reporter - ✓Un elemento que rompería el contrato del almacén se rechaza antes de sustituir el fichero, y el almacén no llega a enterarse
contract:.ontoref/reflection/schemas/backlog.ncl#kind
⊘Deuda declarada: Nada compara un verbo que declara escribir con si escribe. El despachador hace 233 llamadas al log de acciones, 65 declaran escritura, y la auditoría del 2026-08-05 encontró dos que no mutan nada; ambas se corrigieron a mano y nada impide la tercera. Lo saldaría que la entrada del log la EMITA la escritura en vez de ir a su lado — así una mutación que no ocurre no se puede registrar. Dirección: bl-045.
Del vocabulario del proyecto (1)
- 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.