"""Scheduled presentation tasks (#141): the daily auto-hide sweep wrapper + resolved-flag retention. The task opens its own session via _sync_session_factory, monkeypatched here to run against the test's db_sync.""" from datetime import UTC, datetime, timedelta import pytest from sqlalchemy import select from backend.app.models import ( ImageRecord, MLSettings, PresentationReview, Tag, TagHead, ) from backend.app.tasks.ml import ( prune_presentation_reviews, scheduled_presentation_auto_apply, ) pytestmark = pytest.mark.integration class _Ctx: def __init__(self, s): self.s = s def __enter__(self): return self.s def __exit__(self, *a): return False def _sf(db_sync): class _SM: def __call__(self): return _Ctx(db_sync) return _SM() def _img(db, sha, emb=None): img = ImageRecord( path=f"/images/{sha}.jpg", sha256=sha * 32, size_bytes=1, mime="image/jpeg", width=1, height=1, origin="imported_filesystem", integrity_status="unknown", siglip_embedding=emb, ) db.add(img) db.flush() return img def test_scheduled_presentation_sweep_hides_chrome(db_sync, monkeypatch): monkeypatch.setattr( "backend.app.tasks.ml._sync_session_factory", lambda: _sf(db_sync) ) banner = db_sync.execute( select(Tag).where(Tag.is_system.is_(True), Tag.name == "banner") ).scalar_one() s = db_sync.execute(select(MLSettings).where(MLSettings.id == 1)).scalar_one() w = [0.0] * 1152 w[0] = 3.0 db_sync.add(TagHead( tag_id=banner.id, embedding_version=s.embedder_model_version, weights=w, bias=0.0, suggest_threshold=0.5, auto_apply_threshold=0.5, n_pos=60, n_neg=90, ap=0.9, precision_cv=0.98, recall=0.7, )) emb = [0.0] * 1152 emb[0] = 3.0 _img(db_sync, "sc", emb) db_sync.commit() assert "applied=1" in scheduled_presentation_auto_apply() def test_prune_presentation_reviews_drops_old_resolved(db_sync, monkeypatch): monkeypatch.setattr( "backend.app.tasks.ml._sync_session_factory", lambda: _sf(db_sync) ) banner = db_sync.execute( select(Tag).where(Tag.is_system.is_(True), Tag.name == "banner") ).scalar_one() a, b, c = _img(db_sync, "p1"), _img(db_sync, "p2"), _img(db_sync, "p3") old = datetime.now(UTC) - timedelta(days=40) recent = datetime.now(UTC) - timedelta(days=1) # old resolved → pruned; recent resolved → kept; unresolved → kept. db_sync.add(PresentationReview( image_record_id=a.id, tag_id=banner.id, conflict_score=0.7, resolved_at=old)) db_sync.add(PresentationReview( image_record_id=b.id, tag_id=banner.id, conflict_score=0.7, resolved_at=recent)) db_sync.add(PresentationReview( image_record_id=c.id, tag_id=banner.id, conflict_score=0.7)) db_sync.commit() assert prune_presentation_reviews() == "pruned=1" remaining = db_sync.execute( select(PresentationReview.image_record_id) ).scalars().all() assert set(remaining) == {b.id, c.id}