"""ORCH-110 TC-03: classify_retest_failure distinguishes infra-timeout from red. Covers D2 (FR-1 / AC-2): the pure predicate that lets the engine route an INFRA re-test timeout differently from a deterministically RED re-test, WITHOUT changing the name / PASS-FAIL semantics of the registered ``check_branch_mergeable``. The critical scope guard: an ``auto_rebase_onto_main`` "rebase timeout" is a DIFFERENT timeout (git hung) and must NOT be classified as the infra-tolerated re-test timeout (it stays on the rollback path). """ import os import tempfile os.environ.setdefault("ORCH_DB_PATH", os.path.join(tempfile.gettempdir(), "test_orch110_classify.db")) os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token") os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token") import pytest # noqa: E402 from src import merge_gate # noqa: E402 classify = merge_gate.classify_retest_failure @pytest.mark.parametrize( "reason,expected", [ ("re-test timeout after 900s", "timeout"), ("re-test timeout after 600s", "timeout"), ("re-test failed after rebase: 1 failed, 5 passed", "red"), ("re-test failed: ...AssertionError\n1 failed", "red"), ("merge-lock busy", "lock-busy"), ("rebase conflict: src/db.py", "other"), # SCOPE GUARD: a git "rebase timeout" is NOT the infra-tolerated re-test # timeout — it must stay on the rollback path (ADR D2). ("rebase timeout", "other"), ("push --force-with-lease failed: ...", "other"), ("", "other"), ], ) def test_tc03_classify_reasons(reason, expected): assert classify(reason) == expected def test_tc03_classify_never_raises_on_bad_input(): # None / non-str must degrade to the safe "other" (-> rollback), never raise. assert classify(None) == "other" assert classify(12345) == "other" def test_tc03_case_insensitive(): assert classify("RE-TEST TIMEOUT AFTER 900S") == "timeout" assert classify("Merge-Lock Busy") == "lock-busy" def test_tc03_distinct_from_lock_busy_and_conflict(): """timeout is a distinct class from the existing defer (lock-busy) and rollback (conflict) reasons — the three must never collide.""" classes = { classify("re-test timeout after 900s"), classify("merge-lock busy"), classify("rebase conflict: x"), } assert classes == {"timeout", "lock-busy", "other"}