77of compile errors).
88
99PR-17 introduced ``_tool_error: bool`` as the authoritative flag.
10- ``is_tool_error_result(result)`` checks the sentinel first and falls
11- back to the legacy ``error`` key.
12-
13- **v1.10.0 (PR-24)**: the legacy fallback now emits
14- ``DeprecationWarning`` to nudge external dispatcher integrations off
15- the brittle heuristic. The fallback is removed entirely in v2.0.
10+ ``is_tool_error_result(result)`` checks the sentinel; v1.10.0 emitted
11+ a ``DeprecationWarning`` for the legacy ``"error" in result`` fallback;
12+ **v2.0 (PR-25) removed the fallback entirely** — only the explicit
13+ sentinel marks failure.
1614
1715Tests cover:
1816 * ``is_tool_error_result`` truth table (sentinel-True, sentinel-False,
19- no-error-key, non-dict input). The legacy fallback paths are
20- tested separately so the ``DeprecationWarning`` is asserted at
21- its emission site.
22- * Legacy ``"error"`` key still classifies as an error AND emits
23- ``DeprecationWarning`` (v1.10.0).
24- * Sentinel-driven results never emit ``DeprecationWarning``.
17+ no-error-key, non-dict input, AND a bare ``"error"`` key — which
18+ no longer marks failure post-v2.0).
2519 * Dispatcher synthetic errors carry the sentinel.
2620 * The agent loop (``tdpilot_api_agent``) imports + uses the helper.
2721 * ``tool_batch`` imports + uses the helper.
6458 ({"_tool_error" : 0 }, False ),
6559 ({"_tool_error" : "" }, False ),
6660 ({"_tool_error" : None }, False ),
61+ # v2.0 (PR-25): a bare ``error`` key no longer marks failure —
62+ # the sentinel is the only signal. Handlers that emit
63+ # ``{"error": "..."}`` without the sentinel are silently
64+ # treated as success. Pre-v2.0 these classified as True via
65+ # the legacy heuristic; v1.10.0 emitted DeprecationWarning;
66+ # v2.0 removed the fallback entirely.
67+ ({"error" : "Unknown tool" }, False ),
68+ ({"error" : "" }, False ),
6769 # No sentinel, no error key.
6870 ({"ok" : True , "path" : "/project1" }, False ),
6971 ({}, False ),
7577 ],
7678)
7779def test_is_tool_error_result_truth_table (result , expected ):
78- """Sentinel-driven cases must never emit a warning."""
80+ """No path through ``is_tool_error_result`` should emit a warning
81+ in v2.0 — the legacy ``DeprecationWarning`` was removed alongside
82+ the fallback. ``simplefilter('error')`` is kept as a regression
83+ guard against accidentally re-introducing one."""
7984 with warnings .catch_warnings ():
80- warnings .simplefilter ("error" ) # any DeprecationWarning fails the test
85+ warnings .simplefilter ("error" )
8186 assert disp .is_tool_error_result (result ) is expected
8287
8388
@@ -87,47 +92,6 @@ def test_tool_error_key_constant_is_dunder_underscore():
8792 assert disp .TOOL_ERROR_KEY == "_tool_error"
8893
8994
90- # ---------------------------------------------------------------------------
91- # v1.10.0 (PR-24) — legacy "error"-key fallback emits DeprecationWarning.
92- # These cases used to live in the truth-table parametrize above; they were
93- # extracted here so the warning surface is asserted at its emission site.
94- # In v2.0 these tests flip to expecting `False` and the warning assertion
95- # goes away (the fallback is removed entirely).
96- # ---------------------------------------------------------------------------
97-
98-
99- @pytest .mark .parametrize (
100- "result" ,
101- [
102- {"error" : "Unknown tool" },
103- {"error" : "" }, # empty string still triggers (key-presence semantics)
104- ],
105- )
106- def test_legacy_error_key_classifies_as_error_with_deprecation_warning (result ):
107- with pytest .warns (DeprecationWarning , match = "legacy 'error' key" ):
108- assert disp .is_tool_error_result (result ) is True
109-
110-
111- def test_sentinel_path_emits_no_deprecation_warning ():
112- """Sentinel-driven classification (the new convention) must stay
113- silent — only the legacy fallback is deprecated."""
114- with warnings .catch_warnings ():
115- warnings .simplefilter ("error" ) # any DeprecationWarning fails the test
116- assert disp .is_tool_error_result ({"_tool_error" : True }) is True
117- assert disp .is_tool_error_result ({"_tool_error" : False }) is False
118- assert disp .is_tool_error_result ({"_tool_error" : True , "error" : "x" }) is True
119- assert disp .is_tool_error_result ({"_tool_error" : False , "error" : "x" }) is False
120-
121-
122- def test_no_warning_on_no_error_key ():
123- """A dict with neither sentinel nor error key returns False
124- silently — there's nothing to deprecate."""
125- with warnings .catch_warnings ():
126- warnings .simplefilter ("error" )
127- assert disp .is_tool_error_result ({"ok" : True }) is False
128- assert disp .is_tool_error_result ({}) is False
129-
130-
13195# ---------------------------------------------------------------------------
13296# Dispatcher synthetic errors carry the sentinel
13397# ---------------------------------------------------------------------------
0 commit comments