# DEFINICIONES PREVIAS · CANT-1 · Screens de colusión con ofertas reales por licitador (API de Transparencia de Cantabria) Ejecutor: Opus 5.5 · 26-oct-2026 · Encargo CANT-1 (aprobado por el propietario el 26-oct). Sin modelos de lenguaje, sin red (salvo la descarga única del paso 1, ya hecha), sin producción. Datos: `/cantabria/contratos.parquet` (descarga del 26-oct, 39.436 contratos) → `interno/contratos.parquet`, `interno/ofertas.parquet`, `interno/casado.parquet` (`py/10_tabla.py`, `11_casado.py`, `12_cobertura.py`); `unified_20261025` solo lectura. **Qué se ha mirado antes de escribir esto**: estructura de la exportación (bloques, columnas, formato del detalle), recuentos de ofertas por contrato, presencia de importes > 0, factor IVA de cada oferta (iva / sin_iva), si la adjudicataria está o no en el detalle, nº de licitadores frente a nº en el detalle, casado con unified, cobertura por año, bloque, tipo y órgano, tamaño de las celdas de mercado, y qué positivas del banco de etiquetas caen en Cantabria (`salidas/11_casado.md`, `12_cobertura.md`, `py/03`-`05`, `13`, `01*`). **No se ha calculado ningún screen** (ni dispersión, ni posición de la adjudicataria respecto a la oferta más baja, ni diferencias entre ofertas) sobre ningún contrato. Este texto se sella con md5 y hora en `DEFINICIONES_CANT1.md5` y copia 444 `DEFINICIONES_CANT1.original.md`. No se cambia después; lo que no esté aquí se rotula «exploratorio, no pre-registrado». El resultado nulo o «sin potencia» es un resultado y se publica. Vocabulario de lo publicable: «competencia medida», «screen» (término técnico), «descriptor», «ofertas agrupadas». Nada por empresa ni por contrato fuera de `interno/` (700). ## 0. El sobre sellado de Cantabria (S/0004/25): separación - El sobre `colusion/interno/CANTABRIA_SOBRE_CERRADO.md` (md5 `8145e9e1…`) no se abre, no se lee, no se recalcula (`py/08_cantabria.py` no se ejecuta) y su lista de empresas (`colusion/interno/emp.csv`, V2 de `p8/c06`) **no se usa** en este encargo. S/0004/25 no es etiqueta. - Su ámbito (obras de Cantabria, ventana supuesta 1-1-2019 a 31-3-2025) se solapa con esta fuente. Se marca **`ambito_sobre`** = tipo «Obras» con año de formalización 2019-2025 (años enteros: margen conservador). Sus contratos entran en el cálculo de percentiles (que no usa etiqueta) pero: (a) ningún resultado suyo sale de `interno/` salvo agregados por mercado rotulados; (b) no se cruzan con ninguna lista de empresas; (c) se informan aparte. Medido antes de sellar: 282 de los 320 contratos de obras con vector completo están en el ámbito. ## 1. Unidad, vector de ofertas y población - **Unidad** = contrato de la API (fila; en los bloques general y otros la API no trae lotes: cada fila es un contrato o lote adjudicado). Bloques con detalle de ofertas: `menor`, `general`, `otros` (los basados en acuerdo marco no lo traen). - **Vector de ofertas** = las ofertas del «Ofertas (detalle)» del bloque **más**, si la adjudicataria (NIF o clave de persona física) no está en el detalle, una oferta de la adjudicataria con su **importe de adjudicación sin IVA** (medido: el detalle omite a la adjudicataria en el 98 % de los no menores y nº de licitadores = detalle + 1 en 650 de 670). Importe de cada oferta = **sin IVA**. «La adjudicataria está en el detalle» = mismo NIF (persona jurídica) o, si es persona física, las mismas 4 cifras centrales que publica el portal (el nombre puede venir escrito de otra forma). Si está y su importe del detalle es ≤ 0, se usa el de adjudicación. - **Exclusiones** (en este orden; cada motivo se cuenta): | Motivo | Regla | |---|---| | `bloque` | bloque ∉ {menor, general, otros} o año < 2018 | | `al_alza_tipo` | tipo ∉ {Obras, Servicios, Suministro} (concesiones, patrimoniales, mixtos, otros) | | `sin_detalle` | el contrato no trae detalle de ofertas | | `adj_desconocida` | adjudicataria sin NIF y no está en el detalle (el vector quedaría incompleto) | | `menos_de_3` | vector con < 3 ofertas | | `importe_cero` | alguna oferta del vector con importe sin IVA nulo o ≤ 0 (vector incompleto; va al conjunto **parcial**, §5) | | `nif_repetido` | el mismo licitador (NIF o clave PF = hash de las cifras centrales y el nombre) dos veces en el vector | | `iva_incoherente` | alguna oferta con iva / sin_iva fuera de {1; 1,04; 1,10; 1,21} ± 0,5 % (iva = 0 se admite) | | `adj_incoherente` | la oferta añadida de la adjudicataria fuera de [0,5; 2] × la mediana de las ofertas del detalle (unidad distinta: con IVA, plurianual, precios unitarios) | | `sin_dispersion` | todas las ofertas iguales | | `precio_no_competido` | PBL sin IVA > 0 y ≥ 50 % de las ofertas a ±0,1 % del PBL | **Población P** = lo que queda. **Conjunto amplio** (sensibilidad): P + los excluidos solo por `iva_incoherente` o `adj_incoherente`. **Conjunto parcial** (sensibilidad): contratos con ≥ 3 ofertas con importe > 0 aunque falten importes. **Solo perdedoras** (sensibilidad que no depende de que la adjudicación sea la oferta): las ofertas del detalle sin la adjudicataria añadida, ≥ 3. - **Mercado** = tipo de contrato (Obras, Servicios, Suministro) × **menor / no menor** (no menor = general + otros), todos los años 2018-2026 juntos: 6 mercados (medido: 82 a 393 contratos con vector completo cada uno). Mercado con < 20 contratos en P: sus contratos no reciben percentil (se cuentan). ## 2. Screens (fórmulas de `actas/piloto_a/prereg/PREREG_SCREENS.md` §3.2, sin cambios) Ofertas del contrato ordenadas b(1) ≤ … ≤ b(n); media m; desviación típica s con n − 1; perdedoras = b(2)…b(n) (a efectos del screen la «ganadora» es la oferta más baja, no la adjudicataria). | Screen | Fórmula | Orientación (mayor = más parecido a colusión) | n mín. | En S | |---|---|---|---|---| | CV | s / m | −1 | 3 | sí | | DIFFP | (b(2) − b(1)) / b(1) | +1 | 3 | sí | | RD | (b(2) − b(1)) / s(perdedoras); s(perd) = 0 y b(2) > b(1) → +∞ | +1 | 3 | sí | | SKEW | n / ((n − 1)(n − 2)) · Σ ((b − m)/s)³ | −1 | 3 | sí | | KURTO | n(n + 1) / ((n − 1)(n − 2)(n − 3)) · Σ ((b − m)/s)⁴ − 3(n − 1)² / ((n − 2)(n − 3)) | +1 | 4 | sí, si n ≥ 4 | | SPD | (b(n) − b(1)) / b(1) | −1 | 3 | no (se informa) | | RDALT | (b(2) − b(1)) / ((b(n) − b(2)) / (n − 2)); denominador 0 y numerador > 0 → +∞; numerador 0 → 0 | +1 | 3 | no | | RDNOR | (b(2) − b(1)) / ((b(n) − b(1)) / (n − 1)) | +1 | 3 | no | Además, por contrato (descriptores, no screens): **ADJ_NO_MIN** = 1 si la oferta de la adjudicataria no es la más baja (con tolerancia 0,005 %); **DIFFP_ADJ** = (oferta más baja distinta de la de la adjudicataria − oferta de la adjudicataria) / oferta de la adjudicataria (PREREG_SCREENS S9; puede ser negativa); **HUECO** = 1 si DIFFP < 0,005 (Chassang et al. 2022). - **Percentil orientado** dentro del mercado: pct = (rango medio del valor orientado − 0,5) / N sobre los contratos de P del mercado con ese screen; empates con rango medio; +∞ el mayor. - **S (compuesto)** = media de los percentiles orientados disponibles de CV, DIFFP, RD, SKEW y KURTO (cuatro si n = 3). Sin pesos. - **Licitación nuestra** (secundario): contratos casados E1/E2 con la misma `licitacion_id` de la PLACSP → S_lic = media. ## 3. Etiqueta y contraste - **Positiva** = contrato de P casado (E1/E2) con un `id_canonical` que sea positivo (`rol = 'pos'`) en el banco de etiquetas (`colusion/d5b/interno/c0_et.parquet`: D4c + D5 + v2 + ACCO). **Control** = contrato de P del mismo mercado y año, sin ninguna fila casada en el banco (positiva o control) y fuera de la exclusión del banco (adjudicataria o licitador con NIF de un expediente del banco, `colusion/d5b` exclusión de 519 claves si está disponible; si no, solo NIF de las positivas). S/0004/25 no es etiqueta. - **Regla de potencia (fijada ahora)**: el contraste (AUC estratificada de S por mercado × año, IC bootstrap en dos etapas órgano/contrato, 2.000 réplicas, semilla 20261026; criterio C1 de PREREG_SCREENS: AUC ≥ 0,70 y límite inferior > 0,50) **solo se calcula si hay ≥ 10 licitaciones positivas distintas en P**. Con menos, no se calcula ninguna AUC: el resultado es **«sin potencia: descriptivo»** y así se publica. (Lectura previa, no medida sobre P: las positivas del banco en Cantabria son de 2008-2011 en TED o de órganos estatales que no están en esta API; lo esperable es 0.) ## 4. Descriptivos pre-registrados (principal de este encargo si no hay potencia) Por **mercado** (6) y, aparte, el agregado del **ámbito del sobre** y del **resto**: 1. Nº de contratos en P, nº de órganos, nº de licitadores distintos, media de ofertas por contrato, % de ofertas de personas físicas. 2. Mediana y percentiles 25 y 75 de CV, DIFFP, RD, SKEW, KURTO y SPD; IC95 de la mediana de CV y de DIFFP por bootstrap en dos etapas (órgano, contrato), 2.000 réplicas, semilla 20261026. 3. % de ADJ_NO_MIN, % de HUECO, mediana de DIFFP_ADJ. 4. Las mismas medianas por tramo de nº de ofertas (3 · 4-5 · 6-9 · ≥ 10), para separar lo mecánico del nº de ofertas. 5. Referencia de la literatura (sin umbral validado aquí): CV medio de 3,25 % en el cártel del Ticino frente a 9,51 % después (Imhof, Karagök y Rutz 2018, citado en PREREG_SCREENS §3.2); se informa qué % de contratos de cada mercado tiene CV < 3,25 % y < 9,51 %, rotulado «referencia, no umbral». Por **consejería** (≥ 20 contratos en P): nº de contratos, mediana de CV y de DIFFP, % ADJ_NO_MIN, % HUECO. Nunca por contrato. **Descriptores de presencia (exploratorios, pre-registrados; sobre todos los contratos con detalle y ≥ 3 licitadores identificados, con o sin importes; 2018-2026)**: - **REPE** = % de contratos cuyo conjunto exacto de licitadores (claves) aparece en ≥ 3 contratos del mismo órgano directivo; entre esos conjuntos, nº medio de adjudicatarias distintas (**rotación**: 1 = siempre gana la misma). - **NUNCA_GANA** = % de ofertas perdedoras de licitadores que no ganan ningún contrato de la API en 2018-2026. Por mercado y por consejería; nunca por empresa, pareja ni conjunto. ## 5. Secundarios (declarados; no deciden) - S1 **conjunto amplio**, S2 **parcial**, S3 **solo perdedoras**: las medianas del §4.2 recalculadas. - S4 **capa 1 frente a capa 2** (contratos de P casados E1/E2 con una sola fila PLACSP que trae `oferta_min_eur` y `oferta_max_eur` > 0): (a) conciliación: mín y máx de la API frente a la PLACSP dentro del 0,5 % o de un factor IVA {1; 1,04; 1,10; 1,21}, y nº de ofertas igual a `num_ofertas`; (b) Spearman entre RANGO de la PLACSP ((máx − mín)/mín) y SPD y CV de la API, en los conciliados; (c) % de acuerdo en el quintil superior (dentro del mercado) de −RANGO y de −CV. Ámbito del sobre y resto por separado. - S5 **por licitación nuestra**: nº de licitaciones PLACSP distintas en P y mediana de S_lic. ## 6. Segunda implementación y cotejo - impl1 = `py/20_screens.py` (Python puro, `statistics`); impl2 = `py/21_impl2.py` con todo el cálculo en **SQL de DuckDB** (otra herramienta; fórmulas escritas desde este texto; además, `skewness`/`kurtosis` nativas de DuckDB como tercera comprobación). - Tolerancias: mismo conjunto P y mismos motivos de exclusión (0 diferencias); cada screen |Δ relativo| ≤ 1e−9 (los ∞ coinciden); percentiles y S |Δ| ≤ 1e−9; medianas y % del §4 idénticos (≤ 1e−9). Los IC del bootstrap solo en impl1. Si discrepan, manda la lectura más conservadora y se documenta. Cotejo en `salidas/22_cotejo.md`. ## 7. Qué se publica - Sí: cobertura (`12_cobertura.md`), los descriptivos del §4 por mercado y consejería con su n y la frase «sin validar contra cárteles: en Cantabria no hay etiqueta legal con ofertas» (si así sale), la conciliación capa 1 / capa 2 (§5 S4). - No: nada por empresa, contrato, pareja o conjunto de licitadores; nada del ámbito del sobre salvo agregados por mercado; ningún umbral de alerta; nunca «cártel probable».