Skip to content

Pilar 1 — Fideicomiso de Datos

La tesis. Construir el fideicomiso de datos de la región: una infraestructura de contribución donde instituciones, empresas y personas aportan datos bajo consentimiento granular y revocable, reciben un recibo de procedencia verificable, y se convierten en partes interesadas de primera clase. Derechos, no propiedad. Compensación inmediata en reputación, no promesas diferidas.

Este es el primer pilar del ciclo de los cuatro pilares: el corpus con procedencia es el único activo que hace posible un modelo soberano que nadie más puede replicar.

Por qué un fideicomiso y no una compra de datos

Comprar o raspar datos produce un corpus sin consentimiento, sin licencia clara y sin nadie invertido en su calidad. Un fideicomiso invierte la relación: el aportante es parte interesada, no proveedor. Recibe un recibo verificable en el acto, ve exactamente por qué su contribución valió lo que valió, y conserva el derecho a revocar. El activo que crece no es una tabla — es una red de contribuyentes con incentivo a que los datos sean buenos.

Cómo funciona /contribuir, de punta a punta

La superficie en vivo es /contribuir. El formulario del cliente (src/routes/contribuir.tsx) envía la promesa a la función POST /api/contribute, un transporte delgado sobre un núcleo puro y probado con tests (server/trust/ledger.ts). El flujo, de punta a punta:

1. Validación con puerta de consentimiento

validateContribution() normaliza el cuerpo no confiable — nunca lanza excepción — y rechaza toda promesa sin consentimiento explícito: si consent !== true, la contribución no se crea. Valida el email por regex, exige título (3–160 caracteres) y descripción (10–1.200), y filtra las geografías contra el conjunto canónico de 27 ISO3 de la región (LATAM_ISO3), deduplicadas y con tope — un ledger de procedencia no admite códigos de país basura. Los pilares pasan por regex de slug ([a-z0-9-], tope 12); un idioma no reconocido cae a es.

2. Puntuación con una rúbrica transparente

scoreContribution() asigna puntos con una rúbrica determinista y explicada — no un Shapley opaco (su costo combinatorio se descartó al lanzar). Los puntos se descomponen en: base (20; +8 de bono si la promesa es explícitamente regional, con geografías vacías), cobertura geográfica (3 por ISO3, tope 30), amplitud de pilares (3 por pilar, tope 12), apertura de la licencia (open 15 · cc-by 12 · share-alike 9 · non-commercial 5 · cite-only 2) y modo de privacidad (abierto, sala limpia y cómputo privado 10 por igual; solo-agregados 7). La descomposición (points_breakdown) viaja en el recibo, así el contribuyente ve exactamente por qué ganó lo que ganó.

La privacidad se premia, no se penaliza

Una contribución que preserva la privacidad (sala limpia o cómputo privado) desbloquea datos que de otro modo no podrían compartirse — por eso se recompensa a la par de los datos crudos abiertos, no por debajo. Es el principio de "computar sin poseer": el valor sin la exposición.

3. Recibo de procedencia verificable por hash, listo para cadena

makeReceipt() emite un Receipt cuyo nivel de garantía depende de un interruptor de entorno, y el propio recibo lo declara en su campo version:

  • v1 — verificable por hash (por defecto). El receipt_hash prueba integridad del contenido, no autenticidad del emisor; la prueba de emisión es la presencia del recibo en el ledger del servidor.
  • v2 — firmado por el emisor. Con TRUST_RECEIPT_HMAC_KEY configurada, el recibo pasa a version: 2 y añade sig_alg: "hmac-sha256" más signature = HMAC-SHA256(clave, receipt_hash). Eso autentica al emisor, pero no es verificable por terceros: verificar exige la clave secreta.

La verificabilidad pública por terceros necesita una firma Ed25519 sobre el cuerpo canónico, y sigue en hoja de ruta — ver Procedencia avanzada. Sus propiedades verificables:

  • El email nunca se almacena. El registro público lleva un contributor_id seudónimo — un hash salado del email. El mismo email produce el mismo id, pero el email crudo no es recuperable ni entra jamás al ledger persistente. Un requisito operativo sostiene esa irreversibilidad: TRUST_ID_SALT debe configurarse con un valor secreto, porque la sal de respaldo incluida en el código es pública, y con una sal pública el id deja de ser irreversible frente a quien pruebe emails candidatos. El recibo estampa además un salt_version público, para que una rotación de sal nunca rompa la revocabilidad (ver abajo).
  • El recibo es reproducible. El receipt_hash es un SHA-256 sobre el cuerpo canónico (claves ordenadas recursivamente con stableStringify), así que el mismo valor lógico siempre produce el mismo digest. Cualquiera puede recomputar el hash desde las entradas y verificarlo.
  • Listo para cadena por construcción. El esquema mapea 1:1 a una atestación on-chain futura: contributor_id, contribution_id y receipt_hash son las columnas de esa atestación, y chain_anchor es la ranura reservada para el hash de transacción cuando llegue la liquidación on-chain (fase posterior). Hoy: chain_ready: true, chain_anchor: null — listo fuera de cadena.

