Skip to content

Las poblaciones de examen se declaran, y el servidor verifica lo que hay dentro - #1171

Merged
github-actions[bot] merged 1 commit into
developfrom
feat/declarar-las-poblaciones-de-examen
Nov 8, 2026
Merged

github-actions[bot] merged 1 commit into
developfrom
feat/declarar-las-poblaciones-de-examen

Conversation

@frapercan

Copy link
Copy Markdown
Owner

La decision 2 del ADR-D57: cada poblacion de examen entra como conjunto
declarado, descrito y verificable. Son dos, congeladas una vez por el
laboratorio sobre Swiss-Prot 2022_03, y los ficheros ya estan en el almacen,
subidos por la misma ruta por la que llegaron los vectores de los terminos.

Nada corre contra estas poblaciones hasta que el sobremesa revise esto.
Fusionar a develop no ejecuta nada; el freno esta en el despliegue y en el
job, no aqui.

El payload nombra un manifiesto y nada mas

Una poblacion de examen son varios ficheros: los pares de (accesion, md5 de la
secuencia del examen) con su mitad, el corte, los conceptos, las instancias o
los sitios, y el manifiesto del propio laboratorio con los scripts que los
construyeron, sus huellas, el Swiss-Prot del que salen y las comprobaciones que
corrio. Una fila de query_set tiene un artifact_uri y un content_sha256,
asi que la fila apunta a un manifiesto que nombra cada fichero con su huella.

Ninguna ruta del sistema de ficheros llega a la operacion. Una ruta en un
payload dejaria que la API leyera cualquier fichero del servidor, y un alcance
que vive en un payload es una hipotesis disfrazada de constante.

Y una huella no basta, que es lo que esta operacion anade

Una huella prueba que nadie toco los bytes entre alli y aqui. Nunca prueba que
sean los bytes que se querian.
Esta manana llego un fichero de vectores cuya
etiqueta de linea de comandos nombraba una instantanea mientras su contenido era
de otra, y todas las huellas coincidian.

Asi que la operacion abre cada fichero y comprueba lo que hay dentro contra
lo que el manifiesto afirma:

comprueba contra
la huella de cada fichero la que el manifiesto declara
los bytes de cada fichero los que el manifiesto declara
las filas de cada parquet y del tsv las que el manifiesto declara
la cabecera del tsv (accession, md5, half), en ese orden
el orden de las filas ordenado por accesion, porque su huella es de un orden
la particion contada la que el manifiesto afirma
cada accesion que es una proteina con secuencia en esta base

Lo que reporta y no guarda

Cuantos de los md5 declarados siguen coincidiendo con la secuencia que la
plataforma tiene hoy, y las accesiones donde no. Medido ya a mano sobre el
paquete entregado: 3.325 de 3.335 en sitios y 4.187 de 4.227 en dominios, o
sea las 10 y las 40 que el registro ya nombraba.

Es una MEDIDA de (poblacion, plataforma) en una fecha, no una propiedad del
conjunto: el examen deriva su propia exclusion de la misma comparacion cuando
corre, como dice el registro, y un recuento congelado en una fila esta rancio en
cuanto se mueva una secuencia mas.

A la vista sin descargar nada

La descripcion de la fila lleva la particion y los conceptos por rol,
porque son la identidad de una poblacion de examen: los mismos conceptos
partidos de otra forma son otra poblacion, y los reservados son los que nadie ha
mirado.

La migracion

b7c3f91d2a04 ensancha source_kind a seis valores y crea
ck_query_set_exam_is_declared, con los mismos cuatro criterios que el del
corpus. Es aditiva: ensanchar un CHECK no rompe una fila que ya pasaba, y el
CHECK nuevo solo restringe filas de un tipo del que hay cero.

Y el test que fija el vocabulario a mano hizo exactamente su trabajo: fallo al
anadir el valor sin la linea
, que es para lo que su comentario decia que
estaba.

Los tests

Veinte, y los que importan son los que rechazan: un prefijo de sha donde se
quiere una identidad, una clave con .., un manifiesto que describe un fichero
distinto del que apunta con todas las huellas correctas, un tsv desordenado, una
accesion repetida, una mitad fuera del vocabulario, y la particion contada
contra la afirmada. Mas el que mira el job_id en el flush, porque es ahi
donde el CHECK hermano pillo el defecto de ayer y no al final de la funcion.

Suite completa: 6.623 tests, 0 fallos, exit 0. ruff, mypy sobre 425
ficheros, check_smells, check_sets, check_doc_refs,
check_autodoc_coverage, check_openapi_refs y check_row_alignment, todos en
0.

