"""Domain job handlers: safety scoring and content analysis (US02-06). Importing this module registers the ``safety_score`` and ``analysis`` job types so the generic worker can run them per item (one item = one ``asset_id``). Each handler delegates to its service, which owns the real work and the privacy gate. Handlers are idempotent: re-scoring or re-analyzing one asset is safe after an interrupted attempt. Providers/models are the service defaults here (real NsfwModel / vision provider); tests exercise the services directly with injected fakes rather than the worker. """ from __future__ import annotations from photo_pipeline.jobs.handlers import JobContext, register SAFETY_SCORE = "safety_score" ANALYSIS = "analysis" # Both mutate the library's metadata/derived state; one at a time (concept §one job). LIBRARY_WRITE_LOCK = "library_write" def _safety_score_item(asset_id: str, ctx: JobContext) -> None: from photo_pipeline.services.safety import SafetyService SafetyService(ctx.session_factory).score_assets([asset_id]) def _analysis_item(asset_id: str, ctx: JobContext) -> None: from photo_pipeline.services.analysis import AnalysisService AnalysisService(ctx.session_factory).run([asset_id]) register(SAFETY_SCORE, _safety_score_item) register(ANALYSIS, _analysis_item)