feat(navigation): brique login visuel OCR-ancre + action navigate au replay
- core/navigation/ : visual_verifier (presence=OCR, role=VLM ancre sur tokens), grounding (OCR-anchor first, VLM fallback, cache coords valide par la vue), visual_login (verify_before/after, DETTE-023), action_resolver (pont runtime) - api_stream/replay_engine : dispatch action navigate server-side, never-fail -> needs_review, import depuis core.navigation (boot 5005 garanti) - 131 tests verts (wiring boot, e2e handler, unit modules) Chantier Qwen 01-02/07/2026, revue croisee Claude (plan deploy v2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
62
tests/unit/test_navigate_wiring.py
Normal file
62
tests/unit/test_navigate_wiring.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""Boot non-regression test for navigate wiring — catches import/regression bugs.
|
||||
|
||||
This test would have caught the ImportError where _handle_navigate_action
|
||||
was incorrectly imported from replay_engine instead of core/navigation.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class TestApiStreamImports:
|
||||
"""(1) api_stream must import without error."""
|
||||
|
||||
def test_import_api_stream(self):
|
||||
from agent_v0.server_v1 import api_stream
|
||||
assert api_stream is not None
|
||||
|
||||
|
||||
class TestAllowedActionTypes:
|
||||
"""(2) 'navigate' must be in both _ALLOWED and _SERVER_SIDE."""
|
||||
|
||||
def test_navigate_in_allowed(self):
|
||||
from agent_v0.server_v1.replay_engine import _ALLOWED_ACTION_TYPES
|
||||
assert "navigate" in _ALLOWED_ACTION_TYPES
|
||||
|
||||
def test_navigate_in_server_side(self):
|
||||
from agent_v0.server_v1.replay_engine import _SERVER_SIDE_ACTION_TYPES
|
||||
assert "navigate" in _SERVER_SIDE_ACTION_TYPES
|
||||
|
||||
|
||||
class TestNavigateHandlerCallable:
|
||||
"""(3) _handle_navigate_action must be callable with correct signature."""
|
||||
|
||||
def test_handler_imported_from_core_navigation(self):
|
||||
from core.navigation import _handle_navigate_action
|
||||
assert callable(_handle_navigate_action)
|
||||
|
||||
def test_handler_imported_in_api_stream(self):
|
||||
from agent_v0.server_v1 import api_stream
|
||||
handler = api_stream._handle_navigate_action
|
||||
assert callable(handler)
|
||||
|
||||
def test_handler_signature(self):
|
||||
"""Signature: (action: dict, replay_state: dict, session_id: str) -> bool."""
|
||||
from core.navigation import _handle_navigate_action
|
||||
import inspect
|
||||
sig = inspect.signature(_handle_navigate_action)
|
||||
params = list(sig.parameters.keys())
|
||||
assert params == ["action", "replay_state", "session_id"]
|
||||
assert sig.return_annotation == bool
|
||||
|
||||
|
||||
class TestDispatchBlockExists:
|
||||
"""Verify the navigate dispatch block is wired in api_stream."""
|
||||
|
||||
def test_navigate_dispatch_reference(self):
|
||||
"""Source must contain the navigate dispatch elif block."""
|
||||
import agent_v0.server_v1.api_stream as mod
|
||||
source = inspect.getsource(mod)
|
||||
assert "type_ == \"navigate\"" in source
|
||||
|
||||
|
||||
import inspect
|
||||
Reference in New Issue
Block a user