…hay dentro

La decision 2 del ADR-D57: cada poblacion de examen entra como conjunto
declarado, descrito y verificable. Son dos, congeladas una vez por el
laboratorio sobre Swiss-Prot 2022_03, y ya estan en el almacen: 3.335 proteinas
para el examen de sitios y 4.227 para el de dominios.

EL PAYLOAD NOMBRA UN MANIFIESTO Y NADA MAS. Una poblacion de examen son varios
ficheros (los pares de accesion y md5 con su mitad, el corte, los conceptos, las
instancias o los sitios, y el manifiesto del propio laboratorio con los scripts
que los construyeron y sus huellas) y una fila de query_set tiene un
artifact_uri y un content_sha256. Asi que la fila apunta a un manifiesto que
nombra cada fichero con su propia huella.

NINGUNA RUTA DEL SISTEMA DE FICHEROS LLEGA A LA OPERACION. Los ficheros estan en
el almacen antes de que corra, bajo claves derivadas de su propia huella, por la
misma ruta por la que llegaron los vectores de los terminos. Una ruta en un
payload dejaria que la API leyera cualquier fichero del servidor.

Y UNA HUELLA NO BASTA, que es lo que esta operacion anade sobre la del corpus.
Una huella prueba que nadie toco los bytes entre alli y aqui; nunca prueba que
sean los bytes que se querian. El 2026-11-08 llego un fichero de vectores cuya
etiqueta de linea de comandos nombraba una instantanea y cuyo contenido era de
otra, y todas las huellas coincidian. Asi que la operacion abre cada fichero y
comprueba lo que hay DENTRO contra lo que el manifiesto afirma: las filas de
cada parquet, la cabecera del tsv, su orden, su particion, y que cada accesion
es una proteina de la que esta plataforma tiene secuencia.

Lo que reporta y no guarda: cuantos de los md5 declarados siguen coincidiendo
con la secuencia que la plataforma tiene hoy, y las accesiones donde no. Es una
MEDIDA de (poblacion, plataforma) en una fecha, no una propiedad del conjunto:
el examen deriva su propia exclusion de la misma comparacion cuando corre.

La descripcion de la fila lleva la particion y los conceptos por rol, para que
se vean en la plataforma sin descargar nada: los mismos conceptos partidos de
otra forma son otra poblacion, y los reservados son los que nadie ha mirado.

La migracion b7c3f91d2a04 ensancha el vocabulario de source_kind a seis valores
y crea ck_query_set_exam_is_declared, con los mismos cuatro criterios que el del
corpus. El test que fija el vocabulario a mano hizo su trabajo: fallo al anadir
el valor sin la linea.

Veinte tests nuevos, y los que importan son los que RECHAZAN: un prefijo de sha
donde se quiere una identidad, una clave con "..", un manifiesto que describe un
fichero distinto del que apunta con todas las huellas correctas, un tsv
desordenado cuando su huella es de un orden, una accesion repetida, una mitad
fuera del vocabulario, y la particion contada contra la afirmada. Mas el que
mira el job EN el flush, porque es ahi donde el CHECK hermano pillo el defecto
de ayer.

Suite completa: 6.623 tests, 0 fallos, exit 0. ruff, mypy sobre 425 ficheros,
check_smells, check_sets, check_doc_refs, check_autodoc_coverage,
check_openapi_refs y check_row_alignment, todos en 0.
@github-actions
github-actions Bot enabled auto-merge (squash) November 8, 2026 22:50
@github-actions
github-actions Bot merged commit 43723e7 into develop Nov 8, 2026
17 checks passed
@codecov

codecov Bot commented Nov 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.98758% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.96%. Comparing base (d8bc801) to head (026dd7a).
⚠️ Report is 270 commits behind head on develop.

Files with missing lines Patch % Lines
protea/core/operations/declare_exam_population.py 81.76% 29 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1171      +/-   ##
===========================================
+ Coverage    87.85%   87.96%   +0.11%     
===========================================
  Files          306      405      +99     
  Lines        23414    31547    +8133     
===========================================
+ Hits         20570    27751    +7181     
- Misses        2844     3796     +952     
Files with missing lines Coverage Δ
protea/core/operation_catalog.py 100.00% <100.00%> (ø)
...rotea/infrastructure/orm/models/query/query_set.py 97.36% <ø> (+0.70%) ⬆️
protea/core/operations/declare_exam_population.py 81.76% <81.76%> (ø)

