from datetime import datetime, timezone from inspect import getsource from collections import Counter import pytest from scripts.apply_blif_flow_v2_data_repair import ( EXPECTED_REPAIR_COUNT, FROZEN_REPAIRS, RESOLUTION_CODES, apply_transaction, assert_test_database, phase1_high_rows, validate_frozen_repair_set, validate_target_states, ) def planned_rows(): return [ {"task_id": task_id, "action_code": action, "classification": classification, "opportunity_id": opportunity_id, "safety_tier": "HIGH", "auto_repair_safe": True} for task_id, (action, classification, opportunity_id) in FROZEN_REPAIRS.items() ] def target_rows(*, applied=False): now = datetime.now(timezone.utc) return [ {"id": task_id, "action_code": action, "opportunity_id": opportunity_id, "status": "done" if applied else "pending", "resolution_code": RESOLUTION_CODES[classification] if applied else None, "resolved_at": now if applied else None, "resolved_by_event_id": None, "superseded_by_task_id": None} for task_id, (action, classification, opportunity_id) in FROZEN_REPAIRS.items() ] def test_default_cli_is_dry_run(): source = getsource(__import__("scripts.apply_blif_flow_v2_data_repair", fromlist=["main"]).main) assert 'add_argument("--apply", action="store_true"' in source assert "run(apply=args.apply)" in source @pytest.mark.parametrize("identity", [ ("clientflow", "clientflow_codex_test", "off"), ("other_test", "clientflow_codex_test", "off"), ("clientflow_codex_test", "wrong_user", "off"), ]) def test_wrong_database_or_user_hard_fails(identity): with pytest.raises(RuntimeError, match="refusing repair"): assert_test_database(identity) def test_exact_repair_set_is_required(): rows = planned_rows() validate_frozen_repair_set(rows) assert len(rows) == EXPECTED_REPAIR_COUNT with pytest.raises(RuntimeError, match="expected 12"): validate_frozen_repair_set(rows[:-1]) def test_changed_frozen_identity_aborts(): rows = planned_rows() rows[0] = {**rows[0], "classification": "SUPERSEDED"} with pytest.raises(RuntimeError, match="cohort drift"): validate_frozen_repair_set(rows) def test_ambiguous_and_valid_current_are_never_selected(): result = {"tasks": {"tasks": planned_rows() + [ {"task_id": "ambiguous", "classification": "AMBIGUOUS", "safety_tier": "LOW", "auto_repair_safe": False}, {"task_id": "valid", "classification": "VALID_CURRENT", "safety_tier": "HIGH", "auto_repair_safe": False}, ]}} selected = phase1_high_rows(result) assert {row["classification"] for row in selected}.isdisjoint({"AMBIGUOUS", "VALID_CURRENT"}) def test_resolution_codes_and_deterministic_event_fields_are_written(): source = getsource(apply_transaction) assert "resolved_by_event_id=CAST(:resolved_by_event_id AS UUID)" in source assert RESOLUTION_CODES == { "SATISFIED_BY_EVENT": "satisfied_by_event", "SUPERSEDED": "superseded", "DUPLICATE": "duplicate_obligation", "PREMATURE": "premature_downstream", } def test_duplicate_repair_never_deletes_evidence_or_tasks(): source = getsource(apply_transaction).upper() assert "DELETE" not in source assert "UPDATE TASKS" in source assert "COMMERCIAL_DOCUMENTS" not in source assert "OPERATION_LINKS" not in source def test_apply_is_one_atomic_transaction_with_rollback(): source = getsource(apply_transaction) assert "transaction = conn.begin()" in source assert "transaction.commit()" in source assert "transaction.rollback()" in source def test_second_apply_is_idempotent(): assert validate_target_states(target_rows(applied=False)) == "pending" assert validate_target_states(target_rows(applied=True)) == "already_applied" def test_partial_apply_state_aborts(): rows = target_rows(applied=True) rows[0].update(status="pending", resolution_code=None, resolved_at=None) with pytest.raises(RuntimeError, match="partial repair state"): validate_target_states(rows) def test_premature_resolution_does_not_mutate_projection_or_opportunity(): source = getsource(apply_transaction).upper() assert "UPDATE OPPORTUNITIES" not in source assert "UPDATE OPPORTUNITY_FLOW_STATE_V2" not in source def test_frozen_set_contains_named_duplicate_and_instalbeira_repairs(): assert FROZEN_REPAIRS["a15b2545-591f-4d73-b8a2-3268efd01f98"][1] == "DUPLICATE" assert FROZEN_REPAIRS["b8965dd9-f0fc-42cf-a824-f8804add9e18"][1] == "DUPLICATE" instal = [row for row in planned_rows() if row["opportunity_id"] == "5c33db95-fab8-477a-bddd-0b9cc8f91302"] assert Counter(row["classification"] for row in instal) == Counter({"PREMATURE": 2, "SATISFIED_BY_EVENT": 1}) def test_zero_unsafe_false_negative_categories_in_frozen_set(): assert {classification for _, classification, _ in FROZEN_REPAIRS.values()} == { "SATISFIED_BY_EVENT", "SUPERSEDED", "DUPLICATE", "PREMATURE"}