Published

El PIPELINE, de punta a punta — dónde estamos, medido

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

El PIPELINE, de punta a punta — dónde estamos, medido

Para qué es esto. Levantar la vista después de tres frentes seguidos (el cutover del
catálogo, la política en el plan, la robustez de escritura) y contestar una sola pregunta:
¿qué partes del camino de lectura y de escritura están cerradas, y cuáles siguen
abiertas?

Regla de la casa: cada hecho lleva el comando que lo demuestra. Lo que no lo lleva va
marcado ⏳ u opinión. Y lo que aquí se afirma se volvió a medir el 08-14/15 — no se
copió de los approaches, que es de donde vienen los tres errores corregidos abajo.


0 · Lo que hay que saber primero

  1. 🏁 El build de producción, arreglado (e656679): faltaba importar Security en PlatformSidebar.tsx. Una línea, cuatro deploys en Error y un diagnóstico largo — la lección de método, en §3. ⚠️ Producción sólo sirve lo nuevo cuando hay un deploy de Production en verde: un Ready de Preview no cuenta.
  2. 🏁 La lectura está gobernada de punta a punta: el motor delega el plan en el catálogo, la política viaja dentro, y la credencial ya no la esquiva.
  3. 🏁 La escritura resultó estar más entera de lo que decía su inventario: el reintento OCC existía —heredado— y ahora está atado y declarado.
  4. Pero la autorización no llega al OBJETO, y eso es lo que encarece todo lo demás.
  5. La Action atómica sigue siendo imposible: sin commit multi-tabla y sin transacción multi-sentencia, «escribe A y B, o nada» no se puede sostener.

1 · El camino de LECTURA

evidencia
🏁El motor delega la planificación en el catálogo (scan-planning-mode: server, canary por workspace)s2-gate-delegacion.ts · el contador de Plan table scan sube
🏁La cara completa el plan (plan-tasksfile-scan-tasks), todo-o-nadascan-plan.ts · 17 tests
🏁La política de fila viaja en el plan y cambia lo que el usuario ves3-gate-politica-en-el-plan.ts
🏁El vending está conmutado: sólo recibe llave quien pasa por el plans4-gate-vending-conmutado.ts
🏁El requisito de partición es conocido y comprobable, y hay censop0/p0b/p1/p2
La máscara de columna NO es aplicable en el plan ⇒ deniegamedido: el select no recorta el esquema
🏁La puerta contra un tercero, CERRADA en vivo: con política, una persona no recibe credencial y el motor sík3-gate-s4-en-vivo.ts

Lo que falta en la lectura, por orden de daño:

  1. ⭐⭐ La máscara de columna no tiene camino. Hoy una tabla con column_mask simplemente no se sirve. Es la mitad de la política de celda que sigue sin punto de aplicación, y la única salida es aplicarla en el motor (la «salida A»).
  2. Un segundo inquilino con datos. Todo el aislamiento está probado con uno solo: el control cruzado sólo puede decir «no existe ahí», no «existe y no lo ves».
  3. ⭐⭐ La identidad de Keycloak no está unida a la de Clerk: el sub del realm no es el user_… de los miembros de workspace. Una persona autenticada es alguien REAL y sin grants — sirve para medir la puerta, todavía no para que vea sus tablas.

2 · El camino de ESCRITURA

2·1 · Lo que está cerrado

evidencia
🏁Grants de usuario derivados de la membresía, USER_AUTHZ=enforce vivo/api/diag/motor · medido hoy
🏁El reintento OCC funciona — heredado del cliente Iceberg, la cara no lo rompe12 escritores · 34 conflictos reales · 12/12
🏁Las 7 propiedades de robustez, declaradas en la tabla (4 de reintento + 3 de aislamiento)105/107 tablas · las nuevas nacen con ellas
🏁createTable arreglado (G·1) — crea, sin huérfanas, y admite datosw8-create-sin-ctas.ts
🏁El destino viaja aparte del SQL (writeTarget autorizado fuera de banda)
🏁Idempotencia con huella de SQL+destino, y ledger con el snapshot observadolo mejor construido del repo

2·2 · Lo que sigue abierto, por orden de daño

estado
⛔⛔La autorización no llega al OBJETOMedido hoy: principal_grants = 389 workspace + 24 schema + 0 de tabla. Hay 16 TABLE_WRITE_DATA… todos de ámbito workspace. ⇒ la política discrimina por rol de workspace, no por persona sobre tabla
⛔⛔No hay Action atómicaVerificado hoy: /transactions/commit no existe (404 en 3 variantes · 0 endpoints con «transaction»). Y una sentencia por ejecución. ⇒ «escribe A y B, o nada» es imposible
El CTAS sigue roto (stage-create + hook importTable)Salida decidida: CREATE + relleno. Se pierde la atomicidad
S·5·③: el reintento tras un 500 no tiene gateLa cara ya pregunta al catálogo en vez de inferir del !res.ok, pero no está medido que no duplique
⚠️El fallo parcial se reconcilia A MANO (ControlPlaneUnrecordedError)compensate es corrección visible, no reintento automático
⚠️El bridge comparte UNA sesión de Spark ConnectObservado: al romperse se llevó 5 escrituras en el mismo milisegundo, y una de ellas había escrito pese a reportar error. No reproducible en 3 intentos
🟡INSERT … VALUES vetado con motivo caducadoSu fuente sí se resuelve, medido en frío
🟡dmlVerb decide por la primera palabra del textoYa se sortea preguntando al plan, pero la función sigue decidiendo en el resto de caminos

