Saltar al contenido
← Todos los proyectos

Pipeline regulatorio auto-reparable

193 fuentes jurídicas en 130 jurisdicciones, scrapeadas por fetchers que una IA escribe y repara detrás de un harness determinista.

Rol
Ingeniero senior — arquitectura, toolchain de fetchers y etapas con LLM
Stack
Python 3.12 Airflow 3 Kubernetes LLMs de Anthropic PostgreSQL MongoDB Docling

Problema

La regulación vive en un catálogo de unos 290 portales oficiales y jurídicos repartidos por 130 jurisdicciones. Ninguno tiene API, todos cambian su HTML sin avisar, y el fallo es silencioso por construcción: rediseñan la web, los selectores no encuentran nada y la ejecución reporta éxito con cero resultados. Existían tres fetchers, escritos a mano con unas 170 líneas cada uno. Escribir doscientos más a mano no escala — y cada uno escrito es una cosa más que se va a romper.

Enfoque

La observación sobre la que se apoya todo el diseño es que reparar un fetcher roto y generar uno nuevo son la misma operación con entradas distintas: entra la fila de la fuente, más la evidencia del fallo si la hay, y sale un módulo, sus tests, su registro y un pull request. Así que hay una sola máquina con dos modos, y la frontera de confianza no es la autoevaluación del modelo sino un harness determinista: siete etapas, de barata a cara — cableado, whitelist por AST, lockfile intacto, lint y tipos, la suite unitaria, conformidad de protocolo comprobada por firma, y por último una petición real con presupuesto, juzgada por las mismas reglas de salud que usa la monitorización. El modo de fetch se mide en vez de suponerse, con una sonda que gasta como mucho ocho peticiones en robots.txt, métricas de enlaces, marcadores de SPA y autodescubrimiento de feeds, y decide contra una tabla escrita. Cada pull request lo revisa una persona; no se auto-mergea nada, ni siquiera un heal en verde.

Resultado

193 de las fuentes catalogadas están cubiertas, hay 153 módulos de fetcher en el repositorio, y procesar informes le lleva al equipo jurídico un 70% menos de tiempo que antes. Un job diario marca un fetcher como roto tras tres fallos consecutivos, o degradado tras tres ejecuciones sin resultados contra su propio baseline positivo, y entrega los dos peores al reparador — que abre un pull request revisado en vez de despertar a nadie.

Descubrimiento Catálogo de fuentes ≈290 fuentes · 130 jurisdicciones 193 cubiertas · sin API en ninguna 153 módulos fetcher http · api · browser generados y reparados por IA Harness determinista 7 etapas · revisión humana · sin auto-merge el agente no tiene credenciales Extracción · diaria 00:00 scrape cada fuente que toca extracción PDF Docling puerta ESG ¿es relevante? Insights · cada hora ingest Mongo → process traducción al inglés · resumen · etiquetas ESG bundles: intensidad, alcance, fechas clave, anti-ESG, industrias SICS cada valor con razonamiento y cita literal publish → Mongo Alrededor classify_document_type cada 2 h · resolver de 3 niveles reglas → principios → LLM compare_live_regulations diaria 05:00 · el harness de evaluación puntúa contra la verdad del equipo reg discovery_health diaria 06:00 · marca roto/degradado dispara como mucho 2 heals
Los cinco DAGs del pipeline regulatorio y lo que cada uno alimenta. Descubrimiento y salud cierran el bucle sobre la misma capa de fetchers.
1 · Detección 3 fallos seguidos → roto 3 corridas a cero vs. su baseline → degradado máx. 2 por ejecución 2 · Evidencia la fila de la fuente las últimas 10 ejecuciones el último éxito positivo (el baseline de rendimiento) 3 · Agente enjaulado sin credenciales, sin git, sin curl, sin fetch libre no puede editar su jaula diff contra allowlist mecánica 4 · Revisión humana el PR lleva el JSON del harness, la sonda y el coste sin auto-merge, nunca El harness — de barata a cara, entre el paso 3 y el 4 1. cableado 2. whitelist AST 3. lockfile 4. lint + tipos 5. suite unitaria 6. protocolo 7. fetch real una generación mala muere en segundos, no después de pegarle a una web que aloja leyes
Generar un fetcher y reparar uno roto son la misma operación. El agente propone; el harness decide; una persona aprueba.

El claim por el que todo el mundo pregunta

“Doscientos scrapers en una semana con IA” es la frase que hace desconfiar a cualquier ingeniero con experiencia, y hacen bien. No son doscientos parsers a medida escritos por un chatbot. Es un generador — una skill del repositorio invocada por un agente, en el portátil o headless en CI — que produce módulos contra una interfaz deliberadamente estrecha, cada uno verificado por un harness al que el agente no puede convencer de nada. La palanca no es el modelo. La palanca es que los criterios de aceptación son ejecutables.

El harness es el producto

Siete etapas, ordenadas de barata a cara para que una generación mala muera en segundos y no después de una petición real:

  1. Cableado — ¿está el módulo registrado donde el loader lo va a buscar?
  2. Whitelist por AST — imports comprobados, nada de async, sin escrituras fuera de su carril.
  3. Lockfile intacto — un fetcher no puede añadir una dependencia.
  4. Lint y tipos.
  5. Suite unitaria contra un snapshot de HTML capturado durante el sondeo.
  6. Conformidad de protocolo con inspect.signature — una comprobación estructural que solo mira nombres no es una comprobación.
  7. Una petición real con presupuesto, juzgada por las mismas reglas que el monitor de salud, con enfriamiento por fuente para que iterar no machaque a una web que aloja leyes.

El robots.txt se parsea en condiciones, según la RFC 9309, y un disallow es una negativa que el agente tiene que aceptar: nunca se discute.

El agente corre dentro de una jaula

En CI el agente no tiene credenciales: el token del bot, las credenciales de AWS y el token OIDC se eliminan de su entorno antes de arrancar, y recibe una lista explícita de herramientas sin escritura en git, sin curl y sin peticiones arbitrarias. La jaula se comprueba dos veces — un hook previo a la ejecución se niega a ejecutar nada en cuanto una ruta prohibida está modificada, y el paso de publicación compara el diff final contra una allowlist mecánica, así que un agente al que le hayan inyectado un prompt sigue sin poder editar el fichero que define sus propios límites.

Detectar, y saber cuándo no intentarlo

Un job diario lee el historial de cada fetcher: tres fallos consecutivos lo marcan broken; tres ejecuciones correctas que no devuelven nada, medidas contra el resultado positivo más reciente por antiguo que sea, lo marcan degraded. Se reparan como mucho dos candidatos por ejecución, deduplicados sin estado contra Bitbucket, de forma que una fuente con un PR de reparación tocado en la última semana se aparta. Las fuentes que ya llevan un veredicto humano que ningún cambio de código puede satisfacer — necesita credenciales, necesita navegador, no es realmente una fuente — se siguen monitorizando pero nunca se ofrecen al reparador. Con solo dos plazas, una fuente irreparable reintentada eternamente mataría de hambre a todas las reparables.

Qué puedo y qué no puedo enseñar

Bajo NDA: la forma y el razonamiento, nunca datos de clientes, prompts ni diagramas internos.