🧊 Sustrato · 06 — la arquitectura entera, de una pieza
🧊 CONGELADO el 2026-08-12 — lo sucede
sustrato-07No se actualiza más. Refleja lo que era verdad el 08-11, y se conserva para poder
ver qué cambió y cuándo. Donde discrepe con el 07, manda el 07.⚠️ Lo que este documento afirma y ya no es cierto: N·5 LECTURA figura como
bloqueante (se cerró el 08-12) · los 9 nombres duplicados como ambiguos (ya
direccionan) · y todo el encuadre de la ontología, que dio un viraje entero (§5 del
07).
Fecha de la medición: 2026-08-11 (madrugada). Sucede a
sustrato-05.md(08-11 noche),04,
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 05, en seis líneas:
- 🏁 El paradigma de nombres está CERRADO: nombre ≠ ubicación, como la
referencia. El namespace físico ya no espeja la taxonomía, y hay trinquete.- 🏁 El criterio de salida del auditor era INSATISFACIBLE — y dos de sus tres
condiciones estaban puestas a ojo. Ahora mide cobertura y diversidad.- ⛔⛔ El guardián del
DELETEllevaba TODO EL DÍA APAGADO en producción mientras
elsustrato-05afirmaba lo contrario. La única prueba aportada era que la
variable existía en Vercel.- ⭐⭐ Los dos frentes no eran paralelos: son el mismo. Gobernar el nombre exige
dejar de tratar el SQL como texto.- ⭐ 7 de 8 inquilinos ya se sirven de su propio warehouse.
- ⚠️⚠️ La lección: de ~15 defectos cerrados, la mayoría eran de los INSTRUMENTOS,
no del sistema (§12·38-44). Los dos que sí eran de producto los encontró
escribir SQL de verdad, no ninguno de los 30 gates.
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 cómputo es PLURAL y desechable — aunque hoy, de hecho, sea uno solo (§7).
- La gobernanza emana del catálogo y el grafo la heredará por relación.
- La cuña se sirve por COPIA, no por federación
(
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 (el único elegible) (Iceberg REST gobernado)
duckdb · karma · 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, y ⭐ 7 de esos 8 ya se sirven |
⚠️ Lo que Iceberg NO da: seguridad de fila y columna — ni renombrar un namespace:
el spec tiene renameTable/renameView y no renameNamespace (apache/iceberg
#13023). ⭐ Y desde el 08-11 eso dejó de importarnos: con el namespace opaco no
renombramos namespaces nunca (§7·ter).
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.
⭐ elegirMotorDeLectura(esWrite) → spark en SUS DOS RAMAS, o lanza. Sin fallback.
Es un hecho con consecuencias: §7·ter·4 retiró un guardián entero por él.
4·2 · La cara — la puerta de los MOTORES
app/api/iceberg/v1/[...path]. Un Iceberg REST gobernado que hace lo que el motor no
puede: autoriza por inquilino · acuña credencial acotada · filtra listados · resuelve
nombres lógicos · firma el commit · materializa tablas nuevas en Index · ⭐ y desde
hoy traduce también el NAMESPACE, no sólo el nombre de tabla (§7·ter).
4·3 · ⚠️⚠️ Y quién pasa por la puerta, medido
grep runQuery( → app/api/sql-editor/execute/route.ts
lib/warehouse/catalog-sql/handlers.ts (crear vistas)
⇒ Sigue siendo sólo el SQL Editor. Pipelines, ingesta y notebooks escriben por
iceberg-native-write / lakehouse-landing. ⭐ Pero ya no están fuera del paradigma de
nombres: el canary alcanza los dos runtimes, así que acuñan namespace opaco igual.
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 |
⭐ Y el namespace opaco desbloquea lo que faltaba: OpenFGA hereda jerárquicamente
sobre namespaces, así que con {env}.w_{workspace} la tenencia por fin es aplicable en
el catálogo. Era el motivo estructural de los 360 grants, 0 de usuario.
⚠️ DOS caminos, DOS aplicadores — sin cambios
| Camino | Quién aplica |
|---|---|
| por la cara (Spark) | Index ✅ |
directo a Lakekeeper (warehouse-writer, duck-server) | OpenFGA ⛔ inerte |
6 · Almacenamiento y credenciales
Cloudflare R2, bucket lakehouse. Perímetro explícito: warehouse-writer RW ·
duck-server RO · Lakekeeper · ml-runner ninguna. Vending STS 900 s.
⭐ Y el aislamiento por inquilino dejó de ser teórico: 7 de 8 organizaciones se
sirven de su propio warehouse (carbon-prod-w-<hex>) con su propio key-prefix
(prod/w_<hex>). Comando: n2-que-es-w-uuid.ts.
7 · Cómputo
| Motor | Papel | Estado |
|---|---|---|
| ⭐ spark | ingesta, ETL, ML, notebooks y el SQL Editor entero | 🏁 el ÚNICO elegible |
| duckdb | — | vivo; Junction no lo elige en ninguna rama |
| karma · mlrunner · pg | — | vivos, no elegibles para live-SQL |
| demolido 08-09 | fuera |
El puente (Python/pyspark) existe porque Spark Connect no tiene cliente Node. Sostiene
sesiones calientes: primera 5.832 ms · p50 caliente 125 ms = 47×. Su código vive en un
ConfigMap. ⚠️ No escala en horizontal: 1 réplica.
⭐ N catálogos en una sesión cuestan ~1.062 ms cada uno, UNA vez, perezoso, sin
impuesto por query y sin degradar a los ya registrados
(scripts/bridge/n1-coste-n-catalogos.ts). ⇒ el coste no es el obstáculo de N·6.
7·bis · CARBON SQL — el contrato
Carbon SQL v1 = Apache Spark SQL 4.1.2, bundle 2026_08. Los 7 interruptores
medidos y verdes (c0-pinneo.ts, corrido hoy: motor 4.1.2, los 6 semánticos casan, los 5
conductuales casan).
⚠️ Y los interruptores 🔴 NO están pinneados en el cluster: el sparkConf del CR
carbon-connect no contiene ninguno. Casan porque son los defaults de Spark 4.1.2.
El contrato los DETECTA; nada los IMPONE, y el gate sólo corre a mano.
⭐ Y una cláusula se retiró: ORDER BY ya no se bloquea
null-ordering rechazaba cualquier ORDER BY sin NULLS explícito — la cláusula más
común de SQL después de WHERE; 4 de 15 queries reales caían por ella. Su propio
comentario declaraba la condición de retirada —«mientras convivan dos motores»— y
elegirMotorDeLectura devuelve spark en sus dos ramas. ⇒ soloConDosMotores: true.
⭐ La entrada NO se borra del catálogo: se sigue detectando, así que el conocimiento se conserva y el día que entre un 2º motor vuelve a bloquear sola.
⭐⭐ Quién parsea: el motor — pero todavía AUDITA, no manda
EXPLAIN EXTENDED → Parsed Logical Plan → plan-reader.ts → HechosDelPlan
Los 9 exports de sql-parse.ts siguen decidiendo. La sustitución es P·4·bis, y su
criterio está por fin bien medido (§9).
7·ter · ⭐⭐⭐ EL PARADIGMA DE NOMBRES — cerrado
El principio, y por qué es el de la referencia
El namespace físico espeja lo INMUTABLE (el inquilino), no lo EDITABLE (la taxonomía).
lo que escribes catalog . schema . tabla (editable, en Index)
↕ traduce LA CARA
donde viven bytes {env}.w_{workspace} / ds_{uuid} (opaco, inmutable)
⭐ Unity Catalog hace exactamente esto, y no lo contrario: guarda las tablas
gestionadas en <managed-location>/tables/<table_id UUID> y los motores resuelven por
nombre a través del catálogo, nunca por ruta. UC es limpio porque SEPARÓ el nombre de
la ubicación; Carbon era el que los tenía pegados.
Lo hecho, con su gate
| Qué | Comando | |
|---|---|---|
| N·3·a | el token de entorno decidido (prod) y reconciliado 8/8 | n3a-token-de-entorno.ts → 0 |
| N·3·b | el CREATE TABLE del editor entra al régimen opaco; la cara traduce el namespace | n3-namespace-nuevo.ts |
| N·3·c | canary desplegado | n3-namespace-nuevo.ts → verde de punta a punta |
| N·3·d | control negativo: el canary está ACOTADO | n3d-control-negativo.ts |
| N·3·e | sin regresión en el régimen del espejo | n3e-regresion-espejo.ts |
| N·4 | ⭐ el espejo RETIRADO de los dos caminos de nacimiento + trinquete | npm run check:sin-espejo |
| N·5 escritura | la coordenada gobierna el destino | n5d-gate-escritura-gobernada.ts |
| N·6·a | 7 de 8 inquilinos en su propio warehouse | n6a-encender-warehouse-propio.ts |
El canary está en * en Vercel Y Railway. Estado de las tablas del inquilino con
datos: 84 main.default · 20 (null) · 9 main.test · **7 prod.w_7b500f4d…** · 2 karma.test · 1 main.my_first_project.
⚠️ Lo que N·6 resultó ser
Se planteó como «el catálogo del usuario ES un warehouse» — una pregunta de nombres.
N·1/N·4 ya resolvieron los nombres, así que lo que queda es aislamiento de
ALMACENAMIENTO, que el código ya modelaba como opt-in con motivo (dedicated_storage).
No era una fase pendiente: era una capacidad diseñada y sin encender.
⛔ Y no hay versión incremental: la cara resuelve el warehouse por inquilino y por
petición, no por tabla. Medido: 7 inquilinos → gratis · 1 → 123 tablas / 128.012 filas
quedarían inalcanzables (n6-coste-de-la-mudanza.ts).
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 |
| Workers | Railway «Carbon Jobs» — ingesta, pipelines, provisioning |
| 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. ⚠️ Los cuatro pods en el
MISMO nodo.
⛔⛔ El despliegue de producción sale del WORKING TREE LOCAL
vercel inspect no devuelve metadata de commit: no hay integración con git. ⇒
vercel --prod embarca el árbol sucio. Se despliega desde un git worktree limpio.
Y vercel env pull no devuelve valores: 160 de 169 vacías.
⭐ Y el 08-12 se vio el reverso de esa regla, que es peor: el arreglo que impide
subir los 800 MB de .claude/ vivía sólo en el working tree desde el 08-09. Es
decir: desplegar desde un worktree limpio habría dejado fuera precisamente el arreglo
que hace que el deploy funcione. ⇒ un árbol sucio no sólo mete lo que no quieres:
también esconde lo que sí necesitas. Commiteado en 360b2d8.
9 · Lo que está PROBADO — con su gate
Vigentes: Spark arranca · lee por la cara · vending acotado · 8/8 de aislamiento · W0-W5 · C0-C5 (Carbon SQL como contrato) · P·0-P·6 (el plan del motor).
Lo añadido el 08-11 (madrugada):
| Qué | Evidencia | |
|---|---|---|
| 🏁 | El paradigma de nombres, entero | N·3·a→e · N·4 · N·5 escritura · N·6·a, cada uno con su gate |
| 🏁 | ⭐ CREATE TABLE test.test1.item + UPDATE funcionan | n3-namespace-nuevo.ts verde de punta a punta |
| 🏁 | El latido — el criterio era insatisfacible | p4bis-criterio-de-salida.ts |
| 🏁 | El arnés del corpus — 17 formas por la puerta, 0 no-vista | p4bis-arnes-corpus.ts |
| 🏁 | La comparación del auditor, simétrica | 2 tests; lo destapó N·3 |
| 🏁 | ⭐ ORDER BY desbloqueado | 17/17 queries reales corren |
| 🏁 | ⭐ Una tabla con datos, rescatada: animals era ilegible por CUALQUIER nombre | SELECT nickname, weight_kg FROM animals → 5 filas |
740 tests · tsc sin errores nuevos · 22 commits desde el 05.
⭐ Y el 08-12 (madrugada): desplegado
d12ff92 está en producción — dpl_HGmb1FbfBkChpVUN4kfcorgh6y9p, READY,
target: production, y vercel inspect https://app.paladio.io confirma que es ese
deployment el que sirve el alias. Es la primera vez que sale el arreglo de e965102
(el PLAN_AUDITOR que se apagaba en silencio), así que el auditor ya está midiendo
en prod con el modo visible.
⚠️ Lo que el árbol escondía, encontrado al pasarle el check antes de commitear:
| 28.227 líneas de UI sin commitear, 118 ficheros untracked | En ningún commit de ninguna rama (git log --all -S). Un git clean se las llevaba, y cualquier vercel --prod desde el root las embarcaba sin revisar. Commiteado en d12ff92 |
el .vercelignore con /.claude/ | Ver §8. Commiteado en 360b2d8 |
las 4 sondas de nombres + el filtro estricto de p4bis | Commiteado en 516d5a1 |
⚠️ Y una trampa de medición que hay que anotar antes de que muerda otra vez: en
producción, una ruta que no está en isPublicRoute de proxy.ts devuelve 404, no
401. /api/health y /api/files dan 404 igual que /dev-workspace-home-preview
⇒ un 404 no es prueba de que la ruta no se haya desplegado. El control correcto es
comparar contra una ruta pública del mismo build: /dev-sql-editor-carbon-preview y
/dev-files-carbon-preview dan 200. (Next 16: el middleware.ts se llama proxy.ts.)
🏁 9·bis · N·5 CERRADO — la coordenada direcciona (2026-08-12)
Verificado en producción por el owner, que es la única prueba que cuenta: marcó
karma.test.observatorios con un UPDATE y main.default.observatorios quedó
intacto. Antes, con nueve nombres duplicados, ganaba el orden del Map.
No era un defecto: eran cuatro, encadenados, y cada uno tapaba al siguiente.
| Qué | |
|---|---|
| 1 | El colapso. rewriteDottedFromRefs tiraba FROM a.b.c → FROM c — no por descuido, sino porque el nombre tenía que quedar pelado para casar con la CTE homónima que el plan antepone |
| 2 | El cuerpo de la CTE duplicaba la coordenada (main.default. + el token entero). Vinculaba bien y emitía mal — la peor de las dos |
| 3 | ⭐⭐ El régimen de coordenada era INERTE en la lectura: duck-plan hacía catalog.get(token) a pelo, sin pasar por resolveCatalogRef. NS_COORDENADA gobernaba la escritura y no la lectura |
| 4 | El \b no casaba detrás de una comilla en qualifyWriteTarget: las dos ramas citadas no podían casar jamás. Invisible mientras el colapso dejaba el destino pelado |
⭐ La regla se extrajo a query/coordenada.ts —un módulo sin dependencias, porque
importar catalog.ts arrastraría Clerk y Supabase a un planificador que es código
puro— para que los dos caminos usen la misma, no dos copias.
Y el instrumento estaba roto: n4-la-coordenada-desambigua.ts leía r.baseTables
cuando el resultado es {ok, plan} ⇒ imprimía (sin bindings) en los ocho casos y
parecía un hallazgo. Se arregló antes de rediseñar nada.
Gate: check:plan-diferencial pasó de 4 empates que pierden coordenada a 0.
El criterio de P·4·bis, hoy
⓪ el auditor ESTÁ midiendo ...... SÍ ✅
① sin no-vista sin explicar ..... SÍ ✅ (1 explicada, en `p4bis-discrepancias.ts`)
② 17 formas del corpus .......... SÍ ✅
③ 12 formas DISTINTAS de usuario ⏳ (0) ← lo único que falta
10 · Lo que está abierto
Bloqueantes de producto
| ⏳ ③ de P·4·bis | 12 formas distintas de usuario por el SQL Editor. El registro se desplegó a las 22:57; las queries del owner anteriores a eso no contaron |
| 🏁 | CERRADO el 2026-08-12, desplegado y verificado en vivo por el owner con los dos observatorios: se marcó el de karma.test y el de main.default quedó intacto. Ver §9·bis |
| 🏁 | Siguen siendo nueve, pero ya no son ambiguos: la coordenada direcciona. Lo que queda es que un nombre PELADO sigue dependiendo del default de sesión — que es lo que significa un nombre corto en cualquier catálogo |
| ⛔⛔ Un BIGINT pierde precisión al llegar al cliente | es transporte, no dialecto. Sin arreglar |
⚠️ El DELETE fuera del editor | los pipelines no pasan por la puerta ⇒ el guardián no los cubre |
| ⚠️ Los 7 interruptores 🔴 sin pinnear | casan por defecto de Spark 4.1.2, no por decisión |
| B7 · mantenimiento Iceberg | sin compactar ni expirar |
INSERT en el editor | no admitido (B3). Es lo que deja ② en 17 y no en 19 |
Deuda de sustrato
⚠️ 4 fallos PREEXISTENTES en lib/lakehouse (read-client, namespace-resolution) —
comprobados con git stash: salen igual sin los cambios de hoy · la mudanza del inquilino
con 123 tablas · BRIDGE_JWT_SECRET simétrico · el puente no escala · OpenFGA inerte ·
sin gobernanza por usuario · el cluster se llama trino-compute-clone.
11 · ⭐ Las prioridades — por DAÑO
P0 · lo que YA cobra intereses
1. ③ y con él P·4·bis → enforce ← cuesta 12 queries del owner
2. N·5 LECTURA ← 9 nombres ambiguos, dato real
3. el BIGINT del transporte ← corrompe dato de usuario, en silencio
4. el DELETE fuera del editor ← el guardián sólo cubre la puerta
P1 · el cambio de punto de vista
5. LA PUERTA COMO PASO ÚNICO ← extiende TODO lo construido
6. pinnear los interruptores 🔴
7. mantenimiento Iceberg (B7)
P2 · producto que aún no existe
8. INSERT · time travel · vistas materializadas · resultados grandes
P3 · sustrato ⛔ TODO bajo el techo de CPUS_ALL_REGIONS = 12
Los horizontes
- H2 · la gobernanza efectiva — encender OpenFGA. ⭐ El namespace opaco ya le puso el suelo: la tenencia es aplicable en el catálogo.
- 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 37 anteriores siguen vigentes. Lo que añadió el 08-11 (madrugada):
- ⭐⭐⭐ UN NÚMERO EN UN CRITERIO TIENE QUE DERIVARSE DE ALGO. «500 queries», «300 queries», «14 días»: los tres estaban puestos a ojo, y el de 300 además medía repetición cuando quería medir diversidad (el auditor cachea por hash: N ejecuciones de la misma query son UNA medición repetida N veces). ⇒ un umbral sin derivación es una opinión disfrazada de umbral.
- ⭐⭐ UN INSTRUMENTO QUE MEZCLA DOS CATEGORÍAS DA UN NÚMERO ALARMANTE Y FALSO. «7 datasets romperían» eran en realidad «7 que ya no resolvían». Un número falso hacia arriba bloquea un cambio seguro, que es tan caro como aprobar uno peligroso.
- ⭐⭐ REIMPLEMENTAR UNA CONDICIÓN EN VEZ DE LEERLA. El censo comprobó
state === 'active'cuando la condición real eraisDedicated()(activo Y motivo Y id) y concluyó exactamente lo contrario de la verdad. - ⭐⭐ UNA VENTANA DE TIEMPO MIDE EL RELOJ, NO LA CORRIDA. El arnés contó la discrepancia de la ejecución anterior y declaró que el arreglo no servía. Sí servía.
- ⭐⭐ SE MARCA LO ARTIFICIAL, Y LO MARCADO NUNCA CUENTA. Y el filtro tiene que ser estricto: «todo menos el arnés» dejaba colar cualquier otro origen como si fuera tráfico de usuario. Un gate que no separa su propio ruido se aprueba a sí mismo.
- ⭐⭐ UN GUARDIÁN CON CONDICIÓN DE RETIRADA ESCRITA HAY QUE RELEERLA CUANDO EL MUNDO
CAMBIA.
null-orderingdecía «mientras convivan dos motores»; hacía tiempo que Spark era el único, y seguía bloqueando la cláusula más común de SQL. Retirar el bloqueo sin borrar la entrada conserva el conocimiento y hace que vuelva sola. - ⭐⭐⭐ ESCRIBIR SQL DE VERDAD ENCUENTRA LO QUE 30 GATES NO MIRAN. Los dos únicos
defectos de PRODUCTO del día —una tabla ilegible por cualquier nombre y el
ORDER BYbloqueado— salieron de redactar 15 queries reales contra tablas reales. Ningún gate los veía porque todos medían mecanismos, y ninguno medía el uso. - ⚠️ Y el balance del día, que es la regla que las engloba: de ~15 defectos cerrados, la mayoría eran de los instrumentos, no del sistema. El sustrato aguantó; lo que fallaba era cómo lo mirábamos.
13 · Los documentos que importan
| Doc | Para qué |
|---|---|
| ⭐ este | la foto completa. Manda sobre todo lo demás |
⭐⭐⭐ namespace-paradigm-approach.md | el paradigma de nombres · N·3-N·6 con sus mediciones |
⭐⭐⭐ parser-plan-motor-approach.md | que parsee el motor · P·0-P·7 |
⭐⭐ carbon-sql-contract-approach.md | el contrato + los corpus |
⭐⭐ carbon-sql-contract-v1.md | la superficie publicada — se GENERA |
⭐⭐ federated-catalog-wedge.md · mapa-computo.md | la cuña · Furnace y Rubix |
🧊 05 · 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
npm run check:sin-espejo # ⭐ ¿ha vuelto la fórmula del espejo?
npx vitest run lib/compute lib/warehouse lib/governance # 740
# contra el motor (port-forward al puente)
npx tsx scripts/bridge/c0-pinneo.ts # ¿el motor casa con el contrato?
npx tsx scripts/bridge/n1-coste-n-catalogos.ts # el coste de N catálogos
# por la puerta (necesitan .env.local)
npx dotenv -e .env.local -- npx tsx scripts/governance/n3-namespace-nuevo.ts # ⭐ el paradigma
npx dotenv -e .env.local -- npx tsx scripts/governance/n3d-control-negativo.ts
npx dotenv -e .env.local -- npx tsx scripts/governance/n3e-regresion-espejo.ts
npx dotenv -e .env.local -- npx tsx scripts/governance/n5d-gate-escritura-gobernada.ts
npx dotenv -e .env.local -- npx tsx scripts/governance/p4bis-arnes-corpus.ts # ⭐ la cobertura
npx dotenv -e .env.local -- npx tsx scripts/governance/p4bis-criterio-de-salida.ts # ⭐ ¿enforce ya?
npx dotenv -e .env.local -- npx tsx scripts/warehouse/n2-que-es-w-uuid.ts
npx dotenv -e .env.local -- npx tsx scripts/warehouse/ns-fisicos.ts
14 · ⭐ Lo primero que hay que hacer en la próxima sesión
Doce queries distintas por el SQL Editor, y correr p4bis-criterio-de-salida.ts.
Están escritas y validadas 17/17 en scripts/governance/p4bis-queries.ts.
⭐ Ya está desplegado (d12ff92, §9), así que no hay nada que esperar.
⚠️ Y esto no lo puede cerrar un script. El origen lo pone PLAN_AUDITOR_ORIGEN y
el gate sólo cuenta forma:usuario —la que no lleva marca—, así que un arnés se
marca solo y no suma, y correrlo sin marcar sería falsificar el gate (regla 42). Las
12 tienen que entrar tecleadas en el SQL Editor.
⚠️ Y si ③ sigue en 0 tras hacerlo, no es que falten queries: sería la hipótesis
abierta desde el principio — que en serverless la escritura del auditor no sobrevive a la
congelación del runtime. El arreglo está identificado (after() de Next 16) y ese caso
también es información.