|
1 | 1 | """Behavioral adversarial fixtures for ``_TOOL_RESULT_DISPATCH`` predicate overlap. |
2 | 2 |
|
3 | | -Structural priority guards live in ``test_tool_dispatch_ordering.py``. |
4 | | -These tests construct ``toolUseResult`` JSON that satisfies multiple predicates |
5 | | -and assert the classified winner via ``_parse_tool_result`` (highest priority). |
| 3 | +Overlap blobs and invariant tables live in ``test_tool_dispatch_ordering.py``. |
| 4 | +These tests assert classified output via ``_parse_tool_result``. |
6 | 5 | """ |
7 | 6 |
|
8 | 7 | from __future__ import annotations |
|
12 | 11 |
|
13 | 12 | import pytest |
14 | 13 |
|
15 | | -from tests.test_tool_dispatch_ordering import ORDERING_INVARIANT_IDS, ORDERING_INVARIANTS |
| 14 | +from models.tool_results import is_file_write_tool_result, is_task_message_tool_result |
| 15 | +from tests.test_tool_dispatch_ordering import ( |
| 16 | + ORDERING_INVARIANT_IDS, |
| 17 | + ORDERING_INVARIANTS, |
| 18 | + OVERLAP_BLOBS, |
| 19 | +) |
16 | 20 | from utils import tool_dispatch |
17 | | -from utils.tool_dispatch import _TOOL_RESULT_DISPATCH, _parse_tool_result |
18 | | - |
19 | | -# Overlap blobs: keys chosen so both predicates in each ORDERING_INVARIANTS pair match. |
20 | | -PLAN_FILE_WRITE_OVERLAP: dict[str, object] = { |
21 | | - "plan": {"name": "sprint-plan", "steps": ["index", "search", "render"]}, |
22 | | - "filePath": ".cursor/plans/week28.md", |
23 | | - "content": "Plan body that would also satisfy file_write.", |
24 | | -} |
25 | | - |
26 | | -TASK_MESSAGE_RETRIEVAL_OVERLAP: dict[str, object] = { |
27 | | - "task_id": "task-overlap-retrieval", |
28 | | - "message": "polling retrieval", |
29 | | - "retrieval_status": "found", |
30 | | - "task": {"task_id": "task-overlap-retrieval", "description": "subagent scan"}, |
31 | | -} |
32 | | - |
33 | | -TASK_MESSAGE_COMPLETED_OVERLAP: dict[str, object] = { |
34 | | - "agentId": "agent-overlap-completed", |
35 | | - "totalDurationMs": 3200, |
36 | | - "totalTokens": 900, |
37 | | - "status": "completed", |
38 | | - "message": "task finished", |
39 | | -} |
| 21 | +from utils.tool_dispatch import _TOOL_RESULT_DISPATCH, _parse_tool_result, _winning_dispatch_entry |
40 | 22 |
|
41 | | -TASK_MESSAGE_ASYNC_OVERLAP: dict[str, object] = { |
42 | | - "agentId": "agent-overlap-async", |
43 | | - "isAsync": True, |
44 | | - "description": "explore auth handlers", |
45 | | - "message": "task launched", |
46 | | -} |
| 23 | +PLAN_FILE_WRITE_OVERLAP = OVERLAP_BLOBS["plan_before_file_write"] |
| 24 | +TASK_MESSAGE_RETRIEVAL_OVERLAP = OVERLAP_BLOBS["task_message_before_task_retrieval"] |
| 25 | +TASK_MESSAGE_COMPLETED_OVERLAP = OVERLAP_BLOBS["task_message_before_task_completed"] |
| 26 | +TASK_MESSAGE_ASYNC_OVERLAP = OVERLAP_BLOBS["task_message_before_task_async"] |
47 | 27 |
|
48 | 28 | # Narrow retrieval shape: only the downstream predicate matches (no task_id/message). |
49 | 29 | TASK_RETRIEVAL_NARROW: dict[str, object] = { |
50 | 30 | "retrieval_status": "pending", |
51 | 31 | "task": {"task_id": "task-narrow", "description": "wait for result"}, |
52 | 32 | } |
53 | 33 |
|
| 34 | +FILE_WRITE_TASK_MESSAGE_OVERLAP: dict[str, object] = { |
| 35 | + "message": "status line on a write result", |
| 36 | + "filePath": "/tmp/example.txt", |
| 37 | + "content": "file body", |
| 38 | +} |
| 39 | + |
54 | 40 | AssertWinner = Callable[[dict[str, object]], None] |
55 | 41 |
|
56 | 42 |
|
@@ -119,6 +105,19 @@ def test_task_retrieval_narrow_shape_without_task_message_keys() -> None: |
119 | 105 | assert result.get("task_id") == "task-narrow" |
120 | 106 |
|
121 | 107 |
|
| 108 | +def test_file_write_beats_task_message_when_both_match() -> None: |
| 109 | + """Regression: broad task_message must not outrank earlier shapes via priority.""" |
| 110 | + blob = FILE_WRITE_TASK_MESSAGE_OVERLAP |
| 111 | + assert is_file_write_tool_result(blob) |
| 112 | + assert is_task_message_tool_result(blob) |
| 113 | + winner = _winning_dispatch_entry(blob) |
| 114 | + assert winner is not None |
| 115 | + assert winner.id == "file_write" |
| 116 | + result = _parse_tool_result(blob) |
| 117 | + assert result is not None |
| 118 | + assert result["result_type"] == "file_write" |
| 119 | + |
| 120 | + |
122 | 121 | def test_inverted_plan_file_write_priority_misclassifies_overlap( |
123 | 122 | monkeypatch: pytest.MonkeyPatch, |
124 | 123 | ) -> None: |
@@ -146,3 +145,4 @@ def test_ordering_invariants_have_adversarial_coverage() -> None: |
146 | 145 | assert len(ORDERING_INVARIANTS) == len(ORDERING_INVARIANT_IDS) |
147 | 146 | assert len(ORDERING_INVARIANT_IDS) == len(_INVARIANT_BEHAVIOR) |
148 | 147 | assert set(_INVARIANT_BEHAVIOR.keys()) == set(ORDERING_INVARIANT_IDS) |
| 148 | + assert set(OVERLAP_BLOBS.keys()) == set(ORDERING_INVARIANT_IDS) |
0 commit comments