💎 VALUE — Qué aporta el módulo conector gobernado (y dónde vive la gobernanza)
⚠️ Nota (2026-07-09): el framing "PG fuera" es aspiracional — hoy el read está mayormente por la facade pero el write sigue en PG (legacy/diferido). Estado real de la infra:
docs/INFRA.md.
Documento de paradigma. El README.md tiene la visión + roadmap; los
fase-*-findings.mdtienen el estado operativo. Este documento responde a dos preguntas afiladas:
- ¿Qué valor raw (marginal) aporta el conector respecto a no tenerlo en absoluto?
- ¿Dónde persiste la gobernanza a lo largo de todo el pipeline — para poder usarla (linaje, trazabilidad), no dejarla como proceso backend?
Todo lo de aquí está verificado contra el código (no es pitch). Actualizado 2026-07-03.
Approach de desacoplamiento (building blocks = consumidores puros de la fuente de verdad): ../architecture/source-of-truth.md. Une este hilo (gobernanza sobre el item) con la migración lakehouse "PG fuera" bajo un solo substrato.
0. TL;DR
El módulo conector no tiene stack de datos propio: es una carcasa de gobernanza y negociación alrededor del motor lakehouse que ya existía. Su pieza de aterrizaje (writeIcebergNativeFromParquet) es, literalmente, el tercer hermano de los writers nativos internos, compartiendo withNativeControlPlane byte a byte (iceberg-native-write.ts:306).
Sin el conector: Carbon es un lakehouse soberano single-tenant que ingesta 14 fuentes internas.
Con el conector: Carbon puede absorber el producto de datos de un socio bajo contrato negociado y volverlo un dataset gobernado de primera clase, con el intercambio entero persistido como evidencia — reutilizando el 100% del motor de ingesta.El valor raw es la capa de frontera (protocolo + contrato + identidad + linaje inter-org). Todo lo de dentro de la frontera (R2, Lakekeeper, identidad de fila, read-router) ya existía.
1. Arquitectura real — carcasa vs. motor
Lo que el código realmente hace (no el diagrama de marketing):
PARTNER ──DSP/IDSA (JSON-LD)──▶ edcExecutor(nº88) ──▶ conector EDC 0.17 ┐
catálogo→negociación ODRL→agreement (Mgmt API v4, x-api-key) │ CARCASA
│ transfer (AmazonS3-PUSH) │ (nueva)
▼ ┘
Parquet en R2 (bytes)
│ sync-worker BullMQ
│ NEGOTIATING→TRANSFERRING→COMPLETED
▼
landConsumedTransfer: inspect-parquet → createDatasetArtifact ──┐
│ writeIcebergNativeFromParquet
▼ │ │ MOTOR
══ withNativeControlPlane ══ ◀────────┘ │ (reúso
ledger + iceberg_sync_log + freshness oracle │ exacto)
+ dataset stats + schema version + identidad ┘
▼
DATASET ICEBERG GOBERNADO "EDC: …" con __row_index/__row_id
│ read-router
▼
legible en el workspace, como cualquier dataset Carbon ✅
Piezas NUEVAS (la carcasa): edc-client.ts (cliente Mgmt v4), edc.executor.ts (nº88, thin/stateless), edc-sync-worker.ts (BullMQ), rutas app/api/dataspaces/*, tablas dataspace_*, y el único data-plane nuevo del lakehouse: leer un Parquet de R2 (ingest-parquet en ml-runner).
Piezas REUTILIZADAS (el motor, cero código nuevo): withNativeControlPlane (ledger, oracle, sync_log, stats, schema version), identidad __row_index/__row_id, catálogo Lakekeeper, storage R2, read-router. → El coste marginal de motor es ≈ 0.
2. Línea base vs. con-conector (el delta)
| Cuando un dato cruza la frontera de otra organización | Sin conector | Con conector |
|---|---|---|
| Mecanismo | CSV por email / credenciales de su DB / integración a medida por cada socio (N×M) | Un protocolo (DSP/IDSA); el mismo de Catena-X/Tractus-X/EHDS |
| Contrato | Ninguno, o un PDF fuera de banda | ODRL negociado + agreement_id máquina-a-máquina |
| Identidad del socio | Confianza implícita | DID/VC verificable (llave en mano — Fase 6, pendiente) |
| Evidencia del cruce | No existe | dataspace_transfers + ledger: quién, qué, cuándo, bajo qué acuerdo |
| Estado del dato recibido | Fichero suelto sin gobierno | Dataset Iceberg de primera clase (ontología, pipelines, ML, identidad) |
| Soberanía | El dato acaba donde acabe | Data-plane en tu R2/Lakekeeper; on-prem/cloud soberano; ruta a zero-copy |
3. El valor raw — cuatro cosas, ninguna más
El delta NO está dentro de la frontera (ya existía). El valor raw es la frontera misma:
| # | Valor marginal | Qué es, sin humo | ¿Real hoy? |
|---|---|---|---|
| 1 | Interoperabilidad (anti-N×M / anti-lock-in) | Hablas DSP/IDSA → un conector, no una integración por socio | ✅ protocolo verificado E2E |
| 2 | Contractualización + auditabilidad del cruce | Cada in/out lleva contrato ODRL + agreement_id + transfer_id, persistido = evidencia ante AI Act/EHDS | ✅ persistido · ⚠️ política aún "open" |
| 3 | Postura de soberanía | Data-plane en tu R2/Lakekeeper; ruta a zero-copy ("el dato no sale"); vs. ceder el dato a Palantir/Databricks | 🟡 copia hoy; zero-copy = Fase 5 |
| 4 | Coste marginal de motor ≈ 0 | El dato consumido es de primera clase desde el minuto 1 porque reúsa withNativeControlPlane — sin stack paralelo | ✅ confirmado en código |
La frase: el conector convierte el foso (soberanía + AI Act) de atributo de la plataforma en una red con evidencia.
Qué NO es valor todavía (para no sobrevender)
- El valor-red es latente, no realizado. Con un solo participante vale 0 — es opcionalidad hasta que haya un segundo nodo real (Fase 8).
- Identidad = mock. DID/VC + Gaia-X Trust Framework es Fase 6, no construida. Tienes el contrato, no la prueba criptográfica de con quién.
- Política ODRL abierta. El executor manda
OPEN_POLICYvacía. La mecánica del contrato está; el contenido enforzable (quién/para qué/hasta cuándo) es Fase 5/7. - Superficie operativa nueva (conector Java + IdentityHub + Vault + Federated Catalog). Para un "equipo de 3" no es gratis — la Fase 6 llave-en-mano es lo que lo hace asumible.
4. ⚑ Dónde vive la gobernanza — mapa de persistencia en TODO el espectro
Para usar la gobernanza (no dejarla backend-only) hay que saber qué se guarda, dónde y cuándo. La gobernanza no vive en un sitio: se estampa en 6 almacenes a lo largo del pipeline.
| # | Hecho de gobernanza | Almacén | Cuándo se escribe | Lo escribe |
|---|---|---|---|---|
| 1 | Endpoint + api-key de nuestro conector | env (EDC_MANAGEMENT_URL/_API_KEY) | deploy | ops |
| 2 | Identidad del partner (counterPartyId/Address/protocol) | user_credentials (edc/edcPartner) | al configurar el socio | UI/creds |
| 3 | Asset + Policy(ODRL) + ContractDefinition (provider) | conector EDC (store propio) + espejo dataspace_assets | al publicar (/publish) | publish route |
| 4 | Negociación/transfer (consumer): negotiation/agreement/transfer_id, state, config{offer,dataDestination,…} | dataspace_transfers | al consumir (/consume) + cada tick | consume route + sync-worker |
| 5 | Los bytes transferidos (Parquet) | R2 (bucket lakehouse) | al COMPLETED | data-plane EDC |
| 6 | Procedencia en el dataset: service='edc_consumer', metadata{source,edc_transfer_id,counterparty} | datasets + project_files | al LANDING | landConsumedTransfer |
| 7 | Procedencia en el snapshot: metadata{source:'edc_consumer',edc_transfer_id,sink} | dataset_transactions (ledger) | al escribir snapshot | withNativeControlPlane |
| 8 | Auditoría del snapshot: iceberg_table, snapshot_id, rows, has_identity | iceberg_sync_log | al escribir snapshot | withNativeControlPlane |
| 9 | Enlace transfer ↔ dataset (target_dataset_id) | dataspace_transfers | al LANDED | sync-worker |
| 10 | Identidad de fila (trazabilidad de grano fino / reproducibilidad) | Iceberg/R2 (__row_index/__row_id) | al escribir snapshot | writer.py |
| 11 | Punteros del catálogo (namespace/tabla → metadata.json) | Lakekeeper (Postgres propio) + R2 | al crear/commit tabla | ml-runner |
Los tres planos (memoria del proyecto) escalan a este espectro: (1) config = env, (2) partner = credencial, (3) estado = tablas dataspace_* → y al aterrizar, la procedencia se propaga al ledger, al dataset y al sync_log (filas 6–8), que es lo que la vuelve consultable desde el resto de la plataforma.
5. 🏅 De backend-only a insignia de trazabilidad — la ruta de activación
El hallazgo que lo desbloquea todo: la procedencia ya se estampa en dataset_transactions.metadata (fila 7) y el linaje ya lee ese campo — data-lineage/route.ts expone transactionMetadata: txn.metadata en el nodo sync. El 80% del cableado ya existe. Lo que falta para que sea insignia y no proceso oculto:
El gap (verificado)
El DAG de linaje hoy es credential → sync → dataset → mapping → object_type → link_type. Para un dataset EDC:
- ✅ el nodo dataset aparece (con
service='edc_consumer'). - ✅ el nodo sync aparece, y su
transactionMetadataya llevaedc_transfer_id+source='edc_consumer'. - ❌ no hay nodo
credential(los datasets EDC tienencredential_id=null) → el linaje se corta en el dataset, no cruza la frontera hasta el socio. - ❌ no existe un tipo de nodo que represente el cruce (partner + contrato/agreement).
dataspace_transfers/dataspace_assetsno se unen al linaje pese a tenertarget_dataset_id. - ❌ ninguna UI muestra la procedencia (
grep edc_consumer→ 0 componentes).
La activación (tres pasos, sin re-arquitectura)
- Nodo de frontera en el DAG. Añadir un tipo
counterparty(odataspace) alimentado desdedataspace_transfers(join portarget_dataset_id = dataset.id), a la izquierda del dataset (donde va la credencial en un sync interno). Aristagoverned_by/transferredque llevaagreement_id,transfer_id,counterparty,asset_id. → "este dataset vino de Org X bajo acuerdo Y" se vuelve un salto visible y de primera clase. - Consultas de compliance (reverse). Unir
dataspace_transferspara responder "¿qué datasets importamos del socio X?" y "¿qué hicimos (qué object types / modelos) con el dato gobernado por el acuerdo Y?". El resto de la cadena forward ya existe (object_type_datasets→ object_types;ml_model_training_data→ modelos) → el linaje inter-org completo partner → dataset → object type → modelo queda derivable en cuanto exista el join. Esa es la query del AI Act / EHDS. - La insignia. Superficiar
datasets.service='edc_consumer'+metadata.counterpartyenDataAssetViewcomo "🔒 Importado bajo contrato de <partner>" con link al transfer/agreement. Simétrico en provider:dataspace_assetsda la insignia de "Publicado como producto gobernado bajo política Z".
Sin esto: la gobernanza es un backend que negocia y aterriza — real, pero invisible.
Con esto: cada dataset importado/publicado luce su procedencia gobernada y el linaje cruza la frontera de la organización — que es exactamente lo que convierte "cumplimiento europeo" de promesa en evidencia navegable.
6. Estado + pendientes (puntero)
- Núcleo Fase 4 ✅ verificado en vivo (Parquet R2 → dataset gobernado + legible). Detalle + health del stack + bring-up: fase-4-findings.md.
- Edges abiertos: (a) transfer EDC con source-R2 no completa (provider leyendo R2); (b)
consumeno autofija eldataDestinationR2. Ver findings §2–3. - Siguiente valor: la ruta de activación §5 (linaje inter-org + insignia) es lo que da uso real a la gobernanza ya desbloqueada; en paralelo, Fase 5 (publicar / zero-copy Lakekeeper) y Fase 6 (identidad llave en mano) cierran los caveats §3.
Documento vivo — el companion de valor del charter. Mantener al día cuando el paradigma se afile.