fix: stochastic failure in test_autonomous_goals.py

This commit is contained in:
2026-05-02 22:37:34 +02:00
parent 9c6f80de9d
commit 2f8eebb7e9
4 changed files with 28 additions and 22 deletions

View File

@@ -151,7 +151,7 @@ class GoalExecutor:
original_available = screen.get("available_actions", []).copy()
masked_available = []
for act in original_available:
fail_count = self.action_failures.get(act, 0)
fail_count = self.action_failures.get((screen_type, act), 0)
if fail_count >= MAX_RETRIES:
logger.warning(
f"🚫 [GOAP] Masking action '{act}' due to {fail_count} consecutive failures to prevent loops."
@@ -173,8 +173,8 @@ class GoalExecutor:
# SAE Feedback Loop!
# If we hit this, the LAST action caused an obstacle! Mask it!
if last_action and last_screen_type:
self.action_failures[last_action] = (
self.action_failures.get(last_action, 0) + MAX_RETRIES
self.action_failures[(last_screen_type, last_action)] = (
self.action_failures.get((last_screen_type, last_action), 0) + MAX_RETRIES
) # Instantly mask it
self.planner.knowledge.learn_trap(last_screen_type, last_action, f"caused_obstacle_{obstacle_name}")
logger.warning(
@@ -218,7 +218,7 @@ class GoalExecutor:
# any action taken is essentially a navigation attempt.
explored_nav_actions.add(action)
# Reset failures for this action since it eventually succeeded
self.action_failures[action] = 0
self.action_failures[(screen_type, action)] = 0
if "scroll" in action.lower():
logger.debug(
@@ -230,7 +230,8 @@ class GoalExecutor:
from GramAddict.core.screen_topology import ScreenTopology
keys_to_clear = [
k for k in self.action_failures.keys() if ScreenTopology.is_structural_action(screen_type, k)
k for k in self.action_failures.keys()
if k[0] == screen_type and ScreenTopology.is_structural_action(screen_type, k[1])
]
for k in keys_to_clear:
del self.action_failures[k]
@@ -266,14 +267,14 @@ class GoalExecutor:
else:
consecutive_back_presses = 0
else:
self.action_failures[action] = self.action_failures.get(action, 0) + 1
self.action_failures[(screen_type, action)] = self.action_failures.get((screen_type, action), 0) + 1
# Track failed actions in explored_nav_actions so the planner
# knows NOT to return the same synthetic intent again.
# Without this, synthetic intents (not in available_actions)
# bypass the masking logic and loop forever.
explored_nav_actions.add(action)
if self.action_failures[action] >= MAX_RETRIES:
if self.action_failures[(screen_type, action)] >= MAX_RETRIES:
# ── Topology Guard: Never poison structural HD Map actions ──
from GramAddict.core.screen_topology import ScreenTopology

View File

@@ -134,9 +134,14 @@ class GoalPlanner:
# Build avoid_actions for HD Map route planning
avoid_actions = (explored_nav_actions or set()).copy()
if action_failures:
for act, count in action_failures.items():
if count >= 2: # MAX_RETRIES is 2 in goap
avoid_actions.add(act)
for key, count in action_failures.items():
if isinstance(key, tuple) and len(key) == 2:
scr, act = key
if scr == screen_type and count >= 2: # MAX_RETRIES is 2 in goap
avoid_actions.add(act)
else:
if count >= 2:
avoid_actions.add(key)
target_screen = ScreenTopology.goal_to_target_screen(goal)