Files
codex-app-server/cloud/tests/test_audit_loop_driver.py
host 488aedbcad code-to10 v6 A14 batch2: test E402/F401 cleanup plus touched-file residual E,F cleanup
(cherry picked from commit 1db02545f74c96b3b92be4fc32954659cec1f814)

Reconcile-conflict: A14b E402 imports referencing cloud.handler_core (does not exist here; core methods live in server.py) — kept HEAD imports with incoming's noqa: E402 markers, dropped the unused core_mod import (verified unused elsewhere in both files).
2026-11-03 02:49:26 +00:00

573 lines
26 KiB
Python

"""Audit loop driver: pure decision logic for the project-level
audit rework loop (track 1 of the production built-in loop).
Pins the driver interface the next (wiring) track must use
verbatim, and the counting rules shared by #244 / #241 / #247:
pushbacks cover failures 1-3, the 4th failure (> 3, never >= 3)
rebuilds, rebuilds are 1 per module per contract version, the
3rd failure is triaged, a pass clears failures but not budgets,
a contract-version change clears everything, quota blocks consume
nothing, a correction to pass does not unblock, and ledger events
match the #241 field table.
Style follows the other cloud tests: unittest, stdlib only, import
with a sys.path fallback so the file also runs standalone.
"""
import sys
import unittest
from pathlib import Path
try:
from cloud.audit_loop_driver import (
ACTION_KINDS,
LEDGER_EVENT_TYPES,
apply_correction,
confirm_rebuild,
decide_audit,
emit,
new_loop_state,
validate_ledger_event,
after_fix,
)
except ImportError:
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from cloud.audit_loop_driver import (
ACTION_KINDS,
LEDGER_EVENT_TYPES,
apply_correction,
confirm_rebuild,
decide_audit,
emit,
new_loop_state,
validate_ledger_event,
after_fix,
)
def fail_verdict(**overrides):
verdict = {
"source": "audit",
"verdict": "fail",
"verdict_text": "audit fail: ci red",
"failures": [{"check": "ci_green", "detail": "ci red"}],
"passed_items": [],
"previous_artifacts": [{"path": "app.py", "sha256": "a" * 64}],
"reproduction_steps": ["run ci"],
}
verdict.update(overrides)
return verdict
def pass_verdict(**overrides):
verdict = {
"source": "audit",
"verdict": "pass",
"verdict_text": "audit pass",
"failures": [],
"passed_items": [],
}
verdict.update(overrides)
return verdict
def near_complete_verdict(**overrides):
verdict = fail_verdict(
failures=[{"check": "edge-case"}],
passed_items=[{"check": "p1"}, {"check": "p2"}, {"check": "p3"}],
broken_passed_items=[],
verdict_text="audit fail: one edge case left",
)
verdict.update(overrides)
return verdict
def drive(state, verdict, **kwargs):
return decide_audit(state, verdict, **kwargs)
class PushbackCountingTestCase(unittest.TestCase):
def test_fail_pushbacks_and_blocks(self):
state = new_loop_state("m1", "v1")
action = drive(state, fail_verdict())
self.assertEqual(action.kind, "pushback")
self.assertTrue(action.merge_blocked)
self.assertTrue(action.release_blocked)
self.assertEqual(action.next_state.failure_count, 1)
self.assertEqual(action.next_state.pushback_round, 1)
self.assertEqual(action.next_state.status, "pushback")
package = action.pushback_package
self.assertEqual(package["audit_verdict_text"], "audit fail: ci red")
self.assertEqual(package["failures"][0]["check"], "ci_green")
self.assertEqual(package["reproduction_steps"], ["run ci"])
# Full re-audit criteria, never just the failed items.
self.assertIn("ci_green", package["reaudit_criteria"])
self.assertIn("audit_signer_separation", package["reaudit_criteria"])
self.assertEqual(package["previous_artifacts"][0]["path"], "app.py")
self.assertEqual(
[e["event_type"] for e in action.ledger_events],
["audit_verdict", "audit_pushback_round"])
def test_exactly_three_still_pushes_back(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
action = drive(state, fail_verdict())
state = action.next_state
self.assertEqual(action.kind, "pushback")
self.assertEqual(action.next_state.failure_count, 3)
self.assertEqual(action.next_state.pushback_round, 3)
def test_fourth_failure_rebuilds(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
state = drive(state, fail_verdict()).next_state
action = drive(state, fail_verdict(retained_tests=["t1", "t2"]))
self.assertEqual(action.kind, "rebuild")
self.assertEqual(action.rebuild_no, 1)
self.assertEqual(action.next_state.rebuild_no, 1)
self.assertEqual(action.next_state.failure_count, 0)
self.assertEqual(action.next_state.pushback_round, 0)
self.assertEqual(action.next_state.status, "rebuilding")
self.assertEqual(action.next_state.retained_tests, ["t1", "t2"])
retained = action.pushback_package["retained_assets"]
self.assertEqual(retained["tests"], ["t1", "t2"])
self.assertTrue(retained["contract_unchanged"])
self.assertTrue(retained["design_unchanged"])
def test_rebuild_budget_exhausted_escalates(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
state = drive(state, fail_verdict()).next_state
state = drive(state, fail_verdict()).next_state # rebuild 1
self.assertEqual(state.rebuild_no, 1)
for _ in range(3):
state = drive(state, fail_verdict()).next_state
action = drive(state, fail_verdict())
self.assertEqual(action.kind, "escalate")
self.assertEqual(action.escalation_target, "coordinator")
self.assertEqual(action.next_state.rebuild_no, 1)
self.assertEqual(action.next_state.status, "escalated")
self.assertFalse(action.escalation_grants_user_acceptance)
self.assertFalse(hasattr(action, "tick_acceptance"))
# Full history, not just the last round.
texts = [entry.get("verdict_text")
for entry in action.escalation_history]
self.assertIn("audit fail: ci red", texts)
self.assertGreaterEqual(len(action.escalation_history), 4)
def test_audit_and_acceptance_counts_combine_but_stay_separate(self):
state = new_loop_state("m1", "v1")
state = drive(state, fail_verdict()).next_state
state = drive(state, fail_verdict(source="acceptance")).next_state
action = drive(state, fail_verdict())
self.assertEqual(action.next_state.failure_count, 3)
self.assertEqual(action.next_state.audit_fail_count, 2)
self.assertEqual(action.next_state.acceptance_fail_count, 1)
def test_pass_clears_failures_keeps_rebuild_budget(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
state = drive(state, fail_verdict()).next_state
state = drive(state, fail_verdict()).next_state # rebuild 1
state = drive(state, fail_verdict()).next_state # failure 1, new episode
action = drive(state, pass_verdict())
self.assertEqual(action.kind, "pass")
self.assertFalse(action.merge_blocked)
self.assertEqual(action.next_state.failure_count, 0)
self.assertEqual(action.next_state.pushback_round, 0)
self.assertEqual(action.next_state.rebuild_no, 1)
self.assertEqual(action.next_state.status, "passed")
def test_contract_version_change_clears_everything(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
state = drive(state, fail_verdict()).next_state
state = drive(state, fail_verdict()).next_state # rebuild 1
state = drive(state, fail_verdict()).next_state # failure 1, v1
action = drive(state, fail_verdict(contract_version="v2"))
self.assertEqual(action.kind, "pushback")
self.assertEqual(action.next_state.contract_version, "v2")
self.assertEqual(action.next_state.failure_count, 1)
self.assertEqual(action.next_state.pushback_round, 1)
self.assertEqual(action.next_state.rebuild_no, 0)
self.assertFalse(action.next_state.targeted_used)
class ThirdFailureTriageTestCase(unittest.TestCase):
def _two_failures(self):
state = new_loop_state("m1", "v1")
for _ in range(2):
state = drive(state, fail_verdict()).next_state
return state
def test_structural_third_failure_early_rebuilds(self):
state = self._two_failures()
action = drive(state, fail_verdict(
failures=[{"check": "arch",
"structural_kind": "architecture_boundary"}],
verdict_text="audit fail: architecture boundary crossed"))
self.assertEqual(action.kind, "rebuild")
self.assertEqual(action.rebuild_no, 1)
assessments = [e for e in action.ledger_events
if e["event_type"] == "audit_third_failure_assessment"]
self.assertEqual(len(assessments), 1)
self.assertEqual(assessments[0]["payload"]["determination"], "early_rebuild")
self.assertEqual(assessments[0]["payload"]["failure_total"], 3)
self.assertEqual(assessments[0]["payload"]["max_extra_rounds"], 0)
def test_contract_root_third_failure_goes_to_refreeze(self):
state = self._two_failures()
action = drive(state, fail_verdict(root_cause_hint="contract"))
self.assertEqual(action.kind, "refreeze")
self.assertEqual(action.next_state.status, "refreeze")
self.assertEqual(action.next_state.rebuild_no, 0)
self.assertEqual(action.compat_hint, "audit_wiring_event:escalate_refreeze")
# No rebuild event, and no assessment row forced into the
# wrong determination (see #247: early_refreeze has no
# assessment determination).
kinds = [e["event_type"] for e in action.ledger_events]
self.assertNotIn("audit_rebuild", kinds)
self.assertNotIn("audit_third_failure_assessment", kinds)
def test_near_complete_gets_one_targeted_round_then_rebuilds(self):
state = self._two_failures()
action = drive(state, near_complete_verdict())
self.assertEqual(action.kind, "pushback")
self.assertEqual(action.scope, "targeted")
self.assertEqual(action.targeted_items, ["edge-case"])
self.assertTrue(action.next_state.targeted_used)
self.assertEqual(action.next_state.pushback_round, 3)
assessments = [e for e in action.ledger_events
if e["event_type"] == "audit_third_failure_assessment"]
self.assertEqual(assessments[0]["payload"]["determination"],
"continuation_round")
self.assertEqual(assessments[0]["payload"]["max_extra_rounds"], 1)
# One more failure is the 4th: rebuild, not a 4th pushback.
action = drive(action.next_state, fail_verdict())
self.assertEqual(action.kind, "rebuild")
def test_targeted_budget_not_replenished_by_pass(self):
state = self._two_failures()
state = drive(state, near_complete_verdict()).next_state
self.assertTrue(state.targeted_used)
state = drive(state, pass_verdict()).next_state
self.assertTrue(state.targeted_used)
for _ in range(2):
state = drive(state, fail_verdict()).next_state
action = drive(state, near_complete_verdict())
self.assertEqual(action.kind, "pushback")
self.assertEqual(action.scope, "normal")
self.assertIsNone(action.targeted_items)
def test_unknown_broken_passed_disqualifies_near_complete(self):
state = self._two_failures()
# broken_passed_items absent (unknown, not []) -> normal.
action = drive(state, fail_verdict(
failures=[{"check": "edge-case"}],
passed_items=[{"check": "p1"}, {"check": "p2"}, {"check": "p3"}]))
self.assertEqual(action.scope, "normal")
class RebuildGateAndAcceptanceTestCase(unittest.TestCase):
def _rebuilding_state(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
state = drive(state, fail_verdict()).next_state
return drive(state, fail_verdict(retained_tests=["t1", "t2"])).next_state
def test_old_test_gate_missing_result_counts_as_failure(self):
state = self._rebuilding_state()
action = after_fix(state, {"reaudit_verdict": pass_verdict()})
self.assertEqual(action.kind, "pushback")
self.assertEqual(action.next_state.failure_count, 1)
self.assertEqual(action.next_state.status, "pushback")
checks = [item.get("check") for item in action.pushback_package["failures"]]
self.assertIn("rebuild_first_gate", checks)
def test_old_test_gate_failing_result_counts_as_failure(self):
state = self._rebuilding_state()
action = after_fix(state, {
"reaudit_verdict": pass_verdict(),
"retained_test_results": {"t1": True, "t2": False},
})
self.assertEqual(action.kind, "pushback")
self.assertEqual(action.next_state.failure_count, 1)
def test_old_test_gate_passing_allows_reaudit_pass(self):
state = self._rebuilding_state()
action = after_fix(state, {
"reaudit_verdict": pass_verdict(),
"retained_test_results": {"t1": True, "t2": True},
})
self.assertEqual(action.kind, "pass")
self.assertEqual(action.next_state.status, "passed")
def _acceptance_pending(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
state = drive(state, fail_verdict(source="acceptance")).next_state
return drive(state, fail_verdict(source="acceptance"))
def test_acceptance_rebuild_unconfirmed_does_not_start(self):
action = self._acceptance_pending()
self.assertEqual(action.kind, "pending_user_confirmation")
self.assertTrue(action.next_state.pending_confirmation)
self.assertEqual(action.next_state.rebuild_no, 0)
self.assertEqual(action.next_state.status, "pending_user_confirmation")
notices = [e for e in action.ledger_events
if e["event_type"] == "audit_rebuild_notice"]
self.assertEqual(notices[0]["payload"]["confirmation_status"], "pending")
def test_acceptance_rebuild_confirmed_then_starts(self):
pending = self._acceptance_pending().next_state
action = confirm_rebuild(pending, user_confirmed=True)
self.assertEqual(action.kind, "rebuild")
self.assertEqual(action.rebuild_no, 1)
self.assertEqual(action.next_state.status, "rebuilding")
self.assertFalse(action.next_state.pending_confirmation)
notices = [e for e in action.ledger_events
if e["event_type"] == "audit_rebuild_notice"]
self.assertEqual(notices[0]["payload"]["confirmation_status"], "confirmed")
self.assertEqual(notices[0]["payload"]["confirmed_by"], "user")
def test_acceptance_rebuild_rejected_escalates_without_budget(self):
pending = self._acceptance_pending().next_state
action = confirm_rebuild(pending, user_confirmed=False)
self.assertEqual(action.kind, "escalate")
self.assertEqual(action.escalation_target, "coordinator")
self.assertEqual(action.next_state.rebuild_no, 0)
def test_confirm_without_pending_raises(self):
state = new_loop_state("m1", "v1")
with self.assertRaises(ValueError):
confirm_rebuild(state, user_confirmed=True)
class AfterFixTestCase(unittest.TestCase):
def test_after_fix_pass_clears(self):
state = new_loop_state("m1", "v1")
state = drive(state, fail_verdict()).next_state
action = after_fix(state, {"reaudit_verdict": pass_verdict()})
self.assertEqual(action.kind, "pass")
self.assertEqual(action.next_state.failure_count, 0)
def test_after_fix_failing_reaudit_goes_to_next_pushback(self):
state = new_loop_state("m1", "v1")
state = drive(state, fail_verdict()).next_state
action = after_fix(state, {"reaudit_verdict": fail_verdict()})
self.assertEqual(action.kind, "pushback")
self.assertEqual(action.next_state.failure_count, 2)
self.assertEqual(action.next_state.pushback_round, 2)
def test_after_fix_diff_only_raises(self):
state = new_loop_state("m1", "v1")
state = drive(state, fail_verdict()).next_state
with self.assertRaises(ValueError):
after_fix(state, {"diff": "--- a/x\n+++ b/x\n"})
with self.assertRaises(ValueError):
after_fix(state, {"diff_only": True,
"reaudit_verdict": pass_verdict()})
class CorrectionTestCase(unittest.TestCase):
def test_correction_to_pass_does_not_unblock(self):
state = new_loop_state("m1", "v1")
for _ in range(2):
state = drive(state, fail_verdict()).next_state
action = apply_correction(state, {
"original_verdict": "fail", "corrected_verdict": "pass",
"reviewer": "auditor-b", "original_entry_id": "e1",
"reason": "second look: evidence was sufficient",
})
# Counting view: effective count is 0 ...
self.assertEqual(action.next_state.failure_count, 0)
# ... but the gate view is still blocked until a fresh pass.
self.assertTrue(action.merge_blocked)
self.assertTrue(action.release_blocked)
self.assertEqual(action.next_state.status, "blocked")
self.assertTrue(action.requires_reaudit)
self.assertEqual(action.correction_action, "schedule_reaudit")
self.assertEqual(action.ledger_events[0]["event_type"], "audit_meta_review")
# Only a fresh passing verdict unblocks.
action = drive(action.next_state, pass_verdict())
self.assertEqual(action.kind, "pass")
self.assertFalse(action.merge_blocked)
def test_correction_to_fail_reblocks_at_once(self):
state = drive(new_loop_state("m1", "v1"), pass_verdict()).next_state
action = apply_correction(state, {
"original_verdict": "pass", "corrected_verdict": "fail",
"reviewer": "auditor-b", "original_entry_id": "e1",
"reason": "missed a failing check",
})
self.assertEqual(action.kind, "pushback")
self.assertTrue(action.merge_blocked)
self.assertEqual(action.next_state.failure_count, 1)
self.assertEqual(action.correction_action, "retrigger_pushback_and_reblock")
class QuotaAndCostTestCase(unittest.TestCase):
def test_quota_block_consumes_nothing(self):
state = new_loop_state("m1", "v1")
for _ in range(2):
state = drive(state, fail_verdict()).next_state
action = drive(state, fail_verdict(),
quota_check=lambda estimate: False)
self.assertEqual(action.kind, "quota_blocked")
self.assertIs(action.next_state, state)
self.assertEqual(action.next_state.failure_count, 2)
self.assertEqual(action.next_state.pushback_round, 2)
def test_quota_block_at_rebuild_consumes_no_rebuild(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
state = drive(state, fail_verdict()).next_state
action = drive(state, fail_verdict(),
quota_check=lambda estimate: False)
self.assertEqual(action.kind, "quota_blocked")
self.assertEqual(action.next_state.rebuild_no, 0)
self.assertEqual(action.next_state.failure_count, 3)
def test_quota_check_exception_fails_closed(self):
state = new_loop_state("m1", "v1")
def _boom(estimate):
raise RuntimeError("quota service down")
action = drive(state, fail_verdict(), quota_check=_boom)
self.assertEqual(action.kind, "quota_blocked")
self.assertEqual(action.next_state.failure_count, 0)
def test_cost_threshold_escalates_rebuild_to_user(self):
state = new_loop_state("m1", "v1")
for _ in range(3):
state = drive(state, fail_verdict()).next_state
action = drive(state, fail_verdict(cost_estimate=500),
cost_threshold=100)
self.assertEqual(action.kind, "escalate")
self.assertEqual(action.escalation_target, "user")
self.assertEqual(action.next_state.rebuild_no, 0)
self.assertEqual(action.cost_estimate, 500)
self.assertGreaterEqual(len(action.escalation_history), 4)
self.assertFalse(action.escalation_grants_user_acceptance)
def test_cost_threshold_not_applied_to_pushback(self):
# #244 scope preserved: the threshold gates rebuild steps,
# a fix pushback is quota-checked only.
state = new_loop_state("m1", "v1")
action = drive(state, fail_verdict(cost_estimate=500),
cost_threshold=100)
self.assertEqual(action.kind, "pushback")
class TestChangeTestCase(unittest.TestCase):
def test_test_deletion_violation_does_not_advance(self):
state = new_loop_state("m1", "v1")
state = drive(state, fail_verdict()).next_state
action = drive(state, fail_verdict(test_changes=[
{"action": "delete", "test_id": "t1"}]))
self.assertEqual(action.kind, "escalate")
self.assertTrue(action.violations)
self.assertEqual(action.next_state.failure_count, 1)
self.assertEqual(action.next_state.pushback_round, 1)
def test_test_deletion_allowed_with_refreeze_and_audit(self):
state = new_loop_state("m1", "v1")
action = drive(state, fail_verdict(test_changes=[
{"action": "delete", "test_id": "t1",
"separate_audit_id": "audit-9"}],
refreeze_approved=True, separate_audit_ids=["audit-9"]))
self.assertEqual(action.kind, "pushback")
self.assertEqual(action.violations, [])
class LedgerEventTestCase(unittest.TestCase):
def test_all_seven_event_types_validate(self):
cases = {
"audit_verdict": {"module_id": "m1", "contract_version": "v1",
"verdict": "pass", "source": "audit", "failures": []},
"audit_pushback_round": {"module_id": "m1", "contract_version": "v1",
"round_no": 1, "trigger_items": ["ci_green"],
"pushback_package": {}, "round_status": "pushed"},
"audit_rebuild": {"module_id": "m1", "contract_version": "v1",
"rebuild_no": 1, "root_cause": "implementation",
"status": "decided", "retained_assets": {}},
"audit_third_failure_assessment": {
"module_id": "m1", "contract_version": "v1",
"determination": "continuation_round", "basis": {},
"failure_total": 3, "max_extra_rounds": 1},
"audit_test_change": {"module_id": "m1", "contract_version": "v1",
"test_changes": {"added": ["t9"], "modified": [],
"deleted": []},
"auditor": "auditor-a",
"contract_refrozen": False, "reason": "add only"},
"audit_meta_review": {"original_entry_id": "e1",
"original_verdict": "fail",
"corrected_verdict": "pass",
"misjudgment_found": True,
"reviewer": "auditor-b", "findings": [],
"triggered_process": "re-review"},
"audit_rebuild_notice": {"module_id": "m1", "contract_version": "v1",
"rebuild_no": 1,
"notification_content": "notice text",
"notified_party": "user",
"confirmation_status": "pending"},
}
for event_type, payload in cases.items():
self.assertEqual(validate_ledger_event(event_type, payload), [],
event_type)
event = emit(event_type, payload)
self.assertEqual(event["event_type"], event_type)
self.assertEqual(set(LEDGER_EVENT_TYPES), set(cases))
def test_unknown_event_type_and_missing_field_rejected(self):
self.assertTrue(validate_ledger_event("nope", {}))
with self.assertRaises(ValueError):
emit("audit_verdict", {"module_id": "m1"})
with self.assertRaises(ValueError):
emit("audit_verdict", {"module_id": "m1", "contract_version": "v1",
"verdict": "pass", "source": "audit"})
def test_conditional_maps_to_fail_and_keeps_original(self):
event = emit("audit_verdict", {
"module_id": "m1", "contract_version": "v1",
"verdict": "conditional", "source": "audit", "failures": []})
self.assertEqual(event["payload"]["verdict"], "fail")
self.assertEqual(event["payload"]["extra"]["original_verdict"],
"conditional")
# A driver verdict of conditional is a fail, not a pass.
action = drive(new_loop_state("m1", "v1"),
fail_verdict(verdict="conditional"))
self.assertEqual(action.kind, "pushback")
def test_test_change_hard_gate_in_emit(self):
payload = {"module_id": "m1", "contract_version": "v1",
"test_changes": {"added": [], "modified": ["t1"],
"deleted": []},
"auditor": "auditor-a", "contract_refrozen": False,
"reason": "drop a test"}
with self.assertRaises(ValueError):
emit("audit_test_change", payload)
payload["contract_refrozen"] = True
payload["refreeze_ref"] = "freeze-2"
emit("audit_test_change", payload) # no raise
def test_rebuild_notice_confirmed_needs_confirmer(self):
payload = {"module_id": "m1", "contract_version": "v1",
"rebuild_no": 1, "notification_content": "notice",
"notified_party": "user", "confirmation_status": "confirmed"}
with self.assertRaises(ValueError):
emit("audit_rebuild_notice", payload)
payload["confirmed_by"] = "user"
emit("audit_rebuild_notice", payload) # no raise
def test_action_kinds_are_bounded(self):
for kind in ACTION_KINDS:
self.assertIn(kind, ("pass", "pushback", "rebuild", "refreeze",
"escalate", "pending_user_confirmation",
"quota_blocked"))
action = drive(new_loop_state("m1", "v1"), fail_verdict())
self.assertIn(action.kind, ACTION_KINDS)
if __name__ == "__main__":
unittest.main()