diff --git a/training/train.py b/training/train.py index c6553cec..1abcd205 100644 --- a/training/train.py +++ b/training/train.py @@ -43,8 +43,15 @@ class GoalRateCallback(BaseCallback): def _on_rollout_end(self) -> None: if len(self.model.ep_info_buffer) == 0: return - goal_rate = safe_mean([ep_info["goal_scored"] for ep_info in self.model.ep_info_buffer]) - self.logger.record("rollout/goal_rate", goal_rate) + # The vendored godot_rl sync bridge (Game/addons/godot_rl_agents/sync.gd, + # _training_process) snapshots each agent's info dict once per tick and + # has its own "NEEDS REFACTOR" comment on the reset-timing path, so an + # episode's terminal info entry can arrive without "goal_scored" at all + # (observed crashing a run after 2026-07-28). Skip those rather than + # crash training over a monitoring-only metric. + rates = [ep_info["goal_scored"] for ep_info in self.model.ep_info_buffer if "goal_scored" in ep_info] + if rates: + self.logger.record("rollout/goal_rate", safe_mean(rates)) def parse_args():