Published

💎 VALUE — Qué aporta el módulo conector gobernado (y dónde vive la gobernanza)

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

💎 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.md tienen el estado operativo. Este documento responde a dos preguntas afiladas:

  1. ¿Qué valor raw (marginal) aporta el conector respecto a no tenerlo en absoluto?
  2. ¿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ónSin conectorCon conector
MecanismoCSV 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
ContratoNinguno, o un PDF fuera de bandaODRL negociado + agreement_id máquina-a-máquina
Identidad del socioConfianza implícitaDID/VC verificable (llave en mano — Fase 6, pendiente)
Evidencia del cruceNo existedataspace_transfers + ledger: quién, qué, cuándo, bajo qué acuerdo
Estado del dato recibidoFichero suelto sin gobiernoDataset Iceberg de primera clase (ontología, pipelines, ML, identidad)
SoberaníaEl dato acaba donde acabeData-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 marginalQué es, sin humo¿Real hoy?
1Interoperabilidad (anti-N×M / anti-lock-in)Hablas DSP/IDSA → un conector, no una integración por socio✅ protocolo verificado E2E
2Contractualización + auditabilidad del cruceCada in/out lleva contrato ODRL + agreement_id + transfer_id, persistido = evidencia ante AI Act/EHDS✅ persistido · ⚠️ política aún "open"
3Postura de soberaníaData-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
4Coste marginal de motor ≈ 0El 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_POLICY vací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 gobernanzaAlmacénCuándo se escribeLo escribe
1Endpoint + api-key de nuestro conectorenv (EDC_MANAGEMENT_URL/_API_KEY)deployops
2Identidad del partner (counterPartyId/Address/protocol)user_credentials (edc/edcPartner)al configurar el socioUI/creds
3Asset + Policy(ODRL) + ContractDefinition (provider)conector EDC (store propio) + espejo dataspace_assetsal publicar (/publish)publish route
4Negociación/transfer (consumer): negotiation/agreement/transfer_id, state, config{offer,dataDestination,…}dataspace_transfersal consumir (/consume) + cada tickconsume route + sync-worker
5Los bytes transferidos (Parquet)R2 (bucket lakehouse)al COMPLETEDdata-plane EDC
6Procedencia en el dataset: service='edc_consumer', metadata{source,edc_transfer_id,counterparty}datasets + project_filesal LANDINGlandConsumedTransfer
7Procedencia en el snapshot: metadata{source:'edc_consumer',edc_transfer_id,sink}dataset_transactions (ledger)al escribir snapshotwithNativeControlPlane
8Auditoría del snapshot: iceberg_table, snapshot_id, rows, has_identityiceberg_sync_logal escribir snapshotwithNativeControlPlane
9Enlace transfer ↔ dataset (target_dataset_id)dataspace_transfersal LANDEDsync-worker
10Identidad de fila (trazabilidad de grano fino / reproducibilidad)Iceberg/R2 (__row_index/__row_id)al escribir snapshotwriter.py
11Punteros del catálogo (namespace/tabla → metadata.json)Lakekeeper (Postgres propio) + R2al crear/commit tablaml-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 campodata-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 transactionMetadata ya lleva edc_transfer_id + source='edc_consumer'.
  • no hay nodo credential (los datasets EDC tienen credential_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_assets no se unen al linaje pese a tener target_dataset_id.
  • ninguna UI muestra la procedencia (grep edc_consumer → 0 componentes).

La activación (tres pasos, sin re-arquitectura)

  1. Nodo de frontera en el DAG. Añadir un tipo counterparty (o dataspace) alimentado desde dataspace_transfers (join por target_dataset_id = dataset.id), a la izquierda del dataset (donde va la credencial en un sync interno). Arista governed_by/transferred que lleva agreement_id, transfer_id, counterparty, asset_id. → "este dataset vino de Org X bajo acuerdo Y" se vuelve un salto visible y de primera clase.
  2. Consultas de compliance (reverse). Unir dataspace_transfers para 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.
  3. La insignia. Superficiar datasets.service='edc_consumer' + metadata.counterparty en DataAssetView como "🔒 Importado bajo contrato de <partner>" con link al transfer/agreement. Simétrico en provider: dataspace_assets da 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) consume no autofija el dataDestination R2. 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.