Diario
Secciones
Ajustes de lectura
Voz natural grabada para este curso, la misma en todos los navegadores.
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
Progreso
Sección titulada «Progreso»- Datos: las páginas, los enlaces y el historial de Git de este repositorio en el commit
cbcbb42, y las ejecuciones de CI del curso de DuckDB - CI: el Cypher de cada lección comparado con su salida esperada en tres sistemas operativos, y una verificación cruzada en SQL con DuckDB
- Lección 1: un primer grafo
- Lección 2: cargar archivos
- Lección 3: caminos
- Lección 4: el historial de Git y las ejecuciones de CI como grafo
- Datos: los proyectos .NET de GuitarAlchemist/ga en el commit
a26a7893 - Lección 5: LadybugDB desde C#
- Lección 6: LadybugDB desde Java
- Lección 7: algoritmos de grafos y búsqueda de texto completo
- Lección 8: persistencia, transacciones y concurrencia
- Lección 9: un laboratorio de grafos — traducciones, ciclos de prerrequisitos, alcanzabilidad acotada
LadybugDB 0.20.4 es la base de datos de otros, y escribir ocho lecciones sobre ella sacó nueve hallazgos. Seis son bugs silenciosos — sin error, un resultado equivocado — cada uno con una reproducción que corre en una base en memoria vacía; ninguno tenía incidencia aguas arriba cuando se buscó en el tracker el 14 de septiembre de 2026, y ninguno se ha reportado. Los tres últimos vienen de las lecciones mismas, y uno de ellos ya estaba abierto aguas arriba. El laboratorio de la lección 9 añadió un décimo, el orden invertido de un testigo cerrado; no se ha buscado aguas arriba.
| Esperado | Lo que pasa | Dónde | Medición | Estado |
|---|---|---|---|---|
Un COPY a una tabla de relaciones desde una subconsulta conecta los nodos que encontró el MATCH |
Conecta los nodos equivocados: las claves se emparejan por posición en lugar de por el MATCH |
COPY … FROM (LOAD FROM … MATCH …) |
Reproducción 1 2026-09-14 | Reproducido, ninguna incidencia aguas arriba, no reportado |
count(DISTINCT …) junto a sum(…) deja la suma en paz |
La sum vuelve como NULL en cuanto un count(DISTINCT …) la precede |
Agregación | Reproducción 2 2026-09-14 | Reproducido, ninguna incidencia aguas arriba, no reportado |
ACYCLIC descarta todo camino que repite un nodo |
Conserva algunos | Patrones de caminos recursivos | Reproducción 3 2026-09-14 | Reproducido, ninguna incidencia aguas arriba, no reportado |
Un COPY que falla deja la tabla de nodos como estaba |
La corrompe | COPY a una tabla de nodos |
Reproducción 4 2026-09-14 | Reproducido, ninguna incidencia aguas arriba, no reportado |
Agrupar por una subconsulta COUNT conserva el grupo cuyo recuento es 0 |
Ese grupo desaparece | GROUP BY sobre una subconsulta |
Reproducción 5 2026-09-14 | Reproducido, ninguna incidencia aguas arriba, no reportado |
timestamp() y CAST(… AS TIMESTAMP) respetan el desfase escrito en el literal |
Ambos lo ignoran | Conversión temporal | Reproducción 6 2026-09-14 | Reproducido, ninguna incidencia aguas arriba, no reportado |
INSTALL algo obtiene la build que corresponde a la CLI |
La CLI 0.20.4 descarga la build 0.20.0, y LOAD algo falla después en los tres ejecutores, con rutas de la máquina de build de LadybugDB en el mensaje |
extensión algo, CLI 0.20.4 |
libnetworkit.so: cannot open shared object file en Linux, Library not loaded: @rpath/libnetworkit.dylib en macOS, The specified module could not be found. en Windows |
Abierto aguas arriba como incidencia #857, no abierta por este curso 2026-09-14 |
| Louvain da las mismas comunidades para el mismo grafo y el mismo número de hilos | Los tamaños cambian de un proceso a otro, con CALL threads = 1 puesto |
extensión algo, Louvain |
[27,20,17,14,14] en un proceso, [25,20,18,18,11] en los dos siguientes; tres llamadas dentro de un mismo proceso coinciden. Los nodos sin relación reciben louvain_id -1 |
Reproducido, no reportado 2026-09-14 |
| Un proceso de solo lectura y un escritor sobre el mismo archivo se comportan como dice la documentación | La página sobre concurrencia dice que la combinación no está permitida, pero es justo lo que pasa: un proceso de solo lectura abre el archivo de un escritor en Linux y macOS y ve sus cambios confirmados a través del .wal; un escritor abre y hace checkpoint de un archivo que tiene un lector, en los tres, y el lector sigue respondiendo desde el estado antiguo |
storage_manager.cpp 87-91 |
En Windows el LockFileEx del escritor hace que la lectura falle con Error 33 |
Reproducido; la documentación y el comportamiento se contradicen 2026-09-14 |
nodes(p) sobre un patrón cerrado (a)-[…]->(a) lista las páginas en el orden de las flechas, como sobre un patrón abierto |
Las lista en contra de las flechas; las páginas y la longitud son correctas | nodes() sobre un patrón cerrado de longitud variable; fuente no localizada |
Flechas /lab/cycles/ → /lab/paths/ → /lab/intro/ → vuelta: [/lab/cycles/,/lab/intro/,/lab/paths/,/lab/cycles/]. Un camino abierto desde la misma página está en orden. Reproducido en los ciclos de 3 y de 6 páginas 2026-09-27 |
Reproducido en Windows; seguimiento upstream no consultado, no reportado |
Experimentos
Sección titulada «Experimentos»Una fila por experimento medido, con la hipótesis tal como se escribió antes de ejecutar en data/lab/preregistration.md.
| Pregunta | Hipótesis (antes de ejecutar) | Resultado | Veredicto | Entrada y código |
|---|---|---|---|---|
Tras un COPY fallido en una tabla de relaciones, ¿qué queda? |
La tabla sin cambios, y el índice de claves de los nodos intacto | 2 enlaces, como antes; found_by_key 1 |
Confirmado, 0.20.4 en Windows; observado, no una garantía | 2026-09-27, 09-graph-lab.cypher |
| Traducciones que faltan por identidad de contenido o por título | Identidad: 1 página hermana que falta; título: 4 filas, 3 falsas | 1 (/lab/paths/, es); 4 filas, 3 falsas |
Confirmado | 2026-09-27 |
| ¿Es completa una cota de sendero cerrado cuando alcanza el número de páginas? | DAG: 0 con cota 3; ciclo de 6: 0 con 5, 6 senderos de longitud 6 con 6 | 0; 0; 6 de longitud 6 | Confirmado | 2026-09-27 |
| ¿Necesitan navegación y prerrequisitos tablas de relaciones separadas? | Navegación: 2 senderos cerrados de longitud 2; prerrequisitos: 0 | 2 de longitud 2; 0 | Confirmado | 2026-09-27 |
| ¿Lista un testigo cerrado sus páginas en el orden de las flechas? | Sí, como un camino abierto | No: invertido (fila QA de arriba) | Refutado | 2026-09-27 |
2026-09-14 — Los datos
Sección titulada «2026-09-14 — Los datos»extract.py, ejecutado con el commitcbcbb42como argumento, lee los archivos Markdown y el historial de Git en ese commit, congit ls-tree,git showygit log, no la copia de trabajo: los archivos CSV no cambian cuando cambia el sitio.- 319 páginas, 712 enlaces internos, 3.712 enlaces externos, 74 commits, 73 enlaces de parentesco y 1.019 archivos modificados.
- Las ejecuciones son el
runs.jsondel curso de DuckDB, 125 ejecuciones exportadas hacia las 14:04 UTC, reutilizadas tal cual. - Las fechas de los commits conservan su desfase
-04:00encommits.csv; LadybugDB las guarda en UTC.
2026-09-14 — Instalar LadybugDB
Sección titulada «2026-09-14 — Instalar LadybugDB»- Windows:
lbug_cli-windows-x86_64.zipde la release v0.20.4 solo contienelbug.exe, 14.772.736 bytes.lbug --versionimprimeLbug 0.20.4. - CI: el workflow descarga el asset de la release de cada sistema operativo (
linux-x86_64,windows-x86_64,osx-arm64) y añade la carpeta aGITHUB_PATH. Instala DuckDB 1.5.5 de la misma manera, para la verificación cruzada en SQL de la lección 3. INSTALL jsonpuso la extensión en~/.lbdb/extension/0.20.0/win_amd64/json/: la carpeta lleva el nombre de 0.20.0, no de 0.20.4. El historial del shell está en~/.lbdb/history.txt.- En una ventana de Git Bash,
lbug.exeno encuentra las rutas/c/Users/…, y las barras invertidas en una cadena de Cypher son caracteres de escape: los scripts usan rutas relativas acode/ladybugdb, yC:/…funciona cuando hace falta una ruta completa.
2026-09-14 — La CI
Sección titulada «2026-09-14 — La CI»- La CLI termina con 0 incluso cuando una consulta falla, e imprime los errores en la salida estándar (
embedded_shell.cpp, líneas 608-611):check.shcompara toda la salida, errores incluidos, así que un error inesperado sigue haciendo fallar el job. - La barra de progreso escribe códigos de escape incluso cuando la salida va a un pipe:
check.shpasa--no_progress_bary--no_stats. - Primer push: falló en Linux, pasó en Windows y macOS. Borrar una lección que aún tenía relaciones daba un mensaje que nombraba
HAS_LESSONen Windows y macOS, yLINKS_TOen Linux: el ejecutor nombra la primera tabla de relaciones que comprueba (delete_executor.cpp, líneas 33-42), y su orden difiere. Ahora la lección 1 borra una lección cuyas relaciones están todas en una sola tabla. - Mismo push:
ACYCLICdio 14 caminos en Windows y 29 en Linux y macOS (ver más abajo). La lección 3 usais_acyclic(p), igual en los tres. - Dos salidas podían variar de una ejecución a otra: un
LOAD FROM … LIMIT 3sinORDER BY, y la primera clave que falta según unCOPYfallido, que depende del hilo que la encuentra. Los scripts ordenan, y ejecutanCALL threads = 1antes de eseCOPY. - Un recorrido
LINKS_TO*sin límite sobre el grafo del sitio estuvo más de cinco minutos en marcha antes de que lo detuviera;* SHORTESTsobre el mismo patrón responde al instante.
2026-09-14 — Sorpresas al escribir las lecciones 1-4
Sección titulada «2026-09-14 — Sorpresas al escribir las lecciones 1-4»MERGEhace coincidir el patrón entero: sin la clave primaria falla en la fase de enlace, y con la clave y otra propiedad que difiere, intenta crear el nodo y falla por la clave duplicada.:schemaimprime sentenciasCREATE, conMANY_MANYen cada tabla de relaciones.- La cabecera del CSV se detecta sin
HEADER = true, y sus nombres no tienen que coincidir con las columnas de la tabla. SKIP_DUPLICATE_PK = truefunciona en unCOPYdesde un archivo (constants.h, línea 111) pero no aparece en la documentación, y no se admite en unCOPYdesde una subconsulta (bind_copy_from.cpp, línea 149).- El detector de formato CSV lee las primeras 256 líneas (
constants.h, línea 144); un campo entre comillas más abajo hace fallar elCOPY, salvo que se indiqueQUOTE. - Los campos CSV vacíos se convierten en
NULLpor defecto;NULL_STRINGS = ['NA']los conserva como''. split_part('/es/streeling/', '/', 1)devuelvees: la parte vacía antes del separador inicial se omite. DuckDB devuelve''.nodes(e)sobre una lista de relaciones solo devuelve los nodos intermedios; las listas se indexan desde 1;ORDER BYsobre unSTRING[]falla, un cast aSTRINGfunciona.- Los patrones de longitud variable son recorridos por defecto, así que dos relaciones
CHANGEDde un mismo patrón pueden ser la misma. - El límite superior de un patrón de longitud variable está limitado a 30 (
client_config.h, línea 32) hasta unCALL var_length_extend_max_depth = …; un patrón que necesita más no devuelve nada, sin error. - Los recuentos de caminos de 4 enlaces de la lección 3 se comprobaron dos veces fuera de LadybugDB: un script de Python sobre
links.csv(recorridos 1, 5, 12, 29; senderos 26; acíclicos 1, 5, 9, 10), y una CTE recursiva en DuckDB (recorridos 1, 5, 12, 29), que la CI ejecuta.
2026-09-14 — Lección 5: los datos de ga y el paquete de C#
Sección titulada «2026-09-14 — Lección 5: los datos de ga y el paquete de C#»data/ga/extract.pysolo necesita los archivos de proyecto: un clon con--filter=blob:noney un sparse checkout de*.csproj,*.fsprojy*.slnxdescarga los archivos de proyecto de ga sin el resto de su contenido. Omite las copias que hay en las carpetas.claude.- 111 proyectos, 266 referencias de proyecto, 478 referencias de paquete, 136 paquetes. Una referencia apunta a
reactapp1.client.esproj, un proyecto JavaScript que la extracción no conserva: la lección carga las referencias conIGNORE_ERRORS. - La columna
versiones lo que dice cada archivo de proyecto. ElDirectory.Build.propsde ga sobrescribe 14 paquetes conPackageReference Update, y la extracción no lo aplica; las consultas de la lección evitan esos paquetes. - Dos proyectos se llaman
GaApi.Tests, enTests/Apps/GaApi.TestsyTests/GaApi.Tests; el segundo no está enAllProjects.slnx. En total, 38 proyectos no están en él. - NuGet:
LadybugDBtiene tres versiones,0.17.0-alpha.1,0.18.2y0.19.1; la 0.19.1 incluye el motor 0.19.1, versión de almacenamiento 43. El binding no es ADO.NET y no tiene página en docs.ladybugdb.com: leí su código fuente en el commit0f58f1a. - Primer push de CI: el job de C# falló en los tres sistemas operativos. El ID interno de
GaApiera0:11en Windows y0:47en Linux y macOS, a partir del mismo CSV;SHORTESTeligió un camino que pasaba porGA.Business.MLen mi máquina y porGA.Business.AIen los runners, entre dos de la misma longitud; y la CLI del runner de Linux imprimíaWarning: failed to create directory: /home/runner/.lbdb/al abrir un archivo en solo lectura. Ahora el programa compara los IDs en lugar de imprimirlos y lista los caminosALL SHORTESTordenados;check.shfiltra la advertencia. - La CLI 0.20.4, al abrir en lectura-escritura un archivo de base de datos 0.19.1, lo reescribe a la versión de almacenamiento 47 sin ningún mensaje; después, el paquete 0.19.1 falla con
Failed to open Ladybug database at '…', sin la causa.--read_onlydeja el archivo legible por ambos. - El binding no expone
lbug_query_result_has_next_query_result,lbug_connection_interruptnilbug_connection_set_query_timeoutde la API de C: unQuerycon varias sentencias solo devuelve el primer resultado, y una consulta larga no se puede detener desde C#.
2026-09-14 — Lección 6: el paquete de Java
Sección titulada «2026-09-14 — Lección 6: el paquete de Java»com.ladybugdb:lbug0.20.4 en Maven Central: un único jar de 29.339.834 bytes con la biblioteca nativa paralinux_amd64,linux_arm64,osx_arm64ywindows_amd64, sinosx_amd64. Arrastra 13 jars más, 7 MB:kotlin-stdlib2.3.20, Apache Arrow 18.2.0, Jackson, FlatBuffers, commons-codec y SLF4J.- El jar de fuentes coincide con el repositorio
ladybug-javaenf2fb39f, el commit del submódulo de LadybugDB v0.20.4. Las fuentes están en una carpetacom/lbugdb, pero el paquete escom.ladybugdb. - La página de Java de la documentación todavía muestra
throws ObjectRefDestroyedException; la 0.20.4 lanzaRuntimeExceptioncon mensajes comoConnection has been destroyed. - Una consulta fallida devuelve un resultado con
isSuccess()a false;getNext()sobre él lanzaRuntimeExceptioncon el mismo mensaje. - Un
PreparedStatementconserva los valores de su última ejecución:execute(statement, Map.of("nom", 5))después deMap.of("n", 2.5)se ejecuta conn = 2.5y sin error. Sobre una sentencia nueva, el mismo mapa falla conParameter n not found. Value.getValue()lanzaType of value is not supported in value_get_valueparaLISTyMAP, y tampoco manejaSTRUCT,NODE,RELniRECURSIVE_REL; las clasesLbugList,LbugStruct,LbugMapyValue…Utillos leen.interval('1 month 2 days')vuelve comoPT768H: el código JNI convierte el intervalo a segundos con meses de 30 días.setQueryTimeout(1)detiene los recorridos de la lección 3 conInterrupted., ygetNextQueryResult()lee la segunda sentencia de una consulta: ambos faltan en el paquete .NET.- La biblioteca nativa se copia a un nuevo archivo temporal en cada arranque de la JVM, y
deleteOnExitno puede borrar una DLL cargada en Windows: 13 copias, 190 MB, en%TEMP%tras las ejecuciones de esta lección en mi máquina, 3 copias en el runner de Windows tras tres ejecuciones, ninguna en los runners de Linux y macOS. - El primer push de CI del job de Java pasó en los tres sistemas operativos: la lección 5 ya había hecho la salida independiente de los IDs internos y del camino que elige
SHORTEST.
2026-09-14 — Lección 7: extensiones, algoritmos y búsqueda de texto completo
Sección titulada «2026-09-14 — Lección 7: extensiones, algoritmos y búsqueda de texto completo»- Con la CLI 0.20.4,
INSTALL algodescarga la build para 0.20.0, yLOAD algofalla en los tres runners de la CI:libnetworkit.so: cannot open shared object fileen Linux,Library not loaded: @rpath/libnetworkit.dyliben macOS, con rutas de la propia máquina de build de LadybugDB en el mensaje, yThe specified module could not be found.en Windows. El issue #857 está abierto. LOAD ftsfunciona con 0.20.4 en los tres runners, pero en mi máquina Windows la CLI termina con0xC0000409, sin imprimir nada, en el primerCREATE_FTS_INDEX, incluso sobre una tabla de una sola fila. En Linux (WSL), el mismo script funciona con 0.20.4.- La CLI 0.19.1 descarga las builds para 0.19.0;
algoyftsse cargan y dan la misma salida en Windows, Linux y macOS. La CI la instala comolbug19;check.shimprime el resultado deLOAD algoyLOAD ftscon 0.20.4 en cada ejecución, sin compararlo. - La CLI de Windows, 0.19.1 y 0.20.4, importa
libssl-3-x64.dllylibcrypto-3-x64.dll, que no están en el archivo zip; con soloC:\Windows\System32en elPATH, termina con0xC0000135. Git for Windows proporciona ambas DLL. La lección 1 ya lo indica. project_graph_cypherno está en la documentación. Crea un grafo de tipoCYPHER, ypage_rankyweakly_connected_componentssobre él fallan conBinder exception: AA:gds.cpp, línea 72, todavía presente en 0.20.4. El test del motor para esta función solo crea el grafo. Reproducción mínima, con 0.19.1 en Windows:
LOAD algo;CREATE NODE TABLE P(id INT64 PRIMARY KEY, age INT64);CREATE REL TABLE E(FROM P TO P);CREATE (:P {id: 1, age: 5}), (:P {id: 2, age: 20}), (:P {id: 3, age: 7});MATCH (a:P {id: 1}), (b:P {id: 3}) CREATE (a)-[:E]->(b);CALL project_graph_cypher('G1', 'MATCH (n:P) WHERE n.age < 10 RETURN n');CALL page_rank('G1') RETURN node.id, rank;- Louvain sobre el grafo de ga: 5 comunidades de tamaños
[27,20,17,14,14]en un proceso de la CLI,[25,20,18,18,11]en los dos siguientes, conCALL threads = 1; tres llamadas en un mismo proceso dan los mismos tamaños. Los nodos sin ninguna relación recibenlouvain_id-1. - Los rangos de PageRank suman 0,3534 sobre el grafo de ga: los 25 proyectos sin referencia saliente no transmiten su rango. El ejercicio 1 recalcula dos rangos con
(1 - 0.85) / N + 0.85 × Σ rank / out_degree, con cuatro decimales. RETURN n + sum(x), connprocedente deWITH count(*) AS n, falla conCannot evaluate expression with type AGGREGATE_FUNCTION.;RETURN n, n + sum(x)funciona, y tambiénRETURN 2 * sum(x).- FTS: el stemmer inglés hace coincidir queries con query y Persistance con persistant; el stemmer francés no hace coincidir Persistence. Las mayúsculas se ignoran, los acentos no (
donneesno encuentra nada). Las stop words por defecto son inglesas sea cual sea el stemmer. Tras unCREATE, el índice incluye el nuevo nodo y las demás puntuaciones cambian.DROP_FTS_INDEXinformaTable 3_titles_fr_terms has been dropped., una tabla interna.
2026-09-14 — Lección 8: transacciones, archivos y procesos
Sección titulada «2026-09-14 — Lección 8: transacciones, archivos y procesos»- Un error dentro de una transacción manual deshace toda la transacción y la termina, sin ningún mensaje que lo diga: los errores de ejecución (una clave duplicada), los errores del binder, los errores del catálogo, un
BEGINdentro de una transacción yCHECKPOINTdentro de una transacción lo hacen todos. Las sentencias siguientes se ejecutan en auto-commit;ROLLBACKyCOMMITfallan entonces conNo active transaction. La única excepción encontrada: una escritura dentro deBEGIN TRANSACTION READ ONLYfalla, y la transacción sigue abierta. La página de transacciones promete que no persiste nada de una transacción fallida, y no dice que las sentencias posteriores al error se ejecutan por su cuenta. - Una segunda transacción de escritura se rechaza de inmediato,
Cannot start a new write transaction in the system. Only one write transaction at a time is allowed in the system., incluso cuando toca otros nodos; no hay espera ni tiempo límite. Una sentencia en auto-commit rechazada deja la conexión utilizable. - Java, un
BEGIN TRANSACTIONrechazado rompe la conexión: la consulta siguiente lanzaRuntimeException: Unknown Erroren Windows, y hace caer la JVM conSIGSEGVen Linux (CatalogSet::traverseVersionChainsForTransactionNoLock) y macOS (CatalogSet::containsEntry), código de salida 134. UnBEGINque tiene éxito repara la conexión en Windows; unBEGINreintentado no hace caer nada en ninguno de los tres runners (ejercicio 2: 153, 155 y 24 rechazos). Reproducción mínima, unDatabaseen memoria y dos conexiones:firstejecutaBEGIN TRANSACTION,secondejecutaBEGIN TRANSACTION(rechazado),firstejecutaCOMMIT,secondejecuta cualquierMATCH. El paquete de C# y los demás bindings no se probaron. - Los archivos:
.walaparece en el primer commit y desaparece en el checkpoint al cerrar la base de datos; ningún.walpara una transacción sin confirmar.kill -9después de un commit deja el.wal, que la siguiente apertura vuelve a aplicar;kill -9dentro de una transacción pierde la transacción. Cerrar unDatabasede Java con una transacción abierta la deshace. - Un segundo proceso de lectura-escritura falla con
Could not set lock on file, seguido de(Error: 33)en Windows y(Error: Resource temporarily unavailable)en Linux. El código POSIX cierra el descriptor de archivo antes deF_GETLK, así que su mensajeLock is held by PIDno puede aparecer (local_file_system.cpp, líneas 147-172). - Una base de datos de solo lectura no toma ningún bloqueo (
storage_manager.cpp, líneas 87-91). Un proceso de solo lectura abre un archivo que tiene un escritor en Linux y macOS, y ve los cambios confirmados del escritor a partir del.wal; no en Windows, donde elLockFileExdel escritor hace fallar la lectura conError 33. Un escritor abre, escribe y hace checkpoint de un archivo que tiene un proceso de solo lectura, en los tres sistemas operativos, y el lector sigue respondiendo desde el estado antiguo. La página de concurrencia dice que esta combinación no está permitida. - En un mismo proceso Java, un segundo
Databasede lectura-escritura, o uno de solo lectura, sobre un archivo que tiene unDatabasede lectura-escritura: rechazado en Windows, abierto en Linux y macOS (los bloqueosfcntlpertenecen al proceso). new Database(path)lanzajava.lang.Exception, una excepción comprobada que no declara (lbug_java.cpp, líneas 618-636).EXPORT DATABASEen CSV escribe las macros enschema.cypher; la página de migración enumera un archivomacro.cypherque no se crea. Las cabeceras CSV llevan el prefijoa.. El orden de las opciones encopy.cypherdifiere entre Windows y Linux o macOS.IMPORT DATABASEen una base de datos no vacía falla conProject already exists in catalog.- La 0.20.4 abierta en solo lectura deja un archivo 0.19.1 como está; abierta en lectura-escritura, lo actualiza de la versión de almacenamiento 43 a la 47 sin ningún mensaje, y la CLI 0.19.1 dice entonces
Database file version: 47, Current build storage version: 43. - CI: la primera ejecución falló en los tres jobs
cypher, porquefiles.sh, ejecutado conset -e, devolvía el código de salida de la última CLI 0.19.1; ahoracheck.shlo ignora y compara la salida. Los jobsjavade Linux y macOS caían en elBEGINrechazado, que ahora tiene un modo propio. La segunda ejecución falló solo en macOS:lsordenabaProject.csvdespués decopy.cypher; el script ordena conLC_ALL=C. - Con su salida redirigida a un archivo, la CLI no escribe nada hasta que termina:
files.shespera al archivo.wal, o un tiempo fijo, en lugar de una línea de salida.
2026-09-14 — Bugs encontrados en la 0.20.4
Sección titulada «2026-09-14 — Bugs encontrados en la 0.20.4»Seis bugs silenciosos: ningún error, un resultado incorrecto. Ninguno tenía un issue en el tracker de LadybugDB cuando busqué el 2026-09-14; no los he reportado. Cada reproducción de abajo se ejecuta en una base de datos en memoria vacía (lbug -m csv < repro.cypher) y solo se ejecutó en Windows, salvo que se indique lo contrario.
1. COPY desde una subconsulta JSON con MATCH conecta los nodos equivocados
Sección titulada «1. COPY desde una subconsulta JSON con MATCH conecta los nodos equivocados»Con r.json conteniendo [{"id":1,"k":"a"},{"id":2,"k":"b"},{"id":3,"k":"c"}]:
LOAD json;CREATE NODE TABLE K(k STRING PRIMARY KEY);CREATE NODE TABLE R(id INT64 PRIMARY KEY);CREATE REL TABLE ON_K(FROM R TO K);CREATE (:K {k: 'a'}), (:K {k: 'b'}), (:K {k: 'c'}), (:R {id: 1}), (:R {id: 2}), (:R {id: 3});COPY ON_K FROM (LOAD FROM 'r.json' WITH id, k MATCH (x:K) WHERE x.k = k RETURN id, k);MATCH (r:R)-[:ON_K]->(x:K) RETURN r.id, x.k ORDER BY x.k;3 tuples have been copied to the ON_K table.r.id,x.k1,a1,b1,cEsperaba 1,a, 2,b, 3,c, que es lo que da el mismo COPY desde un archivo CSV con las mismas filas. Añadiendo (IGNORE_ERRORS = true), las tres relaciones van en cambio a a: 1,a, 2,a, 3,a. La lección 4 se topó con él con 123 ejecuciones: las 123 relaciones salían todas de la misma ejecución; filtrar con WHERE y sin MATCH funciona.
IGNORE_ERRORS = true en un COPY desde una subconsulta, cuando falta una clave, falla con Error: bad variant access en lugar de omitir la fila.
2. count(DISTINCT …) antes de sum(…) deja la suma en NULL
Sección titulada «2. count(DISTINCT …) antes de sum(…) deja la suma en NULL»CREATE NODE TABLE P(id INT64 PRIMARY KEY, g STRING, n INT64);CREATE (:P {id: 1, g: 'x', n: 10}), (:P {id: 2, g: 'x', n: 20}), (:P {id: 3, g: 'y', n: 5});MATCH (p:P) RETURN p.g, count(DISTINCT p) AS ps, sum(p.n) AS total ORDER BY p.g;MATCH (p:P) RETURN p.g, sum(p.n) AS total, count(DISTINCT p) AS ps ORDER BY p.g;p.g,ps,totalx,2,""y,1,""p.g,total,psx,30,2y,5,1Los mismos agregados, en el otro orden, dan los totales correctos.
La lección 5 encontró una forma más general, también en el motor 0.19.1 del paquete NuGet: con una clave de agrupación, un agregado después de un agregado DISTINCT en la misma proyección es incorrecto. RETURN k.name, collect(DISTINCT u.version) AS versions, count(*) AS projects da 0 proyectos para MongoDB.Driver en lugar de 14.
3. ACYCLIC conserva caminos que repiten un nodo
Sección titulada «3. ACYCLIC conserva caminos que repiten un nodo»Tres nodos, a y b enlazados en ambos sentidos, b enlazado con c:
CREATE NODE TABLE V(id STRING PRIMARY KEY);CREATE REL TABLE E(FROM V TO V);CREATE (:V {id: 'a'}), (:V {id: 'b'}), (:V {id: 'c'});MATCH (x:V {id: 'a'}), (y:V {id: 'b'}) CREATE (x)-[:E]->(y), (y)-[:E]->(x);MATCH (x:V {id: 'b'}), (y:V {id: 'c'}) CREATE (x)-[:E]->(y);MATCH p = (x:V {id: 'a'})-[e:E* ACYCLIC 1..4]->(y:V {id: 'c'}) RETURN properties(nodes(p), 'id') AS path;MATCH p = (x:V {id: 'a'})-[e:E*1..4]->(y:V {id: 'c'}) WHERE is_acyclic(p) RETURN properties(nodes(p), 'id') AS path;path"[a,b,a,b,c]""[a,b,c]"path"[a,b,c]"[a,b,a,b,c] pasa dos veces por b. La comprobación de ACYCLIC está en output_writer.cpp, línea 280; no he encontrado la causa. En el grafo del sitio de la lección 3, LINKS_TO* ACYCLIC 1..4 desde el índice de GitHub Actions hasta su lección 7 devolvió 14 caminos en Windows, incluido uno que pasa dos veces por la misma lección, y 29, todos los recorridos, en los runners de Linux y macOS. Una enumeración en Python da 25 caminos cuyos nodos intermedios son distintos, y 10 con la definición de is_acyclic, ambos extremos incluidos.
4. Un COPY fallido en una tabla de nodos la corrompe
Sección titulada «4. Un COPY fallido en una tabla de nodos la corrompe»Cargada con COPY, y luego un COPY que falla por una clave duplicada, con n.csv conteniendo la cabecera k y las filas a, b, c:
CREATE NODE TABLE N(k STRING PRIMARY KEY);COPY N FROM 'n.csv' (HEADER = true);COPY N FROM (RETURN 'a' AS k);MATCH (n:N {k: 'b'}) RETURN count(*) AS b_by_key;CREATE (:N {k: 'b'});MATCH (n:N) RETURN n.k ORDER BY n.k;En memoria:
Error: Copy exception: Found duplicated primary key value a, which violates the uniqueness constraint of the primary key column.b_by_key0n.kaabcb está ahí, pero su clave no encuentra nada; el CREATE de una clave existente tiene éxito, y el nuevo nodo contiene a, la clave que rechazó el COPY fallido, en lugar de b. En un archivo de base de datos (lbug -m csv d/x.lbdb), esta secuencia funciona: b_by_key vale 1 y el CREATE falla con Runtime exception: Found duplicated primary key value b.
Cuando los tres nodos se crean con CREATE en lugar de COPY, el COPY fallido también estropea un archivo de base de datos: después, CREATE (:N {k: 'z', v: 26}) sobre una tabla N(k STRING PRIMARY KEY, v INT64) añade un nodo que se lee como a,9, la fila rechazada, tanto en memoria como en disco.
5. Agrupar por una subconsulta COUNT pierde el grupo de 0
Sección titulada «5. Agrupar por una subconsulta COUNT pierde el grupo de 0»CREATE NODE TABLE C(id INT64 PRIMARY KEY);CREATE REL TABLE PARENT(FROM C TO C);CREATE (:C {id: 1}), (:C {id: 2}), (:C {id: 3});MATCH (a:C {id: 2}), (b:C {id: 1}) CREATE (a)-[:PARENT]->(b);MATCH (a:C {id: 3}), (b:C {id: 2}) CREATE (a)-[:PARENT]->(b);MATCH (c:C) RETURN c.id, COUNT { MATCH (c)-[:PARENT]->(:C) } AS parents ORDER BY c.id;MATCH (c:C) RETURN COUNT { MATCH (c)-[:PARENT]->(:C) } AS parents, count(*) AS cs ORDER BY parents;c.id,parents1,02,13,1parents,cs1,2La subconsulta devuelve 0 para el nodo 1, pero la consulta agrupada no tiene fila 0,1. OPTIONAL MATCH con count(…) da los dos grupos (lección 4).
6. timestamp() y CAST(… AS TIMESTAMP) ignoran el desfase
Sección titulada «6. timestamp() y CAST(… AS TIMESTAMP) ignoran el desfase»RETURN timestamp('2026-09-14T09:30:00-04:00') AS f, CAST('2026-09-14T09:30:00-04:00' AS TIMESTAMP) AS c, CAST('2026-09-14T09:30:00-04:00' AS TIMESTAMP_TZ) AS tz;f,c,tz2026-09-14 09:30:00,2026-09-14 09:30:00,2026-09-14 13:30:00+00Esperaba 13:30 también para los dos primeros: COPY y LOAD FROM convierten el mismo texto de un archivo CSV a 13:30 UTC (lección 4). El desfase se descarta sin aplicarse. timestamp(…) en el paquete C# 0.19.1 también devuelve 09:30 (lección 5).
2026-09-27 — Lección 9: un laboratorio de grafos
Sección titulada «2026-09-27 — Lección 9: un laboratorio de grafos»Un laboratorio sobre páginas inventadas bajo /lab/, para ampliar las lecciones 2 y 3 en lugar de repetirlas. Las predicciones fueron primero a data/lab/preregistration.md, con hash tomado a las 13:24 EDT (SHA-256 234e0639…040d) antes de cargar ningún conjunto de datos. Cada fichero esperado se escribió a mano a partir de él, antes de la ejecución que comprueba. Entorno: CLI de LadybugDB 0.20.4 en Windows, bases en memoria, CALL threads = 1 antes del COPY comparado. El script completo tarda de 1,5 a 6,5 s.
-
Trazador y extremo que falta: en verde desde la primera ejecución. Tras el
COPYfallido enLINKS_TO, siguen 2 enlaces y el índice de claves funciona. El bug de índice de la lección 2 afectaba a las tablas de nodos. -
Traducciones: en verde desde la primera ejecución. La igualdad de títulos da 3 avisos falsos de 4.
-
La primera ejecución de los casos de ciclos difería del fichero esperado en dos puntos:
- Un defecto del script, mío:
shortestes una palabra clave, y el analizador la rechazó como alias. - Un comportamiento upstream: un sendero cerrado lista sus páginas en contra de las flechas (fila QA). Las páginas y la longitud eran las predichas; solo el orden no.
Una sonda sobre el ciclo de seis páginas, ejecutada antes de escribir el anexo, separó los caminos abiertos (en orden) de los cerrados (invertidos). Los dos puntos constan en un anexo fechado; las predicciones originales se dejaron como estaban.
- Un defecto del script, mío:
-
Cotas: confirmado. Una cota de 5 no ve un ciclo de 6, y 6 lo encuentra. Una cota de 1 oculta un prerrequisito a profundidad 2.
No ejecutado: el check.sh completo en esta máquina. Su INSTALL json descargaría una extensión, y este laboratorio no tenía permitido descargar nada. Solo se compararon en local los dos scripts de la lección 9.
Por verificar
Sección titulada «Por verificar»- La lección 9 en Linux y macOS: el laboratorio solo se ejecutó en Windows.
ladybugdb-examples.ymlla compara en los tres runners. - Si
nodes()sobre un patrón cerrado está invertido a propósito (sin documentar) o por un bug, y si se corrige después de la 0.20.4. No se ha consultado el seguimiento upstream. - El script de instalación (
curl -s https://install.ladybugdb.com | bash) ybrew install ladybug: no se ejecutaron para este curso. - Las reproducciones mínimas solo se ejecutaron en Windows. Los scripts del curso que muestran los bugs 1, 2, 4 y 5 sobre los datos del sitio dan la misma salida en los tres runners de la CI.
- Si estos bugs ya están corregidos en la rama principal de LadybugDB, después de la 0.20.4.
- Si los conflictos de versión mayor del ejercicio 2 de la lección 5 (
MongoDB.Driver2 y 3,Microsoft.ML.Tokenizers1 y 2) rompen ga en tiempo de ejecución: no he compilado ni ejecutado ga. - El programa C# en
linux-arm64yosx-x64, y el programa Java enlinux_arm64: los runners de la CI sonlinux-x64,win-x64yosx-arm64. - Si
CREATE_FTS_INDEXtambién hace fallar la CLI 0.20.4 en el runner de Windows: la CI ejecuta la lección 7 solo con 0.19.1. - Si los dos proyectos aislados de
Common,GA.Business.DSL.SourceGenyGA.Business.Core.Generated, se usan en ga de alguna otra forma que unProjectReference. - Si un proceso de solo lectura que sigue abierto mientras un escritor hace checkpoint devuelve datos incorrectos, y no solo datos antiguos, cuando lee páginas que no tenía en caché (lección 8).
- En Linux y macOS, si cerrar el segundo
Databasede un proceso libera el bloqueofcntldel primero, como cerrar cualquier descriptor de un archivo libera los bloqueos del proceso sobre él, y deja que otro proceso abra el archivo en lectura-escritura. - Si un
BEGINrechazado también rompe una conexión del paquete de C# y de los demás bindings.