Documentación técnica

Cómo funciona Derogada por dentro: el pipeline, las fuentes oficiales que consulta, cómo instalarlo y cómo usarlo como CLI y como biblioteca.

Python ≥ 3.10 BOE API CELLAR / EUR-Lex LiteLLM 51 tests · VCR offline
01

Instalación y configuración

# desde PyPI
$ pip install derogada

# desarrollo
$ python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"

# demo web opcional con IA + EUR-Lex (landing + API local en :8000)
# la landing ya incluye una demo 100% navegador: BOE directo (CORS) y EUR-Lex vía proxy CORS
$ .venv/bin/pip install -e ".[demo]" && .venv/bin/python demo/server.py

La extracción funciona en dos canales: regex determinista (siempre activo, sin configuración) y LLM vía LiteLLM (opcional, mejora el recall con siglas y nombres comunes). Sin LLM configurado, todo sigue funcionando en modo solo-regex.

VariablePara quéEjemplo
DEROGADA_MODELModelo LiteLLM para extracción y sugerenciasgpt-5.6 · anthropic/claude-sonnet-5 · gemini/gemini-3.5-flash · openai/qwen3.6 · ollama/llama4
DEROGADA_API_BASEEndpoint OpenAI-compatiblehttps://api.nan.builders/v1
DEROGADA_API_KEYClave del proveedorsk-…
DEROGADA_CACHE_DIRDirectorio de la caché SQLite (defecto ~/.cache/derogada)/tmp/derogada-cache
02

Uso

$ derogada check demanda.pdf                  # informe Markdown por stdout
$ derogada check demanda.docx -f json -o informe.json
$ derogada check demanda.pdf -f tabla         # tabla en terminal
$ derogada check demanda.pdf --no-llm         # solo regex
$ derogada check demanda.pdf --model openai/qwen3.6
$ derogada norma BOE-A-1992-26318             # estado de una norma suelta
$ derogada norma 32016R0679                   # también CELEX (EUR-Lex)
$ derogada cache clear                        # vacía la caché local

Como biblioteca:

from derogada import analizar_documento

informe = analizar_documento("demanda.pdf")
for r in informe.resultados:
    print(r.cita.texto, "->", r.estado.value, r.derogada_por)
03

Arquitectura: el pipeline

Ingesta
ingest/loader.pytxt / md / docx / pdf → texto plano. Detecta PDF escaneado sin capa de texto.
Extracción
extract/Doble canal: regex determinista + LLM (JSON Schema). Gazetteer de siglas. Deduplicación por norma.
Resolución
resolve/resolver.pyCita → identificador oficial (BOE-A… / CELEX). Valida contra metadatos. Si duda: candidatos.
Verificación
check/status.pyEstado de la norma Y del artículo citado contra BOE / CELLAR.
Sugerencia
suggest/rewrite.pyPropuesta textual solo con normas reales devueltas por la API. Sin fuente, no hay sugerencia.
Informe
report/Markdown, JSON o tabla. Aviso legal permanente y enlace oficial por cita.
04

Fuentes oficiales

Solo APIs oficiales; sin scrapers HTML. Las respuestas se cachean en SQLite (TTL 7 días) con reintentos exponenciales, para ser educados con los servicios públicos.

API de datos abiertos del BOE: https://www.boe.es/datosabiertos/api

EndpointUso en Derogada
GET /legislacion-consolidadaBúsqueda de candidatos por título (DSL tipo Elasticsearch en el parámetro query, JSON)
GET …/id/{id}/metadatosestatus_derogacion, vigencia_agotada, fecha_derogacion, numero_oficial, rango, URLs consolidada y ELI
GET …/id/{id}/analisisReferencias posteriores: quién la deroga (SE DEROGA) o modifica (SE MODIFICA), con id_norma
GET …/id/{id}/texto/indiceBloques del texto consolidado (artículos, disposiciones)
GET …/id/{id}/texto/bloque/{bloque}Versiones de un artículo concreto (nivel artículo)

CELLAR / EUR-Lex: endpoint SPARQL público https://publications.europa.eu/webapi/rdf/sparql

Predicado CDMUso en Derogada
cdm:resource_legal_id_celexLocaliza el acto por CELEX limpio (32016R0679). El endpoint no casa literales simples con xsd:string: se filtra con FILTER(STR(?o) = "…")
cdm:resource_legal_in-forceVigencia codificada "1"/"0"
cdm:resource_legal_date_entry-into-force
cdm:resource_legal_date_end-of-validity
Entrada en vigor y fin de validez
cdm:resource_legal_repeals_resource_legalEn sentido inverso: qué acto deroga al consultado (p. ej. 95/46/CE ← RGPD)
05

La IA en Derogada

La IA se usa para dos cosas puntuales, y nunca para decidir si una norma está vigente: eso pertenece exclusivamente a las APIs oficiales. Un modelo generativo tiene fecha de corte y no puede saber qué está derogado hoy; el BOE y CELLAR sí.

UsoPara quéCómo
extract/llm.pyRecall de citas: siglas y menciones informales ("la LRJCA", "el Estatuto de los Trabajadores") que el regex no veSalida estructurada con JSON Schema estricto (texto, jurisdiccion, rango, numero, articulo, alias), temperatura 0, troceo con solape en documentos largos, degradación a json_object si el proveedor no soporta json_schema
suggest/rewrite.pyRedacta la propuesta de sustitución de citas derogadas o agotadasEl prompt solo contiene datos reales devueltos por la API (norma que deroga, URL, nota oficial, contexto). Regla de oro: sin fuente oficial, no hay sugerencia; si la llamada falla, se omite en silencio
06

Estados y reglas de negocio

EstadoSignificado
VIGENTELa norma está en vigor y sin modificaciones posteriores consolidadas
MODIFICADASigue viva pero tiene modificaciones consolidadas posteriores (con lista y fuentes)
DEROGADADerogada: quién la derogó y cuándo, con enlace oficial
VIGENCIA AGOTADASu vigencia temporal se agotó según el BOE
NO RESUELTACandidatos ambiguos: se listan, nunca se adivina
NO ENCONTRADANo se pudo identificar en las fuentes oficiales
07

Testing, CI y publicación

Limitaciones conocidas del MVP: sin OCR (los PDF escaneados se detectan y avisan), normativa no consolidada en el BOE queda NO ENCONTRADA, la jurisprudencia está fuera de alcance, y los textos consolidados del BOE son meramente informativos (el informe enlaza siempre la publicación oficial).