Skip to content

Las secuencias retiradas vienen de UniParc, y reviewed se queda sin inventar - #1000

Merged
github-actions[bot] merged 2 commits into
developfrom
feat/las-secuencias-retiradas-vienen-de-uniparc
Oct 10, 2026
Merged

github-actions[bot] merged 2 commits into
developfrom
feat/las-secuencias-retiradas-vienen-de-uniparc

Conversation

@frapercan

Copy link
Copy Markdown
Owner

Usa protea-sources#39, ya fusionado; sube el pin a fc43ab9.

El hueco

Una pasada completa de esta operación sobre el universo de la campaña limpia dejó 28.868
accesiones sin secuencia
. Su docstring ya avisaba de que podía pasar, y acertaba: una accesión
que UniProtKB deja de servir sale ausente del endpoint por lotes mientras X-Total-Results la
cuenta, y su propia URL responde 200 con el cuerpo vacío. Lo que no estaba dicho es que esas
secuencias siguen existiendo, en UniParc.

Medido el 2026-10-11 sobre una muestra aleatoria de 600 de esas 28.868: 600 resueltas.

Por qué es un pase y no un fleco

Las que faltan no faltan al azar. Por nivel de evidencia, a lo largo de las 74 releases:

Nivel (alguna vez en la serie) Proteínas Sin secuencia
Llevó evidencia experimental 207.318 9,2%
Sólo inferencia curada (T3) 121.677 7,8%
Ni una ni otra 407.969 0,07%

Y por corte, sobre el banco de donantes experimental:

corte 160   7,5% ausente        corte 220   3,8%
corte 190   7,5%                corte 227   2,1%
corte 211   7,4%                corte 235   0,0%

Un gradiente de visibilidad del 92,5% al 100% se disfraza exactamente de crecimiento del banco,
que es una de las dos cosas que el dataset longitudinal existe para separar. Y es del mismo orden
que el crecimiento real, que va del 84,3% de admisiones en la 156 al 100% en la 235: sin corregirlo
no son distinguibles.

Las dos decisiones que UniParc obliga a tomar

Están en _newest_per_accession, juntas y con su razón, porque las dos son decisiones y no
transporte. El plugin devuelve en crudo justamente para que se tomen aquí.

Qué fila. Una accesión responde una fila por versión de secuencia que haya tenido: 670 filas
para 600 accesiones. Se toma la de last_seen más reciente, la que tenía al desaparecer. La
alternativa —la versión vigente en cada corte— sería una respuesta mejor y un corpus distinto:
todas las demás proteínas del almacén llevan la secuencia que UniProt sirve hoy, así que tomar
la más nueva deja el almacén entero bajo una sola convención en vez de hacer de estas 28.868 las
únicas con una segunda regla. Las fechas quedan guardadas para poder revisarlo sin volver a
preguntar.

Qué accesiones. Las secuencias idénticas comparten UPI, así que una fila responde por entradas
que nadie pidió. Sólo se escriben las del lote: las demás pueden estar perfectamente vivas.

reviewed se queda en NULL

UniParc guarda secuencias, no estado de entrada, y la accesión es una que UniProtKB ya no sirve:
no hay estado que leer. Escribir False sería indistinguible de una entrada que UniProt llamó no
revisada, y NULL ya significa lo que es cierto, que nadie preguntó o nadie pudo contestar.

De ahí el asserts_reviewed de store_records, opt-in: los dos llamantes que sí leen el estado
de una cabecera FASTA siguen escribiéndolo, y hay un test que lo fija. Importa porque el corpus ya
tiene 407.697 proteínas admitidas por haber sido Swiss-Prot en su día cuya evidencia es automática;
un reviewed equivocado encima de eso no se recupera después.

Y dates_pending deja de mentir en seco

resolution_report declara en su propio docstring que un seco devuelve None y no 0, "porque
cero recuperable y no intentado no son lo mismo"
. Ese campo rompía la regla: devolvía 0 con
644.659 filas esperando
, porque el pase que las cuenta es justo el que un seco salta. Un seco es
donde alguien decide si la corrida real merece la pena, así que el único campo que decía "nada que
hacer" era el que no podía saberlo.

Comprobado

Suite completa en verde salvo test_settings::test_load_settings_reads_yaml, que falla igual en el
árbol sin tocar. ruff, mypy y el presupuesto de complejidad limpios.

Los tests tienen dientes: quitando el guardia de asserts_reviewed fallan dos. Y el orden de los
pases está fijado, porque invertirlo tiene consecuencia: preguntar al archivo primero recuperaría
una secuencia para una accesión que UniProtKB habría resuelto como fusión, y la fusión lleva una
identidad que el archivo no tiene.

