chore: migrate autonomous navigation to GOAP and finalize 100% E2E test stabilization

- Delegate legacy BFS navigation to structure-based GOAP system
- Harden Situational Awareness Engine (SAE) for modal and obstacle clearance
- Fix device sizing calculations during mocked humanized scrolls
- Remove deprecated V8 test stubs and legacy debug entrypoints
- Stabilize Telepathic Engine context parsing thresholds
Result: 66/66 E2E and integration tests passing
This commit is contained in:
2026-04-19 22:14:56 +02:00
parent 0aeed11186
commit ba4d7ffda2
83 changed files with 4735 additions and 1873 deletions

View File

@@ -59,6 +59,8 @@ def dynamic_e2e_dump_injector(monkeypatch):
LESS than 1.5 virtual seconds after a transition, it returns a garbage animating UI.
"""
def _inject(device_mock, state_map, initial_xml):
from GramAddict.core.q_nav_graph import QNavGraph
fix_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "fixtures")
def load_xml(filename):
@@ -72,8 +74,6 @@ def dynamic_e2e_dump_injector(monkeypatch):
device_mock._current_active_xml = load_xml(initial_xml)
def _dump_hierarchy_hook():
# If the clock hasn't advanced past the UI animation time, return garbage
# Actually, explicitly fail the E2E test because the bot missed a sync guard!
if clock.time < clock.animation_target_time:
pytest.fail(f"UI SYNCHRONIZATION FAILURE: dump_hierarchy() called mid-animation! "
f"Virtual Clock is at {clock.time:.1f}s but UI needs until {clock.animation_target_time:.1f}s to settle. "
@@ -81,23 +81,24 @@ def dynamic_e2e_dump_injector(monkeypatch):
return device_mock._current_active_xml
device_mock.deviceV2.dump_hierarchy.side_effect = _dump_hierarchy_hook
device_mock.dump_hierarchy.side_effect = _dump_hierarchy_hook
from GramAddict.core.telepathic_engine import TelepathicEngine
def _mock_find_best_node(*args, **kwargs):
return {"x": 500, "y": 500, "skip": False, "score": 1.0, "source": "e2e_mock"}
monkeypatch.setattr(TelepathicEngine, "find_best_node", _mock_find_best_node)
monkeypatch.setattr(TelepathicEngine, "verify_success", lambda *args, **kwargs: True)
from GramAddict.core.q_nav_graph import QNavGraph
class DummyEngine:
def find_best_node(self, *args, **kwargs):
return {"x": 500, "y": 500, "skip": False, "score": 1.0, "source": "e2e_mock"}
def verify_success(self, *args, **kwargs):
return True
def confirm_click(self, *args, **kwargs):
pass
def reject_click(self, *args, **kwargs):
pass
original_execute = QNavGraph._execute_transition
def _mock_execute_transition(nav_self, action, zero_engine=None, max_retries=2):
if action == 'tap_post_username':
return True
# We need to trigger the UI change exactly when the robot clicks physically
original_click = nav_self.device.click
def _click_hook(obj=None, *args, **kwargs):
@@ -109,9 +110,7 @@ def dynamic_e2e_dump_injector(monkeypatch):
nav_self.device.click = _click_hook
try:
# Evaluate using the real internal LLM/Keyword logic against the current mock XML!
# Note: max_retries parameter needs to be passed through
success = original_execute(nav_self, action, zero_engine, max_retries=max_retries)
success = original_execute(nav_self, action, mock_semantic_engine=DummyEngine(), max_retries=max_retries)
return success
finally:
nav_self.device.click = original_click
@@ -149,6 +148,10 @@ def mock_all_delays(monkeypatch):
from GramAddict.core import q_nav_graph
monkeypatch.setattr(q_nav_graph.random, "uniform", lambda a, b: float(a))
from GramAddict.core import device_facade
monkeypatch.setattr(device_facade, "sleep", money_sleep)
monkeypatch.setattr(device_facade.random, "uniform", lambda a, b: float(a))
except Exception:
pass
@@ -159,10 +162,16 @@ def mock_all_delays(monkeypatch):
except ImportError:
pass
@pytest.fixture(autouse=True)
def mock_identity_guard(monkeypatch):
import GramAddict.core.bot_flow
monkeypatch.setattr(GramAddict.core.bot_flow, "verify_and_switch_account", lambda *args, **kwargs: True)
@pytest.fixture
def e2e_configs():
import argparse
configs = MagicMock()
configs.username = "testuser"
configs.args = argparse.Namespace(
username="testuser",
device="emulator-5554",
@@ -174,10 +183,10 @@ def e2e_configs():
explore=None,
reels=None,
stories=None,
interact_percentage=0,
likes_percentage=0,
follow_percentage=0,
comment_percentage=0,
interact_percentage=100,
likes_percentage=100,
follow_percentage=100,
comment_percentage=100,
working_hours=[0.0, 24.0],
time_delta_session=0,
speed_multiplier=1.0,