from __future__ import annotations import json from datetime import UTC, datetime from sqlalchemy import select from app.core.database import session_scope from app.modules.sync.models import FarmHub, SyncRecordState from app.modules.zootech.catalog_apply import load_catalog_row def run_sync_reconcile() -> int: """Compare orchestrator catalog content_hash vs sync_record_state agreed_hash.""" mismatches = 0 with session_scope() as db: hubs = list(db.scalars(select(FarmHub).where(FarmHub.status == "active"))) states = list(db.scalars(select(SyncRecordState))) for state in states: row = load_catalog_row(state.enterprise_id, state.table_name, state.record_id) if not row: continue catalog_hash = str(row.get("content_hash") or "") if state.agreed_hash and catalog_hash and state.agreed_hash != catalog_hash: mismatches += 1 state.agreed_hash = catalog_hash state.agreed_version = int(row.get("version") or state.agreed_version) state.updated_at = datetime.now(UTC) for hub in hubs: from app.modules.sync.models import SyncReconcileRun db.add( SyncReconcileRun( enterprise_id=hub.enterprise_id, status="completed", mismatches_count=mismatches, auto_repaired=mismatches, finished_at=datetime.now(UTC), ) ) return mismatches