Anatomía exacta del Receipt (interfaz en server/trust/ledger.ts):

CampoDerivación
receipt_hashSHA-256 hex sobre el cuerpo canónico — todos los demás campos, con claves ordenadas.
contribution_idd_ + 24 hex: hash de (contributor_id, título, descripción, geografías, pilares, licencia, privacidad, issuedAt, nonce UUID). Único por promesa.
contributor_idc_ + 24 hex: sha256(sal + ":" + email). Estable, seudónimo, irreversible.
points / points_breakdownTotal + descomposición {base, coverage, breadth, license, privacy}.
corpus_postureLo que la licencia permite en el corpus (la puerta de licencia, estampada de antemano).
salt_versions_ + 12 hex: etiqueta pública de qué sal produjo el id — un hash unidireccional que no revela nada de la sal.
issued_at / versionISO-8601 de emisión · versión de esquema: 1 (solo hash) o 2 (firmado por el emisor con HMAC).
chain_ready / chain_anchortrue · null (ranura reservada al tx hash).

Los campos declarativos (tier, dataset_title, geographies, pillars, license, privacy, indigenous_data) viajan tal cual se validaron. makeReceipt() es determinista dadas (promesa, issuedAt, nonce, sal): el mismo insumo siempre produce el mismo recibo — la base de la verificación independiente.

4. Registro append-only y honestidad cuando no está configurado

El ledger es append-only: server/trust/store.ts hace RPUSH a Upstash Redis vía REST (comandos como arrays JSON con fetch plano, sin dependencia npm). Un recibo nunca se muta. Si Upstash no está configurado, la función es honesta: devuelve el recibo con persisted: false en vez de fingir persistencia. El append es resiliente sin dejar de ser honesto: se reintenta con backoff acotado (3 intentos, 100·n ms) antes de degradar a persisted: false, y las lecturas saltan filas corruptas en vez de tumbar el registro.

La disposición de claves en Redis separa fuente de verdad de optimizaciones:

ClaveEstructuraRol
trust:ledger:v1LISTFuente de verdad append-only (RPUSH / LRANGE).
trust:revocations:v1LISTTombstones, en lista hermana — cada lista es mono-tipo, la lectura tipada nunca confunde una fila.
trust:ledger:index:v1HASH id→registroBúsqueda O(1) para revocar (HGET); best-effort — si falla, el append no falla.
trust:revocations:index:v1SETRevocación idempotente: SADD = 0 → ya revocada, no-op.
trust:ledger:dedupe:v1SETClaves de dedupe de promesas.

El ledger también se defiende solo:

  • Dedupe de promesas idénticas. La clave es contenido-direccionada: dk_ + 32 hex del hash de {contributor_id salado, título, descripción} — nunca contiene el email crudo. Dos promesas idénticas colapsan a una fila vía SADD; el contribuyente igual recibe un recibo válido, con la nota de que no se duplicó. Y el dedupe falla abierto: un error del store devuelve fresh: true — un traspié de Redis jamás bloquea una contribución genuina.
  • Límite de tasa y de cuerpo. POST /api/contribute acepta 10 solicitudes/minuto por IP y un cuerpo de máximo 64 KB con guardia en dos etapas (rechazo inmediato por Content-Length, y conteo de bytes durante la lectura contra un Content-Length mentiroso); los índices y sets de Redis tienen techo de crecimiento (500.000 entradas) — pasado el tope se deja de indexar, pero la lista y el escaneo siguen funcionando.
  • Registro público con ventana honesta. GET /api/contribute publica agregados sobre una ventana acotada de 500 registros, etiquetada como tal (stats.window {limit, complete}), y la lista pública omite deliberadamente el contribution_id — así una revocación no se puede falsificar desde afuera ni confirmar el mapeo email→registro.

5. Revocación por tombstone

El consentimiento se prometió revocable; api/revoke.ts es el mecanismo. makeRevocation() escribe un tombstone append-only que computeStats resta al momento de leer — el recibo original permanece en el ledger para siempre (listo para cadena, nunca mutado), pero la contribución queda excluida de los agregados y de la lista pública. La propiedad se prueba recomputando el contributor_id salado desde el email (matchingSalt, del que verifyRevocation es la envoltura): como el email crudo nunca se guardó, solo quien controla ese email puede probar control de la contribución.

