Paquete código abierto · LCSP + EU AI Act

Código descargable. Sin promesas, MIT.

Cinco archivos en la intersección del derecho público español, la regulación europea de IA y el desarrollo software. Cada uno implementa un trozo concreto de normativa que se puede verificar línea a línea. Descarga directa, sin signup, sin trackers.

~60 KB totalLicencia MITStdlib + 2 deps (solo en el generador)

Tres formas de usarlo

CLI, módulo o cron. El que encaje con tu flujo.

En tu máquina

Descarga el archivo, lánzalo con node o python. Cada script viene con CLI y argumentos posicionales.

En tu app

Importa la función exportada (analizarOfertas, generateWithDisclosure) y conéctala a tu lógica de negocio. Sin acoplamiento al framework.

En cron

placsp-fetcher.py y los scripts de análisis corren tal cual en GitHub Actions, cron Linux o Vercel Cron. Sin instalación.

Cinco archivos · descarga directa

Cada archivo, una pieza concreta de normativa.

Vista previa de las primeras líneas para que veas el estilo antes de descargar. El archivo completo trae documentación, CLI y ejemplos de uso.

baja-temeraria.js

JavaScript

art. 85 RGLCAP · RD 1098/2001

Implementación de las cuatro reglas del art. 85 RGLCAP para detección de ofertas anormalmente bajas. Incluye iteración del art. 85.4 (recálculo de media excluyendo ofertas inferiores en >10%). Sin dependencias. Funciona en Node.js 18+ y navegador moderno. Trae CLI integrado.

/**
 * baja-temeraria.js
 *
 * Análisis de baja temeraria conforme al artículo 85 del Real Decreto
 * 1098/2001 (Reglamento General de la LCAP, RGLCAP).
 *
 * Implementa las cuatro reglas según número de licitadores:
 *   1 licitador  → baja > 25 puntos del precio de licitación.
 *   2 licitadores → diferencia > 20 puntos entre ambas.
 *   3 licitadores → inferiores en > 10 puntos a la media.
 *   4+ licitadores → inferiores en > 10% a la media; con recálculo
 *                    iterativo (art. 85.4).
 *
 * Sin dependencias externas. Node.js 18+ y navegador moderno.
 */

export function analizarOfertas(precioLicitacion, ofertas) {
  const validas = ofertas.filter(
    (o) => typeof o === 'number' && Number.isFinite(o) && o > 0
  );
  const n = validas.length;

  // ── Regla 1: 1 licitador ─────────────────────────────
  if (n === 1) {
    const oferta = validas[0];
    const bajaPP = ((precioLicitacion - oferta) / precioLicitacion) * 100;
    return {
      temerarias: bajaPP > 25 ? [oferta] : [],
      regla: '1 licitador: baja > 25 puntos porcentuales',
      detalle: { licitadores: 1, bajaPP, umbral: 25 },
    };
  }
  // ... reglas 2, 3 y 4+ (con iteración art. 85.4)
}

Uso CLI

$ node baja-temeraria.js 100000 85000 78000 92000 88000 75000

baja-temeraria.py

Python 3.10+

art. 85 RGLCAP · RD 1098/2001

Equivalente Python del módulo JavaScript anterior: misma signatura de retorno, mismo algoritmo. Pensado para integrarse en pipelines de licitación (Airflow, scripts internos, batch nocturnos). Standard library únicamente, sin pip install.

"""
baja_temeraria.py

Análisis de baja temeraria conforme al art. 85 RGLCAP.
Equivalente Python del módulo baja-temeraria.js — misma
signatura, mismo algoritmo. Standard library only.
"""

from dataclasses import dataclass, field
from typing import Any


@dataclass
class Resultado:
    temerarias: list[float]
    regla: str
    detalle: dict[str, Any] = field(default_factory=dict)


def analizar_ofertas(
    precio_licitacion: float,
    ofertas: list[float],
) -> Resultado:
    validas = [o for o in ofertas if isinstance(o, (int, float)) and o > 0]
    n = len(validas)

    if n == 1:
        oferta = validas[0]
        baja_pp = ((precio_licitacion - oferta) / precio_licitacion) * 100
        return Resultado(
            temerarias=[oferta] if baja_pp > 25 else [],
            regla="1 licitador: baja > 25 puntos porcentuales",
            detalle={"licitadores": 1, "baja_pp": baja_pp, "umbral": 25},
        )
    # ... reglas 2, 3 y 4+ (con iteración art. 85.4)

Uso CLI

$ python baja_temeraria.py 100000 85000 78000 92000 88000 75000

eu-ai-act-watermark.ts

TypeScript

art. 50 Reg. (UE) 2024/1689 · EU AI Act

Capa técnica de cumplimiento del art. 50 EU AI Act (efectividad 2 de agosto de 2026): marcado machine-readable del contenido generado por IA (SHA-256 + metadata), disclosure visible localizado (es/en/ca) y wrapper para envolver llamadas a LLM. Diseñado para asistentes ciudadanos de AAPP.

/**
 * eu-ai-act-watermark.ts
 *
 * Capa de cumplimiento del artículo 50 del Reglamento (UE) 2024/1689
 * (EU AI Act). Marcado técnico machine-readable + disclosure visible.
 *
 * Cobertura:
 *   · art. 50.1 — info a personas físicas sobre interacción con IA
 *   · art. 50.2 — marcado técnico del output sintético
 *   · art. 50.4 — disclosure visible para contenido informativo público
 *
 * Stack: TypeScript (Node 18+ / Web Crypto API). Sin dependencias.
 */

