ligbox-ops-platform/app/migration/gate.py
Ligbox Spec Hub 3a2c64834b Initial import: ligbox-ops-platform + specs + LAPTOP + obsidian merge (CT130)
Source: VM122 /opt + obsidian-infra + LAPTOP
Hub: CT130 spec-hub 10.10.10.130
2026-06-19 17:26:41 +00:00

69 lines
2.5 KiB
Python

"""DNS gate logic — Spec 019."""
from __future__ import annotations
import os
from typing import Any
from app.migration import store
GATE_MIN_RATIO = float(os.getenv("MIGRATION_GATE_MIN_RATIO", "0.99"))
def evaluate_job(conn, job_id: int) -> dict[str, Any]:
job = store.get_job(conn, job_id)
if not job:
return {"gate": "blocked", "reason": "job_not_found"}
mailboxes = job.get("mailboxes") or []
checks: list[tuple[str, str, str]] = []
if not mailboxes:
checks.append(("mailboxes_present", "fail", "Nenhuma mailbox no job"))
gate = "blocked"
else:
ratios = []
for mb in mailboxes:
src = max(mb.get("messages_source") or 0, 1)
dst = mb.get("messages_dest") or 0
ratio = dst / src if src else 0.0
ratios.append(ratio)
if ratio < GATE_MIN_RATIO:
checks.append(
(
f"sync_{mb['email']}",
"warn" if ratio >= 0.9 else "fail",
f"{mb['email']}: {ratio * 100:.1f}% sincronizado",
)
)
avg = sum(ratios) / len(ratios) if ratios else 0.0
checks.append(("count_ratio", "pass" if avg >= GATE_MIN_RATIO else "warn", f"Média {avg * 100:.1f}%"))
if job.get("approved_by"):
checks.append(("manual_approval", "pass", f"Aprovado por {job['approved_by']}"))
gate = "ready_for_dns" if avg >= GATE_MIN_RATIO else "warning"
elif avg >= GATE_MIN_RATIO:
checks.append(("manual_approval", "fail", "Aguarda aprovação ops_lead"))
gate = "warning"
elif avg >= 0.9:
gate = "warning"
else:
gate = "blocked"
for check_id, status, message in checks:
store.add_gate_check(conn, job_id, check_id, status, message)
store.update_job(conn, job_id, migration_gate=gate, phase=job.get("phase") or "cutover_ready")
return {"gate": gate, "checks": [{"check_id": c[0], "status": c[1], "message": c[2]} for c in checks]}
def approve_gate(conn, job_id: int, approved_by: str) -> dict[str, Any]:
from datetime import datetime, timezone
now = datetime.now(timezone.utc).isoformat()
store.update_job(conn, job_id, approved_by=approved_by, approved_at=now, phase="cutover_ready")
result = evaluate_job(conn, job_id)
if result["gate"] in ("warning", "ready_for_dns"):
store.update_job(conn, job_id, migration_gate="ready_for_dns")
result["gate"] = "ready_for_dns"
return result