import copy import importlib.util import json from pathlib import Path import unittest ROOT = Path(__file__).resolve().parents[1] spec = importlib.util.spec_from_file_location("decision", ROOT / "skills/codex-subagent-router/scripts/validate_decision_record.py") module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) class DecisionTests(unittest.TestCase): def setUp(self): self.record = json.loads((ROOT / "examples/decisions/resolved.json").read_text()) def test_valid_resolution(self): self.assertEqual(module.validate(self.record), []) def test_counter_survives_continuation(self): previous = copy.deepcopy(self.record) self.record["same_class_failures"] = 0 self.assertTrue(module.validate(self.record, previous)) def test_reassessment_required(self): self.record["reassessment"] = "" self.assertTrue(module.validate(self.record)) def test_unresolved_counterexample_blocks_resolution(self): self.record["unresolved"] = ["reproducible contrary result"] self.assertTrue(module.validate(self.record)) def test_stale_baseline_blocks_resolution(self): self.record["verification"]["baseline"] = "old" self.assertTrue(module.validate(self.record)) def test_parent_must_understand(self): self.record["verification"]["parent_understands"] = False self.assertTrue(module.validate(self.record)) def test_environment_and_authority_do_not_escalate_to_astra(self): for category in ("environment", "authority"): self.record["failure_class"] = category self.record["escalation"]["target"] = "astra" self.assertTrue(module.validate(self.record)) def test_zero_failure_proactive_astra_consultation(self): self.record["failure_class"] = "reasoning" self.record["status"] = "investigating" self.record["same_class_failures"] = 0 self.record["reassessment"] = "" self.record["escalation"] = { "target": "astra", "reason": "Proactive review of a high-impact architectural choice.", "expert_consultations": 1, "followup_basis": "", } self.record["unresolved"] = ["expert consultation pending"] self.assertEqual(module.validate(self.record), []) def test_more_than_three_progressive_consultations(self): self.record["escalation"]["expert_consultations"] = 4 self.record["escalation"]["followup_basis"] = "new discriminator results across rounds" self.assertEqual(module.validate(self.record), []) def test_multiple_consultations_need_basis(self): self.record["escalation"]["expert_consultations"] = 2 self.assertIn( "additional consultation requires new evidence or a specific omission", module.validate(self.record), ) def test_consultation_counter_cannot_decrease_across_class_change(self): previous = copy.deepcopy(self.record) previous["escalation"]["expert_consultations"] = 4 previous["escalation"]["followup_basis"] = "prior progressive rounds" self.record["failure_class"] = "reasoning" self.record["escalation"]["expert_consultations"] = 3 self.record["escalation"]["followup_basis"] = "current evidence" self.assertIn( "expert consultation counter decreased across continuation", module.validate(self.record, previous), ) def test_consultation_counter_can_increase_with_basis(self): previous = copy.deepcopy(self.record) previous["escalation"]["expert_consultations"] = 1 self.record["escalation"]["expert_consultations"] = 4 self.record["escalation"]["followup_basis"] = "new discriminator results" self.assertEqual(module.validate(self.record, previous), []) def test_malformed_previous_consultation_counter_is_rejected(self): previous = copy.deepcopy(self.record) previous["escalation"]["expert_consultations"] = True self.assertIn( "previous expert_consultations must be a nonnegative integer", module.validate(self.record, previous), ) def test_recovery_required(self): self.record["recovery_route"] = "" self.assertTrue(module.validate(self.record)) def test_bad_shapes_and_boolean_counters(self): for value in (None, [], True): self.assertTrue(module.validate(value)) self.record["same_class_failures"] = True self.assertTrue(module.validate(self.record)) def test_unhashable_enum_fields_are_rejected(self): for key in ("failure_class", "status"): record = copy.deepcopy(self.record) record[key] = [] self.assertTrue(module.validate(record)) self.record["escalation"]["target"] = {} self.assertTrue(module.validate(self.record))