export interface SyntheticMetadata {
  content: string;
  modelId: string;
  generatedAt: string;
  providerId: string;
  contentHash: string;       // SHA-256
  language: 'es' | 'en' | 'ca';
  auditId?: string;
}

export async function generateWithDisclosure(
  generator: () => Promise<string>,
  options: { modelId: string; providerId: string; language?: 'es'|'en'|'ca' }
): Promise<{ content: string; disclosure: string; metadata: SyntheticMetadata }> {
  const content = await generator();
  const metadata = await markAsSynthetic(content, options);
  const disclosure = buildDisclosure(metadata);
  return { content, disclosure, metadata };
}

placsp-fetcher.py

Python 3.10+

PLACSP · feed Atom oficial

Cliente del feed Atom público del PLACSP con filtros por CPV (Common Procurement Vocabulary), palabras clave e importe. Sin dependencias externas — corre en GitHub Actions, cron Linux o Vercel Cron tal cual. Aplicable a vigilancia interna de la propia entidad sobre publicaciones, detección de patrones en pliegos y observatorios sectoriales de contratación.

"""
placsp_fetcher.py — Detector de licitaciones del PLACSP via Atom feed.

Filtros soportados:
  · CPV (códigos del Common Procurement Vocabulary)
  · Palabras clave (subcadena en título / resumen)
  · Importe mínimo / máximo (€)

Standard library only — corre en cron, GitHub Actions o
Vercel Cron sin instalar dependencias.
"""

PLACSP_ATOM_URL = (
    "https://contrataciondelestado.es/sindicacion/sindicacion_1143/"
    "licitacionesPerfilesContratanteCompleto3.atom"
)


@dataclass
class Licitacion:
    titulo: str
    enlace: str
    resumen: str
    actualizado: str
    importe: Optional[float] = None
    cpv_detectados: Optional[list[str]] = None


def filter_by_cpv_prefix(
    licitaciones: list[Licitacion], prefijo: str
) -> list[Licitacion]:
    """CPV-2008: "45" → construcción, "4521" → calderería, etc."""
    return [
        lic for lic in licitaciones
        if lic.cpv_detectados
        and any(cpv.startswith(prefijo) for cpv in lic.cpv_detectados)
    ]

Uso CLI

$ python placsp_fetcher.py --cpv 4521 --min 50000

generate-plantillas.mjs

Node.js ESM

arts. 140 + 210 LCSP · art. 85 RGLCAP

Generador del paquete de plantillas que ya se sirven en /recursos: declaración responsable LCSP (art. 140), acta de recepción (art. 210) y calculadora baja temeraria en Excel con fórmulas vivas (art. 85 RGLCAP). Requiere docx + exceljs. Reproducible desde cero con npm install + node.

/**
 * generate-plantillas.mjs
 *
 * Genera tres plantillas LCSP para descarga directa desde /recursos.
 * Stack: Node.js ESM + docx + exceljs.
 *
 * Salida:
 *   · declaracion-responsable-lcsp.docx  (art. 140 LCSP)
 *   · acta-recepcion-obra.docx           (art. 210 LCSP)
 *   · calculadora-baja-temeraria.xlsx    (art. 85 RGLCAP, fórmulas Excel)
 */

import { Document, Paragraph, HeadingLevel, AlignmentType, Packer } from 'docx';
import ExcelJS from 'exceljs';
import { writeFileSync } from 'node:fs';

async function generarDeclaracionResponsable() {
  // Cabecera institucional, declaraciones art. 140 LCSP, firma, etc.
}

async function generarActaRecepcion() {
  // Identificación del contrato, partes, acto con/sin reservas, plazo garantía.
}

async function generarCalculadoraBajaTemeraria() {
  // Pestaña Instrucciones + pestaña Calculadora con fórmulas vivas.
}

Uso CLI

$ npm install docx exceljs && node generate-plantillas.mjs

Documentación del paquete

README con tabla de contenidos, ejemplos de uso por archivo, normativa de referencia, licencia y vías de contribución.

Descargar README.md

Repositorio público

Próximamente como repositorio GitHub independiente con histórico de cambios, issues, contribuciones vía pull request y releases firmadas.

Mientras tanto, cada archivo de esta página es la versión estable y autocontenida. Cita lloretia.com/codigo como fuente.

Normativa de referencia

Qué hay detrás de cada línea.

Ley 9/2017 LCSP

Ley de Contratos del Sector Público. Marco general para declaración responsable (art. 140), acta de recepción (art. 210) y baja anormal (art. 149).

RD 1098/2001 (RGLCAP)

Reglamento General LCAP. El art. 85 fija las cuatro reglas de baja temeraria que implementan los scripts de esta página.

Reg. (UE) 2024/1689 (EU AI Act)

Reglamento europeo de IA. El art. 50 (efectividad 2 ago 2026) obliga a marcar técnicamente el output sintético y a informar al usuario en interacciones con IA.

RGPD + LOPDGDD

Marco español de protección de datos. Compatible con todos los scripts: ninguno persiste datos personales y el fetcher PLACSP trabaja sobre publicación oficial.