fix(navigation): Resolve planner loop, semantic mapping, and structural verification
This commit is contained in:
@@ -7,14 +7,9 @@ TDD: Close Friends Guard & ContextMemory Circuit Breaker
|
||||
3. The circuit breaker threshold must be LOWER for core actions.
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from GramAddict.core.behaviors import BehaviorContext, BehaviorResult
|
||||
from GramAddict.core.behaviors import BehaviorContext
|
||||
from GramAddict.core.behaviors.close_friends_guard import CloseFriendsGuardPlugin
|
||||
|
||||
|
||||
# ── Fixtures ──
|
||||
|
||||
|
||||
@@ -97,10 +92,10 @@ REELS_WITH_GREEN_STAR = """<?xml version='1.0' encoding='UTF-8' standalone='yes'
|
||||
|
||||
|
||||
class TestCloseFriendsGuard:
|
||||
"""The guard must detect close friends via STRUCTURAL markers, not just text."""
|
||||
"""The guard must detect close friends via Telepathic Engine classification."""
|
||||
|
||||
def test_detects_friendly_bubbles_component(self):
|
||||
"""RED: Guard must detect friendly_bubbles_component resource-id."""
|
||||
def test_detects_friendly_bubbles_component(self, monkeypatch):
|
||||
"""Guard must use TelepathicEngine to detect close friends."""
|
||||
plugin = CloseFriendsGuardPlugin()
|
||||
ctx = BehaviorContext(
|
||||
device=DummyDevice(),
|
||||
@@ -110,11 +105,14 @@ class TestCloseFriendsGuard:
|
||||
configs=None,
|
||||
cognitive_stack=None,
|
||||
)
|
||||
assert plugin.can_activate(ctx), (
|
||||
"CloseFriendsGuard must detect 'friendly_bubbles_component' as a close friend indicator"
|
||||
)
|
||||
|
||||
def test_does_not_fire_on_normal_post(self):
|
||||
from GramAddict.core.telepathic_engine import TelepathicEngine
|
||||
|
||||
monkeypatch.setattr(TelepathicEngine, "classify_screen_content", lambda self, xml, target: "close_friends")
|
||||
|
||||
assert plugin.can_activate(ctx), "CloseFriendsGuard must detect close friends via VLM"
|
||||
|
||||
def test_does_not_fire_on_normal_post(self, monkeypatch):
|
||||
"""Guard must NOT fire on normal posts without close friend markers."""
|
||||
plugin = CloseFriendsGuardPlugin()
|
||||
ctx = BehaviorContext(
|
||||
@@ -125,51 +123,22 @@ class TestCloseFriendsGuard:
|
||||
configs=None,
|
||||
cognitive_stack=None,
|
||||
)
|
||||
|
||||
from GramAddict.core.telepathic_engine import TelepathicEngine
|
||||
|
||||
monkeypatch.setattr(TelepathicEngine, "classify_screen_content", lambda self, xml, target: "normal_post")
|
||||
|
||||
assert not plugin.can_activate(ctx), "Guard must not fire on normal posts"
|
||||
|
||||
def test_detects_profile_header_close_friend(self):
|
||||
"""RED: Guard must detect profile_header_close_friend resource-id on profiles."""
|
||||
plugin = CloseFriendsGuardPlugin()
|
||||
ctx = BehaviorContext(
|
||||
device=DummyDevice(),
|
||||
session_state=type("S", (), {"job_target": "test"})(),
|
||||
shared_state={},
|
||||
context_xml=PROFILE_WITH_CLOSE_FRIEND_BADGE,
|
||||
configs=None,
|
||||
cognitive_stack=None,
|
||||
)
|
||||
assert plugin.can_activate(ctx), (
|
||||
"CloseFriendsGuard must detect 'profile_header_close_friend' resource-id"
|
||||
)
|
||||
|
||||
def test_detects_close_friends_badge_in_reels(self):
|
||||
"""RED: Guard must detect close_friends_badge resource-id in Reels."""
|
||||
plugin = CloseFriendsGuardPlugin()
|
||||
ctx = BehaviorContext(
|
||||
device=DummyDevice(),
|
||||
session_state=type("S", (), {"job_target": "test"})(),
|
||||
shared_state={},
|
||||
context_xml=REELS_WITH_GREEN_STAR,
|
||||
configs=None,
|
||||
cognitive_stack=None,
|
||||
)
|
||||
assert plugin.can_activate(ctx), (
|
||||
"CloseFriendsGuard must detect 'close_friends_badge' resource-id in Reels"
|
||||
)
|
||||
|
||||
def test_no_hardcoded_text_matching(self):
|
||||
"""
|
||||
META-TEST: The guard must NOT rely solely on text matching.
|
||||
It must use structural resource-id markers.
|
||||
META-TEST: The guard must NOT rely on hardcoded text matching or resource ids anymore.
|
||||
It must use TelepathicEngine.
|
||||
"""
|
||||
import inspect
|
||||
|
||||
source = inspect.getsource(CloseFriendsGuardPlugin.can_activate)
|
||||
# Must contain resource-id based detection
|
||||
assert "resource-id" in source.lower() or "resource_id" in source.lower() or \
|
||||
"friendly_bubbles" in source or "close_friends_badge" in source or \
|
||||
"profile_header_close_friend" in source, (
|
||||
"can_activate must use structural resource-id markers, not just text matching"
|
||||
)
|
||||
assert "classify_screen_content" in source, "can_activate must use TelepathicEngine"
|
||||
|
||||
|
||||
# ── Tests: ContextMemory Circuit Breaker ──
|
||||
@@ -187,6 +156,7 @@ class TestContextMemoryCircuitBreaker:
|
||||
Old failures (> 1 hour) must be forgiven to allow re-exploration.
|
||||
"""
|
||||
import inspect
|
||||
|
||||
from GramAddict.core.qdrant_memory import ContextMemoryDB
|
||||
|
||||
source = inspect.getsource(ContextMemoryDB.is_allowed)
|
||||
@@ -202,12 +172,14 @@ class TestContextMemoryCircuitBreaker:
|
||||
must be harder to permanently block than obscure actions.
|
||||
"""
|
||||
import inspect
|
||||
|
||||
from GramAddict.core.qdrant_memory import ContextMemoryDB
|
||||
|
||||
source = inspect.getsource(ContextMemoryDB.is_allowed)
|
||||
# Must have differentiated thresholds or a protected action concept
|
||||
assert "0.2" not in source or "core" in source.lower() or "protected" in source.lower() or \
|
||||
"updated_at" in source, (
|
||||
assert (
|
||||
"0.2" not in source or "core" in source.lower() or "protected" in source.lower() or "updated_at" in source
|
||||
), (
|
||||
"The 0.2 hard threshold is too aggressive. Core actions must be protected "
|
||||
"from permanent blocking or the threshold must be time-aware."
|
||||
)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
from GramAddict.core.perception.screen_identity import ScreenIdentity, ScreenType
|
||||
|
||||
|
||||
def test_gallery_screen_is_modal():
|
||||
"""
|
||||
Test that the Gallery/New Post screen is correctly identified as a MODAL,
|
||||
preventing it from being hallucinated as POST_DETAIL or HOME_FEED.
|
||||
"""
|
||||
xml_dump = """<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||
<hierarchy rotation="0">
|
||||
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.instagram.android" bounds="[0,0][1080,2400]">
|
||||
<node index="0" text="New post" resource-id="" class="android.widget.TextView" bounds="[0,0][100,100]" />
|
||||
<node index="1" text="" resource-id="com.instagram.android:id/gallery_grid_item_thumbnail" class="android.widget.Button" content-desc="Selected media number 1 Photo thumbnail created on 3 May 2026 10:30" bounds="[0,100][500,600]" />
|
||||
<node index="2" text="" resource-id="com.instagram.android:id/next_button_textview" class="android.widget.Button" content-desc="Next" bounds="[900,0][1080,100]" />
|
||||
</node>
|
||||
</hierarchy>
|
||||
"""
|
||||
identity = ScreenIdentity("bot_user")
|
||||
result = identity.identify(xml_dump)
|
||||
|
||||
assert result["screen_type"] == ScreenType.MODAL
|
||||
|
||||
|
||||
def test_camera_screen_is_modal():
|
||||
"""
|
||||
Test that the Camera creation screen is correctly identified as a MODAL.
|
||||
"""
|
||||
xml_dump = """<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||
<hierarchy rotation="0">
|
||||
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.instagram.android" bounds="[0,0][1080,2400]">
|
||||
<node index="0" text="" resource-id="com.instagram.android:id/camera_cancel_button" class="android.widget.ImageView" bounds="[0,0][100,100]" />
|
||||
<node index="1" text="" resource-id="com.instagram.android:id/quick_capture" class="android.widget.FrameLayout" bounds="[0,100][1080,2400]" />
|
||||
</node>
|
||||
</hierarchy>
|
||||
"""
|
||||
identity = ScreenIdentity("bot_user")
|
||||
result = identity.identify(xml_dump)
|
||||
|
||||
assert result["screen_type"] == ScreenType.MODAL
|
||||
Reference in New Issue
Block a user