from __future__ import annotations import unittest from autofarm.contracts import ActionType, ControlState, MissionTask, PriorityBand from tests.sim_support import make_interactive_environment class InteractiveChallengeRadiusTest(unittest.TestCase): def test_challenge_placement_keeps_robot_belief_until_measurement(self) -> None: env = make_interactive_environment(zone_id="zone_r02_c01") self.assertEqual(env._zone_state("zone_r02_c01").static_features.get("scenario_priority_hint"), 0.4) self.assertEqual(env._zone_state("zone_r02_c01").static_features.get("recommended_action"), "none") self.assertFalse(bool(env._zone_state("zone_r02_c01").static_features.get("needs_intervention", False))) success, _ = env.place_challenge("actionable_high_priority", "zone_r02_c01", radius=1) self.assertTrue(success) self.assertEqual(env._zone_state("zone_r02_c01").static_features.get("scenario_priority_hint"), 0.4) self.assertEqual(env._zone_state("zone_r02_c01").static_features.get("recommended_action"), "none") self.assertFalse(bool(env._zone_state("zone_r02_c01").static_features.get("needs_intervention", False))) self.assertEqual(env.hidden_zone_states["zone_r02_c01"].true_priority_hint, 0.88) self.assertEqual(env.hidden_zone_states["zone_r02_c01"].true_recommended_action, "irrigate") self.assertTrue(env.hidden_zone_states["zone_r02_c01"].true_needs_intervention) def test_planning_observation_masks_active_challenge_summaries(self) -> None: env = make_interactive_environment(zone_id="zone_r02_c01") success, _ = env.place_challenge("actionable_high_priority", "zone_r02_c01", radius=1) self.assertTrue(success) self.assertEqual(env.observation().active_challenge_summaries_by_zone, {"zone_r02_c01": ["Drought"]}) self.assertEqual(env.planning_observation().active_challenge_summaries_by_zone, {}) def test_move_over_tile_triggers_direct_measurement_and_resolves_unseen_state(self) -> None: env = make_interactive_environment(zone_id="zone_r02_c01") success, _ = env.place_challenge("actionable_high_priority", "zone_r02_c01", radius=1) self.assertTrue(success) self.assertEqual(env.hidden_zone_states["zone_r02_c01"].control_state, ControlState.INSPECT_REQUIRED) event = env._move_to_neighbor( MissionTask( task_type=ActionType.MOVE, target_zone="zone_r02_c01", priority=1.0, preconditions=[], rationale="enter field", ), "zone_r02_c01", ) self.assertEqual(event.action, ActionType.MOVE) self.assertEqual(event.control_state_before, ControlState.INSPECT_REQUIRED) self.assertEqual(event.control_state_after, ControlState.RESOLVED_COMPLETE) self.assertEqual(env.hidden_zone_states["zone_r02_c01"].guarded_context.inspection_count, 1) self.assertEqual(env.hidden_zone_states["zone_r02_c01"].current_uncertainty, 0.0) self.assertEqual(env._zone_state("zone_r02_c01").static_features.get("recommended_action"), "irrigate") self.assertEqual(env._zone_state("zone_r02_c01").static_features.get("scenario_priority_hint"), 0.88) self.assertIn("Drive-over measurement refreshed the tile state.", event.details["revealed_facts"]) def test_radius_one_targets_only_the_selected_tile(self) -> None: env = make_interactive_environment(zone_id="zone_r02_c02") self.assertEqual(env.challenge_target_zone_ids("zone_r02_c02", radius=1), ["zone_r02_c02"]) success, _ = env.place_challenge("actionable_high_priority", "zone_r02_c02", radius=1) self.assertTrue(success) self.assertEqual(set(env.active_challenges), {"zone_r02_c02"}) self.assertEqual(env.hidden_zone_states["zone_r02_c02"].true_priority_band, PriorityBand.HIGH) def test_radius_two_forms_a_single_ring_around_the_selected_tile(self) -> None: env = make_interactive_environment(zone_id="zone_r02_c02") expected_zone_ids = { "zone_r01_c01", "zone_r01_c02", "zone_r01_c03", "zone_r02_c01", "zone_r02_c02", "zone_r02_c03", "zone_r03_c01", "zone_r03_c02", "zone_r03_c03", } self.assertEqual(set(env.challenge_target_zone_ids("zone_r02_c02", radius=2)), expected_zone_ids) success, message = env.place_challenge("actionable_high_priority", "zone_r02_c02", radius=2) self.assertTrue(success) self.assertIn("radius 2", message) self.assertEqual(set(env.active_challenges), expected_zone_ids) def test_radius_three_clips_cleanly_at_the_field_border(self) -> None: env = make_interactive_environment(zone_id="zone_r02_c02") expected_zone_ids = { "zone_r01_c01", "zone_r01_c02", "zone_r01_c03", "zone_r02_c01", "zone_r02_c02", "zone_r02_c03", "zone_r03_c01", "zone_r03_c02", } self.assertEqual(set(env.challenge_target_zone_ids("zone_r01_c01", radius=3)), expected_zone_ids) success, message = env.place_challenge("actionable_high_priority", "zone_r01_c01", radius=3) self.assertTrue(success) self.assertIn("8 tiles", message) self.assertEqual(set(env.active_challenges), expected_zone_ids) def test_radius_placement_skips_tiles_with_existing_active_challenges(self) -> None: env = make_interactive_environment(zone_id="zone_r02_c02") success, _ = env.place_challenge("actionable_high_priority", "zone_r02_c02", radius=1) self.assertTrue(success) success, message = env.place_challenge("actionable_high_priority", "zone_r02_c02", radius=2) self.assertTrue(success) self.assertIn("Skipped 1 tile", message) self.assertEqual(len(env.active_challenges), 9) if __name__ == "__main__": unittest.main()