Saltar al contenido
crawlforgeEnglish
Se rompió12 de octubre de 20267 min de lecturaRead in English

El fichero de diff que nadie sabía abrir

La 0.12.0 reabre el fichero que guarda diff --out, lista todas las filas sin corte y arregla un resumen que escondía 1.171 cambios de sitemap.

crawlforge diff tiene un flag --out desde su primera versión. Escribe la comparación en un fichero SQLite propio, con una fila por cambio y una tabla de cabecera que dice de qué dos rastreos sale y si el resultado es de fiar. La idea era buena, porque un diff que se guarda se puede volver a mirar el mes que viene o pasárselo a otra persona.

Lo que no tenía la herramienta era forma de leerlo. Si se lo dabas a report, contestaba con un error educado explicando que aquello era un fichero de diff y no un rastreo. Ese mensaje ya era un arreglo, porque antes la respuesta era no such table: urls. Pero educado o no, la única manera de ver lo guardado era abrirlo con un cliente de SQLite y escribir consultas. Una herramienta que genera un fichero que luego no sabe abrir ha hecho la mitad del trabajo, y la 0.12.0 hace la otra mitad.

El mismo comando con un solo fichero

crawlforge diff antes.sqlite despues.sqlite --out cambios.sqlite   # como siempre
crawlforge diff cambios.sqlite                                     # nuevo

Pensé en un comando aparte y lo descarté. Con cambios.sqlite delante, lo primero que uno teclea es crawlforge diff cambios.sqlite, así que eso es lo que lo abre. Si pasas un solo fichero y resulta ser un rastreo, el error dice que para comparar hacen falta dos, y si el rastreo tiene su .prev.sqlite al lado, te da el comando exacto.

El resumen reabierto sale del mismo código de impresión que el de una comparación en vivo, y ese era el objetivo. Un lector que dibujara su propia versión del resumen acabaría diciendo algo un poco distinto del original, y entonces habría dos verdades sobre el mismo diff. Para comprobarlo comparé dos rastreos reales de especialmundial.com, del 31 de julio y del 2 de agosto, guardé el resultado y pasé un diff normal sobre las dos salidas:

5a6
>   Saved     diff generated 2026-10-12T08:14:45Z by crawlforge 0.11.0 · …/em.diff.sqlite

Esa es la única diferencia, una línea que dice cuándo se generó el fichero y con qué versión. Está ahí porque un diff de hace un mes leído como si fuera de hoy hace que alguien arregle cosas que ya estaban arregladas.

Los avisos estaban horneados en inglés

Un diff puede no ser concluyente. Si uno de los dos rastreos se cortó por un límite de URLs, una URL que falta en él puede haber desaparecido o puede que el rastreo no llegara nunca hasta ella. En ese caso la herramienta oculta las ausencias que no puede afirmar y lo dice lo primero, en un aviso. Ese aviso pesa más que cualquier otra línea del fichero.

Cuando se escribió --out decidimos guardar los avisos solo en inglés, para que el mismo fichero no dijera cosas distintas según el terminal que lo hubiera creado. La decisión era correcta y dejaba un problema: al reabrirlo con --lang es saldría un resumen en español con los avisos en inglés en medio.

Ahora cada aviso se guarda con un kind y sus datos, por ejemplo {"kind": "truncated", "side": "after", "reason": "max_urls"}, junto al texto en inglés que ya estaba. El lector reconstruye el aviso y lo traduce. Las claves son añadidas, así que la versión del formato no cambia y un fichero escrito por la 0.11.0 sigue abriéndose. Lo probé con el binario 0.11.0 que tenía instalado: sus avisos vuelven con el texto en inglés que guardaron y un diff que no era concluyente sigue marcado como tal. Un aviso que se perdiera al reabrir podría ser justo el que decía que el diff no era de fiar.

Todas las filas y no solo tres

El resumen de terminal enseña tres ejemplos por grupo a propósito, porque un informe que imprime cuatrocientas URLs no lo lee nadie. El resto estaba en el fichero y hasta ahora llegar a él pasaba por escribir SQL.

Hay dos flags que lo listan todo, sobre un diff guardado o sobre una comparación en vivo:

crawlforge diff cambios.sqlite --rule CONTENT-THIN
crawlforge diff cambios.sqlite --change url_removed

Con el par de especialmundial, --rule CONTENT-THIN da las cinco páginas con un hallazgo nuevo de contenido escaso y la que dejó de tenerlo. Los cambios de título, meta description y canonical enseñan el texto entero de antes y de después, que es lo que se viene a buscar. Un robots.txt cambiado enseña solo las líneas que se van y las que llegan, en vez de los dos ficheros completos. Si escribes mal el tipo de cambio, el error lista los doce que valen. Es la misma idea que report --rule, que ya hacía esto con un solo rastreo.

Hay un flag que un diff guardado rechaza, --fail-on, la puerta de integración continua. Decidir si los hallazgos nuevos se pueden afirmar depende de que el rastreo «antes» terminara, y el fichero no lo guarda. Una puerta que aprueba por falta de datos es peor que no tener puerta, así que el error te manda a lanzarlo sobre los dos rastreos.

Lo que salió con un rastreo de verdad

Hacer el lector obligó a mirar el resumen con otros ojos, y en el rastreo más grande que tenemos, dos pasadas de 20.000 URLs de diariodelamancha.com, apareció esto:

── Otros cambios ────────────────────────────
  sitemap https://diariodelamancha.com/category-sitemap.xml present: yes → no
  …
  sitemap https://diariodelamancha.com/post-sitemap10.xml url_count: 196 → 150
  Hallazgos que persisten            278.244

Seis líneas de sitemap y ni una más, cuando el fichero tenía 1.177. Todas las demás listas del resumen terminan con «… y N más» y esta se paraba en seis sin decir nada. Aquellos dos rastreos estaban truncados, así que ese diff ya salía como no concluyente, pero una lista que esconde el 99 % de sus filas sin avisar es un fallo en cualquier diff. Ahora dice «… y 1.171 más», y cuando algo se ha cortado, el resumen termina nombrando los dos flags que enseñan el resto.

El test que me pilló primero

Entre los tests del lector hay uno de robots.txt: un fichero que pasa de Disallow: /wp-admin/ a Disallow: / debería listar exactamente esas dos líneas. Falló la primera vez que corrió, con esta salida:

- User-agent: *�Disallow: /wp-admin/

El texto que viene del sitio pasa por un filtro que sustituye los caracteres de control, para que un título con secuencias de escape no pueda pintarte la terminal. Yo lo aplicaba antes de partir el fichero en líneas, y un salto de línea es un carácter de control. Ahora cada línea se limpia por separado, después de partir.

Ese se puso en rojo solo. Con los demás seguí la norma que salió del test que pasaba con el fallo puesto: romper el código a propósito y ver fallar cada test nuevo. Catorce de los quince fallaron. El que queda comprueba que reabrir un diff no modifica el fichero, y sigue en verde aunque lo abra en escritura, porque abrir sin escribir no cambia nada. Protege de que el fallo vuelva, pero por sí solo no demuestra nada. En total pasan 1.069 tests.

La prueba de rendimiento de antes de publicar dio 61.831 elementos por segundo, bastante por debajo de lo habitual. Igual que en la entrada anterior, el Mac estaba ocupado, con una carga media entre 11 y 14. Y esta versión no toca ni el motor ni las reglas: todos los cambios están en la línea de comandos.

Se construye en público

Cada dos semanas: mediciones, fallos y ejemplos de uso. Nada más.

← Volver a la bitácora