test_rollout_governance.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. from __future__ import annotations
  2. import unittest
  3. import pandas as pd
  4. from dragon_rollout_governance import (
  5. FORWARD_OK,
  6. HOLD_AND_REVIEW,
  7. ROLLBACK_REVIEW_REQUIRED,
  8. evaluate_rollout,
  9. )
  10. class TestRolloutGovernance(unittest.TestCase):
  11. def _manifest(self, latest_bar_date: str = "2026-04-08") -> dict[str, object]:
  12. return {
  13. "release_version": "RC1",
  14. "branch": "alpha_first_glued_refined_hot_cap",
  15. "as_of_request_date": latest_bar_date,
  16. "latest_bar_date": latest_bar_date,
  17. }
  18. def _monitor_history(self, latest_bar_date: str = "2026-04-08", status: str = "ok") -> pd.DataFrame:
  19. return pd.DataFrame(
  20. [
  21. {
  22. "latest_bar_date": latest_bar_date,
  23. "metric": "next_open_avg_return_delta_vs_control",
  24. "actual_value": 0.01,
  25. "status": status,
  26. "warning_streak": 0 if status == "ok" else 3,
  27. "hard_breach_streak": 0 if status != "hard_breach" else 1,
  28. }
  29. ]
  30. )
  31. def _divergence_log(self, latest_bar_date: str = "2026-04-08", divergence_level: str = "none") -> pd.DataFrame:
  32. return pd.DataFrame(
  33. [
  34. {
  35. "latest_bar_date": latest_bar_date,
  36. "divergence_level": divergence_level,
  37. "same_position_flag": True,
  38. "same_latest_real_event_flag": True,
  39. }
  40. ]
  41. )
  42. def test_forward_ok_when_all_gates_pass(self) -> None:
  43. decision, gates, reasons, active_branch = evaluate_rollout(
  44. manifest=self._manifest(),
  45. monitor_history=self._monitor_history(),
  46. divergence_log=self._divergence_log(),
  47. monitor_health_report_exists=True,
  48. )
  49. self.assertEqual(decision, FORWARD_OK)
  50. self.assertEqual(reasons, [])
  51. self.assertEqual(active_branch, "alpha_first_glued_refined_hot_cap")
  52. self.assertTrue(all(g.status == "ok" for g in gates))
  53. def test_hard_breach_requires_rollback_review(self) -> None:
  54. decision, gates, reasons, active_branch = evaluate_rollout(
  55. manifest=self._manifest(),
  56. monitor_history=self._monitor_history(status="hard_breach"),
  57. divergence_log=self._divergence_log(),
  58. monitor_health_report_exists=True,
  59. )
  60. self.assertEqual(decision, ROLLBACK_REVIEW_REQUIRED)
  61. self.assertTrue(any("hard_breach_budget" in reason for reason in reasons))
  62. self.assertEqual(active_branch, "alpha_first_selective_veto")
  63. self.assertTrue(any(g.status == "hard_fail" for g in gates))
  64. def test_material_divergence_or_warning_moves_to_hold(self) -> None:
  65. monitor = pd.DataFrame(
  66. [
  67. {
  68. "latest_bar_date": "2026-04-08",
  69. "metric": "next_open_avg_return_delta_vs_control",
  70. "actual_value": 0.01,
  71. "status": "warning",
  72. "warning_streak": 1,
  73. "hard_breach_streak": 0,
  74. },
  75. {
  76. "latest_bar_date": "2026-04-08",
  77. "metric": "next_open_profit_factor_delta_vs_control",
  78. "actual_value": 0.20,
  79. "status": "warning",
  80. "warning_streak": 1,
  81. "hard_breach_streak": 0,
  82. },
  83. ]
  84. )
  85. decision, gates, reasons, _ = evaluate_rollout(
  86. manifest=self._manifest(),
  87. monitor_history=monitor,
  88. divergence_log=self._divergence_log(divergence_level="material"),
  89. monitor_health_report_exists=True,
  90. )
  91. self.assertEqual(decision, HOLD_AND_REVIEW)
  92. self.assertTrue(any(g.status == "warning" for g in gates))
  93. self.assertTrue(any(reason.startswith("warning_budget") or reason.startswith("branch_divergence_level") for reason in reasons))
  94. if __name__ == "__main__":
  95. unittest.main()