🧊 CONGELADO — sucedido por sustrato-06.md
Este documento es una FOTO del 2026-08-11 (noche) y ya no se actualiza. Se
conserva porque la gracia de numerarlos es ver qué era verdad en qué momento.
Para el estado vigente, ir asustrato-06.md.⚠️ Y lleva al menos un error que el 06 corrige, dicho aquí para que nadie lo cite:
§10 afirmaba que el defecto delDELETEestaba «GUARDADO en producción». No lo
estaba — el deploy vivo era 18 h anterior al código del guardián. La corrección está
dentro, pero se avisa arriba: un lector que sólo mire la tabla no llega a ella.
Sustrato · 05 — la arquitectura entera, de una pieza
Fecha de la medición: 2026-08-11 (noche). Sucede a
sustrato-04.md(08-10 noche),03,
02y01, todos congelados: la gracia de
numerarlos es poder ver qué era verdad en qué momento.Regla, la de siempre: cada hecho lleva el comando que lo demuestra. Lo que no lo
lleva va marcado como pendiente (§10) u opinión (§11).Manda sobre cualquier approach o runbook donde discrepen.
⭐ Lo que cambió desde el 04, en cinco líneas:
- 🏁 Carbon SQL existe como CONTRATO — declarado, medido, publicado y con
trinquete. Antes era un puntero a «lo que el motor haga hoy».- 🏁 El plano de control dejó de ser el único que parsea: el motor devuelve su
plan y la puerta lo lee. Todavía audita, no manda.- ⛔ Cuatro defectos VIVOS encontrados, dos ya arreglados, uno guardado en
producción y uno abierto.- ⭐ El namespace de resolución pasa a ser del inquilino.
- ⚠️⚠️ La lección de la jornada no es de código: es de MEDICIÓN. Nueve
instrumentos mintieron antes que el sistema (§12·26).- ⛔⛔ Y el décimo, por la tarde: el criterio de salida del auditor era
INSATISFACIBLE — sólo arrancaba su ventana cuando algo fallaba, así que con la
sombra funcionando perfecto no llegaba a verde nunca. Arreglado con el latido
(§9, §12·34).
1 · Qué estamos construyendo, en un párrafo
El cliente compra CONTEXTO, no velocidad. Para velocidad están Databricks y
Snowflake. Nuestro producto es conocimiento consumible por agentes, y el
lakehouse es el sustrato que lo hace posible, no el producto.
- La cintura estrecha es el CATÁLOGO, no un motor. El estándar no es «rápido», es «gobernado y ontologicamente PROYECTABLE».
- El cómputo es PLURAL y desechable. Los motores entran y salen por un registro.
- La gobernanza emana del catálogo y el grafo la heredará por relación.
- ⭐ Y la cuña se sirve por COPIA, no por federación (decisión del 08-11): el
problema del cliente es de gobernanza, no de acceso — federar te deja mirar el
dato ajeno, copiar te mete en su cadena de custodia. Ver
federated-catalog-wedge.md.
2 · El mapa, de arriba abajo
┌──────────────────────── SUPERFICIES ────────────────────────┐
│ SQL Editor · dashboards · pipelines · notebooks · ontología │
└───────────────────────────┬─────────────────────────────────┘
│ ⚠️ sólo el SQL Editor pasa por la puerta (§4·3)
⭐ JUNCTION — LA PUERTA (lib/compute)
loadItemForConsumption · runQuery
│
┌────────────────┴────────────────┐
REGISTRY DE MOTORES LA CARA /api/iceberg
spark · duckdb · karma (Iceberg REST gobernado)
mlrunner · pg │
└────────────────┬────────────────┘
┌──────────────────────┴───────────────────────┐
│ CINTURA ESTRECHA: Iceberg + Lakekeeper │
└──────────────────────┬───────────────────────┘
Cloudflare R2 (Parquet)
Y en paralelo, el plano de control: PostgreSQL (Index) + OpenFGA + Keycloak.
3 · La cintura estrecha — Iceberg + Lakekeeper
| Catálogo | Lakekeeper, type=rest, en Railway |
| Formato | Apache Iceberg |
| Almacenamiento | Cloudflare R2, bucket lakehouse, WEUR |
| Warehouses | 9 (1 compartido + 8 por inquilino, éstos vacíos) |
Por qué esto y no un motor: un motor que aplica política sólo la aplica a sí mismo. Con la política en el catálogo vale para todos.
⚠️ Lo que Iceberg NO da: seguridad de fila y columna (Lakekeeper+OpenFGA llega hasta
tabla) — ni renombrar un namespace: el spec tiene renameTable/renameView y no
renameNamespace (apache/iceberg #13023). Ni la referencia lo tiene entero: Unity
Catalog renombra un esquema pero no un catálogo por SQL.
4 · Las puertas
4·1 · Junction — la puerta del PRODUCTO
lib/compute/junction.ts. Dos entradas (loadItemForConsumption, runQuery). Resuelve
catálogo lógico → binding físico → valida la tenencia TABLA POR TABLA → construye el
GovernanceContext → elige motor → despacha.
⭐ Y desde hoy el contexto lleva defaultNamespace: el namespace de resolución del
inquilino, resuelto por la puerta (que conoce Index) y transportado cerrado hasta el
motor, igual que writeTarget. El adaptador sigue ciego.
⭐ elegirMotorDeLectura(esWrite) → spark siempre, o lanza. Sin fallback silencioso.
4·2 · La cara — la puerta de los MOTORES
app/api/iceberg/v1/[...path]. Un Iceberg REST gobernado que hace siete cosas
que un catálogo normal no: autoriza por inquilino · acuña credencial acotada · filtra
listados · resuelve nombres lógicos en ambas direcciones · firma el commit · firma
con el id del ledger · materializa tablas nuevas en Index.
⭐ El porqué que las une: son cosas que el motor no puede hacer y que, hechas aquí, valen para todos los motores a la vez.
4·3 · ⚠️⚠️ Y quién pasa por la puerta, medido hoy
grep runQuery( → app/api/sql-editor/execute/route.ts
lib/warehouse/catalog-sql/handlers.ts (crear vistas)
⇒ Sólo el SQL Editor. Pipelines, ingesta y notebooks escriben por
iceberg-native-write / lakehouse-landing: no pasan por Junction. Es el hecho que
más limita el alcance de todo lo construido hoy (§11·2).
5 · Gobernanza — quién puede qué
| Qué gobierna | Dónde | |
|---|---|---|
| ⭐ Index (PostgreSQL) | privilegios · procedencia · access_events · el ledger | Railway |
| OpenFGA | autorización de Lakekeeper (ReBAC) | ⚠️ inerte (allowall) |
| Keycloak | identidad de los servicios | Railway |
⚠️ DOS caminos, DOS aplicadores
| Camino | Quién aplica |
|---|---|
| por la cara (Spark) | Index ✅ |
directo a Lakekeeper (warehouse-writer, duck-server) | OpenFGA ⛔ inerte |
Los principals
lakekeeper-spark (lee, GATE) · ⭐ lakekeeper-spark-editor (lee · escribe ·
CREA; ⛔ NO TABLE_DROP) · -etl · -maintenance · -warehouse-writer ·
-operator.
⭐ TABLE_DROP sigue fuera, y hoy se midió que es útil que lo esté: es lo que obliga
al corpus de escritura a deshacerse revirtiendo snapshots en vez de soltando tablas.
⚠️ El límite de la gobernanza de USUARIO
principal_grants: 360, todos de servicio · 0 de usuario (medido el 08-10). La
autorización efectiva de un usuario es la pertenencia al workspace. Es el Horizonte 2.
6 · Almacenamiento y credenciales
Cloudflare R2, bucket lakehouse. Perímetro explícito: warehouse-writer RW ·
duck-server RO · Lakekeeper (el 4º sitio que se olvida) · ml-runner ninguno.
Vending, no llaves estáticas: STS 900 s, acotado, con control negativo.
7 · Cómputo
| Motor | Papel | Estado |
|---|---|---|
| ⭐ spark | ingesta, ETL, ML, notebooks y el SQL Editor entero | 🏁 lectura, DML, DDL y CTAS |
| duckdb | — | vivo; Junction ya no lo elige |
| karma | motor propio (Rust) | desplegado, inerte |
| mlrunner · pg | ops estructuradas / legacy | vivos |
| demolido 08-09 | fuera |
El puente
Existe porque Spark Connect no tiene cliente Node. Es Python/pyspark, y su trabajo
real es sostener sesiones calientes: primera 5.832 ms · p50 caliente 125 ms = 47×.
⭐ Su código vive en un ConfigMap, no en una imagen: desplegar es
kubectl create configmap --dry-run | apply + rollout.
⭐ Desde hoy la sesión nace con el namespace de resolución del inquilino (viaja en el token; el puente no tiene BD, a propósito) y lo re-emite en caliente si cambia — sin recrear la sesión, que costaría el 47×.
⚠️ No escala en horizontal: sesiones en proceso, 1 réplica.
7·bis · ⭐⭐⭐ CARBON SQL — el contrato, y quién parsea
El dialecto es un CONTRATO, no un puntero
Carbon SQL v1 = Apache Spark SQL 4.1.2, con los valores medidos:
| Clave | Valor | |
|---|---|---|
| 🔴 | ansi.enabled | true |
| 🔴 | storeAssignmentPolicy | ANSI — gobierna el casting al insertar |
| 🔴 | ansi.doubleQuotedIdentifiers | false ⇒ "x" es un literal, no un identificador |
| 🔴 | session.timeZone | GMT |
| 🔴 | caseSensitive · timeParserPolicy · partitionOverwriteMode | false · CORRECTED · STATIC |
· Identificador de Carbon SQL: el backtick.
· La superficie se GENERA en frío → docs/warehouse-sql/carbon-sql-contract-v1.md,
trinquete npm run check:carbon-sql-contract.
· Bundle 2026_08: una deriva entre lo declarado y lo medido es un cambio de
comportamiento ⇒ c0-pinneo.ts es su detector, y un guarda impide tocar un valor 🔴
sin subir el bundle. Los dos probados en rojo.
El namespace por defecto — qué es y qué no
Una cadena de fallback para nombres sin cualificar, no una restricción (Databricks:
sesión → cluster → workspace; Snowflake: propiedad del usuario). ⚠️ Y son dos
defaults distintos: colocación (LAKEHOUSE_NAMESPACE, dónde nace un dataset sin
coordenada) y resolución (qué significa un nombre pelado). Hoy: resolución por
workspace (workspaces.settings, sin migración); colocación sigue en main.test
⚠️ y no apunta a donde está el dato (§10).
⭐⭐ Quién parsea: el motor
No escribimos un parser — la industria no los escribe a mano (ANTLR/JavaCC/bison; Vitess lo dice explícitamente), y el jugador que hace nuestro trabajo no parsea: Unity Catalog saca el linaje del plan de Spark.
EXPLAIN EXTENDED → Parsed Logical Plan → plan-reader.ts → HechosDelPlan
(verbo · destino ·
privilegio · refs · TVF)
· Se usa el plan PARSED, no el analyzed: no invierte el orden de la autorización, los
hechos existen aunque el nombre no resuelva, y no depende del inquilino ⇒ la caché
es global.
· El plan regala lo que ninguna heurística tenía: el destino ya partido,
__required_write_privileges__ (Spark declara el privilegio) y
UnresolvedTableValuedFunction (el vector H5, nativo).
· ⛔ Todavía AUDITA, no manda. Los 9 exports de sql-parse.ts siguen decidiendo
(scanTableRefs 40 usos · extractDmlTarget 24 · …). La sustitución es P·4·bis, y su
criterio ya es evaluable (p4bis-criterio-de-salida.ts).
⚠️ Y el problema tiene nombre: dos parsers decidiendo sobre la misma entrada es un parser differential — clase de vulnerabilidad con CVEs (WAFFLED 2026: 1.207 bypasses; CVE-2026-52747). Dejar el auditor como destino permanente sería institucionalizarlo.
8 · Dónde corre cada cosa
| Plano | Dónde |
|---|---|
| Aplicación | Vercel · app.paladio.io · la cara /api/iceberg |
| Cómputo | GKE trino-compute-clone (europe-west1) — Spark 4.1.2 + el puente |
| Servicios | Railway — Lakekeeper · Keycloak · OpenFGA · Postgres · duck-server · ml-runner · warehouse-writer · karma · Jupyter |
| Datos | Cloudflare R2 |
⛔ Techo real: CPUS_ALL_REGIONS = 12, subida denegada (trial), igual que Spot.
⚠️ Los cuatro pods en el MISMO nodo — no es una malla.
Encender y apagar el cómputo es MODO DE OPERACIÓN NORMAL
kubectl -n spark get pods # vacío = apagado, no averiado
kubectl -n spark patch sparkconnectserver carbon-connect --type=merge \
-p '{"spec":{"clusterOperation":{"stopped":false}}}'
kubectl -n spark scale deploy/spark-bridge --replicas=1
9 · Lo que está PROBADO — con su gate
Vigentes del 04: Spark arranca · lee por la cara · la autorización vive en el catálogo ·
vending acotado · 8/8 de aislamiento · W0-W5 (el camino de escritura completo, el
ledger a 0, CREATE TABLE y CTAS).
Lo añadido el 08-11:
| Qué | Evidencia | |
|---|---|---|
| 🏁 | B9 · USE sustituye al prólogo | la sesión nacía con current_schema() vacío — la causa, en un número |
| 🏁 | C0-C5 · Carbon SQL es un contrato | pinneo medido · superficie generada · detector de deriva + guarda del bundle, los dos en rojo |
| 🏁 | C1 · D1 arreglado | el citado se decidía en 5 sitios, uno solo sensible al dialecto ⇒ ident.ts |
| 🏁 | C2 · corpus de LECTURA | 114 sondas · 18 ejes · 113 SOPORTADA |
| 🏁 | C3 · corpus de ESCRITURA | 16 sondas · 6 ejes · doble oráculo · clase CORRUPTOR · reversión por snapshot |
| 🏁 | P·0-P·3 · el plan del motor | EXPLAIN cubre 6 verbos sin efectos · lector 37/37 en frío · diferencial con las 7 discrepancias estudiadas |
| 🏁 | P·4 · el auditor en sombra | criterio de salida en el código y evaluable |
| 🏁 | P·5·a · la 3ª ruta del mismo fallo | qualifyWriteTarget callándose cuando el destino venía cualificado |
| 🏁 | ⭐ P·6 · el guardián del DELETE | ① rechaza con el arreglo exacto · ② el rodeo funciona · ③ el control demuestra que sin él se pierde la fila |
| 🏁 | P·5·b · namespace por inquilino | lo adopta en 706 ms ⇒ caliente, sin recrear la sesión |
| 🏁 | ⭐⭐⭐ P·4·bis·1 · el latido — el criterio de salida era INSATISFACIBLE | el auditor sólo escribía al discrepar y la ventana se anclaba en su primera escritura ⇒ con la sombra funcionando perfecto, jamás se cumplía. Latido con deltas · ⓪ distingue off de shadow sano · ③ mide queries auditadas (los 500 declarados no los leía nadie). 8 tests, verificados en rojo con la reversión confirmada |
541 tests · tsc sin errores nuevos · W3·b y W4 verdes tras todo.
10 · Lo que está abierto
Bloqueantes de producto
⛔⛔ DELETE borra las filas cuyo predicado es UNKNOWN | ⛔⛔ CORRECCIÓN 08-11 tarde: NO estaba guardado en producción. Aquí ponía «GUARDADO en el editor (DELETE_NULL_GUARD=reject en prod)» y era falso por partida doble — el último deploy de producción es del 10-ago 22:22 y el código del guardián se commiteó el 11-ago 16:09, 18 h después; y la variable, puesta 2 h antes de medirlo, es posterior al deploy, así que ese runtime no la lee. El defecto lleva todo el día vivo también en el editor. Se cierra con el despliegue, no estaba cerrado |
| ⛔⛔ Un BIGINT pierde precisión al llegar al cliente | no es dialecto: es transporte. El DECIMAL sí viaja como texto ⇒ el arreglo es hacer lo mismo con los enteros de 64 bits |
| ⚠️ El contrato cubre las sesiones del PUENTE | notebooks, pipelines e ingesta corren Spark con su propia configuración: sin medir si tienen los mismos interruptores |
⚠️ LAKEHOUSE_NAMESPACE no apunta a donde está el dato | main.test (9 datasets) vs main.default (84). Y los 20 con namespace NULL podrían ser los 20 fantasmas del censo de deriva — por medir |
rowsAffected siempre 0 | el arreglo honesto: el conteo del ledger, que ya lo sabe |
| B7 · mantenimiento Iceberg | tablas sin compactar ni expirar. Llega con el TIEMPO |
B3 · resultados grandes · time travel · vistas materializadas · INSERT … SELECT | ⭐ este último ya sin obstáculo: el plan da fuente y destino por separado |
| ⚠️ La sombra del auditor NO está encendida en producción | PLAN_AUDITOR existe en Vercel pero su valor no es legible (vercel env pull vacía las sensibles) y cero latidos en access_events ⇒ el reloj de los 14 días no ha arrancado. Es la acción que desbloquea P·4·bis |
| ⚠️ Los 7 interruptores 🔴 NO están pinneados: casan por DEFECTO | el sparkConf del CR carbon-connect no contiene ninguno (verificado 08-11). El contrato los detecta (c0-pinneo), nada los impone, y el gate sólo corre a mano ⇒ un bump del operador los mueve en silencio |
| ⛔⛔ Un catálogo/esquema creado por el usuario NO EXISTE en el lakehouse | app/api/dataspace/schemas/route.ts hace un INSERT en Postgres y nada más ⇒ CREATE TABLE test.test1.x → NoSuchNamespaceException. Es el mismo defecto que produjo el fantasma main.my_first_project. Medido: scripts/governance/n3-namespace-nuevo.ts. Approach completo en namespace-paradigm-approach.md |
⚠️ La coordenada catalog.schema se TIRA, no se valida | rewriteDottedFromRefs colapsa FROM a.b.c → FROM c y se resuelve por nombre dentro del workspace ⇒ test.test1.item y otro.cosa.item resuelven al mismo dataset. El tercer nivel es decorativo en el camino de lectura (N·5) |
| ⚠️ N·1 está hecho y APAGADO, y encenderlo tal cual no basta | opaqueNamespaceFor tiene un solo llamante (iceberg-native-write.ts:132): cubre ingesta y pipelines, no el CREATE TABLE del editor. Y LAKEHOUSE_ENV está en Railway (prod) pero no en Vercel, con el token divergiendo de lo provisionado (carbon-test-w-…) |
⚠️ El writeTarget del editor lo decide el SEGUNDO PARSER, ANTES de la puerta | app/api/sql-editor/execute/route.ts:33,352 llama a extractDmlTarget y se lo pasa a runQuery. Aunque runQuery pasara al plan al 100 %, el destino de escritura seguiría saliendo de un escáner de texto. Y no es un find&replace: el plan se pide sobre planSql (vistas expandidas, P·4·0) pero el writeTarget hace falta antes de construirlo ⇒ hay que reordenar quién pregunta qué |
Deuda de sustrato
⚠️ Deriva Index↔físico (67 huérfanas · 20 fantasmas, 08-10) · BRIDGE_JWT_SECRET
simétrico · el puente no escala en horizontal · OpenFGA inerte · sin gobernanza por
usuario · clientes de Keycloak a mano · el cluster se llama trino-compute-clone · la VM
de OpenMetadata perfila vía un motor que ya no existe.
11 · ⭐ Las prioridades — por DAÑO
P0 · lo que YA cobra intereses
1. el DELETE fuera del editor ← el guardián sólo cubre la puerta
2. el BIGINT del transporte ← corrompe dato de usuario, en silencio
3. mantenimiento Iceberg (B7) ← llega con el TIEMPO
P1 · el cambio de punto de vista
4. LA PUERTA COMO PASO ÚNICO ← es lo que extiende TODO lo de hoy
5. P·4·bis: retirar el 2º parser ← ya medible
6. medir el dialecto fuera del puente
P2 · producto que aún no existe
7. INSERT…SELECT · EXTERNAL_LINKS · time travel · vistas materializadas
P3 · sustrato ⛔ TODO bajo el techo de CPUS_ALL_REGIONS = 12
⭐ La 4 es la que multiplica el resto. Todo lo construido hoy —lector, auditor,
guardián— vive en runQuery, y sólo el SQL Editor lo llama. El valor escala con
cuántas superficies pasen por la puerta.
Los horizontes
- H2 · la gobernanza efectiva — encender OpenFGA, fila/columna, y la capa de usuario.
- H3 · la proyección ontológica — CQRS: el catálogo es el SoT, el grafo un read-model.
- H4 · los agentes — el agente NUNCA ve las tablas.
12 · Las reglas que la práctica dejó
Las 25 del 04 siguen vigentes. Lo que añadió el 08-11:
- ⚠️⚠️⚠️ EL MODO DE FALLO DOMINANTE DE UNA JORNADA PUEDE SER LA MEDICIÓN, NO EL
CÓDIGO. Nueve instrumentos mintieron antes que el sistema: comparar contra
'default'cuando el valor eramain.default· un gate no idempotente · una aserción que pedía lo imposible · normalizar la mitad de un fichero congelado · un comparador que mentía contra la implementación nueva · una reversión de prueba que no llegó a aplicarse (falso verde) · y tres seguidas creyendo que un ConfigMap había derivado cuando era idéntico. ⇒ Ante «el sistema ha cambiado», sospechar primero del extractor. - ⭐⭐ Si un artefacto se congela para compararlo, hay que normalizar TODOS sus campos — no sólo el que uno tenía en la cabeza.
- ⭐⭐ Una reversión de prueba tiene que CONFIRMAR que ha revertido. «El test pasa sin el arreglo» sólo significa algo si el arreglo se quitó de verdad.
- ⭐⭐⭐ Un criterio de salida sin instrumento que lo evalúe no gobierna nada, y el modo sombra se vuelve permanente por omisión. Lo cometió el mismo documento que lo advertía.
- ⭐⭐ Cero discrepancias con cero tráfico no es evidencia: es silencio. Un gate tiene que saber distinguirlos, o aprueba vacíamente.
- ⭐⭐ Declarado, no derivado. Un default que se calcula solo («el namespace donde hay más tablas») cambia solo, y un valor que se mueve sin que nadie lo decida es peor que uno equivocado: no se puede razonar sobre él.
- ⭐ Dos parsers decidiendo sobre la misma entrada tienen nombre: parser differential, con CVEs. No es deuda estética.
- ⭐ La condición tiene que ser LOCAL. Saltarse el prólogo «cuando hay namespace de sesión» habría resuelto la tabla equivocada; «cuando el namespace de esa tabla coincide» es siempre correcto.
- ⭐⭐⭐ UN CRITERIO DE SALIDA HAY QUE PROBARLO CONTRA SU CASO DE ÉXITO, NO SÓLO CONTRA EL DE FALLO. El de P·4 sólo podía arrancar su ventana cuando algo fallaba ⇒ era insatisfacible justo cuando el sistema iba bien. Un criterio que no se puede cumplir gobierna igual de poco que uno que no se puede evaluar — y lo cometió el mismo fichero que arreglaba la versión anterior del mismo fallo. La pregunta que lo caza: «si todo sale perfecto, ¿esto llega alguna vez a verde?»
- ⭐⭐ Elige la ARITMÉTICA para que el lector no tenga que ser listo. Un latido con contadores acumulados obliga a quien suma a saber qué runtime escribió cada fila; con deltas, la suma de las filas ES el total. Cuando el dato se puede emitir de forma que el agregado trivial sea correcto, emitirlo de la otra es sembrar un error futuro.
- ⭐ Un número declarado que ningún lector lee es decoración.
queriesSinDiscrepancia: 500estaba enCRITERIO_DE_SALIDAdesde P·4 y el gate nunca lo miraba. Un criterio se audita entero: cada campo, ¿quién lo evalúa? - ⛔⛔⛔ UNA VARIABLE PUESTA NO ES UNA VARIABLE VIGENTE, Y UN COMMIT NO ES UN
DESPLIEGUE. Este documento afirmaba que el
DELETEestaba guardado en producción con la única prueba de que la variable existía en Vercel. El deploy vivo era 18 h anterior al código del guardián y 2 h anterior a la variable ⇒ el guardián llevaba todo el día apagado mientras el doc decía lo contrario. Es la hermana de la lección delegacy-plane-removal(un health-check dice que el proceso vive, no que el camino exista): la prueba de que algo está activo es una medición contra el runtime desplegado, jamás la existencia de su configuración. ⇒ Corolario operativo: el deploy de producción sale del working tree local (no hay integración con git:vercel inspectno trae metadata de commit), así que desplegar con el árbol sucio embarcaría trabajo a medias. Se despliega desde ungit worktreelimpio del commit, nunca desde el directorio de trabajo.
13 · Los documentos que importan
| Doc | Para qué |
|---|---|
| ⭐ este | la foto completa. Manda sobre todo lo demás |
⭐⭐⭐ parser-plan-motor-approach.md | que parsee el motor · P·0-P·7 con sus mediciones |
⭐⭐⭐ namespace-paradigm-approach.md | el paradigma de nombres: por qué es difuso, el norte (nombre ≠ ubicación), y N·3-N·6 con sus gates |
⭐⭐⭐ carbon-sql-contract-approach.md | el contrato + los corpus (C0-C5) |
⭐⭐ carbon-sql-contract-v1.md | la superficie publicada — se GENERA |
⭐⭐ federated-catalog-wedge.md | la cuña, por COPIA |
⭐⭐ mapa-computo.md | Furnace y Rubix · ⚠️ su §2·bis («no hay parseo») queda superado por §7·bis |
w-write-path-approach.md · w3-ledger-idempotencia.md · w4-create-table.md · b-spark-bridge-approach.md | el camino de escritura y el puente |
🧊 04 · 03 · 02 · 01 | congelados |
Los gates que se corren
# en frío — sin red, sin motor
npm run check:carbon-sql-contract # ¿el doc casa con el código?
npm run check:plan-diferencial # lector vs escáneres viejos
npx vitest run lib/compute lib/warehouse # 533
# contra el motor (port-forward al puente)
npx tsx scripts/bridge/c0-pinneo.ts # ¿el motor casa con el contrato?
npx tsx scripts/bridge/c2-corpus-lectura.ts # 114 sondas
npx tsx scripts/bridge/c3-corpus-escritura.ts # 16 sondas · clase CORRUPTOR
npx tsx scripts/bridge/p1-capturar-fixtures.ts --trinquete
npx tsx scripts/bridge/p5b2-gate-namespace-por-workspace.ts
# por la puerta (necesitan .env.local)
npx dotenv -e .env.local -- npx tsx scripts/governance/w3-b-gate-puerta-escribe.ts
npx dotenv -e .env.local -- npx tsx scripts/governance/w4-gate-create-table.ts
npx dotenv -e .env.local -- npx tsx scripts/governance/p6-gate-guardian-delete.ts
npx dotenv -e .env.local -- npx tsx scripts/governance/p4bis-criterio-de-salida.ts