Published

Programa de unificación del Warehouse — los 5 puntos

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...

Programa de unificación del Warehouse — los 5 puntos

⚠️ PARCIALMENTE OBSOLETO (predata 2026-07-09). Estado real y vigente: docs/INFRA.md. Correcciones: catálogo activo = Lakekeeper (type=rest); SqlCatalog RETIRADO (P2.5); el vending vended está ROTO sobre R2 → ruta = remote-signing; el hop /lakehouse/plan-files fue suprimido. Queda como registro de diseño.

Qué es esto. El plan de trabajo que deriva de warehouse-as-narrow-waist.md:
el punto único de la plataforma es el catálogo/formato (la cintura estrecha), no un
motor; el cómputo es plural. Este documento desarrolla los 5 puntos de ese plan — qué
es cada uno, por qué, qué implica en el código de Carbon, sus dependencias y su criterio de
"hecho". El Punto 1 se detalla como entregable aparte en
warehouse-compact-unit.md.


Mapa de dependencias

  (1) Warehouse = unidad compacta con UN contrato ────┐  la base: sin esto, todo lo demás
       │  (el objeto Warehouse + la puerta única)     │  sigue fragmentado
       ▼                                              │
  (2) Defender la SPEC abierta (Iceberg REST) ────────┤  el contrato de (1) es un estándar,
       │  (el catálogo como interfaz, no producto)    │  no un producto interno
       ▼                                              │
  (3) Migrar TODOS los puertos a la puerta ───────────┤  cada building block = cliente de (1)
       │                                              │
       ├──▶ (4) LIVE-SQL como puerto + Karma detrás ──┤  el caso especial (SQL arbitrario)
       │                                              │
       └──▶ (5) Cómputo plural gobernado por (1) ─────┘  N motores, una gobernanza

(1) es el cimiento; (2) define de qué material es su contrato; (3) es el grueso del trabajo (convergencia); (4) es el sub-caso que reintroduce a Karma correctamente; (5) es la regla transversal que gobierna todos los motores.


Punto 1 · Formalizar el Warehouse como unidad compacta con UN contrato de acceso

Qué. Hacer del Warehouse un objeto de primera clase: un modelo atómico de entidades (Catalog › Schema › Table/View/Volume, respaldadas por el tridente R2+catálogo+gobernanza) y una sola puerta de acceso por la que pasa toda lectura y escritura. Hoy el Warehouse está implícito (repartido entre datasets, dataset_rows, la facade, los routers, el ml-runner); el Punto 1 lo vuelve explícito y compacto.

Por qué. Es el cimiento de todo el programa: mientras el Warehouse no sea una unidad con un contrato, cada módulo seguirá improvisando su forma de hablar con él (la fragmentación observada). Los cinco grandes (Databricks/Snowflake/Foundry/Fabric/BigQuery) empiezan aquí: el control-plane como objeto único.

En Carbon. La cintura ya existe en germen: loadItemForConsumption ("LA PUERTA", item-consumption.ts) + la jerarquía catalogs › schemas › datasets (mig. 20261231) + el tridente. El Punto 1 = (a) atomizar la estructura (nombrar las entidades del Warehouse y sus invariantes), (b) congelar el contrato de la puerta (ItemRef → DatasetHandle con read/stream/aggregate/write/schemaOnly

  • gobernanza), (c) cerrar los bypass estructurales para que la puerta sea la única vía.

Hecho cuando. Existe una definición versionada del objeto Warehouse + su contrato de acceso, y ningún nuevo building block puede tocar dataset_rows/R2 sin pasar por la puerta. → Entregable detallado: warehouse-compact-unit.md.


Punto 2 · Defender la SPEC abierta (Iceberg + REST catalog), no un binario ni un catálogo propietario

Qué. El contrato del Punto 1 debe ser un estándar abierto (la Iceberg REST Catalog spec), no una API interna acoplada a nuestro código. La cintura es una interfaz, no un producto.

Por qué. Es la lección más sutil de la investigación: cuando centralizas en el catálogo, el peligro de lock-in se traslada del motor al catálogo. Si el catálogo es un binario propietario, cualquier motor nuevo (o un tercero, o un segundo motor que valide a Karma) queda atado a nuestra implementación. La industria lo evita estandarizando la interfaz: Databricks (UC Open APIs), Snowflake (Apache Polaris OSS), Google (BigLake Metastore expone Iceberg REST) — todos hablan la misma spec REST. Defender la spec, no el binario, es también lo que hace a Karma genuinamente sustituible (el test de robustez ASF).

En Carbon. Hoy el catálogo es un PyIceberg SqlCatalog sobre Postgres servido por el ml-runner (no hay endpoint REST). El Punto 2 = exponer ese catálogo por la Iceberg REST Catalog spec (provisionar Lakekeeper como fachada REST del SqlCatalog, o implementar el subconjunto REST sobre el catálogo existente), de modo que la resolución de tablas + el credential vending sean un contrato estándar. Karma ya trae RestResolver para consumirlo.

Dependencias. Habilita (3), (4) y (5): todos los puertos y motores resuelven por el mismo contrato REST. Es la corrección arquitectónica central que ya señaló compute-integration.md (retirar el hop ad-hoc plan-files).

Hecho cuando. Un motor externo (o Karma) resuelve una tabla del Warehouse por Iceberg REST

  • credenciales vendidas, sin tocar código interno de Carbon.

