fix(db): 90 días, porque 30 no era una política sino una suposición
Build & Deploy ResearchOwl / build-and-push (push) Successful in 9s

30 días no medía cuánto hay que guardar: medía cuánto se creía que duraba el
material. Los 17 specs `short_en` del catálogo se escribieron entre el 2 y el
13 de agosto y seguían siendo el material de trabajo el 1 de septiembre —tres
semanas después de que su ventana empezara a correr—, y el 31 de agosto se
re-renderizaron tres de ellos. Con 90 días, lo que se purga es lo que de
verdad nadie va a volver a mirar.

El plazo se escribe UNA vez. Estaba en el arranque, en `/purge` y en la firma
por defecto: tres copias de un plazo son tres plazos esperando a divergir, y
ese es el mismo error de clase que tenía el tope de palabras por línea antes de
derivarse de la duración del plano.

El test nuevo fija la ventana por COMPORTAMIENTO y no por el número: un output
de 45 días sobrevive y uno de 200 no. Estrecharla por debajo de mes y medio lo
tumba, que es donde empieza a llevarse cosas que aún se usan.

Y el fixture de purga pasa a llamar al valor por defecto cuando no se le dice
otro, porque pasarle el plazo a mano en cada test dejaba el de producción sin
que ninguna prueba lo mirara.

Suite: 279 pasan.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
ChemaVX
2026-09-01 17:30:01 +00:00
co-authored by Claude Opus 5
parent a14e5b99f9
commit 7c18ae68f1
3 changed files with 46 additions and 6 deletions
+28 -2
View File
@@ -339,7 +339,7 @@ async def test_purging_a_session_takes_its_video_with_it(tmp_path, monkeypatch):
assert (shorts / "2.mp4").exists(), "la sesión reciente conserva su vídeo"
async def purge_fixture(tmp_path, monkeypatch, sessions, outputs, days=30):
async def purge_fixture(tmp_path, monkeypatch, sessions, outputs, days=None):
"""Una BD con sesiones y outputs de las edades que se le pidan, purgada.
`sessions` y `outputs` llevan la edad en días: positiva es pasado. Devuelve
@@ -380,7 +380,11 @@ async def purge_fixture(tmp_path, monkeypatch, sessions, outputs, days=30):
await conn.commit()
try:
counts = await ResearchDB(conn).purge_old_data(days)
db = ResearchDB(conn)
# `days=None` deja hablar al valor por defecto, que es lo que corre en
# producción — pasarlo a mano en cada test convierte la ventana real en
# algo que ninguna prueba mira.
counts = await (db.purge_old_data(days) if days else db.purge_old_data())
vivos = [r[0] for r in await (await conn.execute(
"SELECT id FROM outputs ORDER BY id")).fetchall()]
sesiones = [r[0] for r in await (await conn.execute(
@@ -457,6 +461,28 @@ async def test_a_session_that_loses_its_last_short_loses_its_video(tmp_path,
assert not (shorts / "1.mp4").exists()
@pytest.mark.asyncio
async def test_the_default_window_keeps_material_still_in_use(tmp_path, monkeypatch):
"""La ventana por defecto, fijada por comportamiento y no por el número.
30 días no era una política de retención, era una suposición sobre cuánto
dura el material: los 17 specs del catálogo se escribieron entre el 2 y el
13 de agosto y seguían siendo el material de trabajo el 1 de septiembre.
Este test falla si alguien vuelve a estrechar la ventana por debajo de mes
y medio, que es donde empieza a llevarse cosas que aún se usan.
"""
from src.db.database import RETENTION_DAYS
counts, vivos, _, _ = await purge_fixture(
tmp_path, monkeypatch,
sessions=[(1, 120)],
outputs=[(1, 1, 45), (2, 1, 200)]) # uno de mes y medio, uno de siete meses
assert RETENTION_DAYS >= 45
assert vivos == [1], "un output de 45 días sigue siendo material de trabajo"
assert counts["outputs"] == 1, "y uno de 200 días no"
@pytest.mark.asyncio
async def test_the_youtube_url_never_passes_for_an_article_url(tmp_path):
"""Subir un Short escribe su URL de YouTube en `published_url`. Si