Published

⭐⭐⭐ C·6·0 · LA MEDIDA DEL TUBO — cuánto queda, y de qué está hecho

Connect any source, model it as an ontology, transform it, and operationalize it, analytics, automation and machine learning, under one governed, self-hostable roof. --- Most teams stitch the...

⭐⭐⭐ C·6·0 · LA MEDIDA DEL TUBO — cuánto queda, y de qué está hecho

Generado, no escrito a mano: scripts/ingesta/c6-0-medir-el-tubo.ts.
Supersede en alcance al censo de capacidades de C·0, que sigue valiendo para el
qué — aquí está el cuánto y el si alguien lo usa.


1 · La superficie · 59 ficheros · 9 711 líneas

⚠️ CORREGIDO. La primera medida dijo 85 ficheros / 11 839 líneas porque contaba
lib/triggers/polling-* como orquestación del tubo. No lo es: es la cola
trigger-polling de los workflows del canvas, sin una sola referencia a datasets
ni al writer. Lo cazó el trinquete al dar un falso positivo sobre
canvas-workflows/[id]/activate27 ficheros y 2 348 líneas de otra funcionalidad.
⭐ Un censo que se equivoca de frontera cuenta de más, y contar de más para justificar
un borrado es la peor manera de equivocarse.

subsistemafich.líneas
CDC (log de replicación) — Oracle LogMiner, redo parser, snapshots343 283
Polling workers (uno por origen: pg, mysql, oracle, sqlserver, s3, azure, dynamo, hubspot, excel)165 516
Colas de ingesta (las que el scheduler llenaba)1220
Sync workers (Iceberg, EDC)2245
Cara HTTP del CDC4283
Perfiles y disparadores2164

2 · ⭐⭐⭐ Los tres hallazgos

① El subsistema CDC NUNCA ha corrido

cdc_syncs       0 filas
cdc_sync_runs   0 filas   ⇒ ni una sola corrida registrada

34 ficheros y 3 283 líneas —Oracle LogMiner, un parser de redo logs, snapshots de MySQL y Oracle— que no se han ejecutado ni una vez. No es código poco usado: es código sin usar, y llevaba tiempo pareciendo una capacidad.

⭐ Encaja con lo que C·0 ya había olido por otro camino: las estrategias hash y cdc estaban declaradas en el tipo y sin implementación que las eligiera. El censo de capacidades vio el enum vacío; éste ve las 3 283 líneas detrás.

② ⭐⭐⭐ El tubo NO está dormido: se sigue llamando y falla en silencio

datasets con datos de verdad55 · la última: 11-ago-2026 (order_items, 112 650 filas)
FANTASMAS (0 filas, sin namespace)7 · el último: 16-ago-2026

El último fantasma es más reciente que la última escritura real. Hoy mismo entró categorias con row_count = 0 e iceberg_namespace = null: una fila registrada en Index para una tabla que nunca se materializó.

⇒ Eso cambia la decisión. Un tubo dormido se puede dejar pudrirse; uno que se invoca y falla sin decirlo produce daño cada vez: ocupa un nombre, deja una fila que nadie reconcilia, y le enseña al usuario un dataset vacío como si la ingesta hubiera funcionado. Es el patrón «el estado dice que está bien», sirviéndose solo.

③ El writer responde 200 — y no significa nada

WAREHOUSE_WRITER_URL (warehouse-writer-production.up.railway.app) contesta 200 en /health. ⚠️ Ya está apuntado y se vuelve a cumplir: un health-check dice que el proceso vive; sólo un e2e que ESCRIBA prueba el camino de escritura. El proceso está sano y el camino roto desde el ~11-ago, cuando dejó de existir el warehouse por inquilino que le pide a Lakekeeper.


3 · La cobertura, releída contra lo entregado

⚠️ Y esta relectura no es ceremonia: C·0 daba por cubiertas en C·5 la idempotencia y los lotes, y ninguna de las dos estaba cuando C·5 se cerró. Aparecieron al releer, no al escribir. ⇒ Un censo que dice «lo cubre la fase X» hay que releerlo cuando X se cierra, o es una promesa que nadie comprueba.