... and 165 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

github-actions Bot pushed a commit that referenced this pull request Nov 8, 2026
…los (#1172)

Seguimiento de #1171 con la revision del laboratorio. Y empieza por
**una
afirmacion falsa mia** que el sobremesa pillo leyendo los manifiestos
del
almacen antes de declarar nada. Era el momento barato y lo fue.

## Lo que escribi mal, y es la tercera vez hoy con la misma forma

El manifiesto llevaba `"positions_are": "indices, base 0"` **en la
raiz**. Era
cierto de seis indices de selenocisteina de las comprobaciones del
laboratorio y
**falso de todos los ficheros de etiquetas**, que cuentan residuos desde
1 como
las lineas FT de Swiss-Prot.

Un examen portado que se fiara de esa clave habria **desplazado todos
los sitios
y todos los dominios un residuo**, y nada habria fallado. Tome un hecho
cierto
de una cosa y lo escribi como propiedad de todo el documento.

Medido antes de reescribirlo:

```
sites.parquet      position de 1 a 7924, cero filas en 0, sobre 1.986.242
instances.parquet  las 10.070 cumplen 1 <= start <= end <= longitud
                   contra proteins.parquet
```

La convencion va ahora **por fichero y por columna**, con la linea del
codigo
del laboratorio que la lee, y **se comprueba contra los datos**. Y la
operacion
**exige** `position_conventions` y `halves` en el manifiesto, que es lo
que deja
indeclarables los dos manifiestos escritos antes: el arreglo no es
borrar esos
dos objetos, es que el siguiente escrito a mano tampoco pueda repetirlo.

## Las comprobaciones entre ficheros, que una huella no cubre

Una huella habla de los bytes de **un** fichero y no tiene nada que
decir de
dos. Cada fichero puede estar intacto y describir otra poblacion.

| comprueba | contra |
|---|---|
| las mitades del tsv | las de `split.parquet` |
| las accesiones de `sites.parquet` e `instances.parquet` | la
pertenencia a la poblacion |
| `md5(proteins.parquet.sequence)` | el md5 que el tsv declara, fila a
fila |
| los roles por concepto | **contados** en `concepts.json`, no copiados
|

Lo ultimo importa mas de lo que parece: esos numeros llegan a la
**descripcion
de la fila**, que es la identidad visible de la poblacion, asi que una
afirmacion no basta. Y los dos examenes los anidan distinto, asi que el
mapa por
concepto se **busca**: sitios bajo `concepts`, dominios bajo
`concepts_detail`,
y `roles` en dominios ya es un agregado.

## Y la puerta me pillo cometiendo el error que persigo

`check_row_alignment` refuso `dict(zip(...))`, que **se queda el ultimo
valor de
una clave repetida**. Un `split.parquet` que nombrara una proteina dos
veces en
dos mitades distintas habria pasado mi comprobacion de desacuerdo. Ahora
usa
`lookup_by`, que levanta, y hay dos tests que lo fijan.

## La medida que decide el diseno

Etiquetas que caen fuera de la secuencia que **esta** plataforma guarda:

```
sitios      38 filas, 2 accesiones    todas con md5 distinto
dominios     8 filas, 5 accesiones    todas con md5 distinto

y al contrario NO se cumple:
sitios       8 de las 10 con md5 distinto tienen etiquetas que SI caben
dominios    35 de las 40
```

Un control por rango coge **7 de las 50** proteinas cuya secuencia se
movio; el
md5 coge **las 50**. Asi que el rango se reporta como medida y el md5 es
la
regla de exclusion, como dice el ADR.

## Ensayado contra los manifiestos reales, sin escribir fila

```
sitios     5 ficheros verificados   roles contados 79/42/47/1 = los afirmados
           split coincide           position min 1 max 7924
dominios   6 ficheros verificados   roles contados 71/40/9 = los afirmados
           split coincide           secuencias == su md5, fila a fila
           instancias dentro de la secuencia del propio examen
```

Suite completa **6.642 tests, 0 fallos**. `ruff`, `mypy` sobre 426
ficheros,
`check_smells`, `check_row_alignment`, `check_sets`, `check_doc_refs`,
`check_autodoc_coverage` y `check_openapi_refs` en 0.

> El sobremesa pidio no desplegar ni lanzar los jobs hasta que esten su
punto 1
> (los manifiestos, ya rehechos en el almacen) y su punto 3 (esto). Con
esto
> fusionado, quedan los dos hechos.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant