# A1 · «Precio frente a comparables» · DEFINICIONES PREVIAS (pre-registro del piloto) Ejecutor: coordinador A1 (Opus 5.5) · 22-oct-2026. Decisión del propietario (22-oct): adelante con el piloto, previsión ≈ 4,2 M tokens, **PARADA DURA a 6 M notificados** (lectores + jueces). Sale de `PROPUESTA_PREREG_A1.md` (borrador del 21-oct) con los cambios de §9. **Escrito y sellado antes de leer nada con modelos y antes de calcular ningún hecho por órgano ni cruzar nada con ninguna etiqueta.** Lo único visto antes de sellar: la prueba de concepto descriptiva del 21-oct (mediana del mercado con reglas v1), la cobertura de las etiquetas (recuentos, sin cruzar con razones: §5.3) y el tamaño del recorte en 20 licitaciones (§4.2). Reglas de la casa (FRAMEWORK §5 y auditoría del 22-oct): universo `NOT es_copia`; validación contra cárteles a nivel de lote; «estable» ≠ «válido»; importe comparable sin IVA; sesgo de la etiqueta; claves de persona física fuera de toda salida pública; nunca empresas ni personas; vocabulario sin «fraude», «sobrecoste» ni «sospechoso». ## 1. Universo, unidad y mercado - **Construcción**: `unified_20261018` (y sus satélites `.vinculos`, `.identidad`, `.documentos`), solo lectura. - **Unidad = contrato**: fila `unidad = 'adjudicacion'` (contrato o lote adjudicado), `anio_ref` 2022-2025, todas las fuentes. - **Universo `NOT es_copia`** con la definición de la web: `copia_de IS NOT NULL OR correccion_imp_adj = 'copia_otra_fuente' OR NOT cuenta` (vínculos `filas.parquet`, por `source` + `id_canonical`). - **Mercado carburantes**: reglas v1 (`scripts/reglas.py`: CPV 09130000-09134999 u objeto, con exclusiones) **y** exclusión v2 (`scripts/reglas_v2.py`: limpiador|aditivo|hidrolimpiadora|congelador). Electricidad: reglas v1 (solo lectura, §6). - **Importe comparable (IVA)**: `imp_adj_eur_comparable` > 0, que solo existe con `iva_base` 'sin' o 'sin_medido' (importe sin IVA publicado o medido). Lo publicado con IVA no se convierte: queda fuera del cociente y se cuenta en la cobertura. - Fuera: `rol_am` 'acuerdo' o 'sda' (topes, no compras); Canarias, Ceuta y Melilla (provincia INE 35, 38, 51, 52 o NUTS ES70/ES63/ES64: otros impuestos). - **Mercado de referencia = producto × provincia × mes.** Producto ∈ {gasóleo A, gasóleo B, gasóleo C, gasolina 95}; mes = el de la fecha de adjudicación (si no, formalización; si no, publicación) si cae en 2022-2025, y si no julio de `anio_ref`; provincia INE por NUTS3 o por nombre (`scripts/comun_a1.py`), desconocida → referencia nacional. ## 2. Referencias y su fecha (`scripts/e4_referencias.py`) - **Weekly Oil Bulletin** de la Comisión Europea (histórico XLSX descargado el 21-oct-2026, semanas 03-01-2005 → 19-10-2026, sha256 en `salidas/02_descargas.jsonl`): España, precios **con impuestos**; referencia nacional mensual = media de las semanas del mes, ÷ 1,21 (IVA). A = gasóleo de automoción, gasolina 95 = Euro-super 95, C = gasóleo de calefacción. - **Geoportal de gasolineras (MITECO)**, servicio REST histórico: un día por trimestre (el 15 del mes central: feb, may, ago, nov) de 2022 a 2025, 16 días descargados el 22-oct-2026 (`salidas/14_referencias_red.jsonl`). Factor provincial (A y 95) = media de las estaciones de la provincia ÷ media de la Península y Baleares (≥ 5 estaciones); B = diésel del WOB × (B/A nacional del día del trimestre); C sin factor (solo nacional). - **Licencias** (comprobadas el 22-oct): WOB = contenido de la Comisión bajo **CC BY 4.0** (aviso legal de la Comisión, Decisión 2011/833/UE): permite el uso con atribución e indicación de cambios. Geoportal = MITECO: su aviso legal permite usar la información «en parte o en su integridad, sin necesidad de autorización expresa, siempre que se cite la fuente» (Ley 37/2007, RD 1495/2011). **Las dos permiten el uso**; se cita la fuente y se dice que el precio se transforma (÷ 1,21, medias). El servicio REST vive en la sede del Ministerio de Industria y no tiene aviso propio localizable (página de una sola aplicación): se aplica el del titular del geoportal (MITECO). - **Electricidad**: sin referencia en este piloto (los ficheros anuales del OMIE dieron 404; peajes y cargos sin descargar): **parcial declarada** (§6). ## 3. Cantidad, producto, cociente y validez ### 3.1 Vías de la cantidad - **R (reglas v2, 0 tokens)**: primera cantidad en litros del objeto que no sea capacidad (`reglas_v2.cantidad_principal`): coma de millares inglesa, capacidades (carrillo, depósito, bidón, petaca, garrafa, lata, capacidad, maletero, congelador en los 40 caracteres previos, o «/100 km» detrás). Producto `reglas_v2.producto2` (C, B, gasolina, A explícito; sin letra → «sin_producto»; gasóleo y gasolina → «mixto»). Pruebas: `pruebas/test_reglas_v2.py` (41 comprobaciones, 0 fallos) y las 21 de v1. - **L (lectura con modelos, §4)**: solo en los contratos de las licitaciones de la muestra; cantidad, unidad, producto, periodo de la cantidad y tipo de importe, con cita filtrada. Si un contrato tiene L, L gana (en la muestra R no tiene cantidad por construcción). - **Cantidad total del contrato** (L): `total_contrato` → la cantidad; `anual` → × duración/12; `mensual` → × duración; duración = `duracion_meses` del anuncio, si no la leída. Sin duración o con periodo desconocido → fuera («periodo_desconocido», «sin_duracion»). Unidad distinta de litros → fuera. **`importe_tipo = descuento_surtidor` → fuera** (el importe es un presupuesto, no litros × precio: «se dice, no se imputa»). - Producto fuera de {A, B, C, 95} (sin_producto, mixto, gasolina 98, otro) → fuera («sin_producto_comparable»). ### 3.2 Cociente `razón = (imp_adj_eur_comparable ÷ cantidad_total) ÷ referencia(producto, provincia, mes)`, referencia en € por litro sin IVA = nacional mensual × factor provincial del trimestre (A y 95; si falta, 1). - **Núcleo**: estado «comparable», cantidad_total ≥ 200 l y (vía L o una sola cantidad distinta en el objeto). - **Válido** (lo único que entra en un hecho): núcleo y razón en [0,5; 2]. Fuera de ese rango = **«dato dudoso»**, nunca hecho. ### 3.3 Intervalo esperado y hecho (K de N por órgano) - Por producto, **intervalo esperado = [P10, P90]** de las razones válidas de **los demás órganos** (cuantil continuo lineal, tipo 7), es decir, dejando fuera al propio órgano. - Unidad del hecho = órgano (`organo_clave` de la identidad 20261018) × producto, 2022-2025. N = contratos válidos; **K_sup** = cuántos tienen razón > P90; **K_inf** = cuántos < P10. - **n mínimo: N ≥ 10.** Prueba binomial de cola superior P(X ≥ K | N, 0,10) para cada lado; **Holm-Bonferroni con α = 0,05** sobre todas las pruebas (unidades evaluables × 2 lados). - **Hecho «por encima»** si la prueba de K_sup se rechaza; **«por debajo»** si la de K_inf; si no, «ninguno»; N < 10 → «no evaluable». Se publica con N, K y la mediana del órgano con IC 95 % (bootstrap por contrato, 10.000 réplicas, semilla 20261021). Texto: «En *N* contratos de *producto* de 2022-2025 con cantidad publicada, *K* pagaron por litro más que el 90 % de los contratos del mismo producto de otros órganos, frente al precio medio de surtidor del mes y la provincia». - Lo que el hecho **no** dice: que el precio sea indebido. Un depósito aislado, el transporte, pedidos pequeños o urgentes, o un descuento pactado lo explican; un contrato a «descuento sobre surtidor» con presupuesto máximo no se puede comparar. ## 4. Lectura con modelos (protocolo) ### 4.1 Muestra 200 licitaciones (`scripts/e3_muestra.py`, `priv/muestra_200.csv`): **160 de carburantes y 40 de electricidad**, PLACSP, 2023-2025, licitadas, `NOT es_copia`, sin exclusión v2, **sin cantidad en el objeto** (reglas v2), con PPT, importe comparable > 0, sin acuerdo marco, fuera Canarias/Ceuta/Melilla; orden por md5('precios-a1-20261021' ‖ licitacion_id), estratos año × tipo de órgano × basado, reparto proporcional (mayores restos). Población: 1.882 y 1.998 licitaciones. 257 contratos. ### 4.2 Texto que se lee (RECORTE_V1, `scripts/g3_recorte.py`) PPT entero si ≤ 10.000 caracteres; si no, ventanas de ±600 alrededor de los términos de cantidad, producto y precio, tope 8.000; PCAP: ventanas de ±400 (cantidad, consumo, precio unitario, descuento, surtidor, sistema de determinación del precio, presupuesto base), tope 4.000; prioridad a las ventanas con número + unidad. **Medido en las 20 primeras** (40 peticiones): 19 con texto, **5.473 tokens de media** (máx. 6.280); 11 traen una cantidad en el texto completo y las 11 la conservan en el recorte. Cabecera del caso: identificador opaco (HMAC con semilla secreta), objeto del anuncio y lotes (clave y objeto); **sin importes, órgano ni fechas**. Casos con contenido idéntico (basados con los mismos pliegos) se leen una vez. ### 4.3 Lectores, juez y ceguera - **Prompt sellado** `lectura/PROMPT_LECTOR_A1_v1.md` (el mismo para A y B) y `lectura/PROMPT_JUEZ_A1_v1.md` (md5 en `lectura/SELLO.md5`). `lectura/encargo.py` no imprime un encargo si el prompt no coincide con el sello. - **A = Sonnet** sobre los 200 (lotes ≤ 75.000 tokens de texto), **B = Opus** sobre los 200 (lotes ≤ 150.000). Lectores **ciegos**: no ven la otra lectura, ni importes, ni referencias, ni la hipótesis. - **Filtro mecánico** (`lectura/combinar.py`): una cita que no está literalmente en el texto anula su dato; el número de la cantidad debe estar en su cita salvo suma declarada (`duda`), que va al juez. - **Concordancia** por caso × lote: misma unidad, producto y periodo, cantidad a ±1 % (o las dos vacías), mismo tipo de importe y ninguna duda. **Juez = Opus**, ciego al modelo (orden de las respuestas al azar fijo), **solo en las discrepancias**: elige 1, 2, ambas o ninguna con el texto delante. «Ninguna» → no extraído. - **Como máximo UN lector o juez a la vez.** Orden: A carburantes → B carburantes → juez carburantes → A electricidad → B electricidad → juez electricidad (una parada deja completo lo principal). - **Tokens por lote** en `lectura/TOKENS.tsv` (los notificados). **PARADA DURA**: `encargo.py` no imprime un lote si acumulado + (texto del lote + 55.000) × 1,5 > 6.000.000. JSON roto o sin salida: se relanza una vez; si vuelve a fallar, el lote queda sin leer y se dice. ### 4.4 Aceptación de la lectura (umbrales) 1. **Acuerdo A-B** (tras el filtro, casos × lote con las dos respuestas) ≥ 90 % en cantidad (±1 % y misma unidad, o las dos vacías) y ≥ 90 % en producto; kappa de «tipo de importe» informado (umbral 0,6). 2. **Citas inexistentes** ≤ 2 % de los datos antes del filtro (0 después, por construcción). 3. **Cobertura de la lectura**: ≥ 60 % de las licitaciones de carburantes con texto dan cantidad y producto con cita (tras juez). Se publica siempre al lado la cobertura del mercado (contratos e importe), sin umbral: el techo medido es ~15 % de los contratos de carburantes (`VIABILIDAD_A1.md`). ### 4.5 Preparación medida y previsión (22-oct, antes de sellar) 392 peticiones a la PLACSP y 2 a Euskadi (URL con caracteres de control, no enviadas): 374 documentos (16 HTTP 500 de documentos retirados), 6 escaneados. **183 licitaciones con texto (17 sin texto legible) → 176 casos únicos** (141 de carburantes, 35 de electricidad), **1.001.607 tokens de texto** (5.691 por caso). Lotes: A (Sonnet) 15, B (Opus) 8 (`lectura/lotes.json`). Previsión con la medida de la casa (texto + 55.000 fijos por lote): A 1,83 M + B 1,44 M + juez ≈ 0,4-0,6 M = **≈ 3,7-3,9 M**; con el desvío observado en el piloto de pliegos (×1,36-1,56) ≈ 5,1-5,6 M: cabe bajo la parada de 6 M, que manda (`encargo.py`). ## 5. Validaciones del indicador (umbrales fijados ahora) 1. **Mediana del mercado** (núcleo, todos los productos y vías): dentro de [0,85; 1,15]. Si no: «el dato está mal, no el órgano»; NO PASA. 2. **No regresión**: gasóleo C del núcleo ≥ 75 % dentro de ±15 %; núcleo ≥ 50 % dentro de ±15 %. 3. **Etiquetas externas** (regla de X2: FUNCIONA = AUC ≥ 0,65 con límite inferior del IC 95 % > 0,55; NULO = AUC ≤ 0,55; débil en medio; IC por bootstrap de conglomerados, 2.000 réplicas, semilla 20261022; **NO EVALUABLE si < 10 positivos o < 10 negativos**). Recuentos medidos antes de sellar (sin cruzar con ninguna razón): - **Cárteles a nivel de lote** (`colusion/etiquetas/casado/salidas/lotes_cartel_v2.csv`, V2 + V3, PLACSP, md5(source|id)): **0 contratos de carburantes del universo casan** → NO EVALUABLE ya antes de leer. Si casara alguno: puntuación = razón, controles = válidos del mismo producto sin cártel, conglomerado órgano. Sesgo de la etiqueta: selecciona cárteles con varios licitadores; un sentido inverso no se interpreta como protector. - **Fiscalización (banco P6, el de X2)**: entidad-año (`entidad_clave` de la identidad), etiqueta positivo/negativo, puntuación = mediana de las razones válidas de la entidad-año (≥ 3); con reglas v2 hoy casan **7 positivas y 1 negativa** → previsiblemente NO EVALUABLE. 4. **Estabilidad entre periodos** (se llama «estable», nunca «válido» ni «fiable»): órgano × producto con ≥ 5 válidos en 2022-2023 y ≥ 5 en 2024-2025; Spearman de la mediana; IC por bootstrap de órganos (2.000, semilla 20261022). «Estable» si ρ ≥ 0,30 y límite inferior > 0; no evaluable con < 15 unidades. 5. **Segunda implementación** (`scripts/f2_impl2.py`, pyarrow + Python, sin DuckDB, escrita aparte de `e2_hechos.py`): diferencias ≤ 0,5 % de los contratos (estado, válido, razón a 1e-9) y ≤ 0,5 % de las unidades órgano × producto (N, K, hecho). Banco sintético con órganos plantados y caso de cero válidos (`pruebas/banco_e2.py`, `pruebas/correr_banco.sh`): 0 diferencias, plantados detectados, clave de persona física fuera de lo publicable. 6. **Cotejo manual de 30 contratos válidos** (yo, coordinador, contra el texto): muestra por md5('cotejo-a1' ‖ id), 15 de vía L (si hay menos, todos) y el resto de vía R, como mucho 2 por órgano. Por contrato: cantidad (±1 %), unidad, producto, y para L periodo y tipo de importe, contra el PPT/PCAP leído; para R contra el objeto del anuncio. **≥ 28/30 correctos.** ### 5.1 Veredicto (fijado ahora) - **NO PASA** si falla cualquiera de: 1, 2, 5, 6, o la aceptación de la lectura 4.4.1-4.4.2 (en ese caso la vía L se descarta y el resto se evalúa solo con R, diciéndolo). - **PASA** si se cumplen 1, 2, 5, 6 y **alguna etiqueta externa (3) FUNCIONA**. - **COTA** si se cumplen 1, 2, 5 y 6 pero ninguna etiqueta externa es evaluable o funciona: el dato (precio pagado frente a referencia) está bien medido, pero **no hay validación de que el hecho señale un riesgo**; se puede publicar como dato descriptivo con su precisión y su cobertura (cota de lo observable), nunca como indicador de riesgo. En el registro de precisión, «cota» = «no confirmada». - La estabilidad (4) se informa siempre y no cambia el veredicto. ## 6. Electricidad (parcial declarada) Solo extracción (A, B, juez) en los 40 de la muestra; se informa €/kWh pagado (importe ÷ energía total) de forma descriptiva y la calidad de la extracción. Sin referencia, sin cociente, sin hechos. Fase 2 con su propio pre-registro (OMIE + peajes y cargos por periodo). Medicamentos, gas, papel y vehículos: fuera. ## 7. Salidas `INFORME_A1.md`; `salidas/publicable_organo_anio.csv` (órgano, tipo, año, producto, contratos válidos, K por encima y por debajo, hecho 2022-2025; sin claves de persona física, sin empresas); `salidas/para_registro_precision.json` (formato de `app/datos/precision.json`); boceto SVG de la razón por mes. Nada a producción ni a TRASPASO.md. ## 8. Ficheros sellados md5 en `DEFINICIONES_PREVIAS.md5` (este texto) y `SELLO_CODIGO.md5` (código, prompts, muestra, lotes y textos de lectura). ## 9. Cambios sobre el borrador del 21-oct 1. **Sin Haiku**: A = Sonnet y B = Opus leen los 200 (antes: Haiku sobre 200 y doble lectura en 100), juez Opus solo en discrepancias (antes: Opus y Fable en los 100). Decisión del propietario (22-oct) y regla «toda la operativa en Opus 5.5». 2. **Recorte medido** (5.473 tokens de media, no 8.000) y lotes de lectura definidos. 3. **El hecho** pasa de «mediana del órgano con IC» a **K de N fuera del intervalo esperado** (P10-P90 dejando fuera al órgano) con Holm; la mediana con IC queda como acompañante. 4. Universo `NOT es_copia` (antes `copia_de IS NULL`); años 2022-2025 en todas las vías. 5. Validaciones externas, estabilidad, segunda implementación y cotejo manual añadidos con umbrales; veredicto con «cota». 6. Electricidad: «parcial declarada», sin referencia (OMIE anual 404).