Entregable ✅ redactado: warehouse-open-catalog.md — arquitectura de dos capas (gobernanza Carbon/Doberman sobre catálogo técnico Iceberg REST), Lakekeeper recomendado (tipo cloudflare-r2 → vending R2 nativo; migración = re-registrar las 82 tablas vía register API), vending scoped al prefijo de tabla (proxied→vended), y rollout P2.0(=D3)→P2.5. Alternativa REST-over-JDBC descartada (reusa el PG pero sin vending R2).


Punto 3 · Completar la migración puerto-a-puerto a loadItemForConsumption

Qué. Cada building block que lee o escribe datos se convierte en cliente de la puerta. Es el grueso del trabajo: no inventar, converger.

Por qué. La fragmentación es, literalmente, convergencia incompleta. Cada puerto que sigue tocando dataset_rows (o el ml-runner, o R2) directamente es una forma más de hablar con el Warehouse que hay que retirar. Google/Microsoft "enchufan building blocks" haciéndolos clientes del contrato de acceso, no integraciones ad-hoc.

En Carbon. La migración ya está en marcha, canary-validada. Puertos ya cableados (según la cabecera de la facade): datasets.browse, graph.explorer.*, export.stream, dataspace.preview, sdk.rows (notebooks). Pendientes (el inventario exacto lo produce el entregable del Punto 1): dashboards data/query, model manager, map/geo, y —el caso especial— LIVE-SQL (Punto 4). El Punto 3 = terminar ese inventario y migrarlo puerto por puerto, cada uno detrás de su reader/writer-flag con shadow→canary.

Dependencias. Se apoya en (1) (la puerta) y (2) (el contrato REST). Contiene (4) como sub-caso.

Hecho cuando. Todo acceso a datos de la plataforma pasa por loadItemForConsumption; no queda ningún lector/escritor que toque dataset_rows/R2 fuera de la puerta.


Punto 4 · Extender la puerta a LIVE-SQL con un motor plural detrás (Karma)

Qué. Las superficies que ejecutan SQL arbitrario de usuario (SQL Editor, Dashboards QUERY) no se expresan como handle.read() estructurado; necesitan un ejecutor detrás de la puerta. Ese ejecutor es Karma — enchufado detrás de la facade, no como un cuarto shim.

Por qué. Es el sub-caso que reintroduce a Karma en su rol correcto: un motor de cómputo subordinado a la cintura (como Photon/DuckDB/Trino frente a Unity Catalog), no el punto único. Hoy estas superficies tienen cada una su propio traductor JSONB→SQL (tres shims paralelos): la mayor fuente de fragmentación de lectura.

En Carbon. El acople anterior (Build 5) se hizo mal (un try/catch con hop ad-hoc) y fue suprimido. El re-acople correcto está especificado en compute-integration.md: un Compute Gateway compartido que las 3 superficies llaman antes de su shim, resolviendo por el contrato REST del Punto 2, con el arnés de equivalencia (shadow/diff) como gate de rollout.

Dependencias. Requiere (1), (2) y el arnés de equivalencia. Es un puerto más dentro de (3).

Hecho cuando. El SQL Editor (y luego Dashboards) sirve queries Iceberg-nativas por Karma a través de la puerta, con equivalencia validada y fallback; el shim dialect.ts se retira por dataset.


Punto 5 · Cómputo plural, no un motor para todo

Qué. La regla transversal: muchos motores sobre el Warehouse, una gobernanza. Karma para SQL analítico; ml-runner para ML/feature; el read-client para lecturas estructuradas; futuros motores (streaming, grafo/Kuzu, search) sobre el mismo Warehouse.

Por qué. Los workloads son irreconciliables en un motor (OLAP-scan ≠ point-lookup ≠ ML ≠ streaming ≠ grafo). "One size does not fit all"; forzar un motor único recrea el monolito y reintroduce lock-in. La gobernanza los unifica en el control-plane; la ejecución permanece plural — es el consenso de los cinco grandes.

En Carbon. Ya es plural de facto: la facade enruta intents distintos a cómputos distintos (read/stream/aggregate → read-client; write → iceberg-native-write; ML → ml-runner; grafo → Kuzu). El Punto 5 = mantener esa pluralidad como principio explícito — cada motor nuevo se enchufa detrás de la puerta y resuelve por el contrato REST, gobernado por el control-plane, sin convertirse en un segundo punto único.

Dependencias. Es la invariante que gobierna (4) y cualquier motor futuro; se apoya en (1) y (2).

Hecho cuando. Añadir un motor nuevo (o sustituir Karma) es un cambio detrás de la puerta, sin tocar el contrato ni la gobernanza — el test de que la cintura, y no el motor, es el eje.


Secuencia recomendada

  1. Punto 1 (la unidad + el contrato) — el entregable inmediato; sin él nada converge.
  2. Punto 2 (Iceberg REST) — en paralelo temprano; define el material del contrato.
  3. Punto 3 (migración de puertos) — el grueso continuo, puerto por puerto, canary.
  4. Punto 4 (LIVE-SQL + Karma) — cuando (1)+(2)+arnés estén listos; es un puerto de (3).
  5. Punto 5 (cómputo plural) — principio permanente que se aplica desde el primer motor.