"""Tests for the UNIFIED audit-of-audit sampling rule (gap 2). This file pins the alignment of track 3 (#244) and track 5 (#238) only; it does not re-test either track's other semantics. Unified rule under test (see ``cloud/audit_sampling.py``): - Mandatory (1.0) = golden-task records + rebuild / refreeze / escalation records + third-failure near-complete still-failed cases. Scope from #244, expanded with #238's third-failure trigger; #244's deterministic every-10th ordinary rule is gone. - The rest by seeded random draw: normal 0.10, critical-path 0.50, ceil so a non-empty group is never rounded to zero. The 0.10 / 0.50 values are TEST DEFAULTS, not approved production rates. - One pass, no double counting: mandatory records leave the random pools before drawing; a multi-trigger record is sampled once with all its triggers listed; correction follows the (original, corrected) verdict pair, not the trigger list. - Correction preserves the original: the original record is never mutated, the correction is a separate appended record, and the corrector must differ from the original signer. """ import copy import os import sys import unittest sys.path.insert(0, os.path.dirname(os.path.dirname( os.path.dirname(os.path.abspath(__file__))))) from cloud.audit_pushback import ( # noqa: E402 build_audit_correction, select_audit_sample) from cloud.audit_sampling import ( # noqa: E402 append_audit_record, build_golden_task_ids, handle_sampling_result, mandatory_trigger, mandatory_triggers, select_sample) def _case(case_id, **kw): case = {"id": case_id} case.update(kw) return case class TestMandatoryUnion(unittest.TestCase): def test_all_mandatory_triggers_sampled(self): cases = [ _case("g-push", task_id="gold-1", kind="pushback"), _case("r", decision="rebuild"), _case("rf", kind="refreeze"), _case("esc", kind="escalate"), _case("third", decision="fail_pushback", failure_count=3, root_cause="near_complete", continuation_failed=True), _case("n0", decision="pass"), ] plan = select_sample(cases, seed="s", golden_task_ids={"gold-1"}) by_id = {e["case_id"]: e["triggers"] for e in plan["mandatory"]} self.assertEqual(by_id["g-push"], ["golden_task"]) self.assertEqual(by_id["r"], ["rebuild"]) self.assertEqual(by_id["rf"], ["refreeze"]) self.assertEqual(by_id["esc"], ["escalate"]) self.assertEqual(by_id["third"], ["third_failure_near_complete_still_failed"]) self.assertIn("n0", plan["random_normal"]) self.assertEqual(len(plan["sampled_ids"]), len(set(plan["sampled_ids"]))) def test_blocked_quota_is_not_mandatory(self): # Track 3's mandatory kind list is rebuild/refreeze/escalate # only; a quota-blocked record reaches the random tiers. case = _case("q", kind="blocked_quota") self.assertEqual(mandatory_triggers(case), []) plan = select_sample([case], seed="s") self.assertEqual(plan["mandatory"], []) self.assertEqual(plan["random_normal"], ["q"]) def test_golden_task_ordinary_record_is_mandatory(self): # Golden membership is per task, not per record kind: even # a plain pass record of a golden task is mandatory. case = _case("g-pass", task_id="gold-1", kind="pushback", decision="pass") plan = select_sample([case], seed="s", golden_task_ids={"gold-1"}) self.assertEqual(plan["mandatory"][0]["triggers"], ["golden_task"]) class TestNoDoubleCounting(unittest.TestCase): def test_golden_rebuild_sampled_once_with_all_triggers(self): cases = [_case("g-re", task_id="gold-1", kind="rebuild")] cases += [_case("n%d" % i, decision="pass") for i in range(20)] plan = select_sample(cases, seed="s", golden_task_ids={"gold-1"}) self.assertEqual(plan["sampled_ids"].count("g-re"), 1) self.assertEqual(plan["mandatory"][0]["triggers"], ["golden_task", "rebuild"]) # The mandatory record consumed no random quota: the draw # is still ceil(0.10 * 20) == 2 over the ordinary pool. self.assertEqual(len(plan["random_normal"]), 2) self.assertNotIn("g-re", plan["random_normal"]) # Legacy single-trigger view reports the first trigger. self.assertEqual( mandatory_trigger(cases[0], {"gold-1"}), "golden_task") def test_triage_and_later_rebuild_are_two_records_not_double(self): # Deduplication is per record: a triage record and the # later rebuild record for the same task are two samples. cases = [ _case("triage", decision="fail_pushback", failure_count=3, root_cause="near_complete", continuation_failed=True), _case("rebuild", decision="rebuild"), ] plan = select_sample(cases, seed="s") self.assertEqual(sorted(plan["sampled_ids"]), ["rebuild", "triage"]) class TestRandomTiersAndCeil(unittest.TestCase): def test_ratios_and_seed_reproducibility(self): cases = [_case("n%d" % i, decision="pass") for i in range(20)] cases += [_case("c%d" % i, decision="pass", critical_path=True) for i in range(10)] plan = select_sample(cases, seed="seed-1") self.assertEqual(len(plan["random_normal"]), 2) self.assertEqual(len(plan["random_critical_path"]), 5) again = select_sample(cases, seed="seed-1") self.assertEqual(plan["sampled_ids"], again["sampled_ids"]) def test_small_groups_never_round_to_zero(self): self.assertEqual(len(select_sample( [_case("only", decision="pass")], seed="s")["random_normal"]), 1) # 9 ordinary records: the old every-10th rule drew ZERO # here; ceil(0.10 * 9) == 1 under the unified rule. self.assertEqual(len(select_sample( [_case("n%d" % i, decision="pass") for i in range(9)], seed="s")["random_normal"]), 1) self.assertEqual(len(select_sample( [_case("n%d" % i, decision="pass") for i in range(19)], seed="s")["random_normal"]), 2) self.assertEqual(len(select_sample( [_case("c0", decision="pass", critical_path=True)], seed="s")["random_critical_path"]), 1) self.assertEqual(len(select_sample( [_case("c%d" % i, decision="pass", critical_path=True) for i in range(3)], seed="s")["random_critical_path"]), 2) def test_missing_seed_rejected(self): with self.assertRaises(ValueError): select_sample([_case("n", decision="pass")], seed="") class TestGoldenSetConstruction(unittest.TestCase): def test_build_golden_ids_applies_both_vocabularies(self): tasks = [ {"id": "gold-1", "human_approved_by": "user"}, {"id": "sample-2", "human_approved_by": "user"}, {"id": "gold-2", "sample": True, "human_approved_by": "user"}, {"id": "gold-3", "is_example": True, "human_approved_by": "user"}, {"id": "gold-4"}, ] self.assertEqual(build_golden_task_ids(tasks), ["gold-1"]) class TestAdapter(unittest.TestCase): def test_adapter_returns_unified_selection_in_record_order(self): records = [ {"task_id": "gold-1", "kind": "pushback"}, {"task_id": "gold-1", "kind": "fix"}, {"task_id": "gold-1", "kind": "rebuild"}, {"task_id": "t-rf", "kind": "refreeze"}, {"task_id": "t-esc", "kind": "escalate"}, ] records += [{"task_id": "t-%d" % i, "kind": "pushback"} for i in range(9)] before = copy.deepcopy(records) golden = set(build_golden_task_ids( [{"id": "gold-1", "human_approved_by": "user"}])) selected = select_audit_sample(records, golden, seed="s") by_record = {id(e["record"]): e for e in selected} # Every golden record is mandatory, whatever its kind; the # golden rebuild record carries both triggers, once. self.assertEqual(by_record[id(records[0])]["reasons"], ["golden_task"]) self.assertEqual(by_record[id(records[1])]["reasons"], ["golden_task"]) self.assertEqual(by_record[id(records[2])]["reasons"], ["golden_task", "rebuild"]) self.assertEqual(by_record[id(records[3])]["reason"], "refreeze") self.assertEqual(by_record[id(records[4])]["reason"], "escalate") # 9 ordinary records contribute ceil(0.10 * 9) == 1. ordinary = [e for e in selected if e["record"]["task_id"].startswith("t-") and e["record"]["task_id"] not in ("t-rf", "t-esc")] self.assertEqual(len(ordinary), 1) self.assertEqual(ordinary[0]["reason"], "random_normal") # Selected entries keep original record order. order = [records.index(e["record"]) for e in selected] self.assertEqual(order, sorted(order)) # Input records are never mutated by selection. self.assertEqual(records, before) with self.assertRaises(ValueError): select_audit_sample(records, golden) class TestCorrectionPreservesOriginal(unittest.TestCase): def test_track3_correction_appends_without_mutating(self): original = {"task_id": "t-1", "round": 0, "verdict": "pass", "signer": "auditor-a", "entry_hash": "h" * 64} before = dict(original) correction, errors = build_audit_correction( original, "fail", "auditor-b", "sample re-run found ci red") self.assertEqual(errors, []) self.assertEqual(original, before) self.assertEqual(correction["original_entry_hash"], "h" * 64) self.assertEqual(correction["restored_action"], "retrigger_pushback_and_reblock") log = [original, correction] self.assertEqual(log[0]["verdict"], "pass") _bad, bad_errors = build_audit_correction( original, "fail", "auditor-a", "same signer") self.assertTrue(bad_errors) def test_track5_correction_appends_without_mutating(self): case = {"id": "a", "decision": "pass"} before = dict(case) entry = handle_sampling_result( case, "incorrect", corrected_verdict="fail_pushback", corrector="auditor-b", original_signer="auditor-a") # Track 5 vocabulary for the same wrong-pass pair as track # 3's retrigger_pushback_and_reblock (synonyms, see the # unified rule in cloud/audit_sampling.py). self.assertEqual(entry["retrigger"], "reopen_audit_and_pushback") self.assertEqual(case, before) log = [] log2 = append_audit_record(log, entry) self.assertEqual(log, []) self.assertEqual(len(log2), 1) with self.assertRaises(ValueError): handle_sampling_result( case, "incorrect", corrected_verdict="fail_pushback", corrector="auditor-a", original_signer="auditor-a") def test_correct_verdict_only_records(self): entry = handle_sampling_result( _case("a", decision="pass"), "correct") self.assertIsNone(entry["corrected_decision"]) self.assertIsNone(entry["retrigger"]) if __name__ == "__main__": unittest.main()