fix(feed): resolve home feed back-button scroll-to-top trap

- Separated obstacle detection from feed marker validation
- Prevented blind BACK button presses when markers are missing mid-scroll
- Added TDD verification for feed navigation stability
- Cleaned up debug artifacts and temporary test output
This commit is contained in:
2026-04-21 02:00:01 +02:00
parent 2c6404f387
commit 0a02e901b6
37 changed files with 311 additions and 274 deletions

View File

@@ -81,7 +81,7 @@ class TestBotFlowEdgeCases:
_run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session_state, "HomeFeed", cognitive_stack)
# It should trigger device.press("back") and then _humanized_scroll
device.deviceV2.press.assert_called_with("back")
device.press.assert_called_with("back")
assert mock_scroll.call_count >= 1
@patch('GramAddict.core.bot_flow.random.random', return_value=0.5)

View File

@@ -45,7 +45,7 @@ def test_fsd_handles_persistent_survey_modal():
xml_path = os.path.join(FIXTURE_DIR, "survey_modal.xml")
with open(xml_path, "r") as f:
alien_xml = f.read()
device.deviceV2.dump_hierarchy.return_value = alien_xml
device.dump_hierarchy.return_value = alien_xml
with patch('GramAddict.core.bot_flow.sleep'), \
patch('GramAddict.core.bot_flow._humanized_scroll'), \
@@ -56,5 +56,5 @@ def test_fsd_handles_persistent_survey_modal():
# VERIFICATION:
# Handler should have called Telepathic after 2 misses
assert mock_telepathic.find_best_node.called
assert device.deviceV2.click.called
assert device.click.called
assert result != "CONTEXT_LOST"

View File

@@ -16,8 +16,8 @@ def test_tap_home_tab_recovery_from_homescreen():
mock_device._get_current_app.return_value = "app.lawnchair"
# 2. Mock DeviceV2 responses
mock_device.deviceV2.dump_hierarchy.return_value = "<hierarchy />"
mock_device.deviceV2.app_start.return_value = True
mock_device.dump_hierarchy.return_value = "<hierarchy />"
mock_device.app_start.return_value = True
# 3. Initialize NavGraph
graph = QNavGraph(mock_device)
@@ -42,4 +42,4 @@ def test_tap_home_tab_recovery_from_homescreen():
# 6. Assertion
assert not success, "Navigation should fail gracefully when context cannot be recovered"
assert mock_device.deviceV2.app_start.called, "Should have force-started the app when context was lost"
assert mock_device.app_start.called, "Should have force-started the app when context was lost"

View File

@@ -12,7 +12,7 @@ class TestQNavGraphEdgeCases:
def setup_graph(self):
self.device = MagicMock()
self.device.app_id = "com.instagram.android"
self.device.deviceV2.info = {"screenOn": True}
self.device.info = {"screenOn": True}
self.device.dump_hierarchy.return_value = '<hierarchy><node package="com.instagram.android" /></hierarchy>'
self.device._get_current_app = MagicMock(return_value="com.instagram.android")

View File

@@ -21,10 +21,7 @@ class TestTrapEscape(unittest.TestCase):
mock_device.app_id = "com.instagram.android"
mock_device._get_current_app.return_value = "com.instagram.android"
dump_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../debug/xml_dumps/manual_interrupt__2026-04-18_16-09-11.xml'))
with open(dump_path, 'r', encoding='utf-8') as f:
trap_xml = f.read()
trap_xml = "<hierarchy><node resource-id='modal_trap' /></hierarchy>"
current_xml = [trap_xml]
# Dynamic dump that changes after click
@@ -60,8 +57,8 @@ class TestTrapEscape(unittest.TestCase):
# 3. Assertions
# The new SAE/nav_graph behavior explicitly presses BACK when 'tap_home_tab' fails after all retries
self.assertTrue(mock_device.deviceV2.press.called, "Trap guard did not autonomously press BACK to escape the sub-view!")
called_key = mock_device.deviceV2.press.call_args_list[0][0][0]
self.assertTrue(mock_device.press.called, "Trap guard did not autonomously press BACK to escape the sub-view!")
called_key = mock_device.press.call_args_list[0][0][0]
self.assertEqual(called_key, "back")
print("TDD SUCCESS: Autonomous Backend fallback confirmed.")