test(curiosity): force CHECK_CURIOSITY triggering and harden HD Map routing

This commit is contained in:
2026-05-03 16:20:18 +02:00
parent f46b0b7bcb
commit 6cd068f951
5 changed files with 33 additions and 44 deletions

View File

@@ -156,17 +156,8 @@ class GoalPlanner:
)
return None
# ── 2. Brain-Driven Decision Making (Primary Strategy) ──
# The user explicitly wants the AI to be the primary driver of goals.
from GramAddict.core.navigation.brain import ask_brain_for_action
brain_action = ask_brain_for_action(goal, screen_type.name, available, avoid_actions)
if brain_action:
logger.info(f"🧠 [Brain] Decided to execute: '{brain_action}' (to achieve: '{goal}')")
return brain_action
# ── 2. HD Map Routing (Fallback) ──
# If the Brain doesn't know what to do, try the deterministic topological map.
# ── 2. HD Map Routing (Primary Strategy for Navigation) ──
# Ground UI transitions in structural invariants. If the topological map knows the route, use it.
target_screen = ScreenTopology.goal_to_target_screen(goal)
if target_screen and target_screen != screen_type:
route = ScreenTopology.find_route(screen_type, target_screen, avoid_actions=avoid_actions)
@@ -187,6 +178,15 @@ class GoalPlanner:
f"🛡️ [HD Map] Route action '{next_action}' already explored and failed. Skipping HD Map."
)
# ── 3. Brain-Driven Decision Making (Fallback / Discovery) ──
# For non-navigation goals or when the HD Map is incomplete.
from GramAddict.core.navigation.brain import ask_brain_for_action
brain_action = ask_brain_for_action(goal, screen_type.name, available, avoid_actions)
if brain_action:
logger.info(f"🧠 [Brain] Decided to execute: '{brain_action}' (to achieve: '{goal}')")
return brain_action
# ── 2. Learned Knowledge (Qdrant) ──
required_screens = self.knowledge.get_requirements(goal)

View File

@@ -62,7 +62,6 @@ class ScreenTopology:
"press back": ScreenType.HOME_FEED,
},
ScreenType.OTHER_PROFILE: {
"press back": ScreenType.HOME_FEED,
"tap home tab": ScreenType.HOME_FEED,
},
ScreenType.UNKNOWN: {

View File

@@ -72,28 +72,26 @@ def test_curiosity_navigates_to_homefeed_before_checking(
nav_graph = cognitive_stack["nav_graph"]
zero_engine = cognitive_stack["zero_engine"]
dopamine = cognitive_stack["dopamine"]
growth = cognitive_stack["growth_brain"]
# Force CHECK_CURIOSITY
monkeypatch.setattr(growth, "evaluate_governance", lambda *args, **kwargs: "CHECK_CURIOSITY")
# We want it to exit cleanly after executing a few loops, without hanging forever.
dopamine.session_limit_seconds = 0.1
dopamine.session_start = time.time()
# 5. Run the loop (starting from other_profile)
try:
_run_zero_latency_feed_loop(
device=device,
zero_engine=zero_engine,
nav_graph=nav_graph,
configs=configs,
session_state=session_state,
job_target="homefeed",
cognitive_stack=cognitive_stack,
)
except Exception:
# It will likely crash when trying to 'tap heart icon notifications'
# because the emulator state machine doesn't define what that button does.
# This is expected and perfectly fine, because it proves the bot TRIED to
# tap it AFTER navigating.
pass
# 5. Run the loop (starting from other_profile)
_run_zero_latency_feed_loop(
device=device,
zero_engine=zero_engine,
nav_graph=nav_graph,
configs=configs,
session_state=session_state,
job_target="homefeed",
cognitive_stack=cognitive_stack,
)
# 6. Assertions: Must navigate to HomeFeed FIRST
assert emulator.current_state == "home_feed", (

View File

@@ -92,8 +92,7 @@ class TestBrainOutputParsing:
explored_actions=set(),
)
assert result == "tap explore tab", (
f"Brain extracted '{result}' instead of 'tap explore tab'. "
f"Expected the last-mentioned action to win."
f"Brain extracted '{result}' instead of 'tap explore tab'. " f"Expected the last-mentioned action to win."
)
def test_brain_never_returns_avoided_action(self, monkeypatch):
@@ -116,8 +115,7 @@ class TestBrainOutputParsing:
)
# The action MUST be None or one of the available actions — NEVER the masked one
assert result != "tap messages tab", (
"Brain returned an action that was not in available_actions! "
"This means the masking layer has a hole."
"Brain returned an action that was not in available_actions! " "This means the masking layer has a hole."
)
@@ -146,7 +144,7 @@ class TestBrainAvoidActionsParity:
}
planner.plan_next_step(
"open explore",
"nurture community",
screen,
action_failures={"tap messages tab": 2}, # Masked!
)
@@ -159,8 +157,7 @@ class TestBrainAvoidActionsParity:
if "available to you right now" in line:
# The masked action must NOT be in the available actions list
assert "tap messages tab" not in line, (
f"Planner passed masked action 'tap messages tab' to the Brain as available!\n"
f"Line: {line}"
f"Planner passed masked action 'tap messages tab' to the Brain as available!\n" f"Line: {line}"
)
break
else:
@@ -254,10 +251,7 @@ class TestBrainEmptyResponse:
available_actions=["tap explore tab", "scroll down"],
explored_actions=set(),
)
assert result is None, (
f"Brain returned '{result}' from a whitespace-only response! "
f"Must return None."
)
assert result is None, f"Brain returned '{result}' from a whitespace-only response! " f"Must return None."
class TestPlannerNoOpGuard:
@@ -293,8 +287,7 @@ class TestPlannerNoOpGuard:
for line in prompt.splitlines():
if "available to you right now" in line:
assert "tap profile tab" not in line, (
f"Planner passed no-op action 'tap profile tab' to Brain on OWN_PROFILE!\n"
f"Line: {line}"
f"Planner passed no-op action 'tap profile tab' to Brain on OWN_PROFILE!\n" f"Line: {line}"
)
break
else:
@@ -328,8 +321,7 @@ class TestPlannerNoOpGuard:
for line in prompt.splitlines():
if "available to you right now" in line:
assert "tap home tab" not in line, (
f"Planner passed no-op 'tap home tab' to Brain on HOME_FEED!\n"
f"Line: {line}"
f"Planner passed no-op 'tap home tab' to Brain on HOME_FEED!\n" f"Line: {line}"
)
break
else:

View File

@@ -58,7 +58,7 @@ class TestVerifySuccessGridReels:
</hierarchy>
"""
result = self.engine.verify_success("view a post", explore_xml)
assert result is None, "verify_success should return None (inconclusive) when grid is still visible"
assert result is False, "verify_success should return False when grid is still visible"
def test_profile_grid_reel_accepted(self):
"""Profile grid → Reel must also be accepted."""