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.
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:
- Cableado — ¿está el módulo registrado donde el loader lo va a buscar?
- Whitelist por AST — imports comprobados, nada de async, sin escrituras fuera de su carril.
- Lockfile intacto — un fetcher no puede añadir una dependencia.
- Lint y tipos.
- Suite unitaria contra un snapshot de HTML capturado durante el sondeo.
- Conformidad de protocolo con
inspect.signature— una comprobación estructural que solo mira nombres no es una comprobación. - 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.