3 · ⭐ Las tres cosas que este repaso CORRIGIÓ

Las tres estaban escritas en documentos vigentes, y las tres eran falsas o imprecisas. No es casualidad: es el coste de arrastrar approaches escritos antes de poder medir.

decíalo medido
⭐⭐⭐«No hay ningún bucle de reintento ⇒ una de dos escrituras concurrentes se la come el usuario»El reintento existe, heredado del cliente Iceberg, y la cara pasa el 409 íntegro. Se estuvo a punto de construir uno al lado
⭐⭐«La política sólo protege si el filtro se resuelve por poda — tabla particionada u ordenada»Podar no es lo que protege. Sin partición se poda igual y queda residuo; bucket también. Sólo identity resuelve
«Se perdió el commit multi-tabla»Cierto — verificado contra el servidor, no contra la lista de endpoints, que ya mintió una vez con /scan

🪤 Y una cuarta, de método, que costó cuatro deploys

El build de producción moría con ReferenceError: Security is not defined mientras npm run build en local PASABA. Se persiguió durante cuatro intentos —se descartó la versión del paquete, el lock, ficheros que faltaran, la caché de webpack, el prerender— y la causa era un import que faltaba en PlatformSidebar.tsx. Una línea.

⭐⭐ El build local mentía porque el árbol local tenía trabajo SIN COMMITEAR que ya lo arreglaba, y el deploy sale de git. «En local pasa y en Vercel no», con el árbol sucio, no es una paradoja: es que no se estaba construyendo lo mismo.

🪤 Y lo que lo alargó: se miró git status | grep -v "^ M components" para quitar ruido, y ese filtro escondió justo el fichero culpable. Filtrar la lista de cambios mientras buscas una diferencia entre dos árboles es quitarte la respuesta de delante.

Regla: ante «en local funciona y en el deploy no», lo primero es git status, entero.


4 · ⏭️ El orden que se deduce AHORA

🏁 arreglar el BUILD                    ← hecho (e656679)
🏁 el SUJETO humano existe              ← hecho: Keycloak respalda, la cara distingue persona
                                          de servicio, y S·4 quedó cerrado en vivo
①  FEDERAR Keycloak ↔ Clerk            ← sin esto, una persona autenticada no es NADIE conocido
②  alcance de OBJETO en los grants      ← depende de ①: hoy no discriminaría a nadie (G·0)
③  la máscara de columna, en el motor   ← la mitad de la política de celda que no tiene camino
④  S·5·③: reintento tras 500 sin duplicar
⑤  la sesión compartida del bridge      ← un fallo suyo se lleva TODAS las escrituras en vuelo
⑥  Action atómica                       ← ya no es «estrenar» una capacidad: hay que reconstruirla

⚠️ ② dejó de ser el primero, y por una medición. G·0 midió que el ámbito de objeto no discriminaría a nadie hoy: los grants se derivan de workspace_members (12 sujetos de Clerk) y el único creador humano es el owner, que ya lo recibe todo. Sigue siendo la condición que abarata el futuro —mientras la autorización sea de workspace, cada verbo que se abra se abre para todo el mundo a la vez—, pero primero hace falta ①, o se construye una retícula sin nadie dentro.

Y ① no es fontanería de identidad: es lo que convierte a una persona en sujeto de gobierno. Hoy el sub de Keycloak es alguien real y sin grants; el user_… de Clerk tiene membresía y no puede hablarle al catálogo. Unirlos es lo que hace que todo lo construido —política en el plan, vending conmutado, partición por columna— le aplique a una persona.

⚠️ ⑥ cambió de naturaleza con el cutover. Cuando el inventario lo listó, la capacidad estaba «comprada y sin estrenar» (Lakekeeper exponía /transactions/commit). Gravitino no la expone ⇒ ahora hay que construirla o suplirla, y eso es otro tamaño de problema.


5 · Comandos que se corren

# el runtime — NUNCA la consola de Vercel
curl -H "x-diag-key: $SPARK_BRIDGE_JWT_SECRET" https://app.paladio.io/api/diag/motor

# la lectura gobernada
npx dotenv -e .env.local -- npx tsx scripts/warehouse/s3-gate-politica-en-el-plan.ts
npx dotenv -e .env.local -- npx tsx scripts/warehouse/p1-gate-particion-gobernada.ts
npx dotenv -e .env.local -- npx tsx scripts/warehouse/p2-censo-servibilidad.ts

# la escritura robusta (el gate necesita kubectl para contar los conflictos)
S5_ESCRITORES=12 npx dotenv -e .env.local -- npx tsx scripts/warehouse/s5-gate-reintento-occ.ts
npx dotenv -e .env.local -- npx tsx scripts/warehouse/s5d-barrido-robustez.ts   # --aplicar

# en frío
npx vitest run lib/governance     # 331 verdes
npx tsc --noEmit                  # limpio