Dos garantías de ingeniería sostienen la promesa:

  • La rotación de sal no rompe la revocación. El orden de resolución es preciso (saltCandidates + matchingSalt en ledger.ts): las sales candidatas son TRUST_ID_SALT vigente, luego cada entrada separada por comas de TRUST_ID_SALT_PREVIOUS, con la sal por defecto del código como respaldo. Si el registro trae salt_version estampado, se busca la candidata cuya etiqueta coincide y solo esa debe reproducir el contributor_id — una versión desconocida falla seguro (no se puede probar propiedad). Un registro legado sin estampa prueba cada candidata directamente.
  • La revocación es O(1) e idempotente. Un índice HSET (contribution_id → registro) resuelve la búsqueda con un HGET sin escanear el ledger completo — con un escaneo completo único como respaldo para registros legados que precedieron al índice — y un índice de revocaciones (SADD) convierte revocar dos veces en un no-op barato. El endpoint valida la forma del id (d_ + 24 hex) antes de tocar el store, y responde 404 si la contribución no existe y 403 si el email no prueba propiedad.

La puerta de licencia: solo-cita nunca se vuelve valor

Este es el gate estructural que deja fluir datos aportados al corpus sin violar su licencia (server/trust/license-gate.ts). Espeja la puerta de LicensePosture del registro de fuentes: una contribución cuya licencia prohíbe la redistribución solo puede volverse una referencia de cita, jamás un valor de indicador horneado.

LicenciaAcción en el corpusQué permite
open / cc-by / share-alikeindicatorLos valores pueden hornearse en el corpus y la API pública.
non-commercialaggregates_onlySolo agregados derivados; nunca republicación fila a fila.
cite-onlycitation_onlySolo referencia de cita; jamás un valor horneado.

La puerta se aplica en tiempo de horneado: scripts/bake-contributions.ts lee el export del ledger (public/data/contributions.json) y publica la proyección con licencia aplicada (gateContribution()) a public/api/v1/contributions.json — la superficie de contribuciones de la API pública. Al proyectar una contribución solo-cita a su forma pública, sus geografías y pilares se vacían a [] — no se republica cobertura alguna (gateViolation() es el invariante probado por tests detrás de esa regla). El recibo estampa la postura (corpus_posture) para que el contribuyente vea de antemano en qué puede convertirse su dato.

El artefacto declara su propio contrato: lleva la nota license_gate en texto plano y los contadores redistributable / citation_only, así un consumidor de la API ve cuántos registros están gateados sin leer el código. El script solo reescribe ese artefacto y dos campos del manifiesto — nunca regenera el árbol completo de la API (bake-api.ts también lo produce en un rebake total).

Derechos, no propiedad — y el anclaje CARE / LGPD

El marco es derechos, no propiedad: el contribuyente no "vende" un activo, retiene derechos sobre su uso — consentimiento con propósito acotado, revocable. Los datos etiquetados como indígenas llevan una bandera explícita de autoridad-para-controlar, siguiendo los principios CARE (Collective Benefit, Authority to Control, Responsibility, Ethics). El manejo del email — usado solo para una notificación operativa fuera de banda (Mailgun, best-effort), nunca persistido — sigue la lógica de minimización de datos de la LGPD brasileña y marcos afines de la región, no una plantilla importada. La misma disciplina alcanza a la analítica: el cliente identifica con un SHA-256 del email calculado en el navegador; la dirección cruda nunca sale de la página.

Qué está en vivo hoy vs. por fases

Estado
Contribución con puerta de consentimientoEn vivo/contribuir
Recibo verificable por hash (SHA-256 reproducible)En vivo
Ledger append-only + revocación por tombstoneEn vivo (Upstash; honesto si no está configurado)
Puerta de licencia (solo-cita nunca es valor)En vivo (regla de build)
Rúbrica de puntos transparenteEn vivo
Firma de emisor HMAC-SHA256 (recibo v2)En el aire, por entorno — se activa con TRUST_RECEIPT_HMAC_KEY; autentica al emisor, no verificable por terceros
Firma Ed25519 verificable por tercerosEn hoja de ruta — sin ella, la emisión se prueba por presencia en el ledger
Custodia por un fideicomisario independientePor fase — a largo plazo la administración sale del operador
Niveles de privacidad / salas limpias operativasPor fase — el esquema ya los modela; la ejecución llega después
Liquidación on-chainPor fase — esquema listo (chain_anchor reservado); sin cadena aún
Niveles de sensibilidad + cifrado de registrosPor fase: hoy el modo de privacidad (PrivacyMode) es metadato declarado, no aplicado; los registros se guardan en texto plano
Prueba de registro de conocimiento cero (ZK proof-of-record)Por fase: sin código aún; probaría la presencia de un registro en el ledger sin revelarlo
Notas comunitarias sobre contribucionesPor fase: sin código aún
Carta de incentivos del contribuyentePor fase: la rúbrica transparente de puntos ya está en vivo; lo que queda por fases es la carta que la gobierna y la liquidación en token

Superficies relacionadas

  • /contribuir — el formulario de contribución y el registro público de recibos.
  • /datos-abiertos — el corpus abierto con su licencia declarada.
  • /linaje — el linaje de procedencia de las cifras.
  • /confianza — las insignias de confianza y la trazabilidad.

Sigue el ciclo hacia el Pilar 2 — Modelo Soberano, el modelo que este corpus hace posible.

Cada cifra con su fuente — la trazabilidad es el contrato.