P5 · La mudanza al warehouse del inquilino — por qué sigue RETIRADA, y cómo se desbloquea F2 sin ella
2026-08-06. Este documento nació proponiendo ejecutar P5, y la investigación lo
refutó. Se conserva con la conclusión correcta porque el camino hasta ella tiene tres
mediciones que valen, y porque el error de encuadre es instructivo: F2·a encontró un
404, y la reacción natural —«hay que mudar los datos»— era la equivocada.Conclusión: P5 no se hace. F2 se desbloquea creando un dataset NUEVO.
1 · La corrección: P5 ya estaba retirada, y con buena razón
storage-tenancy-approach.md §P5, decisión del owner del 2026-08-04:
P5 · Migrar lo que ya existe— ❌ RETIRADA
Las 112 tablas del inquilino histórico no se migran: son sustrato de desarrollo, no
dato de cliente. Se quedan donde están, enwarehouse/<uuid>/.
⭐ Con eso desaparece la única fase con riesgo de pérdida del plan, y con ella la
ventana en la que un inquilino tendría tablas en dos warehouses. Lo que queda es sólo
construcción hacia delante.
Esa razón sigue intacta. Trino no la cambia — y proponer resucitar P5 por un 404 de F2·a era confundir «no puedo leer las tablas viejas» con «hay que mover las tablas viejas».
⭐ El razonamiento que lo resuelve, y estaba en la propia decisión
Si las 86 tablas son sustrato de desarrollo y no dato de cliente, entonces
F2 no necesita leerlas. F2 necesita demostrar que el camino funciona:
Trino → cara → Lakekeeper → R2, con gobernanza. Y para eso sirve cualquier tabla
que esté donde el modelo dice —incluida, y mejor, una que nazca hoy.
2 · Las tres mediciones que sí valen
① Lakekeeper valida el prefijo — no se puede re-registrar in-place
Experimento con metadata-location falsa pero bien formada, para que el tipo de
error fuera la respuesta. Sin tocar ninguna tabla real:
| Respuesta | |
|---|---|
| register cross-warehouse | InvalidLocation 400 — «is not a valid sublocation of the storage profile s3://lakehouse/test/w_7b500f4d…» |
| ⭐ control positivo: misma location, su propio warehouse | NotFound — «IO error … head operation: NotFound» |
Errores distintos: el primero rechaza antes de leer; el segundo va a por el fichero.
Y es una propiedad de seguridad, no un obstáculo: es lo que impide que la tabla del
inquilino A apunte a bytes del prefijo de B. El aislamiento del pool se aplica en el
catálogo. Si se pudiera saltar, el modelo de tenencia sería decorativo.
② Copiar los ficheros tampoco bastaría
«Because the paths to metadata files and data files are hardcoded in the Iceberg
manifests, just replicating the files to some other location renders them
useless.»
La vía oficial es rewrite_table_path, y Trino no la tiene
(trino#25499, abierto); es un
procedimiento de Spark, que no corremos. ⇒ una P5 «de verdad» costaría montar Spark
para mover 54 MB, o reimplementar la reescritura de metadata sobre datos de producción.
Dos razones independientes más para no hacerla.
③ El camino de escritura ya apunta al warehouse del inquilino
tenantWarehouseNameForDataset() (P3) está cableado en producción:
ingest-client.ts:71 · read-client.ts:95,243 · duckdb.ts:158.
⇒ Las tablas nuevas ya nacen donde deben. No hay nada que arreglar aguas arriba: las 86 son rezagadas históricas, no un modelo roto.
3 · El estado real de los dos candidatos — y por qué ninguno servía
Medido el 2026-08-06:
| Workspace | En Index (datasets) | En su warehouse de inquilino |
|---|---|---|
7b500f4d… | 86 datasets | vacío — sus tablas están en el compartido |
cccc70a5… | 0 datasets | poblado ([["test"],["main"]], tablas en main.test) |
Los dos están desemparejados, en direcciones opuestas. Las de cccc70a5… son tablas
de gates que nacieron en el catálogo sin registrarse en Index — así que
governedNamespaces() (que lee datasets) devuelve vacío y la cara filtraría todo.
Y esto es un hallazgo por sí mismo: existen tablas en el catálogo Iceberg sin
fila en Index. Es la asimetría que warehouse-index.md §5.3 ya
tiene medida —«una puerta de lectura, ninguna de escritura»— con su forma física.
Un objeto del Warehouse puede nacer sin pasar por Index, y ésos son invisibles para la
gobernanza. No bloquea F2, pero es exactamente lo que I·2 existe para cerrar.
4 · ⇒ Cómo se desbloquea F2: un dataset nuevo
En vez de mudar 86 tablas con riesgo de pérdida:
- Crear un dataset nuevo en un workspace con warehouse activo y grants
(
7b500f4d…los tiene). Por P3, nace en el warehouse del inquilino y queda registrado en Index — las dos mitades emparejadas, por construcción. - Ése es el canary de F2: se lee por la cara con
lakekeeper-trino, y luego por Trino. - Las 86 históricas se quedan donde están. Se leen por su pin, como hasta hoy.
Lo que se gana frente a P5: cero riesgo de pérdida · cero Spark · cero ventana con un inquilino en dos warehouses · y el canary prueba más, porque ejercita el camino de nacimiento completo (Index + catálogo + storage) en vez de sólo el de lectura.
El precio, dicho: las 86 tablas históricas no serán consultables por Trino hasta
que mueran o se re-materialicen por su cuenta. Con «sustrato de desarrollo» como
etiqueta, es aceptable — y es la misma decisión que el owner ya tomó el 2026-08-04,
ahora con Trino delante y sin que cambie.
5 · Lo que queda anotado para el futuro
- El día que una organización REAL tenga tablas en el compartido, P5 vuelve — y entonces sí habrá que decidir entre Spark y re-materializar. Las mediciones de §2 son el punto de partida de esa conversación.
rewrite_table_pathen Trino (trino#25499) es la pieza que la abarataría. Merece seguimiento.- Tablas sin fila en Index (§3) — es I·2, y ahora tiene un caso concreto que enseñar.
Cruza con: storage-tenancy-approach.md (§P5, la decisión que este documento confirma) · f2-catalog-substrate-approach.md (F2·a y su bloqueante) · trino-first-viraje.md (R3) · warehouse-index.md (§5.3, la asimetría de escritura).