"""Tests for immutable classification and repair policy enforcement.""" from __future__ import annotations import pytest from swe_data_processing.policy import ( PolicyViolation, enforce_classification_policy, enforce_repair_policy, ) def _classification() -> dict: dimensions = { "trajectory_integrity": "PASS", "tool_integrity": "PASS", "patch_presence": "PASS", "patch_trajectory_consistency": "PASS", "instruction_compliance": "PASS", "verification_consistency": "PASS", "final_claim_alignment": "PASS", "patch_hygiene": "PASS", "issue_patch_alignment": "PASS", } return { "source_outcome_class": "POSITIVE_CANDIDATE", "qc_decision": "ACCEPT_SILVER_POSITIVE", "training_use": "SFT_FULL", "qc_passed": True, "hard_fail_codes": [], "verification": {"status": "PASS_RELIABLE"}, "dimensions": dimensions, } def test_valid_silver_positive_passes() -> None: enforce_classification_policy({"resolved": 1}, _classification()) def test_resolved_zero_cannot_be_promoted() -> None: result = _classification() result["source_outcome_class"] = "EXPLICIT_NEGATIVE" with pytest.raises(PolicyViolation, match="resolved=0"): enforce_classification_policy({"resolved": 0}, result) def test_unknown_cannot_be_full_sft() -> None: result = _classification() result["source_outcome_class"] = "UNVERIFIED" result["qc_decision"] = "HOLD_UNVERIFIED" result["qc_passed"] = False with pytest.raises(PolicyViolation, match="resolved=-1"): enforce_classification_policy({"resolved": -1}, result) def _repair_result() -> dict: """Return a minimal non-mutating repair result for policy tests.""" return { "repair_decision": "NO_CHANGE", "maximum_training_use": "HOLD", "invariants": { "resolved_unchanged": True, "tool_outputs_unchanged": True, "model_patch_unchanged": True, "reference_patch_unchanged": True, "no_synthetic_execution_result": True, }, "operations": [], "requires_second_review": True, } def test_nonmutating_repair_decision_rejects_operations() -> None: """A hold decision cannot smuggle in an operation the applier will ignore.""" result = _repair_result() result["repair_decision"] = "REQUIRES_EXECUTION" result["operations"] = [ { "op": "REWRITE_FINAL_SUMMARY", "target_turns": [3], "preconditions": ["Turn 3 is an assistant summary"], "replacement": "Honest summary", "reason": "Align the claim with evidence", } ] with pytest.raises(PolicyViolation, match="must not contain"): enforce_repair_policy(result) def test_step_example_requires_operations() -> None: """Step-only salvage must include a concrete correction and truncation.""" result = _repair_result() result["repair_decision"] = "CREATE_STEP_EXAMPLE" result["maximum_training_use"] = "SFT_STEP_ONLY" with pytest.raises(PolicyViolation, match="requires at least one"): enforce_repair_policy(result)