Commit ab23ffa
fix(code-mode): address round-2 review findings
Implements the 4 real bugs, 3 doc fixes, and 3 test gaps identified by
the second-pass review of the persistence + blocklist work.
Bugs
----
* ``_API_POST_BLOCKED_PREFIXES``: removed the ``config/scene/config/``
entry. The error message it returned told the LLM to use
``ha_config_set_scene``, which does not exist in the registered tool
catalogue (no scene-related ``set`` tool exists at all). Blocking the
REST path without a validated alternative was net-negative — it just
removed capability. The block can come back when a wrapping tool
lands; comment in the code records that decision.
* ``_save_saved_tools`` now returns ``bool`` and the persistence
failure path is no longer silent. The save_as branch in
``ha_manage_custom_tool`` rolls back the in-memory cache on a False
return and surfaces a ``save_warning`` field in the response, with
``saved_as`` reset to ``None``. ``_delete_saved_tool`` also rolls
back on failure and returns ``{"error": ...}`` instead of the prior
misleading ``{"deleted": True}``. Persistence was the documented
contract of this PR, so the prior "log at WARNING and lie with
success: True" behaviour was a real reliability gap, not just
cosmetic.
* ``_load_saved_tools`` distinguishes ``FileNotFoundError`` (legitimate
"starting empty") from other ``OSError``s (genuine I/O failure on
an existing file). When the latter fires, a new module-level
``_saved_tools_load_failed`` flag suppresses subsequent persistence
for the session — preventing a transient ``PermissionError`` at
startup from cascading into "next save wipes out the unreadable
file with empty content" data loss. The flag is cleared on the
next successful load.
* The audit-log line now uses ``sorted(map(str, data.keys()))`` instead
of ``sorted(data.keys())``. Monty allows mixed-type dict keys, and
the previous form would raise ``TypeError`` on the first
``api_post("/foo", {1: "x", "a": "y"})`` invocation, propagating
through the audit-log step into the catch-all ``except Exception``
and surfacing as a generic "api_post failed" with no hint that the
audit-log step was the real culprit.
Schema-version contract honoured
--------------------------------
``_load_saved_tools`` now actually reads ``data.get("version")`` and
refuses to interpret anything that isn't ``_SAVED_TOOLS_SCHEMA_VERSION``
(currently 1). The prior code wrote the version field but never
checked it, so a future v2 file would have been silently downgraded
to v1 semantics by current code. Mismatch sets the load-failed flag
so we don't atomically replace the unfamiliar file with our v1
shape.
Docs
----
* ``docs/beta.md`` audit-log paragraph now shows the correct
``configuration.yaml`` / ``logger.logs.<name>: debug`` snippet
instead of the previous bogus "set ``logger
ha_mcp.tools.tools_code: debug`` in your add-on configuration."
(HA's logger integration lives in configuration.yaml, not addon
options.)
* The "blocked endpoints" paragraph in beta.md was updated to match
the now-shorter ``_API_POST_BLOCKED_PREFIXES`` and explicitly notes
the scene exception.
* The stale ``ha_config_set_scene`` reference in the
``ha_config_set_yaml`` Known Limitations section (preexisting) was
also removed since I was in the file.
* The ``_MAX_SAVED_TOOLS`` constant comment now mentions both load-
and save-time enforcement; the ``_SAVED_TOOLS_SCHEMA_VERSION``
comment matches reality (the load path actually consults it).
* The ``_API_POST_BLOCKED_PREFIXES`` block comment splits the
conflated rationale into two flavours (no-legitimate-use-case vs
has-wrapping-tool).
Tests
-----
* ``TestSaveSavedTools.test_returns_true_on_success`` and
``test_returns_true_when_path_unset`` pin the new bool contract.
* ``TestSchemaVersionGuard`` (3 tests) covers refusing unknown
version, missing version field, and not overwriting an unfamiliar
file.
* ``TestLoadFailedFlag`` (2 tests) covers flag-clear-on-success and
save-skipped-when-set.
* ``TestHydrationRoundTrip`` (2 tests) covers the load→modify→save→
reload lifecycle, which the original suite was missing.
* ``TestSaveCapEnforcement`` (2 tests) covers the load-side cap and
pins that ``_save_saved_tools`` itself does not self-cap (the
registration-site code is the upper-bound guard).
24 unit tests now pass (was 13). Lint/mypy/ast-grep clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent a08348d commit ab23ffa
3 files changed
Lines changed: 393 additions & 38 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
| 58 | + | |
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
| |||
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
88 | | - | |
| 88 | + | |
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
94 | | - | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
95 | 107 | | |
96 | 108 | | |
97 | 109 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
60 | 70 | | |
61 | 71 | | |
62 | 72 | | |
| |||
75 | 85 | | |
76 | 86 | | |
77 | 87 | | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | 88 | | |
84 | 89 | | |
85 | 90 | | |
| |||
266 | 271 | | |
267 | 272 | | |
268 | 273 | | |
269 | | - | |
270 | | - | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
271 | 278 | | |
272 | 279 | | |
273 | | - | |
274 | | - | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
275 | 284 | | |
276 | 285 | | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
277 | 296 | | |
278 | 297 | | |
279 | 298 | | |
280 | 299 | | |
281 | | - | |
282 | | - | |
283 | | - | |
284 | | - | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
285 | 311 | | |
| 312 | + | |
| 313 | + | |
286 | 314 | | |
287 | 315 | | |
288 | 316 | | |
| |||
291 | 319 | | |
292 | 320 | | |
293 | 321 | | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
294 | 342 | | |
295 | | - | |
| 343 | + | |
296 | 344 | | |
297 | | - | |
| 345 | + | |
| 346 | + | |
298 | 347 | | |
299 | 348 | | |
300 | 349 | | |
| |||
308 | 357 | | |
309 | 358 | | |
310 | 359 | | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
311 | 379 | | |
312 | 380 | | |
313 | 381 | | |
| |||
353 | 421 | | |
354 | 422 | | |
355 | 423 | | |
356 | | - | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
357 | 427 | | |
358 | 428 | | |
359 | | - | |
360 | | - | |
361 | | - | |
362 | | - | |
363 | | - | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
364 | 440 | | |
365 | 441 | | |
366 | | - | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
367 | 450 | | |
368 | 451 | | |
369 | 452 | | |
| |||
387 | 470 | | |
388 | 471 | | |
389 | 472 | | |
390 | | - | |
391 | | - | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
392 | 477 | | |
393 | 478 | | |
| 479 | + | |
394 | 480 | | |
| 481 | + | |
| 482 | + | |
395 | 483 | | |
396 | 484 | | |
397 | 485 | | |
| |||
560 | 648 | | |
561 | 649 | | |
562 | 650 | | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
563 | 656 | | |
564 | 657 | | |
565 | 658 | | |
566 | | - | |
| 659 | + | |
567 | 660 | | |
568 | 661 | | |
569 | 662 | | |
| |||
670 | 763 | | |
671 | 764 | | |
672 | 765 | | |
673 | | - | |
674 | | - | |
675 | | - | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
676 | 771 | | |
677 | 772 | | |
678 | 773 | | |
| |||
685 | 780 | | |
686 | 781 | | |
687 | 782 | | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
688 | 788 | | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
689 | 800 | | |
690 | | - | |
691 | 801 | | |
692 | 802 | | |
693 | 803 | | |
| |||
1021 | 1131 | | |
1022 | 1132 | | |
1023 | 1133 | | |
| 1134 | + | |
1024 | 1135 | | |
1025 | 1136 | | |
1026 | 1137 | | |
1027 | 1138 | | |
1028 | 1139 | | |
1029 | 1140 | | |
1030 | | - | |
| 1141 | + | |
| 1142 | + | |
| 1143 | + | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
1031 | 1161 | | |
1032 | 1162 | | |
0 commit comments