Expediente 2/16: el arreglo que no arregló nada

Dieciséis títulos rotos, un arreglo, un build en verde — y los dieciséis títulos intactos, porque la clave se calculaba en dos sitios y cambié el que nadie lee

Jesús Pérez
Dieciséis de veinte páginas servían el nombre de una clave rota como título, a 200, incluidas la política de privacidad y el aviso legal. Encontré la derivación culpable, la arreglé, recompilé, y el build salió en verde. Los dieciséis títulos siguieron igual: la clave se calcula en DOS crates y arreglé el que la cabecera no lee. Y mientras lo perseguía, descubrí que la respuesta guardada del proyecto —verificada, con fecha— afirmaba que un mecanismo no existía. Existía, aplicado, con su variable de entorno exportada. Un build en verde no dice que el arreglo entró: dice que compila.
Expediente 2/16: el arreglo que no arregló nada

🕵️ Mostrar expediente completo → 📋 Protocolo de sesión →

Expediente · Depto. de Homicidios de Código

Dieciséis de veinte páginas servían el nombre de una clave rota como <title>, a 200, incluidas la política de privacidad y el aviso legal. Encontré la derivación culpable, la arreglé, recompilé, y el build salió en verde. Los dieciséis títulos siguieron exactamente igual. La clave se calcula en DOS sitios, en dos crates distintos, y yo había arreglado el que el <head> no lee. Y esto es solo la mitad del caso: mientras perseguía eso descubrí que la respuesta guardada del proyecto —verificada, con fecha, escrita para que nadie tuviera que adivinar— afirmaba que un mecanismo no existía. Existía. Estaba aplicado. Con su variable de entorno exportada y los ficheros del consumidor ya escritos. Estuve a un comando de reimplementarlo.

Caso Nº 2/16Clasificación: ANTI-PAP · DOS FUENTES PARA UN HECHO, Y UN DOCUMENTO QUE DEJÓ DE SER CIERTOEstado: RESUELTO
Mostrar glosario
derivación
La regla que convierte un dato en otro: de `OntorefPage` a la clave `ontoref-page-title`. Una derivación es un HECHO calculado, y un hecho calculado en dos sitios son dos hechos que acabarán discrepando. La pregunta no es si divergen: es cuándo.
costura
El punto por donde un consumidor añade algo suyo sin tocar la implementación: aquí, sus propias rutas, fusionadas al arrancar sobre las que trae la imagen compartida. Una costura que existe y que nadie sabe que existe no sirve de nada — y es peor que no tenerla, porque el que la busca y no la encuentra construye una segunda.
howto
Una respuesta guardada en el registro de conocimiento del proyecto, con su fecha y su marca de verificada. Existe para que nadie tenga que adivinar. Y por eso mismo, cuando deja de ser cierta, es más peligrosa que no tener nada: con documentación, dejas de mirar.
clave Fluent
Cada texto de una página estática vive en una clave. Y hay dos formas de matar el fichero entero: repetir una clave, o escribir una sin valor. La segunda la cometió el generador que este mismo autor había blindado contra la primera.

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

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

Mira la proporción que preside la tabla: dos derivaciones, dieciséis títulos. No es un error grande. Es un error duplicado, que es otra cosa: un defecto que sobrevive a su propia reparación y, mientras tanto, consume la confianza del que lo reparó. Y fíjate en el cero de abajo del todo: «veces que existe el comando de verificación que dos documentos mandan ejecutar». Cero. Ahí no hay una red rota; hay una red pintada en el suelo.

