Spaces:
Sleeping
Sleeping
| """Round 2 environment enhancements: curriculum, rubrics, and training logging.""" | |
| import io | |
| import json | |
| import os | |
| import sys | |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) | |
| from client import NexusgridEnv | |
| from models import ActionType, GridAction | |
| from server.curriculum import CurriculumManager | |
| from server.nexusgrid_environment import NexusgridEnvironment | |
| from server.rubric import evaluate_task_rubrics, get_task_rubric_specs | |
| from server.training_logger import TrainingLogger | |
| class TestCurriculumManager: | |
| def test_recommends_task_zero_initially(self): | |
| curriculum = CurriculumManager(unlock_threshold=0.7, window=3) | |
| assert curriculum.get_recommended_task() == 0 | |
| def test_unlocks_next_task_after_threshold(self): | |
| curriculum = CurriculumManager(unlock_threshold=0.7, window=3) | |
| curriculum.record_score(0, 0.8) | |
| curriculum.record_score(0, 0.75) | |
| assert curriculum.is_unlocked(1) is True | |
| assert curriculum.get_recommended_task() == 1 | |
| class TestRubrics: | |
| def test_task_three_rubrics_reflect_forensic_sequence(self): | |
| actions = [ | |
| {"action_type": "advance_tick", "tick": 0}, | |
| {"action_type": "run_state_estimation", "tick": 1, "result": {"consistent": False}}, | |
| {"action_type": "quarantine_scada_node", "tick": 2, "node_id": "NODE_14"}, | |
| {"action_type": "dispatch_generation", "tick": 3, "node_id": "NODE_09", "mw": 100}, | |
| ] | |
| state = {"spoof_target": "NODE_14", "logs_read_before_estimation": True} | |
| result = evaluate_task_rubrics(3, actions, state) | |
| assert result["rubrics"]["log_inspection"] == 1.0 | |
| assert result["rubrics"]["state_estimation"] == 1.0 | |
| assert result["rubrics"]["correct_quarantine"] == 1.0 | |
| assert result["rubrics"]["reroute_dispatch"] == 1.0 | |
| assert result["weighted_score"] == 1.0 | |
| def test_task_specs_available_for_manifest_sync(self): | |
| specs = get_task_rubric_specs(5) | |
| assert any(spec["name"] == "hydro_bootstrap" for spec in specs) | |
| class TestTrainingLogger: | |
| def test_training_logger_writes_jsonl(self): | |
| buffer = io.StringIO() | |
| logger = TrainingLogger(stream=buffer) | |
| record = logger.build_record( | |
| episode=7, | |
| task_id=3, | |
| seed=42, | |
| score=0.6, | |
| rubrics={"state_estimation": 1.0}, | |
| actions_taken=["advance_tick", "run_state_estimation"], | |
| frequency_min=59.8, | |
| ticks_used=2, | |
| ) | |
| logger.write_episode(record) | |
| payload = json.loads(buffer.getvalue().strip()) | |
| assert payload["episode"] == 7 | |
| assert payload["task_id"] == 3 | |
| assert payload["rubrics"]["state_estimation"] == 1.0 | |
| class TestRoundTwoMetadata: | |
| def test_environment_exposes_rubric_breakdown(self): | |
| env = NexusgridEnvironment() | |
| obs = env.reset(seed=42, task_id=3) | |
| assert "rubric_breakdown" in obs.metadata | |
| assert obs.metadata["rubric_breakdown"]["task_id"] == 3 | |
| def test_emit_training_log_uses_episode_summary(self): | |
| env = NexusgridEnvironment() | |
| env.reset(seed=42, task_id=0) | |
| env.step(GridAction(action_type=ActionType.DISPATCH_GENERATION, node_id="NODE_01", mw=100)) | |
| buffer = io.StringIO() | |
| line = env.emit_training_log(episode=1, logger=TrainingLogger(stream=buffer)) | |
| payload = json.loads(line) | |
| assert payload["episode"] == 1 | |
| assert payload["task_id"] == 0 | |
| assert "valid_dispatch" in payload["rubrics"] | |
| class TestClientMetadataParsing: | |
| def test_client_preserves_metadata(self): | |
| client = NexusgridEnv(base_url="http://localhost:8000") | |
| payload = { | |
| "observation": { | |
| "topology_graph": {}, | |
| "telemetry_stream": [], | |
| "weather_forecast_matrix": [], | |
| "network_packet_logs": [], | |
| "grid_frequency_hz": 60.0, | |
| "tick": 1, | |
| "task_id": 2, | |
| "done": False, | |
| "reward": 0.2, | |
| "weather_summary": "", | |
| "metadata": {"rubric_breakdown": {"task_id": 2}}, | |
| }, | |
| "reward": 0.2, | |
| "done": False, | |
| } | |
| result = client._parse_result(payload) | |
| assert result.observation.metadata["rubric_breakdown"]["task_id"] == 2 | |
| def test_client_parses_state_with_model_validation(self): | |
| client = NexusgridEnv(base_url="http://localhost:8000") | |
| state = client._parse_state({"episode_id": "ep-1", "step_count": 4, "extra": "ok"}) | |
| assert state.episode_id == "ep-1" | |
| assert state.step_count == 4 | |