Lo que falta después de esto

Mover DECLARED-REVISION.txt y lanzar el job. La precondición se cumple: cero jobs en QUEUED o
RUNNING.

…nventar

Una pasada completa dejo 28.868 accesiones sin secuencia. La operacion ya avisaba
de que podia pasar: una accesion que UniProtKB deja de servir sale ausente del
endpoint por lotes mientras X-Total-Results la cuenta, y su propia URL responde 200
con el cuerpo vacio. Lo que no estaba dicho es que esas secuencias siguen existiendo
en UniParc, que guarda todas las que UniProtKB ha tenido alguna vez. Sobre una
muestra aleatoria de 600 de esas 28.868, la ruta nueva resolvio 600.

POR QUE MERECE UN PASE Y NO ES UN FLECO. Las que faltan no faltan al azar. Por nivel
de evidencia sobre las 74 releases, no tiene secuencia el 9,2% de las proteinas que
ALGUNA VEZ llevaron evidencia experimental y el 7,8% de las de inferencia curada,
contra el 0,07% del resto. En un corte antiguo eso es el 7,5% del banco de donantes
y en el ultimo es el 0%: un gradiente de visibilidad que se disfraza exactamente de
crecimiento del banco, que es una de las dos cosas que un dataset longitudinal existe
para medir.

LAS DOS DECISIONES QUE UNIPARC OBLIGA A TOMAR, y por que se toman asi. Una accesion
responde una fila por version de secuencia que haya tenido: 670 filas para 600
accesiones. Se toma la de `last_seen` mas reciente, que es la que tenia al
desaparecer, porque todas las demas proteinas del almacen llevan la secuencia que
UniProt sirve HOY y asi el almacen entero queda bajo una sola convencion en vez de
hacer de estas 28.868 las unicas con una segunda regla. Las fechas quedan guardadas
para que una pasada posterior pueda revisarlo sin volver a preguntar. Y una fila
responde por todas las accesiones que comparten esa secuencia exacta, asi que solo se
escriben las del lote: las demas pueden estar perfectamente vivas.

REVIEWED SE QUEDA EN NULL. UniParc guarda secuencias, no estado de entrada, y la
accesion es una que UniProtKB ya no sirve, asi que no hay estado que leer. Escribir
False seria indistinguible de una entrada que UniProt llamo no revisada, y NULL ya
significa lo que es cierto: nadie pregunto, o nadie pudo contestar. De ahi el
`asserts_reviewed` del store, opt-in, con los dos llamantes que SI leen el estado de
una cabecera FASTA intactos.

Y de paso, dates_pending deja de mentir en seco. El informe declara en su propio
docstring que un seco devuelve None y no 0 "porque cero recuperable y no intentado no
son lo mismo", y ese campo rompia la regla: devolvia 0 con 644.659 filas esperando,
porque el pase que las cuenta es justo el que un seco salta. Un seco es donde alguien
decide si la corrida real merece la pena, asi que el unico campo que decia "nada que
hacer" era el que no podia saberlo.
@github-actions
github-actions Bot enabled auto-merge (squash) October 10, 2026 23:15
`poetry install` fallaba con "pyproject.toml changed significantly since
poetry.lock was last generated", y con el se caian ocho comprobaciones que no
tenian nada que ver: test, lint, docs, mutation y pip-audit instalan dependencias
antes de hacer su trabajo.

Regenerado y comprobado linea a linea: cambian la referencia de protea-sources, su
resolved_reference y el content-hash. Nada mas. El torch +cpu sigue donde estaba,
que es lo unico que daba miedo de tocar este fichero.
@github-actions
github-actions Bot merged commit 1f4cd2a into develop Oct 10, 2026
17 checks passed
@codecov

codecov Bot commented Oct 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.91667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 88.02%. Comparing base (d8bc801) to head (6247a52).
⚠️ Report is 100 commits behind head on develop.

Files with missing lines Patch % Lines
...rotea/core/operations/resolve_protein_sequences.py 97.56% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1000      +/-   ##
===========================================
+ Coverage    87.85%   88.02%   +0.17%     
===========================================
  Files          306      330      +24     
  Lines        23414    25494    +2080     
===========================================
+ Hits         20570    22442    +1872     
- Misses        2844     3052     +208     
Files with missing lines Coverage Δ
protea/core/operations/_protein_store.py 100.00% <100.00%> (ø)
protea/core/operations/_universe_sources.py 94.73% <100.00%> (ø)
...rotea/core/operations/resolve_protein_sequences.py 73.51% <97.56%> (ø)

... and 37 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.

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