Lo que costó el crimen

  • Rutas que el sitio declara 24
  • Títulos que servían el nombre de una clave rota, a 200 16 de 20
  • Derivaciones de esa clave, en dos crates distintos 2
  • La que arreglé primero la que el <head> NO lee
  • Títulos rotos DESPUÉS de recompilar con ese arreglo 16 · los mismos
  • Días que la derivación duplicada llevaba viva (git) desde el 2026-07-10
  • El howto que consulté: fecha y marca 2026-07-13 · verified: true
  • …y lo que afirma «un consumidor NO PUEDE declarar sus propias rutas»
  • El mecanismo que dice que no existe existe, aplicado, con su variable de entorno exportada
  • Ficheros de rutas del consumidor que ya estaban escritos 2 · es.ncl y en.ncl
  • El verificador que ese howto manda ejecutar ore rustelo routes --check
  • Veces que ese comando existe 0 · ni el alias, ni el subcomando
  • Invocaciones de ore —un alias que YA NO EXISTE— en la base de conocimiento 355
  • Ficheros que lo invocan 83 · 21 de ellos ADRs
  • Invocaciones de onre (el alias de HOY, mismo defecto sin romper) 126
  • El comando real, que ninguno nombra ontoref
  • Veces que el expediente 0/318 ya condenó esto 1 · «alias, no binarios»
  • Checks ejecutables que aquel caso arregló 33
  • Invocaciones en PROSA que dejó intactas 481
  • Páginas que PARECÍAN curadas, por coincidencia 1 de 2
  • Claves Fluent que mi generador borró con un valor vacío 9 · mientras 1861 seguían
  • Cerrojos que yo había escrito contra eso 1 · el de los duplicados. Hacían falta 2.
  • Títulos rotos al final 0 de 20

Lo que el caso dejó

  • La regla arreglar una de dos derivaciones no cambia nada, y parece que lo cambia todo
  • La derivación una sola, pública, y el generador del <head> la LLAMA en vez de copiarla
  • La cabecera el <head> lee el registro de rutas, igual que el cuerpo — se acabó la media página
  • La ruta declarada gana al segmento de la URL; se acabó curarse por coincidencia
  • El otro filo del cuchillo el generador se niega también a emitir una clave SIN VALOR
  • El howto corregido, y con la fecha de su mentira escrita dentro

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

El punto de abandono estuvo justo después del primer arreglo, y lo crucé con una sensación de trabajo terminado. Había encontrado la derivación, la había cambiado, había escrito tres tests, el build había salido en verde y la lógica era impecable. Lo único que no hice fue pedirle la página al servidor. Escribí «los dieciséis títulos están arreglados, solo falta reiniciar» — una frase que suena a diligencia y es una predicción disfrazada de hallazgo. Y era falsa. Bastaba un curl. Lo que salvó el caso no fue mi rigor: fue que la siguiente medición era inevitable, porque había que reiniciar de todos modos.

Los sospechosos — las pistas falsas

«La ruta estaba en el fichero equivocado»“«La ruta estaba en el fichero equivocado.» Cierto: la declaré en `routes.ncl` y la página dio 404; la costura del sitio (`site/config/routes/.ncl`) la sirve a 200 sin recompilar nada. Pero eso es el síntoma, no el arma — y menos aún el culpable: el comentario de ese mismo fichero AVISA de ello, con estas palabras, «declarada solo en routes.ncl, la página daba 404». La costura estaba documentada dentro de sí misma. Yo no la abrí.”descartado — es el síntoma, y estaba avisado
«El howto estaba caducado»“«El howto estaba caducado.» Lo estaba, y es el arma. Verificado el 13 de julio, con `verified: true`, afirma que un consumidor NO PUEDE declarar sus propias rutas y que «el arreglo es pequeño y localizado». El arreglo ya estaba hecho: `merge_site_routes` se aplica, `run.sh` exporta su variable de entorno, y los dos ficheros de rutas del consumidor existen. Pero un documento no se mantiene solo. Culpar al howto es culpar a la pistola.”descartado — es el arma, no el culpable
«Faltaba el mecanismo para que el sitio aporte rutas»“«Faltaba el mecanismo para que el sitio aporte rutas.» Esto es lo que yo creí, y llegué a proponer un plan para implementarlo. Se descarta leyendo doce líneas de Rust: el mecanismo existe, y existe EXACTAMENTE donde tenía que existir — el comentario del código dice por qué está en la rama embebida y no en la del sistema de ficheros: «un arreglo que solo viviera ahí sería un arreglo que nadie podría ejecutar». Quien lo escribió pensó en esto. Yo no lo leí.”descartado — el mecanismo existía, y explicado
«Lo he arreglado» — dicho ante un build en verde“«Lo he arreglado.» CULPABLE, y no es de nadie: es la frase que todo el mundo dice. La dije tras cambiar el código y ver el build en verde — es decir, tras comprobar que el compilador estaba contento, que es una afirmación sobre el CÓDIGO y no sobre la PÁGINA. Y la página, que era lo único que importaba, seguía sirviendo dieciséis títulos rotos. Un build en verde no dice que el arreglo entró: dice que compila. Entre esas dos frases cabe un caso entero.”CULPABLE — y es la frase de todos

El arma — Dos crates, una clave, y el que se lee no es el que arreglé

// crates/server/build.rs  ← la derivación que el <head> USA
fn component_to_key_prefix(component: &str) -> String {
    format!("{}-page", component.to_lowercase())     // OntorefPage → ontorefpage-page
}

// crates/build-config/src/site_config.rs  ← la derivación que YO ARREGLÉ
pub fn ftl_page_prefix(component: &str) -> String {
    // quita el sufijo Page, kebab-case                OntorefPage → ontoref
}

// Los .ftl del sitio, desde siempre:
//     ontoref-page-title = ...
//
// Una de las dos coincide con el dato. La otra es la que se lee.
// Cambié la que coincide. Recompilé. El build salió en VERDE.
// Y los dieciséis títulos siguieron sirviendo `[ontorefpage-page-title]`.

Y hay un detalle que convierte esto de anécdota en caso: una de las dos páginas parecía curada. /conceptos servía su título bien, y no porque el arreglo funcionase, sino porque su segmento de URL —«conceptos»— coincide por casualidad con su identificador de página, y la rama que deriva el título del segmento acertaba de chiripa. Si las dos páginas nuevas hubieran tenido esa suerte, habría cerrado el caso con el defecto vivo. Lo delató /sobre-el-idioma, cuya clave es lenguaje-page-title y cuyo segmento no se le parece en nada. Una coincidencia estuvo a punto de firmar el alta.

El giro — Fundir las dos en una, y que la cabecera lea lo mismo que el cuerpo

# 1. UNA derivación. Y el otro crate la LLAMA, no la copia.

  fn component_to_key_prefix(component: &str) -> String {
      format!("{}-page", build_config::ftl_page_prefix(component))
  }

# 2. El <head> lee el REGISTRO, no el enum horneado. Una página que el sitio
#    aporta al arrancar no existe en el enum — y servía su cuerpo perfecto
#    con el título roto.

  let registry_title = load_routes_config().routes.iter()
      .find(|r| r.path == path && r.language == language)
      .map(|r| r.title_key);

# 3. Y la ruta declarada GANA al segmento de la URL. Sin esto, /conceptos
#    parecía curada — porque su segmento coincide con su id, por casualidad.

  if registry_title.is_none() && (component == NotFound) { ...derivar del segmento... }

# Dos funciones que deben coincidir son dos funciones que acabarán discrepando.

Falta confesar la última, porque es la que más duele. Mientras arreglaba todo esto, mi propio generador de la página nueva emitió una clave Fluent sin valor — que en Fluent es error de sintaxis— y borró las nueve claves de su página mientras las otras mil ochocientas sesenta y una seguían tan tranquilas. Yo había escrito, semanas antes, un cerrojo en otro generador contra las claves duplicadas, y publiqué un expediente entero sobre ello. No se me ocurrió que el mismo cuchillo tuviera dos filos. Un cerrojo contra la mitad de un defecto es un cerrojo contra nada.

El veredicto

La serie pregunta: ¿con ontoref no hubiera sido así? Y este caso es el más incómodo de responder, porque el protocolo estaba puesto y funcionando, y no falló nada suyo. La respuesta estaba en el registro de conocimiento, se consulta con un comando, y la consulté. El mecanismo estaba implementado, documentado dentro de sí mismo, con su porqué escrito en el código. Las puertas estaban verdes. Todo lo que ontoref promete estaba ahí, y aun así los dieciséis títulos siguieron rotos, porque el fallo no estuvo en el sistema: estuvo en la frontera entre el sistema y el que pregunta. Yo hice tres cosas, y las tres son la misma. Me fié de un documento en vez del código — y el documento llevaba verified: true, que es exactamente lo que hace que dejes de mirar. Me fié de un diff en vez de la página — cambié una derivación creyendo que era la derivación, sin preguntarme nunca si habría dos. Y me fié de un build en verde en vez de un curl — que es fiarse de que el compilador está contento cuando lo que preguntabas era si el lector ve un título. Las tres veces medí la cosa de al lado. Lo que este expediente añade a la serie no es un mecanismo nuevo: es una advertencia sobre los que ya hay. Un verified: true no caduca solo. Un comando de comprobación que nadie ha ejecutado nunca puede no existir siquiera —y aquí no existía, y lo mandaban ejecutar dos documentos distintos—. Y un hecho calculado en dos sitios es un hecho que, el día que alguien arregle uno, va a mentirle con una sonrisa y un build en verde.

Un hecho calculado en dos sitiosSe funden en uno. No se hace que «coincidan»: se hace que sean el mismo. build-config ya era dependencia de build del otro crate — la función se hizo pública y el generador del <head> la llama. Dos funciones que deben coincidir son dos funciones que acabarán discrepando.
Media página del registro y media del binarioEl <head> lee el registro de rutas, igual que el cuerpo. El sitio aporta sus rutas al arrancar y resolve_static_page sirve su contenido sin recompilar — pero el título salía del enum generado en el build, que no puede conocer una ruta añadida después. Contenido perfecto y <title> roto, a 200, en el único elemento que lee Google.
Una coincidencia que hace parecer curado lo que no lo estáLa ruta declarada gana al segmento de la URL. Sin esa guarda, el título se derivaba del segmento cuando el componente no estaba compilado — y en /conceptos eso coincidía con la clave correcta POR CASUALIDAD. Una de las dos páginas parecía curada. La otra fue la que delató a las dos.
Una respuesta verificada que dejó de ser ciertaSe corrige, y se le escribe dentro la fecha de su mentira. Un howto lleva verified: true y una fecha — y ninguna de las dos caduca sola. Éste afirmaba que un consumidor no puede declarar rutas, y el mecanismo ya existía, aplicado, con su variable de entorno exportada. Lo leí, me lo creí, y estuve a un comando de reimplementar lo que ya estaba hecho.
Un verificador que no existe, mandado por dos documentosore rustelo routes --check. Lo nombran el howto Y el propio fichero de rutas. No existe por partida doble: ore es un alias renombrado a onre que hoy no resuelve a nada, y el subcomando rustelo tampoco existe bajo el comando real, ontoref. Un paso de verificación que no se puede ejecutar es peor que ninguno: el que lo lee cree que hay una red.
Una base de conocimiento que manda ejecutar un aliasUn ADR, un howto y un comentario no se ejecutan: se leen. Por eso 355 invocaciones de ore —un alias que ya no existe— sobrevivieron en 83 ficheros, 21 de ellos ADRs, más 126 de onre, que es el mismo defecto todavía sin romperse. Un alias vive en el perfil del shell de una persona; el binario se llama ontoref y existe para todo el mundo. En un documento se escribe el COMANDO, nunca el atajo de su autor.
El mismo defecto, condenado y supervivienteEl expediente 0/318 ya dictaminó esto: «ore y onre son alias, no binarios… una restricción que sólo puede pasar en el portátil de su autor no es una restricción». Y arregló los 33 checks que SE EJECUTAN. Dejó 481 invocaciones en la prosa — porque la prosa no se ejecuta, nada falló, y el defecto siguió vivo justo donde el proyecto explica cómo funciona. Se caza donde se ejecuta; sobrevive donde solo se lee.
Un generador que emite una clave sin valorEl otro filo del cuchillo del expediente 1/1852. Allí un generador escribió una clave DUPLICADA y se llevó el idioma entero; le puse un cerrojo. Aquí el mismo generador —escrito por el mismo autor, después de publicar aquel caso— emitió una clave SIN VALOR, que en Fluent es error de sintaxis, y borró las 9 claves de su página mientras las otras 1861 seguían. Un cerrojo contra la mitad de un defecto es un cerrojo contra nada.

La reconstrucción — la sesión, repetida con protocolo

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

correcciones en el sitio web ontoref version 0.1.8 el diagrama de Arquitenctura
en home page dice v0.1.7
¿ hay que actualizar algo en él para 0.1.8 ? ¿ por qué un click soble él no hace
zoom modo lightbox como con las imágnes en los posts ?
- hay que revisar y verificar con el lexico de ontoref las slided de ontologia
- hacer una versión de rustikon.md a español con la verificación lexico y términos

Lo que había que pedir

Correcciones del sitio para 0.1.8 — un frente por microtarea, y ninguna se
cierra con el compilador:

1. Cada «arreglado» lleva su testigo pegado: el curl o el grep de LA PÁGINA
   servida, nunca el exit 0 del build. Si el hecho vive en dos sitios
   (registro y binario), el testigo mira los dos.
2. Antes de tocar una derivación duplicada, busca sus copias: `rg` de la clave
   por todos los crates — y si hay dos, la microtarea es UNIFICAR, no parchear
   la primera que aparezca.
3. Si un documento manda ejecutar un verificador, ejecútalo tal cual está
   escrito ANTES de confiar en él; si no existe o es un alias, es un hallazgo
   que se reporta, no se rodea.
MicrotareaVerificable
Localizar TODAS las derivaciones del hecho antes de arreglar ningunarg de la clave del título por el workspace: dos derivaciones, dos crates — la lista pegada
Dejar UNA derivación, la que se leeuna sola queda y server/build.rs la llama — la otra ya no compila
Afirmar «arreglado» sólo con la página delanteel curl de la página servida muestra los 16 títulos correctos — el build en verde no es testigo de nada
Ejecutar el verificador que mandan los documentos, tal cual está escritoel comando existe como binario —no como alias— y su salida va pegada; si no existe, hallazgo

La puerta antes de delegar: La definición de «hecho» se cierra antes de delegar: qué comando prueba cada afirmación de la lista. Un encargo multi-frente sin oráculo por frente invita a cerrar frentes con el compilador — y así se firmó «lo he arreglado» sobre dieciséis títulos rotos.

El disparador de ADR: El caso no dejó ADR propio: empuja la regla que ADR-072 ya recoge —la página es la publicación— y su pauta quedó exigida en governed-delivery, al derivar los contratos.

La jurisprudencia — qué exige hoy la lección

  • La página es la publicación: se verifica lo servido, nunca el compiladoradr:072/the-page-is-the-publication
  • El testigo vivo cuenta la tarjeta en la página, no la cadena en el HTMLtest:scripts/build/check-served-live.nu
  • El oráculo del contrato lee la superficie SERVIDA cuando lo entregado es una página — nunca el compiladormode:governed-delivery/derive-contracts

Queda una cosa por decir y no es cómoda. Este expediente lo escribe el mismo que publicó el 1/1852 —«el generador que informó éxito»— hace unas horas, cuya moraleja, en mayúsculas, era verifica la página, no el fichero. Y volvió a hacerlo: verificó el diff, no la página. Escribió un cerrojo contra las claves duplicadas y su siguiente generador murió por una clave vacía. Eso no invalida la lección; la confirma. Una lección aprendida no es un mecanismo, y por eso el proyecto insiste en que el mecanismo tiene que negarse — porque el que aprendió la lección va a volver a olvidarla, y el cerrojo no.

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.