capacidadestadocontra qué se comprobó
Lectura completa (full_scan)🏁c5-gate-copia · 250 filas + suma en el destino
Streaming por lotes (techo de RAM)🏁fetchsize — sin él pgjdbc materializa todo
Idempotencia / REPLACE🏁dos pasadas, sigue en 250
Esquema y tipos del origen🏁DESCRIBE sobre la vista JDBC
Fan-out por rangos🏁4 lectores — era POSPONE en C·0 y hoy está
Estrategia automática (ts›seq›full)⏭️incremental
Cursor timestamp/sequence⏭️incremental — §7 dejó el WHERE puesto
Modo UPSERT⏭️incremental — la carga YA es MERGE, sólo cambia el ON
Checkpoint / reanudación⏭️incremental
Programación⏭️el disparador, no el motor: ejecuta la misma sentencia
Descubrimiento de FKs⏭️alimenta UI y grafo; no participa en copiar filas
Estrategia hashvocabulario muerto
Estrategia cdcidem — y ahora se sabe que son 3 283 líneas sin correr
Escritura por warehouse-writeres la causa de que la ingesta esté rota

5 cubiertas · 6 pospuestas · 3 abandonadas.

⭐⭐ De las 6 pospuestas, CINCO son la misma cosa: cursor, estrategia, upsert, checkpoint y programación son las piezas de un incremental, no cinco huecos sueltos. La sexta (FKs) no participa en copiar filas.

Suprimir el tubo deja UN agujero con nombre, no seis sin nombre.


4 · Hasta qué punto queda opacado

Lo que el tubo hacía y hoy hace el carril gobernado, mejor:

  • copiar de PostgreSQL — ahora es una sentencia, con permisos (CONNECTION_USE), credencial que no viaja en el SQL, compensación si falla y recuento verificado en el destino;
  • disparable desde el editor, un notebook o la UI — el mismo camino, porque la UI genera la sentencia;
  • y con lo que el tubo no tenía: SHOW SCHEMAS/TABLES IN <conexión>, CREATE TABLE … LIKE (metadata-only) e idempotencia real.

Lo que el tubo tenía y no está: un incremental — que nunca funcionó (cdc_syncs a cero), así que no se pierde una capacidad, se hereda una deuda con el alcance ya medido.

Lo que el tubo tiene y sobra: 9 orígenes distintos con un worker cada uno. El carril nuevo cubre PostgreSQL. ⚠️ Ésa es la asimetría honesta de este censo y no se tapa: suprimir el tubo entero retira mysql, oracle, sqlserver, s3, azure, dynamo, hubspot y excel. La pregunta que decide C·6·1 no es técnica —¿los usa alguien?—, y la contesta la tabla de §2·②: 55 datasets con datos, todos de postgresql/postgres. Ningún otro origen ha escrito nunca.


5 · 🏁 EL CORTE (2026-08-16)

El tubo está suprimido, no apagado con un flag — un interruptor deja creer que volver a encenderlo funciona, y no funciona: reactivarlo no ingiere, produce fantasmas.

scripts/start-workers.tsya no importa ni arranca los 9 polling workers, el scheduler ni el motor CDC
colas del tubono se abren, así que no hay ninguna que cerrar
trinquetenpm run check:sin-tuboverde, 3 985 ficheros mirados

Lo que el trinquete vigila es la ALCANZABILIDAD, no la existencia. Borrar 9 711 líneas es otra entrega; exigirlo aquí obligaría a desactivar el trinquete hasta hacerlo, y un trinquete desactivado no vigila nada.

⚠️ Y import type no cuenta: se borra al compilar, no arrastra código y no puede ejecutar una ingesta. Prohibirlo habría obligado a duplicar PartitionPlan y PartitionOutcome para complacer al vigilante — empeorar el código por el trinquete.


6 · ⏭️ Lo que este censo NO contesta

  • Qué se rompe al borrar. Eso lo dice el trinquete de C·6·1: debe fallar si alguien vuelve a llamar al writer desde el camino de ingesta.
  • Los 7 fantasmas. Hay que reconciliarlos (reconcileDropInIndex), y antes hay que cortar quien los produce — reconciliar sin cortar es barrer con el grifo abierto.