Skip to content

feat: rename ha_delete_helpers_integrations → ha_remove_helpers_integrations + raise on missing target - #1424

Merged
Patch76 merged 1 commit into
homeassistant-ai:masterfrom
Patch76:feature/issue-1412
May 24, 2026
Merged

feat: rename ha_delete_helpers_integrations → ha_remove_helpers_integrations + raise on missing target#1424
Patch76 merged 1 commit into
homeassistant-ai:masterfrom
Patch76:feature/issue-1412

Conversation

@Patch76

@Patch76 Patch76 commented May 23, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Closes #1412.

Renames ha_delete_helpers_integrationsha_remove_helpers_integrations and unifies the tool's behavioural contract across all four routing paths under a single missing-target contract that raises a structured error on confirmed-absent targets.

Rename rationale

The _remove_* naming family (12 tools) all carry idempotentHint: True and operate on "make the target not-there" semantics. The previous _delete_ prefix put this tool with two other _delete_ tools that have three different not-found behaviours (no convention). Joining the _remove_* family + adding idempotentHint makes the contract explicit.

Per .gemini/styleguide.md § Breaking Changes, "Tool renaming with clear migration path" is explicitly listed under NOT Breaking (alongside tool consolidation, refactoring, parameter changes, and return-value restructuring). The migration path here is the conventional-commit rename in this PR.

Missing-target contract

A target that is confirmed absent raises a structured error rather than returning silent success — the typo / hallucinated-identifier case surfaces immediately at the caller layer instead of being masked as a false success. Error codes follow the target shape per path:

Path helper_type Confirmed-absent path Error code Other failure modes
1 SIMPLE input_button, input_boolean, … state + registry both empty (incl. never-existed targets where get_entity_state 404s) ENTITY_NOT_FOUND unique_id missing but registry still has entry → SERVICE_CALL_FAILED
2 FLOW utility_meter, template, … step-1 not_in_registry ENTITY_NOT_FOUND step-3 TOCTOU 404 on resolved entry_id → RESOURCE_NOT_FOUND; no_config_entry (YAML) → RESOURCE_NOT_FOUND; lookup_failed (transient) → WEBSOCKET_DISCONNECTED; bare_id_not_supportedENTITY_NOT_FOUND
3 Direct entry None HA REST returns 404 (HomeAssistantAPIError.status_code == 404) RESOURCE_NOT_FOUND non-404 API errors → exception_to_structured_error
4 Subentry config_subentry HA WS structured error code: "not_found" only (generic message substring match dropped per Gemini review to avoid colliding with unrelated "X not found" errors) RESOURCE_NOT_FOUND other WS failure modes → SERVICE_CALL_FAILED

ENTITY_NOT_FOUND for entity-shaped targets (Path 1, Path 2 step-1) matches the existing bare_id_not_supported branch within Path 2 and sibling ha_remove_entity. RESOURCE_NOT_FOUND for config-shaped targets (Path 2 step-3, Path 3, Path 4) matches Path 2's existing no_config_entry branch and sibling ha_config_remove_automation.

Idempotency at the contract level still holds: N calls produce the same response. The earlier draft of this PR returned silent success on absent — that conflated idempotent ("no additional effect on repeat") with tolerant ("absent → success"); only the first is part of the contract. Transient connectivity errors keep their separate codes (WEBSOCKET_DISCONNECTED, CONNECTION_ERROR) so retry logic can branch on those independently.

Surface touched

  • src/ha_mcp/tools/tools_integrations.py: rename + idempotentHint: True annotation + four per-path raise branches on confirmed-absent + docstring with full MISSING-TARGET contract.
  • src/ha_mcp/tools/tools_groups.py: 3 cross-reference docstrings.
  • ~130 mechanical rename occurrences across 21 test files + 1 cleanup utility + README.
  • 6 unit tests flipped from assert fallback_used="already_deleted" to pytest.raises(ToolError) with per-path code (5 in test_tools_integrations.py, 1 in test_config_subentries_folded.py); the pre-existing negative-assertion tests ("already_deleted" not in json.dumps(err)) stay green and continue to pin the no-mislabeling rule across 404 and non-404 paths.
  • 2 E2E tests flipped to assert the structured failure dict.
  • site/src/data/tools.json + README.md + homeassistant-addon/DOCS.md regenerated via scripts/extract_tools.py.
  • CHANGELOG.md historical entries referencing the old name intentionally untouched.

Type of change

  • 🐛 Bug fix
  • ✨ New feature
  • 📚 Documentation
  • 🔧 Maintenance/refactor
  • 🧪 Tests only
  • 💥 Breaking change

Testing

  • I have tested these changes with a LLM agent
  • All automated tests pass (uv run pytest)
  • Code follows style guidelines (uv run ruff check)

Local verification:

  • ruff check src/ tests/ — All checks passed
  • ruff format on changed files
  • mypy src/ha_mcp/tools/tools_integrations.py — no issues
  • 76 unit tests in test_tools_integrations.py + test_config_subentries_folded.py pass after rework

Checklist

  • PR title follows the convention used in repo (semver-release Angular parser)
  • Commits follow conventional commits format
  • Code is properly tested (or tests-not-needed label is added)
  • Documentation is updated if needed
  • No unrelated changes are included

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the helper deletion tool by renaming it to ha_remove_helpers_integrations and establishing a robust idempotent post-state contract. By ensuring that requests to remove non-existent resources return a success status, the tool becomes more reliable for automated agents. The changes include comprehensive updates to documentation, test suites, and internal tool routing logic.

Highlights

  • Tool Rename: Renamed the tool ha_delete_helpers_integrations to ha_remove_helpers_integrations to align with naming conventions.
  • Idempotent Contract: Implemented a unified idempotent post-state contract across all four routing paths, ensuring that attempts to remove already-absent targets return a success response.
  • Tool Annotation: Added idempotentHint: True to the tool definition to make the new contract explicit.
  • Documentation: Updated README, DOCS.md, and tool metadata to reflect the rename and new behavior.
  • Testing: Updated numerous unit and E2E tests to use the new tool name and verify the idempotent behavior.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request renames the ha_delete_helpers_integrations tool to ha_remove_helpers_integrations and implements an idempotent-success contract across all deletion paths, ensuring that requests to remove already absent targets return a successful response instead of an error. Feedback was provided to refine the error message string matching for subentry deletions by using more specific substrings to prevent false positives, in accordance with repository guidelines.

Comment thread src/ha_mcp/tools/tools_integrations.py Outdated
Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 23, 2026
Drop the generic ``"not found" in error_msg.lower()`` substring fallback
from the Path 4 (config subentry) idempotent-success branch. The check
now relies solely on the structured ``error_code == "not_found"`` from
the HA ``config_entries/subentries/delete`` response.

Generic substring matching was too permissive: HA error messages like
"Repository not found" or "Integration not found" returned by unrelated
failure modes would have silently classified as idempotent success,
masking real errors. The structured ``code: "not_found"`` is the
contract HA uses for this operation; if a future HA version emits a
different code, the tool surfaces SERVICE_CALL_FAILED rather than
mis-classifying — the safer default for a destructive operation.

Adopts Gemini Code Assist finding on PR homeassistant-ai#1424 (inline thread on the
substring check). Existing Path 4 unit test
(test_delete_helpers_integrations_subentry_not_found_is_idempotent)
mocks the response with ``code: "not_found"`` so it remains the canonical
contract pin; no test changes needed. Sibling-sweep across the other
three idempotent branches confirmed they already key on structured
discriminators (Path 1: state+registry probes, Path 2: lookup-helper
reason field, Path 3: HomeAssistantAPIError.status_code).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Patch76

Patch76 commented May 23, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request renames the ha_delete_helpers_integrations tool to ha_remove_helpers_integrations and implements an idempotent-success contract across its various routing paths, ensuring that targets already absent from Home Assistant return a successful response. Feedback focuses on refining exception handling to align with repository standards; specifically, several broad except Exception blocks need to be narrowed to prevent masking programming errors, and an API error catch in the simple helper path should be restricted to 404 status codes to correctly identify absent entities.

Comment thread src/ha_mcp/tools/tools_integrations.py
Comment thread src/ha_mcp/tools/tools_integrations.py
Comment thread src/ha_mcp/tools/tools_integrations.py
@Patch76

Patch76 commented May 23, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request renames the ha_delete_helpers_integrations tool to ha_remove_helpers_integrations and implements a comprehensive idempotent-success contract across all deletion paths (Simple, Flow, Direct, and Subentry). The changes ensure that targets already absent from Home Assistant return a success state rather than an error. Feedback focuses on maintaining consistency by removing redundant logging when delegating to centralized error handlers and ensuring the response schema for config subentry deletion matches the other logic branches by including missing keys like entry_id and entity_ids.

Comment thread src/ha_mcp/tools/tools_integrations.py Outdated
Comment thread src/ha_mcp/tools/tools_integrations.py Outdated
Comment thread src/ha_mcp/tools/tools_integrations.py Outdated
Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 23, 2026
…ant-ai#1424

F1 + F2: drop redundant logger.error calls in _delete_direct_entry's
HomeAssistantAPIError-non-404 branch and Exception fallback branch.
exception_to_structured_error emits a structured ToolError carrying
the right ErrorCode + message but deliberately does NOT log at ERROR
for classified failures — by design in helpers.py (only
ErrorCode.INTERNAL_ERROR triggers logger.exception there, to avoid
duplicate ERROR-log noise on classified failures). The local
logger.error therefore duplicated the information surface that the
structured ToolError already carries and went against the design
intent.

F3: add entry_id, entity_ids, require_restart keys to Path 4 (config
subentry) idempotent return shape so it matches the schema used by
the Path 1/2/3 idempotent returns. Callers that branch on these
fields (e.g. to determine whether HA needs a restart, or to enumerate
removed entity_ids) now see a consistent contract across all four
idempotent branches.

Net change: -2 / +3 lines in src/ha_mcp/tools/tools_integrations.py.
74 unit tests pass unchanged across test_tools_integrations.py (52) +
test_config_subentries_folded.py (22).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Patch76

Patch76 commented May 23, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request renames the ha_delete_helpers_integrations tool to ha_remove_helpers_integrations and implements an idempotent-success contract across all deletion paths. The tool now returns a successful response with a specific fallback indicator when a target is already absent, specifically handling 404 errors from the Home Assistant API and missing registry entries. Safety annotations were updated to include idempotentHint, and comprehensive updates were applied to documentation and tests to reflect these changes. I have no feedback to provide.

@Patch76

Patch76 commented May 23, 2026

Copy link
Copy Markdown
Member Author

Implementation Summary

Choices Made:

  • Original choice: Path (c) from issue [FEATURE] decide ha_delete_helpers_integrations idempotent dual-success contract #1412 — rename ha_delete_helpers_integrationsha_remove_helpers_integrations, add idempotentHint: True, and unify all four routing paths under an idempotent-success contract that returned success=True, fallback_used="already_deleted" on confirmed-absent.
  • Reworked under review pressure to Path (b) — kp13's review identified that success=True on a confirmed-absent target is a silent false-success for wrappers that branch on success: a typo'd or hallucinated identifier would surface as a successful removal while the real target remained. The original framing also conflated idempotent ("N calls = same result") with tolerant ("absent → success"). All five already_deleted branches were flipped to raise_tool_error with structured codes; idempotency at the contract level still holds (N calls = same raise).
  • Per-target-shape error codes rather than uniform RESOURCE_NOT_FOUND. Empirically Path 2 already differentiated internally (bare_id_not_supportedENTITY_NOT_FOUND, no_config_entryRESOURCE_NOT_FOUND), so the new branches were classified the same way:
    • Path 1 SIMPLE state-gone + registry-empty (entity-shape) → ENTITY_NOT_FOUND. Matches sibling ha_remove_entity.
    • Path 2 FLOW not_in_registry (entity-shape) → ENTITY_NOT_FOUND. Matches Path 2's existing bare_id_not_supported branch.
    • Path 2 FLOW TOCTOU 404 (resource-shape, post-resolution) → RESOURCE_NOT_FOUND with a distinct "concurrent removal" diagnostic hint (the entry WAS resolvable at step 1).
    • Path 3 Direct REST 404 (config_entry shape) → RESOURCE_NOT_FOUND.
    • Path 4 Subentry code: "not_found" (subentry shape under parent entry) → RESOURCE_NOT_FOUND.
  • Diagnostic-hint wording on each raise carries the structured "may indicate already removed, never existed, or typo. Verify with ha_search_entities() / ha_get_integration() before retrying" framing so the caller-layer (isError per MCP spec) gets the typo signal regardless of whether the wrapper surfaces error messages. Pinned by substring assertions in the raise-branch tests so future edits can't silently degrade the wording.
  • Deliberately kept (Boy-Scout-decided as out-of-scope-for-rename):
    • Internal helper method names _delete_simple_helper, _delete_flow_helper, _delete_direct_entry, _delete_config_subentry — these describe the underlying HA backend operation (HA's API uses delete), not the public tool verb.
    • "action": "delete" field in the response shape — backward compatibility for any LLM agent or downstream tool that branches on the action label.
  • Broad except Exception blocks left as-is (Gemini findings on the broad-except idiom in this module): the except ToolError: raise + except Exception → exception_to_structured_error(e, ...) pair is the idiom for outer handlers in this module — six places use it. Narrowing only the two flagged sites would create inconsistency; a repo-wide narrowing sweep is the appropriate vehicle.

Problems Encountered:

  • E2E test_helper_delete_nonexistent failed on the first push with ENTITY_NOT_FOUND instead of the documented already_deleted (pre-rework state). Root cause: Path 1's existing already_deleted short-circuit only fired when get_entity_state returned None, never when it raised HomeAssistantAPIError(status_code=404) — and HA raises 404 for never-existed entity_ids. Fix in 49e3cdd: extracted state_gone boolean to handle both falsy return AND 404 APIError. (Post-rework this fix still routes the 404 case into the confirmed-absent classification, but the result is now a structured raise rather than success.)
  • First Path 1 APIError catch was too permissive — would have classified ANY HomeAssistantAPIError (500, 401, …) as state-gone. Caught on review; narrowed to if e.status_code != 404: raise in e9e13ff. Mirrors the e.status_code == 404 guard in _delete_direct_entry.
  • Path 4 substring match "not found" in error_msg.lower() would have classified unrelated HA errors ("Repository not found", "Integration not found") as the confirmed-absent path. Tightened to structured code: "not_found" only in bf50016. The HA contract was verified live against home-assistant/core source: config_entries/subentries/delete raises with ERR_NOT_FOUND: Final = "not_found".
  • kp13's review-1 (R23) called the whole idempotent-success contract a silent false-success. Live testing against the deployed RBO instance (Phase A) confirmed empirically: master ha_delete_helpers_integrations raises on typo targets across Paths 1/2/3, sibling ha_remove_entity raises ENTITY_NOT_FOUND, ha_config_remove_automation raises RESOURCE_NOT_FOUND. The PR's pre-rework contract was the outlier, not the consolidation. Reworked in 20799d7 (impl) + 48a4f7b (tests).
  • Empirically the sibling family is not uniform on the not-found code (a side discovery of Phase A): ha_remove_zone and ha_remove_area_or_floor surface SERVICE_CALL_FAILED rather than *_NOT_FOUND. Out of scope for this PR — flagged for separate code-cleanup.
  • Ultrareview pass on the post-rework state surfaced two docstring NITs: CONNECTION_ERROR was a non-existent code name (real one is CONNECTION_FAILED per errors.py:33), and the wait parameter's "Ignored when helper_type=None" note didn't name config_subentry (Path 4 also drops wait). Both fixed + site/src/data/tools.json regenerated in 7449c43.
  • Post-rework ruff format drift on test_tools_integrations.pyruff format collapsed two multi-line function signatures back to single-line under the 88-char width. Caught by CI Ruff Lint on 7449c43; fixed in 98f6ed2.
  • kp13's review-2 surfaced two test-coverage gaps: a missing "already_deleted" not in json.dumps(err) regression pin on test_remove_helpers_integrations_subentry_other_error_surfaces_service_call_failed, and an unpinned diagnostic-hint wording on the six raise-branch tests. Both addressed in bd48061 — the diagnostic hint substring is now part of the test assertion surface on every confirmed-absent path.
  • ha_backup_create reporting drift discovered during Phase A live testing (not in scope for this PR): the tool returns success: false, code: TIMEOUT_OPERATION even when the backup actually succeeds on disk. Worth filing as a separate issue.

Suggested Improvements:

None deferred. Every NIT / Nice-to-have / While-you're-in flagged across the review cycles (Gemini Findings 1-8, kp13 reviews 1+2, ultrareview pass) was addressed in-PR per feedback_nits_are_mandatory + Boy Scout Rule. The broad-except Exception pattern flagged by Gemini Findings 1+2 is the only item not in-PR — narrowing only the two flagged sites would create inconsistency with the four other places in this module using the same idiom; the right vehicle is a file-wide or repo-wide sweep.

@Patch76
Patch76 requested a review from kingpanther13 May 23, 2026 20:18
Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 23, 2026
Drop the generic ``"not found" in error_msg.lower()`` substring fallback
from the Path 4 (config subentry) idempotent-success branch. The check
now relies solely on the structured ``error_code == "not_found"`` from
the HA ``config_entries/subentries/delete`` response.

Generic substring matching was too permissive: HA error messages like
"Repository not found" or "Integration not found" returned by unrelated
failure modes would have silently classified as idempotent success,
masking real errors. The structured ``code: "not_found"`` is the
contract HA uses for this operation; if a future HA version emits a
different code, the tool surfaces SERVICE_CALL_FAILED rather than
mis-classifying — the safer default for a destructive operation.

Adopts Gemini Code Assist finding on PR homeassistant-ai#1424 (inline thread on the
substring check). Existing Path 4 unit test
(test_delete_helpers_integrations_subentry_not_found_is_idempotent)
mocks the response with ``code: "not_found"`` so it remains the canonical
contract pin; no test changes needed. Sibling-sweep across the other
three idempotent branches confirmed they already key on structured
discriminators (Path 1: state+registry probes, Path 2: lookup-helper
reason field, Path 3: HomeAssistantAPIError.status_code).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 23, 2026
…ant-ai#1424

F1 + F2: drop redundant logger.error calls in _delete_direct_entry's
HomeAssistantAPIError-non-404 branch and Exception fallback branch.
exception_to_structured_error emits a structured ToolError carrying
the right ErrorCode + message but deliberately does NOT log at ERROR
for classified failures — by design in helpers.py (only
ErrorCode.INTERNAL_ERROR triggers logger.exception there, to avoid
duplicate ERROR-log noise on classified failures). The local
logger.error therefore duplicated the information surface that the
structured ToolError already carries and went against the design
intent.

F3: add entry_id, entity_ids, require_restart keys to Path 4 (config
subentry) idempotent return shape so it matches the schema used by
the Path 1/2/3 idempotent returns. Callers that branch on these
fields (e.g. to determine whether HA needs a restart, or to enumerate
removed entity_ids) now see a consistent contract across all four
idempotent branches.

Net change: -2 / +3 lines in src/ha_mcp/tools/tools_integrations.py.
74 unit tests pass unchanged across test_tools_integrations.py (52) +
test_config_subentries_folded.py (22).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Patch76
Patch76 marked this pull request as ready for review May 23, 2026 20:19
@Patch76
Patch76 force-pushed the feature/issue-1412 branch from a078055 to 922a2ab Compare May 23, 2026 20:19
@Patch76
Patch76 requested a review from a team May 23, 2026 20:19
@kingpanther13

Copy link
Copy Markdown
Member

Walking through Path 1 (SIMPLE) for a typo'd never-existed target — e.g. agent calls target="my_buton", helper_type="input_button" when only my_button exists:

On upstream/master (_delete_simple_helper, lines 1685–1787): registry retries 3× → no unique_id → direct-ID fallback delete fails → final get_entity_state("input_button.my_buton") raises HomeAssistantAPIError(404) (HA returns 404 for never-existed entity_ids) → caught at line 1760, logged as debug, falls through to line 1773 → raises ENTITY_NOT_FOUND.

On this PR (same method, lines 1819–1878): the 404 from that final state check now sets state_gone=True, registry verify confirms no entity, and the tool returns success=True, fallback_used="already_deleted". This is the change called out in commit 49e3cdd7: "Path 1's existing already_deleted short-circuit only fired when get_entity_state returned None, never when it raised HomeAssistantAPIError(status_code=404) — and HA raises 404 for never-existed entity_ids."

So for the typo / hallucinated-target case — agent meant my_button, called with my_buton — this PR changes behavior from "raises `ENTITY_NOT_FOUND`" to "returns `success=True`". An agent wrapper branching on `success` would report deletion succeeded while the real `my_button` is untouched. (Paths 2/3/4 newly adopt the same shape, but Path 1 is the one where existing callers see different behavior on never-existed inputs.)

Three things to make sure I'm reading the intent correctly:

  1. Is the typo / hallucinated-target case in-scope for the `confirmed absent → success` contract? My read of the PR text and the `49e3cdd7` fix is yes (never-existed and already-deleted both count as confirmed absent), but I want to verify that's intentional and not just a side-effect of fixing the e2e test failure.

  2. Is `fallback_used == "already_deleted"` the intended signal for callers to distinguish "actually removed" from "was never there"? Do any of the e2e tests or known agent harnesses currently branch on that field, or is that left to the caller?

  3. Was the prior Path 1 behavior (raise `ENTITY_NOT_FOUND` on never-existed) viewed as a bug to fix here, or as a contract being deliberately replaced? The PR notes read as the former; want to confirm I'm not misreading.

@kingpanther13 kingpanther13 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The clarifying comment above raises one design question I want resolved before merge. The rest of this review is the substantive findings from a full pass over the diff — please treat as a single bundle, not a checklist of optional nits.

Blocking — contract correctness

1. Path 4 happy-path response shape diverges from the uniform contract.
_delete_config_subentry at src/ha_mcp/tools/tools_integrations.py:1675-1684 omits entry_id, entity_ids, and require_restart on the success path. The Path 4 idempotent branch (1652-1667) includes them. The IDEMPOTENT-SUCCESS CONTRACT docstring (1223-1232) implies a uniform response shape across paths; this break is the most likely place a caller's downstream parsing chokes silently. Either add the three keys to the happy path or remove them from the idempotent branch and document the asymmetry.

2. Path 4 happy-path leaks a result passthrough key no other path returns (tools_integrations.py:1683). Drop it or hoist into the contract docstring as a Path-4-only addition.

3. Path 4 only matches error.code == "not_found" when error is a dict (tools_integrations.py:1650-1651). The narrow is correct, but there is no test that pins it — a regression that loosened to substring-matching "not found" on string-form errors would pass CI silently. Add a negative test asserting that {"success": False, "error": "not found"} raises SERVICE_CALL_FAILED and does NOT classify as idempotent.

4. Path 3 has no negative test for non-404 HomeAssistantAPIError on delete_config_entry. Paths 1, 2, and 4 each have a paired non-target-shape negative pinning the narrow; Path 3 doesn't. Add one (e.g. 500 or 401 from the delete call must surface as a structured error, not idempotent success).

5. Two test assertions are tautological in their failure mode and don't actually pin the intent.

  • tests/src/unit/test_tools_integrations.py:391-393: assert err["error"]["code"] != "ENTITY_NOT_FOUND" or "already_deleted" not in ... passes whenever the left disjunct is true, regardless of the right; a regression that leaks fallback_used into a non-ENTITY_NOT_FOUND error wouldn't fail this test. Replace with a single positive assertion on the expected code AND a separate assert "already_deleted" not in str(err).
  • tests/src/unit/test_tools_integrations.py:440-441: HomeAssistantAPIError("404 simulated") is constructed without status_code, so the test never exercises the status_code == 404 branch it claims to cover. Pass status_code=404 explicitly.

Blocking — docstring / contract accuracy

6. The IDEMPOTENT-SUCCESS CONTRACT docstring (tools_integrations.py:1223-1232) does not acknowledge the typo/never-existed equivalence on Paths 1 and 2. This is the same concern raised in the clarifying comment. Whatever the resolution there, the docstring needs to say plainly that a never-existed target (e.g. a typo'd target) is indistinguishable from an already-removed target and returns the same idempotent success — so callers reading the contract aren't surprised.

7. Verb drift across target, helper_type, subentry_id, confirm, wait Field descriptions (tools_integrations.py:1117-1188) — all still say "delete"/"deletion" while the tool verb and title are "Remove". Mixed verbs in the public schema. Fix in this PR.

8. Stale path-count comments: tools_integrations.py:1264 and 1282 both say "uniform for all three paths" after Path 4 (config_subentry) was added. Either four or three — pick one and match.

9. Stale tool-name reference in docs/superpowers/specs/2026-05-21-1288-auto-backup-design.md:234 — still says ha_delete_helpers_integrations. Rename to ha_remove_helpers_integrations to match the auto-backup decorator on the renamed method.

Blocking — error-handling

10. _get_entry_id_for_flow_helper broad except Exception (tools_integrations.py:144-148) maps KeyError/AttributeError/TypeError (i.e. programmer bugs) to lookup_failed, which the caller then converts to WEBSOCKET_DISCONNECTED — mis-labeling local bugs as transient network errors. Narrow to the exception types you actually expect from the WS client.

While you're in there (small)

  • One-line module comment somewhere near the private helpers explaining that internal _delete_* names follow the HA backend verb (HA's WS API is <type>/delete, REST is DELETE), while the public tool exposes remove. Prevents future rename drift pressure.
  • The "Combines simple-helper websocket deletion, config-entry deletion, and config-subentry deletion under one entry point with four routing paths" line (1194-1196) is "three deletion kinds in four paths" — phrasing reads as a typo. Tighten.
  • The FLOW contract bullet (1228-1230) lists no_config_entry raising RESOURCE_NOT_FOUND but doesn't mention bare_id_not_supported (raises ENTITY_NOT_FOUND); per-path contract reads as exhaustive while it isn't. Add the third FLOW failure mode or note the list isn't exhaustive.
  • The state_gone block comment at tools_integrations.py:1813-1818 restates what the next 6 lines literally do; a one-liner pointing at the never-existed-target consequence carries the load.

@Patch76

Patch76 commented May 24, 2026

Copy link
Copy Markdown
Member Author

Re: clarifying comment on Path 1 typo / hallucinated-target behavior

Intentional on all three questions. Walking through:

  1. Typo / never-existed case IS in-scope for the "confirmed absent → success" contract. Issue [FEATURE] decide ha_delete_helpers_integrations idempotent dual-success contract #1412 framing is agent-MCP idempotency, and at the HA backend layer "never existed" and "was deleted" are indistinguishable — both surface as HomeAssistantAPIError(status_code=404) on get_entity_state. The contract is "confirmed absent from HA's perspective"; HA cannot validate the target was ever real.

  2. fallback_used == "already_deleted" IS the explicit caller-signal for "this call did not change state". Agents needing to distinguish "actually removed by this call" vs "was already gone" must check externally — state history, audit log, or a pre-flight get_entity lookup. The tool does not disambiguate; that's by design.

  3. Path 1's prior ENTITY_NOT_FOUND-on-never-existed was a path-internal inconsistency, not deliberate contract. Path 1 already had an already_deleted short-circuit that fired when get_entity_state returned None, but the 404-raising branch — the path HA actually takes for never-existed entity_ids — fell through to the ENTITY_NOT_FOUND raise. Commit 49e3cdd7 makes Path 1 self-consistent; same shape Paths 2/3/4 now adopt.

The agent-wrapper concern (success-branch reports deletion when caller meant a different existing target) is real. Mitigation lives in your item 6 — the IDEMPOTENT-SUCCESS CONTRACT docstring will say plainly that "confirmed absent" includes the never-existed case and that callers needing disambiguation must do so externally. Folding into the next round, alongside the 13 other items.

Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 24, 2026
Addresses 8 of kp13's 10 numbered review items + all 4 while-you're-in
bullets on PR homeassistant-ai#1424. Items 1 and 6 (Path 4 happy-path schema
harmonization and IDEMPOTENT-SUCCESS CONTRACT docstring rewrite) are
held pending the design-clarification response in issue-comment
4527825242.

Contract / schema:
- Drop the ``result`` passthrough key from Path 4 happy-path return
  (no other path returns it). [Item 2]

Docstring / contract accuracy:
- Field descriptions for ``target``, ``helper_type``, ``subentry_id``,
  ``confirm`` switched from "delete"/"deletion" to "remove"/"removal"
  to match the public tool verb. [Item 7]
- ``uniform for all three paths`` updated to ``four`` in both confirm
  and empty/whitespace gates; Path 4 added to the empty-target gate's
  enumeration. [Item 8]
- Stale ``ha_delete_helpers_integrations`` reference in
  docs/superpowers/specs/2026-05-21-1288-auto-backup-design.md updated.
  [Item 9]

Error handling:
- Narrowed ``_get_entry_id_for_flow_helper`` broad ``except Exception``
  to ``(OSError, TimeoutError)``. KeyError/AttributeError/TypeError now
  propagate so programmer bugs surface instead of being mis-classified
  as ``WEBSOCKET_DISCONNECTED``. [Item 10]

Tests:
- Replaced the tautological OR-disjunct in
  test_simple_path_non_404_apierror_propagates with two independent
  assertions so a regression that leaks ``already_deleted`` into a
  non-``ENTITY_NOT_FOUND`` code still fails. [Item 5a]
- Pass ``status_code=404`` to ``HomeAssistantAPIError`` in
  test_simple_path_disabled_state_check_apierror_resolves_via_registry
  — the test now actually exercises the 404 narrow it claims to cover.
  [Item 5b]
- New test_direct_path_non_404_apierror_surfaces_structured_error pins
  the Path 3 narrow (non-404 surfaces as structured error). [Item 4]
- New test_remove_helpers_integrations_subentry_string_error_surfaces_
  service_call_failed pins the Path 4 dict-only narrow against
  string-form ``"error": "not found"`` regressions. [Item 3]

While you're in there (Boy-Scout):
- Module comment near the private ``_delete_*`` helpers explaining the
  prefix-asymmetry (HA backend verb vs public ``remove`` family).
- Tightened "three deletion kinds in four paths" phrasing.
- FLOW contract bullet now lists ``bare_id_not_supported`` as a third
  failure mode (raises ``ENTITY_NOT_FOUND``).
- ``state_gone`` block comment compressed to one note about the
  never-existed-target consequence of the APIError-404 branch.

76 affected unit tests pass locally; ruff clean on touched files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Patch76

Patch76 commented May 24, 2026

Copy link
Copy Markdown
Member Author

Review-pass status

Pushed f3d9ac3: 8 of 10 numbered items + all 4 while-you're-in NITs addressed. CI re-running. The remaining 2 items are intentionally held pending your design-clarification answer.

Addressed in this push

Item Change
2 Drop result passthrough on Path 4 happy-path (no other path returns it)
3 New negative test pins Path 4 dict-only narrow against string-form "error": "not found" regressions
4 New negative test pins Path 3 narrow against non-404 HomeAssistantAPIError (500 / 401)
5a Tautological OR-disjunct → two independent assertions: code != "ENTITY_NOT_FOUND" AND "already_deleted" not in json.dumps(err)
5b HomeAssistantAPIError("404 simulated") now passes status_code=404 — the 404 narrow it claims to cover is actually exercised
7 Verb drift delete / deletionremove / removal in the target, helper_type, subentry_id, confirm Field descriptions
8 uniform for all three pathsfour (both confirm and empty-target gates); Path 4 added to empty-target enumeration
9 Stale ha_delete_helpers_integrations reference in docs/superpowers/specs/2026-05-21-1288-auto-backup-design.md updated
10 _get_entry_id_for_flow_helper broad except Exception(OSError, TimeoutError). KeyError / AttributeError / TypeError now propagate as INTERNAL_ERROR instead of being mis-classified as WEBSOCKET_DISCONNECTED
NIT-a Module comment near the private _delete_* helpers explaining the HA-backend-verb vs public-remove-family prefix asymmetry
NIT-b Combines simple-helper websocket deletion, config-entry deletion, and config-subentry deletion under one entry point with four routing pathsUnifies three backend removal mechanisms — simple-helper websocket delete, config-entry delete, and config-subentry delete — behind one entry point with four routing paths
NIT-c FLOW contract bullet now lists bare_id_not_supported as a third failure mode (raises ENTITY_NOT_FOUND)
NIT-d state_gone block comment compressed — one note on the never-existed-target consequence of the APIError-404 branch

Held — pending your design call

Two items intentionally deferred. Both depend on your read of the design-clarification answer:

  • Item 1 — Path 4 happy-path schema harmonization (add entry_id / entity_ids / require_restart to the success-path return). Direction depends on whether the intended contract is "uniform schema across all four idempotent and happy paths" (add) or "asymmetric and documented" (drop from idempotent + document). Currently leaning uniform.
  • Item 6IDEMPOTENT-SUCCESS CONTRACT docstring rewrite acknowledging the typo / never-existed equivalence on Paths 1 + 2. Phrasing depends on whether you ack the typo-case-in-scope read.

Both land in a follow-up commit on the same review round once your direction is clear.

@Patch76
Patch76 requested a review from kingpanther13 May 24, 2026 09:15
@kingpanther13

Copy link
Copy Markdown
Member

On item 6's docstring mitigation: a docstring caveat won't carry the load. Agent wrappers branch on the success boolean — that's the runtime signal that shapes behavior loops. Docstrings get read once at tool-registration time (often not at all in long sessions); they don't gate per-call decisions. An LLM that sees success: True will report "done" and move on regardless of what the docstring said. And pushing the disambiguation onto callers ("pre-flight get_entity lookup, audit log, state history" — your reply #2) shifts cost per-call onto every consumer; the failure mode when they forget lands on end users who get told a delete succeeded when their real target is still there.

A third option that doesn't break your idempotent contract: keep success=True, populate the project's existing top-level warnings: list[str] field on the already_deleted branches:

warnings=[
    "Target was already absent. If this was unexpected, "
    "verify the identifier — may indicate a typo or stale reference."
]

AGENTS.md § Return Values + tools_config_helpers.py::HelperResponse already standardize the shape; tests/src/unit/test_helper_response_shape.py enforces it. The project pattern is that agents surface warnings to users — most tools that produce them do. The typo signal fires at runtime where it actually catches things, docstring stops being load-bearing for safety, and your idempotent semantic stays intact.

Separately, I'm researching whether there's a better alternative than warnings for the underlying disambiguation. HA does retain a deleted_entities tombstone internally (homeassistant/helpers/entity_registry.py:1116dict[(domain, platform, unique_id), DeletedRegistryEntry]), but no public WS or REST endpoint exposes it today — I checked the registered commands in homeassistant/components/config/entity_registry.py:26-32. If a future surface (ours or upstream's) makes that data queryable, the disambiguation could move out of warnings and into a real signal. For now warnings is the realistic option.

If it doesn't work for you, I'm open to other shapes — but I don't want to land item 6 as "docstring says read fallback_used." That just leaks typos into user-facing reports.

@kingpanther13

Copy link
Copy Markdown
Member

Stupid Claude... Issue isn't "leaks typos into user reports." The issue is that it will return false successes to users, which is a problem... If it tries to delete the wrong thing, then Things that users thought got deleted will still exist, and won't have a good way to know that that even happened. Big silent failure/false success.

@kingpanther13

Copy link
Copy Markdown
Member

Following up on the warnings proposal — pulling back from that. Re-reading, putting the safety signal in warnings has the same shape of problem as the docstring, one rung up: it's optional for the wrapper to surface. The cohort that doesn't surface warnings is the same cohort that branches naively on success — exactly the wrapper class where end users get told a delete succeeded when their real target is still there.

Leaning toward Option B. Concrete shape on the already_deleted branches:

raise_tool_error(create_error_response(
    ErrorCode.RESOURCE_NOT_FOUND,
    f"Target {target} not found. This may indicate it was already removed, "
    "never existed, or the identifier is a typo. Verify with ha_search_entities() "
    "or ha_get_integration() before retrying.",
    context={"target": target, "helper_type": helper_type},
))

What this gets:

  • Aligns with the 12 sibling _remove_* tools — uniform "raise RESOURCE_NOT_FOUND on missing" contract across the family
  • Typo signal preserved at the layer every wrapper reads (isError per MCP spec)
  • Repeated calls return the same response — still idempotent at the contract level (call N times = same result). The "absent → success" framing was conflating idempotent with tolerant; those are different semantics, and only the first one the contract needs

Your argument for "absent → success" was retry-on-network-drop. But transient HA errors are already separately classified (WEBSOCKET_DISCONNECTED, CONNECTION_ERROR, …) — agent retry logic branches on those codes, not on every error. RESOURCE_NOT_FOUND triggers correction or escalation in well-built wrappers, and a tolerable extra round-trip in legitimately-retrying ones. The typo case is where the asymmetry actually bites.

On the underlying data — HA does retain deleted_entities internally (homeassistant/helpers/entity_registry.py:1116). Claude hasn't surfaced a good way to access it yet — no public WS endpoint like config/entity_registry/list_deleted or get_deleted_by_id, and no REST equivalent that I've found so far. Still researching; will report back if anything turns up.

@kingpanther13

Copy link
Copy Markdown
Member

Closing the research loop on disambiguating typo vs already-deleted. The tombstone exists on disk in .storage/core.entity_registry and in HA process memory as registry.deleted_entities, but no public API exposes it. I exhausted:

  • All config/entity_registry/* WS commands — return only registry.entities (verified by raw WS dump against my live 5614-entry registry: the string "deleted appears 0 times in the 3.92 MB response)
  • area_registry / device_registry cross-references — no hits
  • All speculative names (list_deleted, get_by_id, dump, list_with_deleted, …) — all return unknown_command from HA's WS router
  • Jinja templates — read all 21 files in homeassistant/helpers/template/extensions/, zero deleted references; verified live (entity_name("input_button.fake") returns None)
  • Recorder/history — retains state changes within recorder.purge_keep_days (default 10), but rolls off after retention → not contract-grade

Spot-checked a known deleted entity in my install (input_boolean.bat_1152_loop_0, registry id eb4ae8af54a68465cf08ba8949164d4a) — not retrievable via any active-registry endpoint despite being in the on-disk tombstone array.

This all points me to Option B. Go ahead and rework items 1 and 6 to raise RESOURCE_NOT_FOUND on confirmed-absent — concrete shape in my prior comment. I'm done researching the disambiguation path.

Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 24, 2026
…silent success

Addresses kp13 review feedback on homeassistant-ai#1424 (items 1 and 6). The previous
"absent → success" branches across all four paths returned
success=True with fallback_used="already_deleted" — agent wrappers
branching on the success boolean would then report deletion succeeded
to end users whose real target was untouched (typo / hallucinated
identifier). Silent false-success is the high-cost failure mode kp13
called out.

Reverts toward the project's existing per-target-shape raise pattern:

- Path 1 SIMPLE (helper_id / entity_id): state + registry both empty
  now raises ENTITY_NOT_FOUND (matches sibling ha_remove_entity).
- Path 2 FLOW step-1 not_in_registry: raises ENTITY_NOT_FOUND
  (entity-shape target; matches the existing bare_id_not_supported
  branch within the same path).
- Path 2 FLOW step-3 TOCTOU 404 on resolved entry_id: raises
  RESOURCE_NOT_FOUND (resource-shape target post-resolution).
- Path 3 Direct config entry 404: raises RESOURCE_NOT_FOUND.
- Path 4 config_subentry not_found: raises RESOURCE_NOT_FOUND.

Idempotency at the contract level still holds: N calls produce the
same response (the same raise). The previous shape conflated
*idempotent* (no additional effect on repeat) with *tolerant*
(absent → success); only the first is part of the contract. Transient
connectivity errors keep their separate codes (WEBSOCKET_DISCONNECTED,
CONNECTION_ERROR) so retry logic can branch on those independently.

Docstring contract block rewritten as MISSING-TARGET CONTRACT.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Patch76

Patch76 commented May 24, 2026

Copy link
Copy Markdown
Member Author

Reworked items 1 and 6 to raise on confirmed-absent across all five already_deleted branches. Three commits on top of f3d9ac3:

  • fix(tools_integrations): raise on confirmed-absent target instead of silent success (20799d7) — flips the five branches to raise_tool_error, rewrites the docstring contract block as MISSING-TARGET CONTRACT.
  • test(tools_integrations): flip absent-target tests to raise assertions (48a4f7b) — flips 6 unit tests (5 in test_tools_integrations.py, 1 in test_config_subentries_folded.py) and 2 E2E tests; the pre-existing negative "already_deleted" not in json.dumps(err) assertions stay and continue to pin no-mislabeling.
  • fix(tools_integrations): address ultrareview NITs on rework docstring (7449c43) — boy-scout pass on two docstring NITs surfaced by a /ultrareview run on the post-rework state: CONNECTION_ERROR was a wrong code name (real one is CONNECTION_FAILED per errors.py:33), and the wait param's "Ignored when helper_type=None" note was extended to also name config_subentry (Path 4 also drops wait). Regenerated site/src/data/tools.json via scripts/extract_tools.py so the catalog matches the live docstring.

PR body updated with the new contract table.

Branches flipped

# Path Branch Now raises
1 Path 3 _delete_direct_entry REST 404 on entry_id RESOURCE_NOT_FOUND
2 Path 2 _delete_flow_helper step 1 not_in_registry ENTITY_NOT_FOUND
3 Path 2 step 3 TOCTOU 404 on resolved entry_id RESOURCE_NOT_FOUND
4 Path 4 _delete_config_subentry WS error.code == "not_found" RESOURCE_NOT_FOUND
5 Path 1 _delete_simple_helper state-gone + registry-verify empty ENTITY_NOT_FOUND

Note on the error code split

Your concrete code snippet used uniform RESOURCE_NOT_FOUND. I went with per-target-shape codes (ENTITY_NOT_FOUND for entity-shaped targets in branches 2 + 5, RESOURCE_NOT_FOUND for config-shaped in branches 1 + 3 + 4) because Path 2 already differentiates internally: the existing bare_id_not_supported branch at line 1514 (pre-rework) raises ENTITY_NOT_FOUND, and the no_config_entry branch at line 1447 raises RESOURCE_NOT_FOUND. Flipping branch #2 to RESOURCE_NOT_FOUND would have left Path 2 with two codes for absent-target ("bare_id" → ENTITY_NOT_FOUND, "not_in_registry" → RESOURCE_NOT_FOUND), which felt like an internal inconsistency worth avoiding. Branch #5's ENTITY_NOT_FOUND matches sibling ha_remove_entity.

The message text per branch keeps the "may indicate already removed, never existed, or typo. Verify with ha_search_entities() / ha_get_integration() before retrying." shape from your snippet — wrappers branching on isError get the structured signal regardless of which code variant landed.

Happy to flip to uniform RESOURCE_NOT_FOUND if you prefer it, including the existing bare_id_not_supported branch for full internal consistency — let me know.

Verification

Local: 76 pytest items in test_tools_integrations.py + test_config_subentries_folded.py pass after the rework (71 unique test functions, expanded to 76 via one parametrize over 6 helper types; 6 of the 71 functions are reworked, the rest unchanged). CI pipeline kicks off on this push — the 2 flipped E2E tests are the post-deploy verification that the live tool surfaces the new codes against an actual HA instance.

On the disambiguation research closure (your comment from 13:11Z): agreed, no usable signal exists in the active-registry surface today. The deleted_entities tombstone array would have been the right backbone if it had a WS query, but it doesn't. The raise-on-confirmed-absent contract is the realistic shape.

@kingpanther13 kingpanther13 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rework lands cleanly: five branches raise as requested, docstring contract matches code, error messages include verification hints. On your design question — keep per-target-shape (ENTITY_NOT_FOUND for entity targets, RESOURCE_NOT_FOUND for config targets). It matches the existing bare_id_not_supported (entity-shaped) vs no_config_entry (config-shaped) split in Path 2 and aligns Path 1 with sibling ha_remove_entity. Uniform RESOURCE_NOT_FOUND would have created an internal inconsistency.

Two items before this lands:

1. Ruff format failing in CI on tests/src/unit/test_tools_integrations.py. Per the Ruff Lint job log:

Would reformat: tests/src/unit/test_tools_integrations.py
1 file would be reformatted, 23 files already formatted

Run ruff format tests/src/unit/test_tools_integrations.py and push.

2. Missing "already_deleted" not in json.dumps(err) regression pin on test_remove_helpers_integrations_subentry_other_error_surfaces_service_call_failed (tests/src/unit/test_config_subentries_folded.py:535). Its sibling string-form-error test at line 589 has the pin; this one doesn't. A regression that mis-routes a non-not_found error into the already_deleted shape wouldn't fail this test. Add the assertion.

While you're in there

None of the five raise-branch tests assert the diagnostic hint content in the error message beyond the target id — a regression that strips the "may indicate it was already removed, never existed, or the identifier is a typo. Verify with ha_search_entities()/ha_get_integration()" wording wouldn't fail any test. A "may indicate" in err["error"]["message"] (or equivalent substring check) on each of the five branches would pin the user-facing diagnostic so the message can't silently degrade — we just spent a review cycle landing that exact wording.

HAOS E2E failure noted as flaky — not requesting any change there.

Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 24, 2026
Addresses kp13's second review-pass on PR homeassistant-ai#1424:

- Item 1 (Ruff format on test_tools_integrations.py): already addressed
  upstream in 98f6ed2 — no action in this commit.
- Item 2: adds the missing `"already_deleted" not in json.dumps(err)`
  assertion to test_remove_helpers_integrations_subentry_other_error_
  surfaces_service_call_failed in test_config_subentries_folded.py.
  Symmetric with the string-form sibling test below that already pins
  the no-mislabeling rule.
- "While you're in there": adds diagnostic-hint substring assertions
  to all six confirmed-absent raise-branch tests so the user-facing
  wording (the "May indicate ... typo" framing + the matching
  ha_search_entities() / ha_get_integration() tool suggestion, or the
  TOCTOU-specific "concurrent removal" hint) can't silently degrade
  on future edits.

Test additions per branch:

- test_direct_path_entry_not_found_raises (Path 3): pin "May indicate"
  + "ha_get_integration"
- test_simple_path_state_gone_raises_entity_not_found (Path 1): pin
  "May indicate" + "ha_search_entities"
- test_simple_path_404_on_state_check_raises_entity_not_found (Path 1
  via 404): same pins as state-gone sibling
- test_flow_path_entity_not_in_registry_raises (Path 2 step 1): pin
  "May indicate" + "ha_search_entities"
- test_flow_path_entry_not_found_at_delete_raises (Path 2 TOCTOU):
  pin "concurrent removal" (distinct from the typo-framed hint —
  semantically the entry WAS resolvable at step 1 and only vanished
  before step 3)
- test_remove_helpers_integrations_subentry_not_found_raises (Path 4):
  pin "May indicate" + "ha_get_integration"

76 unit tests pass locally. Ruff format clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Patch76

Patch76 commented May 24, 2026

Copy link
Copy Markdown
Member Author

Thanks for the design ack on the per-target-shape split.

Addressed both blockers + the "while you're in there" in a single commit:

Item 1 — Ruff format on test_tools_integrations.py

Already addressed in 98f6ed2 — pushed at 16:13 UTC, ~7 min before your review submission at 16:20 UTC. The review was filed against the prior commit 7449c43, so the Ruff CI fix wasn't reflected in the state you reviewed. The post-fix CI run shows Ruff Lint green.

Item 2 — Missing "already_deleted" not in json.dumps(err) pin

Added to test_remove_helpers_integrations_subentry_other_error_surfaces_service_call_failed (tests/src/unit/test_config_subentries_folded.py), symmetric with the string-form sibling test in the same file.

Diagnostic-hint pins on the raise branches

Added substring assertions on the user-facing error-message text for all six confirmed-absent raise-branch tests so the wording can't silently regress:

Test Pins added
test_direct_path_entry_not_found_raises (Path 3) "May indicate" + "ha_get_integration"
test_simple_path_state_gone_raises_entity_not_found (Path 1 state-gone) "May indicate" + "ha_search_entities"
test_simple_path_404_on_state_check_raises_entity_not_found (Path 1 via 404) same as state-gone sibling
test_flow_path_entity_not_in_registry_raises (Path 2 step 1) "May indicate" + "ha_search_entities"
test_flow_path_entry_not_found_at_delete_raises (Path 2 TOCTOU) "concurrent removal" (TOCTOU-specific framing)
test_remove_helpers_integrations_subentry_not_found_raises (Path 4) "May indicate" + "ha_get_integration"

Path 2 TOCTOU keeps its distinct hint because semantically the entry WAS resolvable at step 1 — it only vanished before step 3 reached HA, so the typo framing wouldn't fit.

HAOS E2E (inaddon)

Agreed on flake — the failure was an httpx request-timeout during the CREATE step of test_forecast_solar_config_subentry_create_list_delete, before any Path 4 raise code is reached. The 9 prior runs on that workflow across other branches were green. The new CI run after this push is the empirical check.

Verification

76 unit tests in test_tools_integrations.py + test_config_subentries_folded.py pass locally. Ruff format clean on both files.

@Patch76
Patch76 requested a review from kingpanther13 May 24, 2026 17:43
kingpanther13
kingpanther13 previously approved these changes May 24, 2026

@kingpanther13 kingpanther13 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All three items addressed cleanly in bd480611. Verified:

  • Ruff format clean (CI green; commit 98f6ed2 landed before my prior review — my apologies for the cycle-noise on that one)
  • "already_deleted" not in json.dumps(err) pin added to test_remove_helpers_integrations_subentry_other_error_surfaces_service_call_failed at line 565-566
  • Diagnostic-hint substring pins added to all six raise-branch tests; cross-checked against the actual error messages at tools_integrations.py:1404, 1516, 1584, 1707, 1925 — wording matches
  • Path 2 TOCTOU branch correctly gets distinct "concurrent removal" framing since the entry was resolvable at step 1 and only vanished before step 3

CI all green. Approving.

@Patch76 Patch76 changed the title feat: rename ha_delete_helpers_integrations → ha_remove_helpers_integrations + commit to idempotent contract feat: rename ha_delete_helpers_integrations → ha_remove_helpers_integrations + raise on missing target May 24, 2026
…rations + raise on missing target

Closes homeassistant-ai#1412.

Renames `ha_delete_helpers_integrations` → `ha_remove_helpers_integrations`
and unifies the tool's behavioural contract across all four routing paths
under a single missing-target contract that raises a structured error on
confirmed-absent targets — silent `success=True` on absent would be a
false-success for wrappers that branch on `success` (typo / hallucinated
identifier case).

Missing-target contract per path:

- Path 1 SIMPLE (helper_id / entity_id): state-machine empty AND entity
  registry empty → raises ENTITY_NOT_FOUND. Matches sibling
  `ha_remove_entity`.
- Path 2 FLOW step-1 not_in_registry (entity_id): raises
  ENTITY_NOT_FOUND. Matches Path 2's existing `bare_id_not_supported`
  branch.
- Path 2 FLOW step-3 TOCTOU 404 on resolved entry_id: raises
  RESOURCE_NOT_FOUND with a distinct "concurrent removal" diagnostic
  hint.
- Path 3 Direct REST 404: raises RESOURCE_NOT_FOUND.
- Path 4 Subentry `code: "not_found"`: raises RESOURCE_NOT_FOUND.

Idempotency at the contract level still holds (N calls produce the same
raise). Transient connectivity errors keep their separate codes
(WEBSOCKET_DISCONNECTED, CONNECTION_FAILED). Diagnostic-hint wording on
each raise is pinned by substring assertions in the raise-branch tests.

Squash-then-rebase against current upstream/master to resolve textual
conflicts with homeassistant-ai#1430 (forecast_solar flaky-marker + relative-import
sweep on overlapping e2e test files). The conflict resolution is
purely textual — semantic content unchanged from the prior 14-commit
history that kp13 approved at bd48061.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kingpanther13

Copy link
Copy Markdown
Member

@Patch76 sorry I didn't realize my e2e fix PR would conflict with yours, just ping me again once you fix the conflict and I will re-approve.

@Patch76

Patch76 commented May 24, 2026

Copy link
Copy Markdown
Member Author

No worries ...

@Patch76
Patch76 enabled auto-merge (squash) May 24, 2026 19:36

@kingpanther13 kingpanther13 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving after rebase. Verified squashed ce5539ca only resolves the conflict in test_config_entry_flow.py (absolute → relative imports, matching #1430's sweep) and picks up the upstream tools_utility.py changes from #1423. No new substantive changes beyond the prior approved state in bd480611. CI all green.

@Patch76
Patch76 merged commit e16809b into homeassistant-ai:master May 24, 2026
17 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Your changes are now in the dev channel!

Your PR has been merged to master and is available for testing in the dev channel.

Test your changes before the next stable release (biweekly Wednesday):
📖 Dev Channel Documentation

Quick start

# Run dev version
uvx ha-mcp-dev

# Check version
uvx ha-mcp-dev --version

Docker:

docker pull ghcr.io/homeassistant-ai/ha-mcp:dev
docker run --rm -i \
  -e HOMEASSISTANT_URL=http://your-ha:8123 \
  -e HOMEASSISTANT_TOKEN=your_token \
  ghcr.io/homeassistant-ai/ha-mcp:dev

Found an issue? Please open a new bug report and mention this PR for context.

@Patch76
Patch76 deleted the feature/issue-1412 branch May 24, 2026 19:46
doonga pushed a commit to greyrock-labs/home-ops that referenced this pull request May 28, 2026
….0 ) (#141)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.5.0` → `7.6.0` |

---

### Release Notes

<details>
<summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary>

### [`v7.6.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v760-2026-05-27)

[Compare Source](homeassistant-ai/ha-mcp@v7.5.0...v7.6.0)

##### Added

- Make HTTP bind host configurable via MCP\_HOST (closes [#&#8203;1434](homeassistant-ai/ha-mcp#1434))
  ([#&#8203;1436](homeassistant-ai/ha-mcp#1436))
- Tool Security Policies — per-tool approval gating ([#&#8203;966](homeassistant-ai/ha-mcp#966))
  ([#&#8203;1421](homeassistant-ai/ha-mcp#1421))
- Rename ha\_delete\_helpers\_integrations → ha\_remove\_helpers\_integrations + raise on missing target
  ([#&#8203;1424](homeassistant-ai/ha-mcp#1424))
- Auto-backup edited entities before write/destructive tool calls (closes [#&#8203;1288](homeassistant-ai/ha-mcp#1288))
  ([#&#8203;1403](homeassistant-ai/ha-mcp#1403))
- Persistent settings UI for stdio mode
  ([#&#8203;1381](homeassistant-ai/ha-mcp#1381))
- Add fields= projection to ha\_search\_entities, ha\_get\_overview, ha\_get\_state, ha\_get\_history, ha\_config\_list\_areas, ha\_list\_services ([#&#8203;1199](homeassistant-ai/ha-mcp#1199))
  ([#&#8203;1225](homeassistant-ai/ha-mcp#1225))
- Route entity-registration wait through WS events (closes [#&#8203;1152](homeassistant-ai/ha-mcp#1152))
  ([#&#8203;1382](homeassistant-ai/ha-mcp#1382))
- Add config subentry support
  ([#&#8203;1393](homeassistant-ai/ha-mcp#1393))
- Add Assist pipeline management tool
  ([#&#8203;1392](homeassistant-ai/ha-mcp#1392))
- Add knx to ha\_config\_set\_yaml allowlist
  ([#&#8203;1374](homeassistant-ai/ha-mcp#1374))
- Extend automation\_id parity to set/remove automation responses
  ([#&#8203;1343](homeassistant-ai/ha-mcp#1343))
- **haos-e2e**: Add parallel inaddon test tier (ha-mcp runs inside HAOS addon)
  ([#&#8203;1361](homeassistant-ai/ha-mcp#1361))
- Expose integration diagnostics via ha\_get\_integration and ha\_get\_system\_health (closes [#&#8203;1148](homeassistant-ai/ha-mcp#1148))
  ([#&#8203;1328](homeassistant-ai/ha-mcp#1328))
- Return canonical script\_id from ha\_config\_get\_script ([#&#8203;1334](homeassistant-ai/ha-mcp#1334))
  ([#&#8203;1352](homeassistant-ai/ha-mcp#1352))
- Add automation\_id parity key to ha\_config\_get\_automation
  ([#&#8203;1329](homeassistant-ai/ha-mcp#1329))
- Reject empty/whitespace identifiers on registry-metadata writes (closes [#&#8203;1294](homeassistant-ai/ha-mcp#1294))
  ([#&#8203;1312](homeassistant-ai/ha-mcp#1312))
- Add HA brand assets for custom integration
  ([#&#8203;1317](homeassistant-ai/ha-mcp#1317))
- Unify ha\_config\_set\_helper response shape (closes [#&#8203;1293](homeassistant-ai/ha-mcp#1293))
  ([#&#8203;1303](homeassistant-ai/ha-mcp#1303))
- Mirror create-side validation guards onto update path (closes [#&#8203;1292](homeassistant-ai/ha-mcp#1292))
  ([#&#8203;1304](homeassistant-ai/ha-mcp#1304))
- Add array\_patch mode to ha\_manage\_addon for atomic GET-modify-POST
  ([#&#8203;1063](homeassistant-ai/ha-mcp#1063))

##### Changed

- **agents**: Drop ha\_backup\_create + ha\_backup\_restore from accepted exceptions
  ([#&#8203;1445](homeassistant-ai/ha-mcp#1445))
- Update contributors list \[contributors-updated]
  ([`c7665a6`](homeassistant-ai/ha-mcp@c7665a6))
- **overview**: Enumerate dismissed\_repair\_count in fields= description + static drift test
  ([#&#8203;1411](homeassistant-ai/ha-mcp#1411))
- Credit [@&#8203;tomwilkie](https://github.com/tomwilkie) and six other contributors in README
  ([#&#8203;1400](homeassistant-ai/ha-mcp#1400))
- **[#&#8203;1157](homeassistant-ai/ha-mcp#1157: Bump skills-vendor + auto-update via Renovate + native for: field + scrub eval\_template anti-patterns
  ([#&#8203;1383](homeassistant-ai/ha-mcp#1383))
- Extend Boy Scout weasel-phrase list with common variants; clarify semantic match
  ([#&#8203;1373](homeassistant-ai/ha-mcp#1373))
- Merge Boy Scout Rule + Handling Discovered Improvements; tighten deferral gate
  ([#&#8203;1359](homeassistant-ai/ha-mcp#1359))
- Categorize Issue Labels table and document 6 reverse-drift labels
  ([#&#8203;1335](homeassistant-ai/ha-mcp#1335))
- Strip stale L-refs from test\_identifier\_validation\_family docstrings
  ([#&#8203;1324](homeassistant-ai/ha-mcp#1324))
- Align label refs with live label set and fix triaged-removal trigger
  ([#&#8203;1316](homeassistant-ai/ha-mcp#1316))
- Surface tool-discovery / categorized search
  ([#&#8203;1123](homeassistant-ai/ha-mcp#1123))
- Fix two stale ha\_get\_skill\_guide references missed in [#&#8203;1289](homeassistant-ai/ha-mcp#1289)
  ([#&#8203;1305](homeassistant-ai/ha-mcp#1305))
- Clarify setup wizard placeholders need braces removed ([#&#8203;1284](homeassistant-ai/ha-mcp#1284))
  ([#&#8203;1286](homeassistant-ai/ha-mcp#1286))

##### Fixed

- Remove counter from ha\_reload\_core targets ([#&#8203;1453](homeassistant-ai/ha-mcp#1453))
  ([#&#8203;1456](homeassistant-ai/ha-mcp#1456))
- **backup**: Post-timeout match correctness + state-gate (closes [#&#8203;1433](homeassistant-ai/ha-mcp#1433))
  ([#&#8203;1435](homeassistant-ai/ha-mcp#1435))
- Sync addon settings UI with Supervisor options end-to-end
  ([#&#8203;1420](homeassistant-ai/ha-mcp#1420))
- **calendar**: Switch ha\_config\_remove\_calendar\_event to WebSocket (closes [#&#8203;1413](homeassistant-ai/ha-mcp#1413), [#&#8203;1416](homeassistant-ai/ha-mcp#1416))
  ([#&#8203;1418](homeassistant-ai/ha-mcp#1418))
- Error-shape consistency for non-entity not-found (closes [#&#8203;1297](homeassistant-ai/ha-mcp#1297))
  ([#&#8203;1397](homeassistant-ai/ha-mcp#1397))
- Guard against silent automation overwrite on id mismatch ([#&#8203;1404](homeassistant-ai/ha-mcp#1404))
  ([#&#8203;1405](homeassistant-ai/ha-mcp#1405))
- Cache YAML instance to prevent CPU spikes in bulk edits ([#&#8203;1370](homeassistant-ai/ha-mcp#1370))
  ([#&#8203;1371](homeassistant-ai/ha-mcp#1371))
- **client**: Route get\_error\_log via hassio proxy on external-HAOS clients
  ([#&#8203;1360](homeassistant-ai/ha-mcp#1360))
- Classify dashboard 404s ("unknown config specified") as RESOURCE\_NOT\_FOUND
  ([#&#8203;1345](homeassistant-ai/ha-mcp#1345))
- Detect HA addon installs as http transport, not stdio ([#&#8203;1322](homeassistant-ai/ha-mcp#1322))
  ([#&#8203;1327](homeassistant-ai/ha-mcp#1327))
- Actionable 403 suggestion when addon has unmapped container ports ([#&#8203;1319](homeassistant-ai/ha-mcp#1319))
  ([#&#8203;1325](homeassistant-ai/ha-mcp#1325))
- Filter dismissed repairs in overview and system\_health ([#&#8203;1307](homeassistant-ai/ha-mcp#1307))
  ([#&#8203;1309](homeassistant-ai/ha-mcp#1309))
- Exit on HA container death + daily reset before CI check
  ([#&#8203;1295](homeassistant-ai/ha-mcp#1295))
- Align ha\_config\_set\_dashboard with sibling re-fetch-after-save pattern ([#&#8203;1291](homeassistant-ai/ha-mcp#1291))
  ([#&#8203;1301](homeassistant-ai/ha-mcp#1301))
- Allow str.replace in python\_transform; hint at search mode on IndexError
  ([#&#8203;1287](homeassistant-ai/ha-mcp#1287))
- **array\_patch**: Tighten validation and surface silent failures
  ([#&#8203;1285](homeassistant-ai/ha-mcp#1285))
- HA Core proxy fallback for ha\_get\_logs(source=system\_service) on non-addon installs
  ([#&#8203;1283](homeassistant-ai/ha-mcp#1283))

##### Performance Improvements

- Tighten \_poll\_for\_automation\_entity first-poll cadence
  ([#&#8203;1384](homeassistant-ai/ha-mcp#1384))
- Parallelize ha\_get\_system\_health optional sections via asyncio.gather
  ([#&#8203;1336](homeassistant-ai/ha-mcp#1336))

##### Refactoring

- **service**: Compact ha\_call\_service result default ([#&#8203;1446](homeassistant-ai/ha-mcp#1446))
  ([#&#8203;1447](homeassistant-ai/ha-mcp#1447))
- Rename ha\_update\_device → ha\_set\_device
  ([#&#8203;1444](homeassistant-ai/ha-mcp#1444))
- Remove duplicate flat area/floor list tools (consolidation followup to [#&#8203;1016](homeassistant-ai/ha-mcp#1016))
  ([#&#8203;1429](homeassistant-ai/ha-mcp#1429))
- **complexity**: Migrate tools\_utility.py to class-based pattern
  ([#&#8203;1423](homeassistant-ai/ha-mcp#1423))
- **complexity**: Reduce C901 violations in tools/ — batch 4
  ([#&#8203;1408](homeassistant-ai/ha-mcp#1408))
- Route \_poll\_for\_automation\_entity through WS event waiter (closes [#&#8203;1395](homeassistant-ai/ha-mcp#1395))
  ([#&#8203;1406](homeassistant-ai/ha-mcp#1406))
- **yaml**: Use threading.local subclass for cached instance
  ([#&#8203;1396](homeassistant-ai/ha-mcp#1396))
- Align dashboards 404 shape with sibling config tools
  ([#&#8203;1386](homeassistant-ai/ha-mcp#1386))
- Complete singular warning → warnings list migration repo-wide (closes [#&#8203;1332](homeassistant-ai/ha-mcp#1332))
  ([#&#8203;1341](homeassistant-ai/ha-mcp#1341))
- Complete warnings-list migration for lifecycle-write tools
  ([#&#8203;1340](homeassistant-ai/ha-mcp#1340))
- Drop redundant identifier echo key from ha\_config\_get\_automation
  ([#&#8203;1354](homeassistant-ai/ha-mcp#1354))
- Drop logger.error in config-tool except blocks ([#&#8203;1302](homeassistant-ai/ha-mcp#1302))
  ([#&#8203;1353](homeassistant-ai/ha-mcp#1353))
- Extend validate\_identifier\_not\_empty to automations/scripts/dashboards CRUD (closes [#&#8203;1313](homeassistant-ai/ha-mcp#1313))
  ([#&#8203;1321](homeassistant-ai/ha-mcp#1321))
- Migrate tools\_config\_scenes inline empty-id guards to shared helper
  ([#&#8203;1320](homeassistant-ai/ha-mcp#1320))
- Remove ha\_get\_helper\_schema (closes [#&#8203;1186](homeassistant-ai/ha-mcp#1186))
  ([#&#8203;1315](homeassistant-ai/ha-mcp#1315))
- Consolidate skill tools; fix stable submodule packaging
  ([#&#8203;1289](homeassistant-ai/ha-mcp#1289))
- Align tools\_config\_automations.py error-handling with sibling pattern ([#&#8203;1290](homeassistant-ai/ha-mcp#1290))
  ([#&#8203;1298](homeassistant-ai/ha-mcp#1298))

***

<details>
<summary>Internal Changes</summary>

##### Fixed

- **ci**: Install libguestfs in HAOS publish workflow
  ([#&#8203;1358](homeassistant-ai/ha-mcp#1358))

##### Build System

- **deps**: Bump esbuild from 0.24.2 to 0.25.0 in /tests/js
  ([#&#8203;1427](homeassistant-ai/ha-mcp#1427))
- **deps**: Bump devalue from 5.6.4 to 5.8.1 in /site
  ([#&#8203;1282](homeassistant-ai/ha-mcp#1282))
- **deps**: Bump astro from 6.1.6 to 6.1.10 in /site
  ([#&#8203;1274](homeassistant-ai/ha-mcp#1274))

##### Chores

- **addon**: Publish dev addon version 7.5.0.dev360 \[skip ci]
  ([`ad7aed1`](homeassistant-ai/ha-mcp@ad7aed1))
- Sync tool docs after merge \[skip ci]
  ([`9c4984f`](homeassistant-ai/ha-mcp@9c4984f))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.4
  ([#&#8203;1450](homeassistant-ai/ha-mcp#1450))
- **addon**: Publish dev addon version 7.5.0.dev359 \[skip ci]
  ([`b82d4ee`](homeassistant-ai/ha-mcp@b82d4ee))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.16
  ([#&#8203;1449](homeassistant-ai/ha-mcp#1449))
- **addon**: Publish dev addon version 7.5.0.dev358 \[skip ci]
  ([`53fba6d`](homeassistant-ai/ha-mcp@53fba6d))
- Sync tool docs after merge \[skip ci]
  ([`dc7750d`](homeassistant-ai/ha-mcp@dc7750d))
- **addon**: Publish dev addon version 7.5.0.dev357 \[skip ci]
  ([`fd150c9`](homeassistant-ai/ha-mcp@fd150c9))
- **addon**: Publish dev addon version 7.5.0.dev356 \[skip ci]
  ([`5fa1463`](homeassistant-ai/ha-mcp@5fa1463))
- **addon**: Publish dev addon version 7.5.0.dev355 \[skip ci]
  ([`174ac5d`](homeassistant-ai/ha-mcp@174ac5d))
- **addon**: Publish dev addon version 7.5.0.dev354 \[skip ci]
  ([`4f93989`](homeassistant-ai/ha-mcp@4f93989))
- **addon**: Publish dev addon version 7.5.0.dev353 \[skip ci]
  ([`53f282f`](homeassistant-ai/ha-mcp@53f282f))
- **addon**: Publish dev addon version 7.5.0.dev352 \[skip ci]
  ([`4911d46`](homeassistant-ai/ha-mcp@4911d46))
- Sync tool docs after merge \[skip ci]
  ([`8a79837`](homeassistant-ai/ha-mcp@8a79837))
- **addon**: Publish dev addon version 7.5.0.dev351 \[skip ci]
  ([`13afa9d`](homeassistant-ai/ha-mcp@13afa9d))
- **addon**: Publish dev addon version 7.5.0.dev350 \[skip ci]
  ([`e93d680`](homeassistant-ai/ha-mcp@e93d680))
- **addon**: Publish dev addon version 7.5.0.dev349 \[skip ci]
  ([`1631ad1`](homeassistant-ai/ha-mcp@1631ad1))
- **addon**: Publish dev addon version 7.5.0.dev348 \[skip ci]
  ([`18a8aef`](homeassistant-ai/ha-mcp@18a8aef))
- Sync tool docs after merge \[skip ci]
  ([`9e0493d`](homeassistant-ai/ha-mcp@9e0493d))
- **addon**: Publish dev addon version 7.5.0.dev347 \[skip ci]
  ([`e2067e4`](homeassistant-ai/ha-mcp@e2067e4))
- Sync tool docs after merge \[skip ci]
  ([`7bdb3d4`](homeassistant-ai/ha-mcp@7bdb3d4))
- **addon**: Publish dev addon version 7.5.0.dev346 \[skip ci]
  ([`c2d4dd7`](homeassistant-ai/ha-mcp@c2d4dd7))
- Sync tool docs after merge \[skip ci]
  ([`393b354`](homeassistant-ai/ha-mcp@393b354))
- **addon**: Publish dev addon version 7.5.0.dev345 \[skip ci]
  ([`42ede8b`](homeassistant-ai/ha-mcp@42ede8b))
- **addon**: Publish dev addon version 7.5.0.dev344 \[skip ci]
  ([`e6cc7a1`](homeassistant-ai/ha-mcp@e6cc7a1))
- Sync tool docs after merge \[skip ci]
  ([`fb35f30`](homeassistant-ai/ha-mcp@fb35f30))
- **addon**: Publish dev addon version 7.5.0.dev343 \[skip ci]
  ([`401b7b4`](homeassistant-ai/ha-mcp@401b7b4))
- **addon**: Publish dev addon version 7.5.0.dev342 \[skip ci]
  ([`0679371`](homeassistant-ai/ha-mcp@0679371))
- Sync tool docs after merge \[skip ci]
  ([`f6796ec`](homeassistant-ai/ha-mcp@f6796ec))
- **addon**: Publish dev addon version 7.5.0.dev341 \[skip ci]
  ([`3654478`](homeassistant-ai/ha-mcp@3654478))
- **addon**: Publish dev addon version 7.5.0.dev340 \[skip ci]
  ([`64f00b6`](homeassistant-ai/ha-mcp@64f00b6))
- **addon**: Publish dev addon version 7.5.0.dev339 \[skip ci]
  ([`d6e8873`](homeassistant-ai/ha-mcp@d6e8873))
- Sync tool docs after merge \[skip ci]
  ([`7525e93`](homeassistant-ai/ha-mcp@7525e93))
- **addon**: Publish dev addon version 7.5.0.dev338 \[skip ci]
  ([`288ca4a`](homeassistant-ai/ha-mcp@288ca4a))
- **addon**: Publish dev addon version 7.5.0.dev337 \[skip ci]
  ([`f539ae5`](homeassistant-ai/ha-mcp@f539ae5))
- **addon**: Publish dev addon version 7.5.0.dev336 \[skip ci]
  ([`5568a86`](homeassistant-ai/ha-mcp@5568a86))
- **addon**: Publish dev addon version 7.5.0.dev335 \[skip ci]
  ([`e069405`](homeassistant-ai/ha-mcp@e069405))
- **addon**: Publish dev addon version 7.5.0.dev334 \[skip ci]
  ([`f7be6ea`](homeassistant-ai/ha-mcp@f7be6ea))
- **addon**: Publish dev addon version 7.5.0.dev333 \[skip ci]
  ([`cb480ea`](homeassistant-ai/ha-mcp@cb480ea))
- Sync tool docs after merge \[skip ci]
  ([`9a5bc3c`](homeassistant-ai/ha-mcp@9a5bc3c))
- **addon**: Publish dev addon version 7.5.0.dev332 \[skip ci]
  ([`e0e59ee`](homeassistant-ai/ha-mcp@e0e59ee))
- Sync tool docs after merge \[skip ci]
  ([`499ebf0`](homeassistant-ai/ha-mcp@499ebf0))
- **addon**: Publish dev addon version 7.5.0.dev331 \[skip ci]
  ([`3e0ce92`](homeassistant-ai/ha-mcp@3e0ce92))
- **addon**: Publish dev addon version 7.5.0.dev330 \[skip ci]
  ([`e48d056`](homeassistant-ai/ha-mcp@e48d056))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.15
  ([#&#8203;1376](homeassistant-ai/ha-mcp#1376))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.3
  ([#&#8203;1377](homeassistant-ai/ha-mcp#1377))
- **addon**: Publish dev addon version 7.5.0.dev329 \[skip ci]
  ([`c523c50`](homeassistant-ai/ha-mcp@c523c50))
- Sync tool docs after merge \[skip ci]
  ([`5b7a8aa`](homeassistant-ai/ha-mcp@5b7a8aa))
- **addon**: Publish dev addon version 7.5.0.dev328 \[skip ci]
  ([`6c42fba`](homeassistant-ai/ha-mcp@6c42fba))
- **addon**: Publish dev addon version 7.5.0.dev327 \[skip ci]
  ([`aecd025`](homeassistant-ai/ha-mcp@aecd025))
- **addon**: Publish dev addon version 7.5.0.dev326 \[skip ci]
  ([`399c17c`](homeassistant-ai/ha-mcp@399c17c))
- **addon**: Publish dev addon version 7.5.0.dev325 \[skip ci]
  ([`b580b45`](homeassistant-ai/ha-mcp@b580b45))
- Sync tool docs after merge \[skip ci]
  ([`8567c3a`](homeassistant-ai/ha-mcp@8567c3a))
- **addon**: Publish dev addon version 7.5.0.dev324 \[skip ci]
  ([`a65579d`](homeassistant-ai/ha-mcp@a65579d))
- **addon**: Publish dev addon version 7.5.0.dev323 \[skip ci]
  ([`c7667ba`](homeassistant-ai/ha-mcp@c7667ba))
- **addon**: Publish dev addon version 7.5.0.dev322 \[skip ci]
  ([`44d15a8`](homeassistant-ai/ha-mcp@44d15a8))
- **addon**: Publish dev addon version 7.5.0.dev321 \[skip ci]
  ([`8739f6c`](homeassistant-ai/ha-mcp@8739f6c))
- **addon**: Publish dev addon version 7.5.0.dev320 \[skip ci]
  ([`02b6e47`](homeassistant-ai/ha-mcp@02b6e47))
- Sync tool docs after merge \[skip ci]
  ([`ab68c9a`](homeassistant-ai/ha-mcp@ab68c9a))
- **addon**: Publish dev addon version 7.5.0.dev319 \[skip ci]
  ([`4472904`](homeassistant-ai/ha-mcp@4472904))
- **addon**: Publish dev addon version 7.5.0.dev318 \[skip ci]
  ([`e030dbc`](homeassistant-ai/ha-mcp@e030dbc))
- **addon**: Publish dev addon version 7.5.0.dev317 \[skip ci]
  ([`d87855c`](homeassistant-ai/ha-mcp@d87855c))
- Sync tool docs after merge \[skip ci]
  ([`a72a4e8`](homeassistant-ai/ha-mcp@a72a4e8))
- **addon**: Publish dev addon version 7.5.0.dev316 \[skip ci]
  ([`bd9397f`](homeassistant-ai/ha-mcp@bd9397f))
- **addon**: Publish dev addon version 7.5.0.dev315 \[skip ci]
  ([`264bfc2`](homeassistant-ai/ha-mcp@264bfc2))
- **addon**: Publish dev addon version 7.5.0.dev314 \[skip ci]
  ([`df62881`](homeassistant-ai/ha-mcp@df62881))
- **addon**: Publish dev addon version 7.5.0.dev313 \[skip ci]
  ([`f6c47ca`](homeassistant-ai/ha-mcp@f6c47ca))
- **addon**: Publish dev addon version 7.5.0.dev312 \[skip ci]
  ([`2bb7a74`](homeassistant-ai/ha-mcp@2bb7a74))
- Sync tool docs after merge \[skip ci]
  ([`137e279`](homeassistant-ai/ha-mcp@137e279))
- **addon**: Publish dev addon version 7.5.0.dev311 \[skip ci]
  ([`28324ea`](homeassistant-ai/ha-mcp@28324ea))
- Sync tool docs after merge \[skip ci]
  ([`9a753d4`](homeassistant-ai/ha-mcp@9a753d4))
- **addon**: Publish dev addon version 7.5.0.dev310 \[skip ci]
  ([`f893b2e`](homeassistant-ai/ha-mcp@f893b2e))
- **addon**: Publish dev addon version 7.5.0.dev309 \[skip ci]
  ([`8cbdb7b`](homeassistant-ai/ha-mcp@8cbdb7b))
- **addon**: Publish dev addon version 7.5.0.dev308 \[skip ci]
  ([`2d18016`](homeassistant-ai/ha-mcp@2d18016))
- **addon**: Publish dev addon version 7.5.0.dev307 \[skip ci]
  ([`3fc3b28`](homeassistant-ai/ha-mcp@3fc3b28))
- Sync tool docs after merge \[skip ci]
  ([`9e6cff8`](homeassistant-ai/ha-mcp@9e6cff8))
- **addon**: Publish dev addon version 7.5.0.dev306 \[skip ci]
  ([`8bdd0fc`](homeassistant-ai/ha-mcp@8bdd0fc))
- **addon**: Publish dev addon version 7.5.0.dev305 \[skip ci]
  ([`83535b9`](homeassistant-ai/ha-mcp@83535b9))
- **addon**: Publish dev addon version 7.5.0.dev304 \[skip ci]
  ([`1435b3a`](homeassistant-ai/ha-mcp@1435b3a))
- **addon**: Publish dev addon version 7.5.0.dev303 \[skip ci]
  ([`e2da659`](homeassistant-ai/ha-mcp@e2da659))
- Sync tool docs after merge \[skip ci]
  ([`23789fa`](homeassistant-ai/ha-mcp@23789fa))
- **addon**: Publish dev addon version 7.5.0.dev302 \[skip ci]
  ([`6c8e574`](homeassistant-ai/ha-mcp@6c8e574))
- Sync tool docs after merge \[skip ci]
  ([`d2329cb`](homeassistant-ai/ha-mcp@d2329cb))
- **addon**: Publish dev addon version 7.5.0.dev301 \[skip ci]
  ([`bb538f7`](homeassistant-ai/ha-mcp@bb538f7))
- Sync tool docs after merge \[skip ci]
  ([`f70f0e1`](homeassistant-ai/ha-mcp@f70f0e1))
- **addon**: Publish version 7.5.0 \[skip ci]
  ([`9c5eb37`](homeassistant-ai/ha-mcp@9c5eb37))

##### Continuous Integration

- **deps**: Bump actions/upload-artifact in the github-actions group
  ([#&#8203;1437](homeassistant-ai/ha-mcp#1437))
- Share qcow2 cache + GHCR fallback between HAOS lanes
  ([#&#8203;1407](homeassistant-ai/ha-mcp#1407))
- Add ruff format --check on changed Python files
  ([#&#8203;1387](homeassistant-ai/ha-mcp#1387))
- Exempt assigned issues from stale bot
  ([#&#8203;1368](homeassistant-ai/ha-mcp#1368))
- **deps**: Bump the github-actions group with 3 updates
  ([#&#8203;1362](homeassistant-ai/ha-mcp#1362))

##### Refactoring

- Consolidate lovelace/dashboards/list through shared helper
  ([#&#8203;1344](homeassistant-ai/ha-mcp#1344))

##### Testing

- **haos-e2e**: Bake + install webhook-proxy addon and exercise its runtime
  ([#&#8203;1443](homeassistant-ai/ha-mcp#1443))
- **config-subentry**: Mark forecast\_solar e2e as known flaky + relative-import sweep
  ([#&#8203;1430](homeassistant-ai/ha-mcp#1430))
- **haos-e2e**: Trim cache-save race, compress GHCR qcow2, eval boot snapshot
  ([#&#8203;1428](homeassistant-ai/ha-mcp#1428))
- JSDOM behaviour harness + auto-discovery parse coverage for every rendered <script>
  ([#&#8203;1425](homeassistant-ai/ha-mcp#1425))
- **hacs**: Retry TestMcpToolsInstallation on flake
  ([#&#8203;1426](homeassistant-ai/ha-mcp#1426))
- **e2e**: Drop redundant lifecycle roundtrips, keep only Matter Server ([#&#8203;1414](homeassistant-ai/ha-mcp#1414))
  ([#&#8203;1419](homeassistant-ai/ha-mcp#1419))
- **e2e**: Assert backend dispatch matches workflow env on every lane
  ([#&#8203;1409](homeassistant-ai/ha-mcp#1409))
- Escape ideographic space and format file ([#&#8203;1237](homeassistant-ai/ha-mcp#1237))
  ([#&#8203;1410](homeassistant-ai/ha-mcp#1410))
- **e2e**: Measure \_POLL\_CADENCE p50/p99 to validate or retune (closes [#&#8203;1389](homeassistant-ai/ha-mcp#1389))
  ([#&#8203;1398](homeassistant-ai/ha-mcp#1398))
- **e2e**: Wait for addon state=started in haos proxy header test
  ([#&#8203;1402](homeassistant-ai/ha-mcp#1402))
- Pin remaining \_classify\_by\_message branches
  ([#&#8203;1385](homeassistant-ai/ha-mcp#1385))
- **haos-e2e**: Slim addon set + real-addon ha\_manage\_addon coverage (closes [#&#8203;1350](homeassistant-ai/ha-mcp#1350))
  ([#&#8203;1379](homeassistant-ai/ha-mcp#1379))
- **haos-e2e**: Close out [#&#8203;1349](homeassistant-ai/ha-mcp#1349) — lifecycle, integrations, supervisor\_mock migration, no more skips
  ([#&#8203;1375](homeassistant-ai/ha-mcp#1375))
- **e2e**: Consolidate readiness gates onto /api/core/state (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1372](homeassistant-ai/ha-mcp#1372))
- **e2e**: Tighten 5 readiness-gate budgets with 2-63x headroom (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1369](homeassistant-ai/ha-mcp#1369))
- Scaffold HAOS E2E tier image-build pipeline (refs [#&#8203;1281](homeassistant-ai/ha-mcp#1281))
  ([#&#8203;1326](homeassistant-ai/ha-mcp#1326))
- **e2e**: Instrument HA\_MCP\_TOOLS\_WAIT readiness gate (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1346](homeassistant-ai/ha-mcp#1346))
- **e2e**: Centralize wait\_for\_entity\_registration helper (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1308](homeassistant-ai/ha-mcp#1308))
- **e2e**: Unify dict-error message extraction across e2e tests (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1311](homeassistant-ai/ha-mcp#1311))
- **e2e**: Surface readiness-gate elapsed times in CI logs (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1310](homeassistant-ai/ha-mcp#1310))

</details>

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/New_York)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTUuNCIsInVwZGF0ZWRJblZlciI6IjQzLjE5NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19-->

Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/141
eleboucher pushed a commit to eleboucher/homelab that referenced this pull request Jun 8, 2026
…➔ 7.6.0) (#904)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.5.0` → `7.6.0` |

---

### Release Notes

<details>
<summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary>

### [`v7.6.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v760-2026-05-27)

[Compare Source](homeassistant-ai/ha-mcp@v7.5.0...v7.6.0)

##### Added

- Make HTTP bind host configurable via MCP\_HOST (closes [#&#8203;1434](homeassistant-ai/ha-mcp#1434))
  ([#&#8203;1436](homeassistant-ai/ha-mcp#1436))
- Tool Security Policies — per-tool approval gating ([#&#8203;966](homeassistant-ai/ha-mcp#966))
  ([#&#8203;1421](homeassistant-ai/ha-mcp#1421))
- Rename ha\_delete\_helpers\_integrations → ha\_remove\_helpers\_integrations + raise on missing target
  ([#&#8203;1424](homeassistant-ai/ha-mcp#1424))
- Auto-backup edited entities before write/destructive tool calls (closes [#&#8203;1288](homeassistant-ai/ha-mcp#1288))
  ([#&#8203;1403](homeassistant-ai/ha-mcp#1403))
- Persistent settings UI for stdio mode
  ([#&#8203;1381](homeassistant-ai/ha-mcp#1381))
- Add fields= projection to ha\_search\_entities, ha\_get\_overview, ha\_get\_state, ha\_get\_history, ha\_config\_list\_areas, ha\_list\_services ([#&#8203;1199](homeassistant-ai/ha-mcp#1199))
  ([#&#8203;1225](homeassistant-ai/ha-mcp#1225))
- Route entity-registration wait through WS events (closes [#&#8203;1152](homeassistant-ai/ha-mcp#1152))
  ([#&#8203;1382](homeassistant-ai/ha-mcp#1382))
- Add config subentry support
  ([#&#8203;1393](homeassistant-ai/ha-mcp#1393))
- Add Assist pipeline management tool
  ([#&#8203;1392](homeassistant-ai/ha-mcp#1392))
- Add knx to ha\_config\_set\_yaml allowlist
  ([#&#8203;1374](homeassistant-ai/ha-mcp#1374))
- Extend automation\_id parity to set/remove automation responses
  ([#&#8203;1343](homeassistant-ai/ha-mcp#1343))
- **haos-e2e**: Add parallel inaddon test tier (ha-mcp runs inside HAOS addon)
  ([#&#8203;1361](homeassistant-ai/ha-mcp#1361))
- Expose integration diagnostics via ha\_get\_integration and ha\_get\_system\_health (closes [#&#8203;1148](homeassistant-ai/ha-mcp#1148))
  ([#&#8203;1328](homeassistant-ai/ha-mcp#1328))
- Return canonical script\_id from ha\_config\_get\_script ([#&#8203;1334](homeassistant-ai/ha-mcp#1334))
  ([#&#8203;1352](homeassistant-ai/ha-mcp#1352))
- Add automation\_id parity key to ha\_config\_get\_automation
  ([#&#8203;1329](homeassistant-ai/ha-mcp#1329))
- Reject empty/whitespace identifiers on registry-metadata writes (closes [#&#8203;1294](homeassistant-ai/ha-mcp#1294))
  ([#&#8203;1312](homeassistant-ai/ha-mcp#1312))
- Add HA brand assets for custom integration
  ([#&#8203;1317](homeassistant-ai/ha-mcp#1317))
- Unify ha\_config\_set\_helper response shape (closes [#&#8203;1293](homeassistant-ai/ha-mcp#1293))
  ([#&#8203;1303](homeassistant-ai/ha-mcp#1303))
- Mirror create-side validation guards onto update path (closes [#&#8203;1292](homeassistant-ai/ha-mcp#1292))
  ([#&#8203;1304](homeassistant-ai/ha-mcp#1304))
- Add array\_patch mode to ha\_manage\_addon for atomic GET-modify-POST
  ([#&#8203;1063](homeassistant-ai/ha-mcp#1063))

##### Changed

- **agents**: Drop ha\_backup\_create + ha\_backup\_restore from accepted exceptions
  ([#&#8203;1445](homeassistant-ai/ha-mcp#1445))
- Update contributors list \[contributors-updated]
  ([`c7665a6`](homeassistant-ai/ha-mcp@c7665a6))
- **overview**: Enumerate dismissed\_repair\_count in fields= description + static drift test
  ([#&#8203;1411](homeassistant-ai/ha-mcp#1411))
- Credit [@&#8203;tomwilkie](https://github.com/tomwilkie) and six other contributors in README
  ([#&#8203;1400](homeassistant-ai/ha-mcp#1400))
- **[#&#8203;1157](homeassistant-ai/ha-mcp#1157: Bump skills-vendor + auto-update via Renovate + native for: field + scrub eval\_template anti-patterns
  ([#&#8203;1383](homeassistant-ai/ha-mcp#1383))
- Extend Boy Scout weasel-phrase list with common variants; clarify semantic match
  ([#&#8203;1373](homeassistant-ai/ha-mcp#1373))
- Merge Boy Scout Rule + Handling Discovered Improvements; tighten deferral gate
  ([#&#8203;1359](homeassistant-ai/ha-mcp#1359))
- Categorize Issue Labels table and document 6 reverse-drift labels
  ([#&#8203;1335](homeassistant-ai/ha-mcp#1335))
- Strip stale L-refs from test\_identifier\_validation\_family docstrings
  ([#&#8203;1324](homeassistant-ai/ha-mcp#1324))
- Align label refs with live label set and fix triaged-removal trigger
  ([#&#8203;1316](homeassistant-ai/ha-mcp#1316))
- Surface tool-discovery / categorized search
  ([#&#8203;1123](homeassistant-ai/ha-mcp#1123))
- Fix two stale ha\_get\_skill\_guide references missed in [#&#8203;1289](homeassistant-ai/ha-mcp#1289)
  ([#&#8203;1305](homeassistant-ai/ha-mcp#1305))
- Clarify setup wizard placeholders need braces removed ([#&#8203;1284](homeassistant-ai/ha-mcp#1284))
  ([#&#8203;1286](homeassistant-ai/ha-mcp#1286))

##### Fixed

- Remove counter from ha\_reload\_core targets ([#&#8203;1453](homeassistant-ai/ha-mcp#1453))
  ([#&#8203;1456](homeassistant-ai/ha-mcp#1456))
- **backup**: Post-timeout match correctness + state-gate (closes [#&#8203;1433](homeassistant-ai/ha-mcp#1433))
  ([#&#8203;1435](homeassistant-ai/ha-mcp#1435))
- Sync addon settings UI with Supervisor options end-to-end
  ([#&#8203;1420](homeassistant-ai/ha-mcp#1420))
- **calendar**: Switch ha\_config\_remove\_calendar\_event to WebSocket (closes [#&#8203;1413](homeassistant-ai/ha-mcp#1413), [#&#8203;1416](homeassistant-ai/ha-mcp#1416))
  ([#&#8203;1418](homeassistant-ai/ha-mcp#1418))
- Error-shape consistency for non-entity not-found (closes [#&#8203;1297](homeassistant-ai/ha-mcp#1297))
  ([#&#8203;1397](homeassistant-ai/ha-mcp#1397))
- Guard against silent automation overwrite on id mismatch ([#&#8203;1404](homeassistant-ai/ha-mcp#1404))
  ([#&#8203;1405](homeassistant-ai/ha-mcp#1405))
- Cache YAML instance to prevent CPU spikes in bulk edits ([#&#8203;1370](homeassistant-ai/ha-mcp#1370))
  ([#&#8203;1371](homeassistant-ai/ha-mcp#1371))
- **client**: Route get\_error\_log via hassio proxy on external-HAOS clients
  ([#&#8203;1360](homeassistant-ai/ha-mcp#1360))
- Classify dashboard 404s ("unknown config specified") as RESOURCE\_NOT\_FOUND
  ([#&#8203;1345](homeassistant-ai/ha-mcp#1345))
- Detect HA addon installs as http transport, not stdio ([#&#8203;1322](homeassistant-ai/ha-mcp#1322))
  ([#&#8203;1327](homeassistant-ai/ha-mcp#1327))
- Actionable 403 suggestion when addon has unmapped container ports ([#&#8203;1319](homeassistant-ai/ha-mcp#1319))
  ([#&#8203;1325](homeassistant-ai/ha-mcp#1325))
- Filter dismissed repairs in overview and system\_health ([#&#8203;1307](homeassistant-ai/ha-mcp#1307))
  ([#&#8203;1309](homeassistant-ai/ha-mcp#1309))
- Exit on HA container death + daily reset before CI check
  ([#&#8203;1295](homeassistant-ai/ha-mcp#1295))
- Align ha\_config\_set\_dashboard with sibling re-fetch-after-save pattern ([#&#8203;1291](homeassistant-ai/ha-mcp#1291))
  ([#&#8203;1301](homeassistant-ai/ha-mcp#1301))
- Allow str.replace in python\_transform; hint at search mode on IndexError
  ([#&#8203;1287](homeassistant-ai/ha-mcp#1287))
- **array\_patch**: Tighten validation and surface silent failures
  ([#&#8203;1285](homeassistant-ai/ha-mcp#1285))
- HA Core proxy fallback for ha\_get\_logs(source=system\_service) on non-addon installs
  ([#&#8203;1283](homeassistant-ai/ha-mcp#1283))

##### Performance Improvements

- Tighten \_poll\_for\_automation\_entity first-poll cadence
  ([#&#8203;1384](homeassistant-ai/ha-mcp#1384))
- Parallelize ha\_get\_system\_health optional sections via asyncio.gather
  ([#&#8203;1336](homeassistant-ai/ha-mcp#1336))

##### Refactoring

- **service**: Compact ha\_call\_service result default ([#&#8203;1446](homeassistant-ai/ha-mcp#1446))
  ([#&#8203;1447](homeassistant-ai/ha-mcp#1447))
- Rename ha\_update\_device → ha\_set\_device
  ([#&#8203;1444](homeassistant-ai/ha-mcp#1444))
- Remove duplicate flat area/floor list tools (consolidation followup to [#&#8203;1016](homeassistant-ai/ha-mcp#1016))
  ([#&#8203;1429](homeassistant-ai/ha-mcp#1429))
- **complexity**: Migrate tools\_utility.py to class-based pattern
  ([#&#8203;1423](homeassistant-ai/ha-mcp#1423))
- **complexity**: Reduce C901 violations in tools/ — batch 4
  ([#&#8203;1408](homeassistant-ai/ha-mcp#1408))
- Route \_poll\_for\_automation\_entity through WS event waiter (closes [#&#8203;1395](homeassistant-ai/ha-mcp#1395))
  ([#&#8203;1406](homeassistant-ai/ha-mcp#1406))
- **yaml**: Use threading.local subclass for cached instance
  ([#&#8203;1396](homeassistant-ai/ha-mcp#1396))
- Align dashboards 404 shape with sibling config tools
  ([#&#8203;1386](homeassistant-ai/ha-mcp#1386))
- Complete singular warning → warnings list migration repo-wide (closes [#&#8203;1332](homeassistant-ai/ha-mcp#1332))
  ([#&#8203;1341](homeassistant-ai/ha-mcp#1341))
- Complete warnings-list migration for lifecycle-write tools
  ([#&#8203;1340](homeassistant-ai/ha-mcp#1340))
- Drop redundant identifier echo key from ha\_config\_get\_automation
  ([#&#8203;1354](homeassistant-ai/ha-mcp#1354))
- Drop logger.error in config-tool except blocks ([#&#8203;1302](homeassistant-ai/ha-mcp#1302))
  ([#&#8203;1353](homeassistant-ai/ha-mcp#1353))
- Extend validate\_identifier\_not\_empty to automations/scripts/dashboards CRUD (closes [#&#8203;1313](homeassistant-ai/ha-mcp#1313))
  ([#&#8203;1321](homeassistant-ai/ha-mcp#1321))
- Migrate tools\_config\_scenes inline empty-id guards to shared helper
  ([#&#8203;1320](homeassistant-ai/ha-mcp#1320))
- Remove ha\_get\_helper\_schema (closes [#&#8203;1186](homeassistant-ai/ha-mcp#1186))
  ([#&#8203;1315](homeassistant-ai/ha-mcp#1315))
- Consolidate skill tools; fix stable submodule packaging
  ([#&#8203;1289](homeassistant-ai/ha-mcp#1289))
- Align tools\_config\_automations.py error-handling with sibling pattern ([#&#8203;1290](homeassistant-ai/ha-mcp#1290))
  ([#&#8203;1298](homeassistant-ai/ha-mcp#1298))

***

<details>
<summary>Internal Changes</summary>

##### Fixed

- **ci**: Install libguestfs in HAOS publish workflow
  ([#&#8203;1358](homeassistant-ai/ha-mcp#1358))

##### Build System

- **deps**: Bump esbuild from 0.24.2 to 0.25.0 in /tests/js
  ([#&#8203;1427](homeassistant-ai/ha-mcp#1427))
- **deps**: Bump devalue from 5.6.4 to 5.8.1 in /site
  ([#&#8203;1282](homeassistant-ai/ha-mcp#1282))
- **deps**: Bump astro from 6.1.6 to 6.1.10 in /site
  ([#&#8203;1274](homeassistant-ai/ha-mcp#1274))

##### Chores

- **addon**: Publish dev addon version 7.5.0.dev360 \[skip ci]
  ([`ad7aed1`](homeassistant-ai/ha-mcp@ad7aed1))
- Sync tool docs after merge \[skip ci]
  ([`9c4984f`](homeassistant-ai/ha-mcp@9c4984f))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.4
  ([#&#8203;1450](homeassistant-ai/ha-mcp#1450))
- **addon**: Publish dev addon version 7.5.0.dev359 \[skip ci]
  ([`b82d4ee`](homeassistant-ai/ha-mcp@b82d4ee))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.16
  ([#&#8203;1449](homeassistant-ai/ha-mcp#1449))
- **addon**: Publish dev addon version 7.5.0.dev358 \[skip ci]
  ([`53fba6d`](homeassistant-ai/ha-mcp@53fba6d))
- Sync tool docs after merge \[skip ci]
  ([`dc7750d`](homeassistant-ai/ha-mcp@dc7750d))
- **addon**: Publish dev addon version 7.5.0.dev357 \[skip ci]
  ([`fd150c9`](homeassistant-ai/ha-mcp@fd150c9))
- **addon**: Publish dev addon version 7.5.0.dev356 \[skip ci]
  ([`5fa1463`](homeassistant-ai/ha-mcp@5fa1463))
- **addon**: Publish dev addon version 7.5.0.dev355 \[skip ci]
  ([`174ac5d`](homeassistant-ai/ha-mcp@174ac5d))
- **addon**: Publish dev addon version 7.5.0.dev354 \[skip ci]
  ([`4f93989`](homeassistant-ai/ha-mcp@4f93989))
- **addon**: Publish dev addon version 7.5.0.dev353 \[skip ci]
  ([`53f282f`](homeassistant-ai/ha-mcp@53f282f))
- **addon**: Publish dev addon version 7.5.0.dev352 \[skip ci]
  ([`4911d46`](homeassistant-ai/ha-mcp@4911d46))
- Sync tool docs after merge \[skip ci]
  ([`8a79837`](homeassistant-ai/ha-mcp@8a79837))
- **addon**: Publish dev addon version 7.5.0.dev351 \[skip ci]
  ([`13afa9d`](homeassistant-ai/ha-mcp@13afa9d))
- **addon**: Publish dev addon version 7.5.0.dev350 \[skip ci]
  ([`e93d680`](homeassistant-ai/ha-mcp@e93d680))
- **addon**: Publish dev addon version 7.5.0.dev349 \[skip ci]
  ([`1631ad1`](homeassistant-ai/ha-mcp@1631ad1))
- **addon**: Publish dev addon version 7.5.0.dev348 \[skip ci]
  ([`18a8aef`](homeassistant-ai/ha-mcp@18a8aef))
- Sync tool docs after merge \[skip ci]
  ([`9e0493d`](homeassistant-ai/ha-mcp@9e0493d))
- **addon**: Publish dev addon version 7.5.0.dev347 \[skip ci]
  ([`e2067e4`](homeassistant-ai/ha-mcp@e2067e4))
- Sync tool docs after merge \[skip ci]
  ([`7bdb3d4`](homeassistant-ai/ha-mcp@7bdb3d4))
- **addon**: Publish dev addon version 7.5.0.dev346 \[skip ci]
  ([`c2d4dd7`](homeassistant-ai/ha-mcp@c2d4dd7))
- Sync tool docs after merge \[skip ci]
  ([`393b354`](homeassistant-ai/ha-mcp@393b354))
- **addon**: Publish dev addon version 7.5.0.dev345 \[skip ci]
  ([`42ede8b`](homeassistant-ai/ha-mcp@42ede8b))
- **addon**: Publish dev addon version 7.5.0.dev344 \[skip ci]
  ([`e6cc7a1`](homeassistant-ai/ha-mcp@e6cc7a1))
- Sync tool docs after merge \[skip ci]
  ([`fb35f30`](homeassistant-ai/ha-mcp@fb35f30))
- **addon**: Publish dev addon version 7.5.0.dev343 \[skip ci]
  ([`401b7b4`](homeassistant-ai/ha-mcp@401b7b4))
- **addon**: Publish dev addon version 7.5.0.dev342 \[skip ci]
  ([`0679371`](homeassistant-ai/ha-mcp@0679371))
- Sync tool docs after merge \[skip ci]
  ([`f6796ec`](homeassistant-ai/ha-mcp@f6796ec))
- **addon**: Publish dev addon version 7.5.0.dev341 \[skip ci]
  ([`3654478`](homeassistant-ai/ha-mcp@3654478))
- **addon**: Publish dev addon version 7.5.0.dev340 \[skip ci]
  ([`64f00b6`](homeassistant-ai/ha-mcp@64f00b6))
- **addon**: Publish dev addon version 7.5.0.dev339 \[skip ci]
  ([`d6e8873`](homeassistant-ai/ha-mcp@d6e8873))
- Sync tool docs after merge \[skip ci]
  ([`7525e93`](homeassistant-ai/ha-mcp@7525e93))
- **addon**: Publish dev addon version 7.5.0.dev338 \[skip ci]
  ([`288ca4a`](homeassistant-ai/ha-mcp@288ca4a))
- **addon**: Publish dev addon version 7.5.0.dev337 \[skip ci]
  ([`f539ae5`](homeassistant-ai/ha-mcp@f539ae5))
- **addon**: Publish dev addon version 7.5.0.dev336 \[skip ci]
  ([`5568a86`](homeassistant-ai/ha-mcp@5568a86))
- **addon**: Publish dev addon version 7.5.0.dev335 \[skip ci]
  ([`e069405`](homeassistant-ai/ha-mcp@e069405))
- **addon**: Publish dev addon version 7.5.0.dev334 \[skip ci]
  ([`f7be6ea`](homeassistant-ai/ha-mcp@f7be6ea))
- **addon**: Publish dev addon version 7.5.0.dev333 \[skip ci]
  ([`cb480ea`](homeassistant-ai/ha-mcp@cb480ea))
- Sync tool docs after merge \[skip ci]
  ([`9a5bc3c`](homeassistant-ai/ha-mcp@9a5bc3c))
- **addon**: Publish dev addon version 7.5.0.dev332 \[skip ci]
  ([`e0e59ee`](homeassistant-ai/ha-mcp@e0e59ee))
- Sync tool docs after merge \[skip ci]
  ([`499ebf0`](homeassistant-ai/ha-mcp@499ebf0))
- **addon**: Publish dev addon version 7.5.0.dev331 \[skip ci]
  ([`3e0ce92`](homeassistant-ai/ha-mcp@3e0ce92))
- **addon**: Publish dev addon version 7.5.0.dev330 \[skip ci]
  ([`e48d056`](homeassistant-ai/ha-mcp@e48d056))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.15
  ([#&#8203;1376](homeassistant-ai/ha-mcp#1376))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.3
  ([#&#8203;1377](homeassistant-ai/ha-mcp#1377))
- **addon**: Publish dev addon version 7.5.0.dev329 \[skip ci]
  ([`c523c50`](homeassistant-ai/ha-mcp@c523c50))
- Sync tool docs after merge \[skip ci]
  ([`5b7a8aa`](homeassistant-ai/ha-mcp@5b7a8aa))
- **addon**: Publish dev addon version 7.5.0.dev328 \[skip ci]
  ([`6c42fba`](homeassistant-ai/ha-mcp@6c42fba))
- **addon**: Publish dev addon version 7.5.0.dev327 \[skip ci]
  ([`aecd025`](homeassistant-ai/ha-mcp@aecd025))
- **addon**: Publish dev addon version 7.5.0.dev326 \[skip ci]
  ([`399c17c`](homeassistant-ai/ha-mcp@399c17c))
- **addon**: Publish dev addon version 7.5.0.dev325 \[skip ci]
  ([`b580b45`](homeassistant-ai/ha-mcp@b580b45))
- Sync tool docs after merge \[skip ci]
  ([`8567c3a`](homeassistant-ai/ha-mcp@8567c3a))
- **addon**: Publish dev addon version 7.5.0.dev324 \[skip ci]
  ([`a65579d`](homeassistant-ai/ha-mcp@a65579d))
- **addon**: Publish dev addon version 7.5.0.dev323 \[skip ci]
  ([`c7667ba`](homeassistant-ai/ha-mcp@c7667ba))
- **addon**: Publish dev addon version 7.5.0.dev322 \[skip ci]
  ([`44d15a8`](homeassistant-ai/ha-mcp@44d15a8))
- **addon**: Publish dev addon version 7.5.0.dev321 \[skip ci]
  ([`8739f6c`](homeassistant-ai/ha-mcp@8739f6c))
- **addon**: Publish dev addon version 7.5.0.dev320 \[skip ci]
  ([`02b6e47`](homeassistant-ai/ha-mcp@02b6e47))
- Sync tool docs after merge \[skip ci]
  ([`ab68c9a`](homeassistant-ai/ha-mcp@ab68c9a))
- **addon**: Publish dev addon version 7.5.0.dev319 \[skip ci]
  ([`4472904`](homeassistant-ai/ha-mcp@4472904))
- **addon**: Publish dev addon version 7.5.0.dev318 \[skip ci]
  ([`e030dbc`](homeassistant-ai/ha-mcp@e030dbc))
- **addon**: Publish dev addon version 7.5.0.dev317 \[skip ci]
  ([`d87855c`](homeassistant-ai/ha-mcp@d87855c))
- Sync tool docs after merge \[skip ci]
  ([`a72a4e8`](homeassistant-ai/ha-mcp@a72a4e8))
- **addon**: Publish dev addon version 7.5.0.dev316 \[skip ci]
  ([`bd9397f`](homeassistant-ai/ha-mcp@bd9397f))
- **addon**: Publish dev addon version 7.5.0.dev315 \[skip ci]
  ([`264bfc2`](homeassistant-ai/ha-mcp@264bfc2))
- **addon**: Publish dev addon version 7.5.0.dev314 \[skip ci]
  ([`df62881`](homeassistant-ai/ha-mcp@df62881))
- **addon**: Publish dev addon version 7.5.0.dev313 \[skip ci]
  ([`f6c47ca`](homeassistant-ai/ha-mcp@f6c47ca))
- **addon**: Publish dev addon version 7.5.0.dev312 \[skip ci]
  ([`2bb7a74`](homeassistant-ai/ha-mcp@2bb7a74))
- Sync tool docs after merge \[skip ci]
  ([`137e279`](homeassistant-ai/ha-mcp@137e279))
- **addon**: Publish dev addon version 7.5.0.dev311 \[skip ci]
  ([`28324ea`](homeassistant-ai/ha-mcp@28324ea))
- Sync tool docs after merge \[skip ci]
  ([`9a753d4`](homeassistant-ai/ha-mcp@9a753d4))
- **addon**: Publish dev addon version 7.5.0.dev310 \[skip ci]
  ([`f893b2e`](homeassistant-ai/ha-mcp@f893b2e))
- **addon**: Publish dev addon version 7.5.0.dev309 \[skip ci]
  ([`8cbdb7b`](homeassistant-ai/ha-mcp@8cbdb7b))
- **addon**: Publish dev addon version 7.5.0.dev308 \[skip ci]
  ([`2d18016`](homeassistant-ai/ha-mcp@2d18016))
- **addon**: Publish dev addon version 7.5.0.dev307 \[skip ci]
  ([`3fc3b28`](homeassistant-ai/ha-mcp@3fc3b28))
- Sync tool docs after merge \[skip ci]
  ([`9e6cff8`](homeassistant-ai/ha-mcp@9e6cff8))
- **addon**: Publish dev addon version 7.5.0.dev306 \[skip ci]
  ([`8bdd0fc`](homeassistant-ai/ha-mcp@8bdd0fc))
- **addon**: Publish dev addon version 7.5.0.dev305 \[skip ci]
  ([`83535b9`](homeassistant-ai/ha-mcp@83535b9))
- **addon**: Publish dev addon version 7.5.0.dev304 \[skip ci]
  ([`1435b3a`](homeassistant-ai/ha-mcp@1435b3a))
- **addon**: Publish dev addon version 7.5.0.dev303 \[skip ci]
  ([`e2da659`](homeassistant-ai/ha-mcp@e2da659))
- Sync tool docs after merge \[skip ci]
  ([`23789fa`](homeassistant-ai/ha-mcp@23789fa))
- **addon**: Publish dev addon version 7.5.0.dev302 \[skip ci]
  ([`6c8e574`](homeassistant-ai/ha-mcp@6c8e574))
- Sync tool docs after merge \[skip ci]
  ([`d2329cb`](homeassistant-ai/ha-mcp@d2329cb))
- **addon**: Publish dev addon version 7.5.0.dev301 \[skip ci]
  ([`bb538f7`](homeassistant-ai/ha-mcp@bb538f7))
- Sync tool docs after merge \[skip ci]
  ([`f70f0e1`](homeassistant-ai/ha-mcp@f70f0e1))
- **addon**: Publish version 7.5.0 \[skip ci]
  ([`9c5eb37`](homeassistant-ai/ha-mcp@9c5eb37))

##### Continuous Integration

- **deps**: Bump actions/upload-artifact in the github-actions group
  ([#&#8203;1437](homeassistant-ai/ha-mcp#1437))
- Share qcow2 cache + GHCR fallback between HAOS lanes
  ([#&#8203;1407](homeassistant-ai/ha-mcp#1407))
- Add ruff format --check on changed Python files
  ([#&#8203;1387](homeassistant-ai/ha-mcp#1387))
- Exempt assigned issues from stale bot
  ([#&#8203;1368](homeassistant-ai/ha-mcp#1368))
- **deps**: Bump the github-actions group with 3 updates
  ([#&#8203;1362](homeassistant-ai/ha-mcp#1362))

##### Refactoring

- Consolidate lovelace/dashboards/list through shared helper
  ([#&#8203;1344](homeassistant-ai/ha-mcp#1344))

##### Testing

- **haos-e2e**: Bake + install webhook-proxy addon and exercise its runtime
  ([#&#8203;1443](homeassistant-ai/ha-mcp#1443))
- **config-subentry**: Mark forecast\_solar e2e as known flaky + relative-import sweep
  ([#&#8203;1430](homeassistant-ai/ha-mcp#1430))
- **haos-e2e**: Trim cache-save race, compress GHCR qcow2, eval boot snapshot
  ([#&#8203;1428](homeassistant-ai/ha-mcp#1428))
- JSDOM behaviour harness + auto-discovery parse coverage for every rendered <script>
  ([#&#8203;1425](homeassistant-ai/ha-mcp#1425))
- **hacs**: Retry TestMcpToolsInstallation on flake
  ([#&#8203;1426](homeassistant-ai/ha-mcp#1426))
- **e2e**: Drop redundant lifecycle roundtrips, keep only Matter Server ([#&#8203;1414](homeassistant-ai/ha-mcp#1414))
  ([#&#8203;1419](homeassistant-ai/ha-mcp#1419))
- **e2e**: Assert backend dispatch matches workflow env on every lane
  ([#&#8203;1409](homeassistant-ai/ha-mcp#1409))
- Escape ideographic space and format file ([#&#8203;1237](homeassistant-ai/ha-mcp#1237))
  ([#&#8203;1410](homeassistant-ai/ha-mcp#1410))
- **e2e**: Measure \_POLL\_CADENCE p50/p99 to validate or retune (closes [#&#8203;1389](homeassistant-ai/ha-mcp#1389))
  ([#&#8203;1398](homeassistant-ai/ha-mcp#1398))
- **e2e**: Wait for addon state=started in haos proxy header test
  ([#&#8203;1402](homeassistant-ai/ha-mcp#1402))
- Pin remaining \_classify\_by\_message branches
  ([#&#8203;1385](homeassistant-ai/ha-mcp#1385))
- **haos-e2e**: Slim addon set + real-addon ha\_manage\_addon coverage (closes [#&#8203;1350](homeassistant-ai/ha-mcp#1350))
  ([#&#8203;1379](homeassistant-ai/ha-mcp#1379))
- **haos-e2e**: Close out [#&#8203;1349](homeassistant-ai/ha-mcp#1349) — lifecycle, integrations, supervisor\_mock migration, no more skips
  ([#&#8203;1375](homeassistant-ai/ha-mcp#1375))
- **e2e**: Consolidate readiness gates onto /api/core/state (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1372](homeassistant-ai/ha-mcp#1372))
- **e2e**: Tighten 5 readiness-gate budgets with 2-63x headroom (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1369](homeassistant-ai/ha-mcp#1369))
- Scaffold HAOS E2E tier image-build pipeline (refs [#&#8203;1281](homeassistant-ai/ha-mcp#1281))
  ([#&#8203;1326](homeassistant-ai/ha-mcp#1326))
- **e2e**: Instrument HA\_MCP\_TOOLS\_WAIT readiness gate (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1346](homeassistant-ai/ha-mcp#1346))
- **e2e**: Centralize wait\_for\_entity\_registration helper (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1308](homeassistant-ai/ha-mcp#1308))
- **e2e**: Unify dict-error message extraction across e2e tests (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1311](homeassistant-ai/ha-mcp#1311))
- **e2e**: Surface readiness-gate elapsed times in CI logs (refs [#&#8203;366](homeassistant-ai/ha-mcp#366))
  ([#&#8203;1310](homeassistant-ai/ha-mcp#1310))

</details>

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/904
eleboucher pushed a commit to eleboucher/homelab that referenced this pull request Jun 10, 2026
…➔ 7.7.0) (#994)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/homeassistant-ai/ha-mcp](https://github.com/homeassistant-ai/ha-mcp) | minor | `7.5.0` → `7.7.0` |

---

### Release Notes

<details>
<summary>homeassistant-ai/ha-mcp (ghcr.io/homeassistant-ai/ha-mcp)</summary>

### [`v7.7.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v770-2026-06-10)

[Compare Source](https://github.com/homeassistant-ai/ha-mcp/compare/v7.6.0...v7.7.0)

##### Added

- User-configurable custom filesystem directories for the file tools (closes [#&#8203;1567](https://github.com/homeassistant-ai/ha-mcp/issues/1567))
  ([#&#8203;1568](https://github.com/homeassistant-ai/ha-mcp/pull/1568))
- Expose all user-tunable env vars in the settings UI (add-on parity)
  ([#&#8203;1554](https://github.com/homeassistant-ai/ha-mcp/pull/1554))
- Warn when default MCP\_SECRET\_PATH is bound non-loopback
  ([#&#8203;1472](https://github.com/homeassistant-ai/ha-mcp/pull/1472))
- **search**: Consolidate ha\_search\_entities + ha\_deep\_search into ha\_search
  ([#&#8203;1529](https://github.com/homeassistant-ai/ha-mcp/pull/1529))
- **addon**: Install the MCP Server add-on from the ha\_mcp\_tools integration
  ([#&#8203;1528](https://github.com/homeassistant-ai/ha-mcp/pull/1528))
- Add opt-in dashboard screenshot mode
  ([#&#8203;1510](https://github.com/homeassistant-ai/ha-mcp/pull/1510))
- Add Linux support for install & docs
  ([#&#8203;1096](https://github.com/homeassistant-ai/ha-mcp/pull/1096))
- Surface the web settings page for non-add-on installs ([#&#8203;1458](https://github.com/homeassistant-ai/ha-mcp/issues/1458))
  ([#&#8203;1511](https://github.com/homeassistant-ai/ha-mcp/pull/1511))
- Convert Pydantic arg-validation errors to actionable ToolErrors
  ([#&#8203;1491](https://github.com/homeassistant-ai/ha-mcp/pull/1491))
- Per-key toggles for automation/script/scene in packages/\*.yaml
  ([#&#8203;1476](https://github.com/homeassistant-ai/ha-mcp/pull/1476))
- Direct skills retrieval for write tools + improved  best practice checker warnings with embedded skills responses ([#&#8203;1182](https://github.com/homeassistant-ai/ha-mcp/issues/1182))
  ([#&#8203;1448](https://github.com/homeassistant-ai/ha-mcp/pull/1448))
- Detect last\_changed/last\_updated duration math and suggest for: field ([#&#8203;1157](https://github.com/homeassistant-ai/ha-mcp/issues/1157))
  ([#&#8203;1264](https://github.com/homeassistant-ai/ha-mcp/pull/1264))
- Advanced settings panel + nested beta master toggle ([#&#8203;1164](https://github.com/homeassistant-ai/ha-mcp/issues/1164))
  ([#&#8203;1431](https://github.com/homeassistant-ai/ha-mcp/pull/1431))
- Allow automation/script/scene yaml\_path in packages/\*.yaml only
  ([#&#8203;1452](https://github.com/homeassistant-ai/ha-mcp/pull/1452))
- Restrict ha\_mcp\_tools services to ha-mcp callers (caller token + ha\_call\_service refusal)
  ([#&#8203;1459](https://github.com/homeassistant-ai/ha-mcp/pull/1459))

##### Changed

- **security**: Soften vulnerability-response SLA to best-effort
  ([`a24e7da`](https://github.com/homeassistant-ai/ha-mcp/commit/a24e7da4787aad570ac2998a5732de06229fa160))
- Update contributors list \[contributors-updated]
  ([`7cc187f`](https://github.com/homeassistant-ai/ha-mcp/commit/7cc187f4de2f6eb58cafaa4fb21f8016cb180a61))
- Telemetry wording — follow HA analytics setting, not opt-in-only
  ([#&#8203;1481](https://github.com/homeassistant-ai/ha-mcp/pull/1481))
- **security**: Note that security-advisory disposition is API-blind (UI-only)
  ([#&#8203;1561](https://github.com/homeassistant-ai/ha-mcp/pull/1561))
- **tools**: Sharpen ha\_eval\_template usage routing for compute-from-state queries
  ([#&#8203;1550](https://github.com/homeassistant-ai/ha-mcp/pull/1550))
- Differentiate ha-mcp from Home Assistant's built-in MCP Server
  ([#&#8203;1542](https://github.com/homeassistant-ai/ha-mcp/pull/1542))
- Update advanced mode notes
  ([#&#8203;1533](https://github.com/homeassistant-ai/ha-mcp/pull/1533))
- **[#&#8203;1157](https://github.com/homeassistant-ai/ha-mcp/issues/1157)**: Scripts native-for: guidance + fix numeric\_state-condition for: overclaim
  ([#&#8203;1480](https://github.com/homeassistant-ai/ha-mcp/pull/1480))
- Clarify add-on vs uvx; add Codex + HTTP-native client setup
  ([#&#8203;1478](https://github.com/homeassistant-ai/ha-mcp/pull/1478))
- **security**: Explicit threat model for trusted clients, LAN, sandbox, and OAuth tokens
  ([#&#8203;1463](https://github.com/homeassistant-ai/ha-mcp/pull/1463))
- Clarify telemetry is a planned future feature, not implemented
  ([#&#8203;1469](https://github.com/homeassistant-ai/ha-mcp/pull/1469))

##### Fixed

- **tools**: Bring HA API field names to 2026.6 — stale docstrings, automation plural canonicalization, fan speed (closes [#&#8203;1540](https://github.com/homeassistant-ai/ha-mcp/issues/1540))
  ([#&#8203;1566](https://github.com/homeassistant-ai/ha-mcp/pull/1566))
- **energy**: Accept "water" energy source in ha\_manage\_energy\_prefs
  ([#&#8203;1553](https://github.com/homeassistant-ai/ha-mcp/pull/1553))
- **tools**: Use action: not service: in automation docstring examples
  ([#&#8203;1539](https://github.com/homeassistant-ai/ha-mcp/pull/1539))
- **security**: Narrow GHSA-mc92-ww4q-6fg4 to the masker and log redaction
  ([#&#8203;1512](https://github.com/homeassistant-ai/ha-mcp/pull/1512))
- **addon**: Restrict settings UI root routes to HA ingress
  ([#&#8203;1508](https://github.com/homeassistant-ai/ha-mcp/pull/1508))
- Add name attributes to generated settings-UI form controls (a11y)
  ([#&#8203;1497](https://github.com/homeassistant-ai/ha-mcp/pull/1497))
- Add-on-aware code-mode locked note + suppress settings-UI favicon 404
  ([#&#8203;1494](https://github.com/homeassistant-ai/ha-mcp/pull/1494))
- Surface the real reason a WebSocket connection failed
  ([#&#8203;1495](https://github.com/homeassistant-ai/ha-mcp/pull/1495))
- Remove str from ha\_bulk\_control.operations schema + fix wrong-reason test
  ([#&#8203;1492](https://github.com/homeassistant-ai/ha-mcp/pull/1492))
- Remove str from bool/int param schemas across all tools
  ([#&#8203;1490](https://github.com/homeassistant-ai/ha-mcp/pull/1490))
- **addon**: Expose non-beta tool options on the stable add-on
  ([#&#8203;1488](https://github.com/homeassistant-ai/ha-mcp/pull/1488))
- **addon**: Enable ingress so the stable add-on shows the Open Web UI / Settings UI
  ([#&#8203;1486](https://github.com/homeassistant-ai/ha-mcp/pull/1486))
- Refine last\_changed/last\_updated duration-math detector ([#&#8203;1157](https://github.com/homeassistant-ai/ha-mcp/issues/1157))
  ([#&#8203;1483](https://github.com/homeassistant-ai/ha-mcp/pull/1483))
- Remove str from config param schema on service and entity tools
  ([#&#8203;1487](https://github.com/homeassistant-ai/ha-mcp/pull/1487))
- Surface flow-helper config to agents reading UI-created templates
  ([#&#8203;1474](https://github.com/homeassistant-ai/ha-mcp/pull/1474))
- Remove str from config param schema on set tools
  ([#&#8203;1485](https://github.com/homeassistant-ai/ha-mcp/pull/1485))
- Route malformed ha\_mcp\_tools version to a distinct reinstall error
  ([#&#8203;1484](https://github.com/homeassistant-ai/ha-mcp/pull/1484))
- Persist DCR client registrations and HMAC secret across restarts ([#&#8203;1261](https://github.com/homeassistant-ai/ha-mcp/issues/1261))
  ([#&#8203;1265](https://github.com/homeassistant-ai/ha-mcp/pull/1265))
- Stop dev builds from publishing the :latest Docker tag
  ([#&#8203;1477](https://github.com/homeassistant-ai/ha-mcp/pull/1477))
- Subscribe to HACS dispatch signal instead of 10x1s blind poll
  ([#&#8203;1455](https://github.com/homeassistant-ai/ha-mcp/pull/1455))
- Reject python\_transform while loops
  ([#&#8203;1462](https://github.com/homeassistant-ai/ha-mcp/pull/1462))

##### Performance Improvements

- Fast-fail HACS not-found lookups + batch-verify deep-search E2E fixtures ([#&#8203;1515](https://github.com/homeassistant-ai/ha-mcp/issues/1515))
  ([#&#8203;1552](https://github.com/homeassistant-ai/ha-mcp/pull/1552))

##### Refactoring

- Add display title to ha\_get\_skill\_guide tool
  ([#&#8203;1543](https://github.com/homeassistant-ai/ha-mcp/pull/1543))
- Fold ha\_check\_config into ha\_get\_system\_health include="config\_check"
  ([#&#8203;1516](https://github.com/homeassistant-ai/ha-mcp/pull/1516))
- **c901**: Smart\_search.py below C901 threshold
  ([#&#8203;1507](https://github.com/homeassistant-ai/ha-mcp/pull/1507))
- **hacs**: Consolidate HACS tools into ha\_get\_hacs + ha\_manage\_hacs ([#&#8203;1045](https://github.com/homeassistant-ai/ha-mcp/issues/1045))
  ([#&#8203;1502](https://github.com/homeassistant-ai/ha-mcp/pull/1502))
- **c901**: Tools\_config\_helpers.py below C901 threshold
  ([#&#8203;1498](https://github.com/homeassistant-ai/ha-mcp/pull/1498))
- **complexity**: Reduce C901 in tools\_addons.py via class-based pattern
  ([#&#8203;1432](https://github.com/homeassistant-ai/ha-mcp/pull/1432))

***

<details>
<summary>Internal Changes</summary>

##### Changed

- Trim AGENTS.md below 40k + improve subdirectory CLAUDE.md files
  ([#&#8203;1499](https://github.com/homeassistant-ai/ha-mcp/pull/1499))

##### Chores

- **addon**: Publish dev addon version 7.6.0.dev415 \[skip ci]
  ([`2c0148b`](https://github.com/homeassistant-ai/ha-mcp/commit/2c0148ba512a02b5299edbb4086c38410777a295))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.6.1
  ([#&#8203;1571](https://github.com/homeassistant-ai/ha-mcp/pull/1571))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.19
  ([#&#8203;1570](https://github.com/homeassistant-ai/ha-mcp/pull/1570))
- **addon**: Publish dev addon version 7.6.0.dev414 \[skip ci]
  ([`0bf9e39`](https://github.com/homeassistant-ai/ha-mcp/commit/0bf9e39947e8bf87d18bae23877d6b0d955dd35f))
- Sync tool docs after merge \[skip ci]
  ([`8f5e037`](https://github.com/homeassistant-ai/ha-mcp/commit/8f5e037b89296fd483888d158d8f72f4b1b7dfa8))
- **addon**: Publish dev addon version 7.6.0.dev413 \[skip ci]
  ([`6729327`](https://github.com/homeassistant-ai/ha-mcp/commit/6729327de8c0747f5cc7bb639859f95bbe1f0cfc))
- Sync tool docs after merge \[skip ci]
  ([`4341e95`](https://github.com/homeassistant-ai/ha-mcp/commit/4341e9574b3270c67bc016676f854f585fec816f))
- **addon**: Publish dev addon version 7.6.0.dev412 \[skip ci]
  ([`148f506`](https://github.com/homeassistant-ai/ha-mcp/commit/148f506a98c8f89292616a3a05dd0c9156516439))
- **addon**: Publish dev addon version 7.6.0.dev411 \[skip ci]
  ([`287fe55`](https://github.com/homeassistant-ai/ha-mcp/commit/287fe5503917e551f2dcb363cd28250237ed880c))
- Sync tool docs after merge \[skip ci]
  ([`b642b8e`](https://github.com/homeassistant-ai/ha-mcp/commit/b642b8eba67d8015d8fe5a1c1f88c9dd72ffc45f))
- **addon**: Publish dev addon version 7.6.0.dev410 \[skip ci]
  ([`29e34dd`](https://github.com/homeassistant-ai/ha-mcp/commit/29e34dd6eb517399de3c0a6a886e45ecf4749923))
- **addon**: Publish dev addon version 7.6.0.dev409 \[skip ci]
  ([`dec16a1`](https://github.com/homeassistant-ai/ha-mcp/commit/dec16a12d2ac3341908b130e9ea79f950d02466b))
- Sync tool docs after merge \[skip ci]
  ([`dd72535`](https://github.com/homeassistant-ai/ha-mcp/commit/dd725357f5d48a00959aaa7eceb4bad67a7ba202))
- **addon**: Publish dev addon version 7.6.0.dev408 \[skip ci]
  ([`c3c89f1`](https://github.com/homeassistant-ai/ha-mcp/commit/c3c89f1a758b6086b59ff21f9044597da103fa25))
- **addon**: Publish dev addon version 7.6.0.dev407 \[skip ci]
  ([`94195ee`](https://github.com/homeassistant-ai/ha-mcp/commit/94195ee4c8dbd0d8eec13d7c3d7ee392e5b7240f))
- **addon**: Publish dev addon version 7.6.0.dev406 \[skip ci]
  ([`f439424`](https://github.com/homeassistant-ai/ha-mcp/commit/f4394240dd1170f9d978e3c4a5011bab12f17f54))
- Sync tool docs after merge \[skip ci]
  ([`7464277`](https://github.com/homeassistant-ai/ha-mcp/commit/746427745d3debccea57c844278d1ba834d7ebfb))
- **addon**: Publish dev addon version 7.6.0.dev405 \[skip ci]
  ([`146eb07`](https://github.com/homeassistant-ai/ha-mcp/commit/146eb073a6f260ed0b0653cdb71346e9d29deae7))
- **addon**: Publish dev addon version 7.6.0.dev404 \[skip ci]
  ([`6a707bb`](https://github.com/homeassistant-ai/ha-mcp/commit/6a707bba576b987f8c3395adca3d59f7dd8a1050))
- Sync tool docs after merge \[skip ci]
  ([`85f3935`](https://github.com/homeassistant-ai/ha-mcp/commit/85f3935f80d9677f791b3098b201ec9c27e643be))
- **addon**: Publish dev addon version 7.6.0.dev403 \[skip ci]
  ([`be1fa1d`](https://github.com/homeassistant-ai/ha-mcp/commit/be1fa1dd2693170cbe3c037e7a88cf02f1847dcf))
- Sync tool docs after merge \[skip ci]
  ([`d9adbd2`](https://github.com/homeassistant-ai/ha-mcp/commit/d9adbd2c27750c9bc8faa55470d24564c48b3dbf))
- **addon**: Publish dev addon version 7.6.0.dev402 \[skip ci]
  ([`41ad7ca`](https://github.com/homeassistant-ai/ha-mcp/commit/41ad7caf1e0d982dd9e7bda3420ba3ca577cf765))
- **addon**: Publish dev addon version 7.6.0.dev401 \[skip ci]
  ([`8205034`](https://github.com/homeassistant-ai/ha-mcp/commit/820503485386f13dc66a0da3d304739e1f03dafd))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.18
  ([#&#8203;1523](https://github.com/homeassistant-ai/ha-mcp/pull/1523))
- **addon**: Publish dev addon version 7.6.0.dev400 \[skip ci]
  ([`532cdc4`](https://github.com/homeassistant-ai/ha-mcp/commit/532cdc440a8db053c524579f3e6b48b099c13c66))
- Sync tool docs after merge \[skip ci]
  ([`e2c08ff`](https://github.com/homeassistant-ai/ha-mcp/commit/e2c08ff797ffabf7b39bfc4b22b498b1c02ce1fa))
- **addon**: Publish dev addon version 7.6.0.dev399 \[skip ci]
  ([`9501348`](https://github.com/homeassistant-ai/ha-mcp/commit/95013488ea99761535ea9532285839bcd0ec8e3b))
- Sync tool docs after merge \[skip ci]
  ([`e70a050`](https://github.com/homeassistant-ai/ha-mcp/commit/e70a050efcb6edeb65d51dabd5307a192a22e66c))
- **addon**: Publish dev addon version 7.6.0.dev398 \[skip ci]
  ([`0b61424`](https://github.com/homeassistant-ai/ha-mcp/commit/0b61424ed823453dec27bb173d049f901eddc2d3))
- Sync tool docs after merge \[skip ci]
  ([`6df7987`](https://github.com/homeassistant-ai/ha-mcp/commit/6df79877669686a9fee3ec04979dff3960bc5e3f))
- **addon**: Publish dev addon version 7.6.0.dev397 \[skip ci]
  ([`c34915f`](https://github.com/homeassistant-ai/ha-mcp/commit/c34915f40cd82f83f0eb4af5c3a5655843608770))
- Sync tool docs after merge \[skip ci]
  ([`6f88e7e`](https://github.com/homeassistant-ai/ha-mcp/commit/6f88e7e0c8dcb7fee27792e0f87f6acd8aa892c4))
- **addon**: Publish dev addon version 7.6.0.dev396 \[skip ci]
  ([`1490e19`](https://github.com/homeassistant-ai/ha-mcp/commit/1490e190382454b17fc14cd362b17612a6af253f))
- Sync tool docs after merge \[skip ci]
  ([`ac2c7d0`](https://github.com/homeassistant-ai/ha-mcp/commit/ac2c7d038a90fb44466afa8f047378d7e8daed94))
- **addon**: Publish dev addon version 7.6.0.dev395 \[skip ci]
  ([`11e5ee8`](https://github.com/homeassistant-ai/ha-mcp/commit/11e5ee8f07f63f63b8cdf017397263c7602e80f6))
- **addon**: Publish dev addon version 7.6.0.dev394 \[skip ci]
  ([`5fc3e0f`](https://github.com/homeassistant-ai/ha-mcp/commit/5fc3e0f572bfd1bb367e65b3f4d78b96cb78fa91))
- Flag untrusted third-party content in HACS and add-on tool responses
  ([#&#8203;1509](https://github.com/homeassistant-ai/ha-mcp/pull/1509))
- **addon**: Publish dev addon version 7.6.0.dev393 \[skip ci]
  ([`9a37c28`](https://github.com/homeassistant-ai/ha-mcp/commit/9a37c28cfa0d1f3f652fe441ce2fe1d72a7360ab))
- **addon**: Publish dev addon version 7.6.0.dev392 \[skip ci]
  ([`4f737ac`](https://github.com/homeassistant-ai/ha-mcp/commit/4f737ac7c116e9afa046ab45b1230e2cdb5ae959))
- **addon**: Publish dev addon version 7.6.0.dev391 \[skip ci]
  ([`fd5d3f2`](https://github.com/homeassistant-ai/ha-mcp/commit/fd5d3f2d4ce87baa4cfcc85a173bb0cc9d132a35))
- **addon**: Publish dev addon version 7.6.0.dev390 \[skip ci]
  ([`28dedf4`](https://github.com/homeassistant-ai/ha-mcp/commit/28dedf43f3cd094b1c40fb50e535166cc8c33388))
- **addon**: Publish dev addon version 7.6.0.dev389 \[skip ci]
  ([`9443446`](https://github.com/homeassistant-ai/ha-mcp/commit/9443446fdd607a75d8db5fdad009130b188267d6))
- Sync tool docs after merge \[skip ci]
  ([`94fcbeb`](https://github.com/homeassistant-ai/ha-mcp/commit/94fcbeb14bd9cfa3bef274182f95e4562a379971))
- **addon**: Publish dev addon version 7.6.0.dev388 \[skip ci]
  ([`ccc1816`](https://github.com/homeassistant-ai/ha-mcp/commit/ccc18162eec520950c58cc8eabb2aac04ac57ab3))
- Drop dead entity\_cache attr + ruff-format fuzzy\_search.py
  ([#&#8203;1503](https://github.com/homeassistant-ai/ha-mcp/pull/1503))
- **addon**: Publish dev addon version 7.6.0.dev387 \[skip ci]
  ([`057c108`](https://github.com/homeassistant-ai/ha-mcp/commit/057c108b2958959bfee34225899b47b5c989a119))
- **addon**: Publish dev addon version 7.6.0.dev386 \[skip ci]
  ([`66f4ac6`](https://github.com/homeassistant-ai/ha-mcp/commit/66f4ac6a37d85412b895962afef1b03707400e56))
- **addon**: Publish dev addon version 7.6.0.dev385 \[skip ci]
  ([`f331f11`](https://github.com/homeassistant-ai/ha-mcp/commit/f331f1150f525a18bf5bd2e27007b46a07a3492c))
- **addon**: Publish dev addon version 7.6.0.dev384 \[skip ci]
  ([`17c319e`](https://github.com/homeassistant-ai/ha-mcp/commit/17c319e68ba4b4d4e6acd84deb57c588aafcb48b))
- Sync tool docs after merge \[skip ci]
  ([`f36cbb7`](https://github.com/homeassistant-ai/ha-mcp/commit/f36cbb7e620839b16808b37b61dbc7602557b409))
- **addon**: Publish dev addon version 7.6.0.dev383 \[skip ci]
  ([`782ba3b`](https://github.com/homeassistant-ai/ha-mcp/commit/782ba3b2bbcfe50564c5524d6a2c018a4c9c9ba6))
- **addon**: Publish dev addon version 7.6.0.dev382 \[skip ci]
  ([`b647ab6`](https://github.com/homeassistant-ai/ha-mcp/commit/b647ab6eea76a030c7e3c46f72d732ff339398fe))
- **addon**: Publish dev addon version 7.6.0.dev381 \[skip ci]
  ([`e999c24`](https://github.com/homeassistant-ai/ha-mcp/commit/e999c242553a60561ca06dbefe3177c627bb9e2d))
- Sync tool docs after merge \[skip ci]
  ([`50d76b0`](https://github.com/homeassistant-ai/ha-mcp/commit/50d76b04a0691c565fafaabc76fd4bd3cf321953))
- **addon**: Publish dev addon version 7.6.0.dev380 \[skip ci]
  ([`ebdc69b`](https://github.com/homeassistant-ai/ha-mcp/commit/ebdc69bde929fd3342234149956af0710b9f260a))
- Sync tool docs after merge \[skip ci]
  ([`1f03967`](https://github.com/homeassistant-ai/ha-mcp/commit/1f03967160156cbffdfc9fc7deb5ed9a2b25f2ba))
- **addon**: Publish dev addon version 7.6.0.dev379 \[skip ci]
  ([`7cabb2e`](https://github.com/homeassistant-ai/ha-mcp/commit/7cabb2ec342561dbc74251f7697e3c4df0a8fcb3))
- **addon**: Publish dev addon version 7.6.0.dev378 \[skip ci]
  ([`7b631c7`](https://github.com/homeassistant-ai/ha-mcp/commit/7b631c75e0e4163ee13906b90ddad7a1b744e402))
- **addon**: Publish dev addon version 7.6.0.dev377 \[skip ci]
  ([`ea7b614`](https://github.com/homeassistant-ai/ha-mcp/commit/ea7b614615606a8fc05a0a18cb9cafa2f0a42c0d))
- **addon**: Publish dev addon version 7.6.0.dev376 \[skip ci]
  ([`fd33ecd`](https://github.com/homeassistant-ai/ha-mcp/commit/fd33ecd4d260f5fc2ab4f229c90b1a4514c5ccde))
- Sync tool docs after merge \[skip ci]
  ([`ba8fae3`](https://github.com/homeassistant-ai/ha-mcp/commit/ba8fae3cc4f451dc65022756a86cce5275f6e35f))
- **addon**: Publish dev addon version 7.6.0.dev375 \[skip ci]
  ([`afcd0d8`](https://github.com/homeassistant-ai/ha-mcp/commit/afcd0d8e061e1cba65fd119727fc64ed77f1818d))
- Sync tool docs after merge \[skip ci]
  ([`f9b55ad`](https://github.com/homeassistant-ai/ha-mcp/commit/f9b55ad59c6f03d6a98c3d3f6dd52ba9ff7c8a7a))
- **addon**: Publish dev addon version 7.6.0.dev374 \[skip ci]
  ([`eecdf8b`](https://github.com/homeassistant-ai/ha-mcp/commit/eecdf8b058ba932ba94cfb292ebf2331a54d2def))
- Sync tool docs after merge \[skip ci]
  ([`ef16a8a`](https://github.com/homeassistant-ai/ha-mcp/commit/ef16a8a197c76e51a49ae6ac69eecb15d202a194))
- **addon**: Publish dev addon version 7.6.0.dev373 \[skip ci]
  ([`9a93703`](https://github.com/homeassistant-ai/ha-mcp/commit/9a9370362fe5573ac71cd6e90353877faccce8a6))
- **addon**: Publish dev addon version 7.6.0.dev372 \[skip ci]
  ([`7352ce8`](https://github.com/homeassistant-ai/ha-mcp/commit/7352ce88ef59feef74c29ab47f6991cc2ac132a8))
- **addon**: Publish dev addon version 7.6.0.dev371 \[skip ci]
  ([`d7601f5`](https://github.com/homeassistant-ai/ha-mcp/commit/d7601f5796308e1c42a01dbce9861460027a93c4))
- Sync tool docs after merge \[skip ci]
  ([`d0a4482`](https://github.com/homeassistant-ai/ha-mcp/commit/d0a448276306a08f8a52c4645f1b9c5aeaafd68e))
- **addon**: Publish dev addon version 7.6.0.dev370 \[skip ci]
  ([`f83c32c`](https://github.com/homeassistant-ai/ha-mcp/commit/f83c32c747ddaeccffb040bc28d3e08d7507ded4))
- **addon**: Publish dev addon version 7.6.0.dev369 \[skip ci]
  ([`ea16661`](https://github.com/homeassistant-ai/ha-mcp/commit/ea16661f1d144feada93aee119b625f968f990cb))
- **addon**: Publish dev addon version 7.6.0.dev368 \[skip ci]
  ([`af49ea5`](https://github.com/homeassistant-ai/ha-mcp/commit/af49ea5aff5c9f54914943cc2f8a67ebeea2fdee))
- **addon**: Publish dev addon version 7.6.0.dev367 \[skip ci]
  ([`7dd5f4c`](https://github.com/homeassistant-ai/ha-mcp/commit/7dd5f4cd0237ef4d80a454efe4dfc0801f18fdbd))
- **addon**: Publish dev addon version 7.6.0.dev366 \[skip ci]
  ([`6273b7e`](https://github.com/homeassistant-ai/ha-mcp/commit/6273b7ec8695706948eefe8e617cac39363940ce))
- Sync tool docs after merge \[skip ci]
  ([`4e3fd5f`](https://github.com/homeassistant-ai/ha-mcp/commit/4e3fd5f331ce5fefa8e0e5560da411de17f2a8db))
- **addon**: Publish dev addon version 7.6.0.dev365 \[skip ci]
  ([`f3bf17b`](https://github.com/homeassistant-ai/ha-mcp/commit/f3bf17be132ebc67005c33a3c8fde85025d56809))
- Sync tool docs after merge \[skip ci]
  ([`5307b60`](https://github.com/homeassistant-ai/ha-mcp/commit/5307b608879154fccf67bc1894f61e97f26719c6))
- **addon**: Publish dev addon version 7.6.0.dev364 \[skip ci]
  ([`76ec1ae`](https://github.com/homeassistant-ai/ha-mcp/commit/76ec1aefab8e904abf620bf1c1130e5f5d0c4bd9))
- Sync tool docs after merge \[skip ci]
  ([`be864b5`](https://github.com/homeassistant-ai/ha-mcp/commit/be864b5d685f167334487d4fe83324afbb4999ca))
- **addon**: Publish dev addon version 7.6.0.dev363 \[skip ci]
  ([`da10c75`](https://github.com/homeassistant-ai/ha-mcp/commit/da10c75a248dcc19442e4db6f34f325683cb0a71))
- **addon**: Publish dev addon version 7.6.0.dev362 \[skip ci]
  ([`69f4527`](https://github.com/homeassistant-ai/ha-mcp/commit/69f45279707d18c724bd702ced46111b26cd000c))
- **addon**: Publish version 7.6.0 \[skip ci]
  ([`086d75d`](https://github.com/homeassistant-ai/ha-mcp/commit/086d75d72dd7d1c735413d96ef2fd38ae57b90ca))

##### Continuous Integration

- Vendor Puppet add-on as a pinned submodule + retry transient add-on builds
  ([#&#8203;1565](https://github.com/homeassistant-ai/ha-mcp/pull/1565))
- Make sync-tool-docs push resilient to concurrent master advances
  ([#&#8203;1564](https://github.com/homeassistant-ai/ha-mcp/pull/1564))
- Fix stale token-cap comment and harden triage budget tests ([#&#8203;1514](https://github.com/homeassistant-ai/ha-mcp/issues/1514))
  ([#&#8203;1560](https://github.com/homeassistant-ai/ha-mcp/pull/1560))
- **deps**: Bump the github-actions group with 2 updates
  ([#&#8203;1556](https://github.com/homeassistant-ai/ha-mcp/pull/1556))
- Budget triage prompt dynamically under the GitHub Models cap ([#&#8203;1514](https://github.com/homeassistant-ai/ha-mcp/issues/1514))
  ([#&#8203;1522](https://github.com/homeassistant-ai/ha-mcp/pull/1522))
- Reduce Docker Hub pulls in performance-tests workflow
  ([#&#8203;1549](https://github.com/homeassistant-ai/ha-mcp/pull/1549))
- Add JavaScript to the CodeQL code-quality gate
  ([#&#8203;1548](https://github.com/homeassistant-ai/ha-mcp/pull/1548))
- Add CodeQL code-quality CI gate and clear all code-quality findings
  ([#&#8203;1526](https://github.com/homeassistant-ai/ha-mcp/pull/1526))
- Drop tool list from evaluate prompt + tighten caps to fit 8K token limit
  ([`6f47c92`](https://github.com/homeassistant-ai/ha-mcp/commit/6f47c92507ef0d854153632107c0c702812f0c3c))
- Remove broken maintainer check (GITHUB\_TOKEN lacks read:org)
  ([`010ec58`](https://github.com/homeassistant-ai/ha-mcp/commit/010ec58d1f3b6d46b20aa83c3caee373dd826694))
- Switch evaluate step to gpt-4o-mini (16K token free tier vs 8K on gpt-4.1)
  ([#&#8203;1496](https://github.com/homeassistant-ai/ha-mcp/pull/1496))
- Issue bot v2 — GitHub Models triage, needs-info auto-close, duplicate detection
  ([#&#8203;1442](https://github.com/homeassistant-ai/ha-mcp/pull/1442))

##### Refactoring

- Extract settings-UI JavaScript and CSS to separate files
  ([#&#8203;1505](https://github.com/homeassistant-ai/ha-mcp/pull/1505))
- Collapse settings-UI route registration into one table
  ([#&#8203;1504](https://github.com/homeassistant-ai/ha-mcp/pull/1504))

##### Testing

- **oauth**: Add HTTP smoke tests for OAuth metadata-discovery endpoints
  ([#&#8203;1562](https://github.com/homeassistant-ai/ha-mcp/pull/1562))
- **uat**: Relabel c01 as a mode-discrimination probe (taxonomy consistency)
  ([#&#8203;1563](https://github.com/homeassistant-ai/ha-mcp/pull/1563))
- **uat**: Rework c01 routing probe to ha\_search registry-listing mode after [#&#8203;1529](https://github.com/homeassistant-ai/ha-mcp/issues/1529)
  ([#&#8203;1559](https://github.com/homeassistant-ai/ha-mcp/pull/1559))
- **uat**: Add response\_contains\_any check and always log agent responses
  ([#&#8203;1537](https://github.com/homeassistant-ai/ha-mcp/pull/1537))
- **uat**: Treat request timeout as per-story failure, not suite abort
  ([#&#8203;1536](https://github.com/homeassistant-ai/ha-mcp/pull/1536))
- **uat**: Harden BAT story runner against agent crashes
  ([#&#8203;1535](https://github.com/homeassistant-ai/ha-mcp/pull/1535))
- **uat**: Log model and quantization in BAT story results
  ([#&#8203;1525](https://github.com/homeassistant-ai/ha-mcp/pull/1525))
- Capture reasoning tokens and detect inert --no-think in BAT openai agent
  ([#&#8203;1524](https://github.com/homeassistant-ai/ha-mcp/pull/1524))

</details>

### [`v7.6.0`](https://github.com/homeassistant-ai/ha-mcp/blob/HEAD/CHANGELOG.md#v760-2026-05-27)

[Compare Source](https://github.com/homeassistant-ai/ha-mcp/compare/v7.5.0...v7.6.0)

##### Added

- Make HTTP bind host configurable via MCP\_HOST (closes [#&#8203;1434](https://github.com/homeassistant-ai/ha-mcp/issues/1434))
  ([#&#8203;1436](https://github.com/homeassistant-ai/ha-mcp/pull/1436))
- Tool Security Policies — per-tool approval gating ([#&#8203;966](https://github.com/homeassistant-ai/ha-mcp/issues/966))
  ([#&#8203;1421](https://github.com/homeassistant-ai/ha-mcp/pull/1421))
- Rename ha\_delete\_helpers\_integrations → ha\_remove\_helpers\_integrations + raise on missing target
  ([#&#8203;1424](https://github.com/homeassistant-ai/ha-mcp/pull/1424))
- Auto-backup edited entities before write/destructive tool calls (closes [#&#8203;1288](https://github.com/homeassistant-ai/ha-mcp/issues/1288))
  ([#&#8203;1403](https://github.com/homeassistant-ai/ha-mcp/pull/1403))
- Persistent settings UI for stdio mode
  ([#&#8203;1381](https://github.com/homeassistant-ai/ha-mcp/pull/1381))
- Add fields= projection to ha\_search\_entities, ha\_get\_overview, ha\_get\_state, ha\_get\_history, ha\_config\_list\_areas, ha\_list\_services ([#&#8203;1199](https://github.com/homeassistant-ai/ha-mcp/issues/1199))
  ([#&#8203;1225](https://github.com/homeassistant-ai/ha-mcp/pull/1225))
- Route entity-registration wait through WS events (closes [#&#8203;1152](https://github.com/homeassistant-ai/ha-mcp/issues/1152))
  ([#&#8203;1382](https://github.com/homeassistant-ai/ha-mcp/pull/1382))
- Add config subentry support
  ([#&#8203;1393](https://github.com/homeassistant-ai/ha-mcp/pull/1393))
- Add Assist pipeline management tool
  ([#&#8203;1392](https://github.com/homeassistant-ai/ha-mcp/pull/1392))
- Add knx to ha\_config\_set\_yaml allowlist
  ([#&#8203;1374](https://github.com/homeassistant-ai/ha-mcp/pull/1374))
- Extend automation\_id parity to set/remove automation responses
  ([#&#8203;1343](https://github.com/homeassistant-ai/ha-mcp/pull/1343))
- **haos-e2e**: Add parallel inaddon test tier (ha-mcp runs inside HAOS addon)
  ([#&#8203;1361](https://github.com/homeassistant-ai/ha-mcp/pull/1361))
- Expose integration diagnostics via ha\_get\_integration and ha\_get\_system\_health (closes [#&#8203;1148](https://github.com/homeassistant-ai/ha-mcp/issues/1148))
  ([#&#8203;1328](https://github.com/homeassistant-ai/ha-mcp/pull/1328))
- Return canonical script\_id from ha\_config\_get\_script ([#&#8203;1334](https://github.com/homeassistant-ai/ha-mcp/issues/1334))
  ([#&#8203;1352](https://github.com/homeassistant-ai/ha-mcp/pull/1352))
- Add automation\_id parity key to ha\_config\_get\_automation
  ([#&#8203;1329](https://github.com/homeassistant-ai/ha-mcp/pull/1329))
- Reject empty/whitespace identifiers on registry-metadata writes (closes [#&#8203;1294](https://github.com/homeassistant-ai/ha-mcp/issues/1294))
  ([#&#8203;1312](https://github.com/homeassistant-ai/ha-mcp/pull/1312))
- Add HA brand assets for custom integration
  ([#&#8203;1317](https://github.com/homeassistant-ai/ha-mcp/pull/1317))
- Unify ha\_config\_set\_helper response shape (closes [#&#8203;1293](https://github.com/homeassistant-ai/ha-mcp/issues/1293))
  ([#&#8203;1303](https://github.com/homeassistant-ai/ha-mcp/pull/1303))
- Mirror create-side validation guards onto update path (closes [#&#8203;1292](https://github.com/homeassistant-ai/ha-mcp/issues/1292))
  ([#&#8203;1304](https://github.com/homeassistant-ai/ha-mcp/pull/1304))
- Add array\_patch mode to ha\_manage\_addon for atomic GET-modify-POST
  ([#&#8203;1063](https://github.com/homeassistant-ai/ha-mcp/pull/1063))

##### Changed

- **agents**: Drop ha\_backup\_create + ha\_backup\_restore from accepted exceptions
  ([#&#8203;1445](https://github.com/homeassistant-ai/ha-mcp/pull/1445))
- Update contributors list \[contributors-updated]
  ([`c7665a6`](https://github.com/homeassistant-ai/ha-mcp/commit/c7665a6f5a08737d8fcbebbbe6afdc88ec5c4901))
- **overview**: Enumerate dismissed\_repair\_count in fields= description + static drift test
  ([#&#8203;1411](https://github.com/homeassistant-ai/ha-mcp/pull/1411))
- Credit [@&#8203;tomwilkie](https://github.com/tomwilkie) and six other contributors in README
  ([#&#8203;1400](https://github.com/homeassistant-ai/ha-mcp/pull/1400))
- **[#&#8203;1157](https://github.com/homeassistant-ai/ha-mcp/issues/1157)**: Bump skills-vendor + auto-update via Renovate + native for: field + scrub eval\_template anti-patterns
  ([#&#8203;1383](https://github.com/homeassistant-ai/ha-mcp/pull/1383))
- Extend Boy Scout weasel-phrase list with common variants; clarify semantic match
  ([#&#8203;1373](https://github.com/homeassistant-ai/ha-mcp/pull/1373))
- Merge Boy Scout Rule + Handling Discovered Improvements; tighten deferral gate
  ([#&#8203;1359](https://github.com/homeassistant-ai/ha-mcp/pull/1359))
- Categorize Issue Labels table and document 6 reverse-drift labels
  ([#&#8203;1335](https://github.com/homeassistant-ai/ha-mcp/pull/1335))
- Strip stale L-refs from test\_identifier\_validation\_family docstrings
  ([#&#8203;1324](https://github.com/homeassistant-ai/ha-mcp/pull/1324))
- Align label refs with live label set and fix triaged-removal trigger
  ([#&#8203;1316](https://github.com/homeassistant-ai/ha-mcp/pull/1316))
- Surface tool-discovery / categorized search
  ([#&#8203;1123](https://github.com/homeassistant-ai/ha-mcp/pull/1123))
- Fix two stale ha\_get\_skill\_guide references missed in [#&#8203;1289](https://github.com/homeassistant-ai/ha-mcp/issues/1289)
  ([#&#8203;1305](https://github.com/homeassistant-ai/ha-mcp/pull/1305))
- Clarify setup wizard placeholders need braces removed ([#&#8203;1284](https://github.com/homeassistant-ai/ha-mcp/issues/1284))
  ([#&#8203;1286](https://github.com/homeassistant-ai/ha-mcp/pull/1286))

##### Fixed

- Remove counter from ha\_reload\_core targets ([#&#8203;1453](https://github.com/homeassistant-ai/ha-mcp/issues/1453))
  ([#&#8203;1456](https://github.com/homeassistant-ai/ha-mcp/pull/1456))
- **backup**: Post-timeout match correctness + state-gate (closes [#&#8203;1433](https://github.com/homeassistant-ai/ha-mcp/issues/1433))
  ([#&#8203;1435](https://github.com/homeassistant-ai/ha-mcp/pull/1435))
- Sync addon settings UI with Supervisor options end-to-end
  ([#&#8203;1420](https://github.com/homeassistant-ai/ha-mcp/pull/1420))
- **calendar**: Switch ha\_config\_remove\_calendar\_event to WebSocket (closes [#&#8203;1413](https://github.com/homeassistant-ai/ha-mcp/issues/1413), [#&#8203;1416](https://github.com/homeassistant-ai/ha-mcp/issues/1416))
  ([#&#8203;1418](https://github.com/homeassistant-ai/ha-mcp/pull/1418))
- Error-shape consistency for non-entity not-found (closes [#&#8203;1297](https://github.com/homeassistant-ai/ha-mcp/issues/1297))
  ([#&#8203;1397](https://github.com/homeassistant-ai/ha-mcp/pull/1397))
- Guard against silent automation overwrite on id mismatch ([#&#8203;1404](https://github.com/homeassistant-ai/ha-mcp/issues/1404))
  ([#&#8203;1405](https://github.com/homeassistant-ai/ha-mcp/pull/1405))
- Cache YAML instance to prevent CPU spikes in bulk edits ([#&#8203;1370](https://github.com/homeassistant-ai/ha-mcp/issues/1370))
  ([#&#8203;1371](https://github.com/homeassistant-ai/ha-mcp/pull/1371))
- **client**: Route get\_error\_log via hassio proxy on external-HAOS clients
  ([#&#8203;1360](https://github.com/homeassistant-ai/ha-mcp/pull/1360))
- Classify dashboard 404s ("unknown config specified") as RESOURCE\_NOT\_FOUND
  ([#&#8203;1345](https://github.com/homeassistant-ai/ha-mcp/pull/1345))
- Detect HA addon installs as http transport, not stdio ([#&#8203;1322](https://github.com/homeassistant-ai/ha-mcp/issues/1322))
  ([#&#8203;1327](https://github.com/homeassistant-ai/ha-mcp/pull/1327))
- Actionable 403 suggestion when addon has unmapped container ports ([#&#8203;1319](https://github.com/homeassistant-ai/ha-mcp/issues/1319))
  ([#&#8203;1325](https://github.com/homeassistant-ai/ha-mcp/pull/1325))
- Filter dismissed repairs in overview and system\_health ([#&#8203;1307](https://github.com/homeassistant-ai/ha-mcp/issues/1307))
  ([#&#8203;1309](https://github.com/homeassistant-ai/ha-mcp/pull/1309))
- Exit on HA container death + daily reset before CI check
  ([#&#8203;1295](https://github.com/homeassistant-ai/ha-mcp/pull/1295))
- Align ha\_config\_set\_dashboard with sibling re-fetch-after-save pattern ([#&#8203;1291](https://github.com/homeassistant-ai/ha-mcp/issues/1291))
  ([#&#8203;1301](https://github.com/homeassistant-ai/ha-mcp/pull/1301))
- Allow str.replace in python\_transform; hint at search mode on IndexError
  ([#&#8203;1287](https://github.com/homeassistant-ai/ha-mcp/pull/1287))
- **array\_patch**: Tighten validation and surface silent failures
  ([#&#8203;1285](https://github.com/homeassistant-ai/ha-mcp/pull/1285))
- HA Core proxy fallback for ha\_get\_logs(source=system\_service) on non-addon installs
  ([#&#8203;1283](https://github.com/homeassistant-ai/ha-mcp/pull/1283))

##### Performance Improvements

- Tighten \_poll\_for\_automation\_entity first-poll cadence
  ([#&#8203;1384](https://github.com/homeassistant-ai/ha-mcp/pull/1384))
- Parallelize ha\_get\_system\_health optional sections via asyncio.gather
  ([#&#8203;1336](https://github.com/homeassistant-ai/ha-mcp/pull/1336))

##### Refactoring

- **service**: Compact ha\_call\_service result default ([#&#8203;1446](https://github.com/homeassistant-ai/ha-mcp/issues/1446))
  ([#&#8203;1447](https://github.com/homeassistant-ai/ha-mcp/pull/1447))
- Rename ha\_update\_device → ha\_set\_device
  ([#&#8203;1444](https://github.com/homeassistant-ai/ha-mcp/pull/1444))
- Remove duplicate flat area/floor list tools (consolidation followup to [#&#8203;1016](https://github.com/homeassistant-ai/ha-mcp/issues/1016))
  ([#&#8203;1429](https://github.com/homeassistant-ai/ha-mcp/pull/1429))
- **complexity**: Migrate tools\_utility.py to class-based pattern
  ([#&#8203;1423](https://github.com/homeassistant-ai/ha-mcp/pull/1423))
- **complexity**: Reduce C901 violations in tools/ — batch 4
  ([#&#8203;1408](https://github.com/homeassistant-ai/ha-mcp/pull/1408))
- Route \_poll\_for\_automation\_entity through WS event waiter (closes [#&#8203;1395](https://github.com/homeassistant-ai/ha-mcp/issues/1395))
  ([#&#8203;1406](https://github.com/homeassistant-ai/ha-mcp/pull/1406))
- **yaml**: Use threading.local subclass for cached instance
  ([#&#8203;1396](https://github.com/homeassistant-ai/ha-mcp/pull/1396))
- Align dashboards 404 shape with sibling config tools
  ([#&#8203;1386](https://github.com/homeassistant-ai/ha-mcp/pull/1386))
- Complete singular warning → warnings list migration repo-wide (closes [#&#8203;1332](https://github.com/homeassistant-ai/ha-mcp/issues/1332))
  ([#&#8203;1341](https://github.com/homeassistant-ai/ha-mcp/pull/1341))
- Complete warnings-list migration for lifecycle-write tools
  ([#&#8203;1340](https://github.com/homeassistant-ai/ha-mcp/pull/1340))
- Drop redundant identifier echo key from ha\_config\_get\_automation
  ([#&#8203;1354](https://github.com/homeassistant-ai/ha-mcp/pull/1354))
- Drop logger.error in config-tool except blocks ([#&#8203;1302](https://github.com/homeassistant-ai/ha-mcp/issues/1302))
  ([#&#8203;1353](https://github.com/homeassistant-ai/ha-mcp/pull/1353))
- Extend validate\_identifier\_not\_empty to automations/scripts/dashboards CRUD (closes [#&#8203;1313](https://github.com/homeassistant-ai/ha-mcp/issues/1313))
  ([#&#8203;1321](https://github.com/homeassistant-ai/ha-mcp/pull/1321))
- Migrate tools\_config\_scenes inline empty-id guards to shared helper
  ([#&#8203;1320](https://github.com/homeassistant-ai/ha-mcp/pull/1320))
- Remove ha\_get\_helper\_schema (closes [#&#8203;1186](https://github.com/homeassistant-ai/ha-mcp/issues/1186))
  ([#&#8203;1315](https://github.com/homeassistant-ai/ha-mcp/pull/1315))
- Consolidate skill tools; fix stable submodule packaging
  ([#&#8203;1289](https://github.com/homeassistant-ai/ha-mcp/pull/1289))
- Align tools\_config\_automations.py error-handling with sibling pattern ([#&#8203;1290](https://github.com/homeassistant-ai/ha-mcp/issues/1290))
  ([#&#8203;1298](https://github.com/homeassistant-ai/ha-mcp/pull/1298))

***

<details>
<summary>Internal Changes</summary>

##### Fixed

- **ci**: Install libguestfs in HAOS publish workflow
  ([#&#8203;1358](https://github.com/homeassistant-ai/ha-mcp/pull/1358))

##### Build System

- **deps**: Bump esbuild from 0.24.2 to 0.25.0 in /tests/js
  ([#&#8203;1427](https://github.com/homeassistant-ai/ha-mcp/pull/1427))
- **deps**: Bump devalue from 5.6.4 to 5.8.1 in /site
  ([#&#8203;1282](https://github.com/homeassistant-ai/ha-mcp/pull/1282))
- **deps**: Bump astro from 6.1.6 to 6.1.10 in /site
  ([#&#8203;1274](https://github.com/homeassistant-ai/ha-mcp/pull/1274))

##### Chores

- **addon**: Publish dev addon version 7.5.0.dev360 \[skip ci]
  ([`ad7aed1`](https://github.com/homeassistant-ai/ha-mcp/commit/ad7aed13d6843967e2a259ae46fec2bbc6abc896))
- Sync tool docs after merge \[skip ci]
  ([`9c4984f`](https://github.com/homeassistant-ai/ha-mcp/commit/9c4984fc44d30c15a96372fbc1b401fbd679dc8f))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.4
  ([#&#8203;1450](https://github.com/homeassistant-ai/ha-mcp/pull/1450))
- **addon**: Publish dev addon version 7.5.0.dev359 \[skip ci]
  ([`b82d4ee`](https://github.com/homeassistant-ai/ha-mcp/commit/b82d4eea85792b620368d4859e99c143f9fbfadf))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.16
  ([#&#8203;1449](https://github.com/homeassistant-ai/ha-mcp/pull/1449))
- **addon**: Publish dev addon version 7.5.0.dev358 \[skip ci]
  ([`53fba6d`](https://github.com/homeassistant-ai/ha-mcp/commit/53fba6da76ce8c78a0de035883233a36762601bc))
- Sync tool docs after merge \[skip ci]
  ([`dc7750d`](https://github.com/homeassistant-ai/ha-mcp/commit/dc7750de16b60f70e40e6e5c8908d9e84e544683))
- **addon**: Publish dev addon version 7.5.0.dev357 \[skip ci]
  ([`fd150c9`](https://github.com/homeassistant-ai/ha-mcp/commit/fd150c9b9c4bdb9026e67eae340226c36b270d94))
- **addon**: Publish dev addon version 7.5.0.dev356 \[skip ci]
  ([`5fa1463`](https://github.com/homeassistant-ai/ha-mcp/commit/5fa14630229ba0d6b97d9328768e247bf9c20af4))
- **addon**: Publish dev addon version 7.5.0.dev355 \[skip ci]
  ([`174ac5d`](https://github.com/homeassistant-ai/ha-mcp/commit/174ac5dca7667702cd664420c50e0101366e6c3a))
- **addon**: Publish dev addon version 7.5.0.dev354 \[skip ci]
  ([`4f93989`](https://github.com/homeassistant-ai/ha-mcp/commit/4f939892dea2d1951541b1a557c51e957f6751c0))
- **addon**: Publish dev addon version 7.5.0.dev353 \[skip ci]
  ([`53f282f`](https://github.com/homeassistant-ai/ha-mcp/commit/53f282f19ee736637106f5baececa3939393778e))
- **addon**: Publish dev addon version 7.5.0.dev352 \[skip ci]
  ([`4911d46`](https://github.com/homeassistant-ai/ha-mcp/commit/4911d4682c4a865a93a8e821bc86bd26cef0ed5a))
- Sync tool docs after merge \[skip ci]
  ([`8a79837`](https://github.com/homeassistant-ai/ha-mcp/commit/8a798373a7b2f1adb94b93e65d626ab582c7bd5d))
- **addon**: Publish dev addon version 7.5.0.dev351 \[skip ci]
  ([`13afa9d`](https://github.com/homeassistant-ai/ha-mcp/commit/13afa9df026dd27332277140c34f7d41d0229efd))
- **addon**: Publish dev addon version 7.5.0.dev350 \[skip ci]
  ([`e93d680`](https://github.com/homeassistant-ai/ha-mcp/commit/e93d6806025c6d7fd2ef94c509a607c4ac85c8e0))
- **addon**: Publish dev addon version 7.5.0.dev349 \[skip ci]
  ([`1631ad1`](https://github.com/homeassistant-ai/ha-mcp/commit/1631ad10bdada4487d7b54049e92df6ddb29439a))
- **addon**: Publish dev addon version 7.5.0.dev348 \[skip ci]
  ([`18a8aef`](https://github.com/homeassistant-ai/ha-mcp/commit/18a8aef50675c1a881b279666e0af1b093679850))
- Sync tool docs after merge \[skip ci]
  ([`9e0493d`](https://github.com/homeassistant-ai/ha-mcp/commit/9e0493d248e23a8042841e90847662926395a448))
- **addon**: Publish dev addon version 7.5.0.dev347 \[skip ci]
  ([`e2067e4`](https://github.com/homeassistant-ai/ha-mcp/commit/e2067e446b127097e61d07516ae0e742ae2de6c8))
- Sync tool docs after merge \[skip ci]
  ([`7bdb3d4`](https://github.com/homeassistant-ai/ha-mcp/commit/7bdb3d402b60900a1012b8269e52b7cbeb400f84))
- **addon**: Publish dev addon version 7.5.0.dev346 \[skip ci]
  ([`c2d4dd7`](https://github.com/homeassistant-ai/ha-mcp/commit/c2d4dd7091653a618326f665fd34b5458d26c8f6))
- Sync tool docs after merge \[skip ci]
  ([`393b354`](https://github.com/homeassistant-ai/ha-mcp/commit/393b354e8a8e1280029eee9521971c693526970a))
- **addon**: Publish dev addon version 7.5.0.dev345 \[skip ci]
  ([`42ede8b`](https://github.com/homeassistant-ai/ha-mcp/commit/42ede8b0e6066faf3ed6f6920629a8d94d77f69a))
- **addon**: Publish dev addon version 7.5.0.dev344 \[skip ci]
  ([`e6cc7a1`](https://github.com/homeassistant-ai/ha-mcp/commit/e6cc7a1b8ed252f1aaa2b8c964e56c97a27b94c2))
- Sync tool docs after merge \[skip ci]
  ([`fb35f30`](https://github.com/homeassistant-ai/ha-mcp/commit/fb35f305cbf7de6807c29bd3ada9da2f028ff730))
- **addon**: Publish dev addon version 7.5.0.dev343 \[skip ci]
  ([`401b7b4`](https://github.com/homeassistant-ai/ha-mcp/commit/401b7b4d707dbb3c56a3afecad9e9d22ecbc7d1e))
- **addon**: Publish dev addon version 7.5.0.dev342 \[skip ci]
  ([`0679371`](https://github.com/homeassistant-ai/ha-mcp/commit/06793710b04a985ed0d66861266b9b79494e4111))
- Sync tool docs after merge \[skip ci]
  ([`f6796ec`](https://github.com/homeassistant-ai/ha-mcp/commit/f6796ec19b4596455ff54b58746bd3e075d5d280))
- **addon**: Publish dev addon version 7.5.0.dev341 \[skip ci]
  ([`3654478`](https://github.com/homeassistant-ai/ha-mcp/commit/3654478f80428d15671e49162acecea19d67f672))
- **addon**: Publish dev addon version 7.5.0.dev340 \[skip ci]
  ([`64f00b6`](https://github.com/homeassistant-ai/ha-mcp/commit/64f00b658846cad0e0714f37d221fb65327015cf))
- **addon**: Publish dev addon version 7.5.0.dev339 \[skip ci]
  ([`d6e8873`](https://github.com/homeassistant-ai/ha-mcp/commit/d6e88731556464deb768524dc24c90fd0a622a96))
- Sync tool docs after merge \[skip ci]
  ([`7525e93`](https://github.com/homeassistant-ai/ha-mcp/commit/7525e930a872871fed78f9b1461aea8e78eb5ad7))
- **addon**: Publish dev addon version 7.5.0.dev338 \[skip ci]
  ([`288ca4a`](https://github.com/homeassistant-ai/ha-mcp/commit/288ca4abd00b2b366cbaf671c1ace3398cc8f2fd))
- **addon**: Publish dev addon version 7.5.0.dev337 \[skip ci]
  ([`f539ae5`](https://github.com/homeassistant-ai/ha-mcp/commit/f539ae5aa881853d831e6952ff3af8bc85eb8b2a))
- **addon**: Publish dev addon version 7.5.0.dev336 \[skip ci]
  ([`5568a86`](https://github.com/homeassistant-ai/ha-mcp/commit/5568a861002cfb909e29368bd4e93ef0bd2e4c03))
- **addon**: Publish dev addon version 7.5.0.dev335 \[skip ci]
  ([`e069405`](https://github.com/homeassistant-ai/ha-mcp/commit/e0694054bd8627f6464379c34c1e3eec5b080a44))
- **addon**: Publish dev addon version 7.5.0.dev334 \[skip ci]
  ([`f7be6ea`](https://github.com/homeassistant-ai/ha-mcp/commit/f7be6ead486a32840a935a1e5ec78a34f8003c0d))
- **addon**: Publish dev addon version 7.5.0.dev333 \[skip ci]
  ([`cb480ea`](https://github.com/homeassistant-ai/ha-mcp/commit/cb480eae4d855345c19a6465351e0bdef2bdf5c3))
- Sync tool docs after merge \[skip ci]
  ([`9a5bc3c`](https://github.com/homeassistant-ai/ha-mcp/commit/9a5bc3c61372159bb936d7b929166924343dc76f))
- **addon**: Publish dev addon version 7.5.0.dev332 \[skip ci]
  ([`e0e59ee`](https://github.com/homeassistant-ai/ha-mcp/commit/e0e59ee08072bb4aac51e90928fab2d68f6156ce))
- Sync tool docs after merge \[skip ci]
  ([`499ebf0`](https://github.com/homeassistant-ai/ha-mcp/commit/499ebf0c9d4c4ec3784dd72782fe301cd9c19d60))
- **addon**: Publish dev addon version 7.5.0.dev331 \[skip ci]
  ([`3e0ce92`](https://github.com/homeassistant-ai/ha-mcp/commit/3e0ce92e11777a8fd9c86153e4c248007b8edae9))
- **addon**: Publish dev addon version 7.5.0.dev330 \[skip ci]
  ([`e48d056`](https://github.com/homeassistant-ai/ha-mcp/commit/e48d056ab356e11f8b2952b6c675307d1e76a895))
- **deps**: Update ghcr.io/astral-sh/uv docker tag to v0.11.15
  ([#&#8203;1376](https://github.com/homeassistant-ai/ha-mcp/pull/1376))
- **deps**: Update ghcr.io/home-assistant/home-assistant docker tag to v2026.5.3
  ([#&#8203;1377](https://github.com/homeassistant-ai/ha-mcp/pull/1377))
- **addon**: Publish dev addon version 7.5.0.dev329 \[skip ci]
  ([`c523c50`](https://github.com/homeassistant-ai/ha-mcp/commit/c523c502c5c6f282905620d3db489e9c69ec2472))
- Sync tool docs after merge \[skip ci]
  ([`5b7a8aa`](https://github.com/homeassistant-ai/ha-mcp/commit/5b7a8aa0794359a90d7b89a9cc61d73d8cf038d2))
- **addon**: Publish dev addon version 7.5.0.dev328 \[skip ci]
  ([`6c42fba`](https://github.com/homeassistant-ai/ha-mcp/commit/6c42fba92d4786d7498f738c53dfe50c899d0890))
- **addon**: Publish dev addon version 7.5.0.dev327 \[skip ci]
  ([`aecd025`](https://github.com/homeassistant-ai/ha-mcp/commit/aecd025eeea3d1edcd9466db3720cb17de71b90a))
- **addon**: Publish dev addon version 7.5.0.dev326 \[skip ci]
  ([`399c17c`](https://github.com/homeassistant-ai/ha-mcp/commit/399c17c36602a7767491df6e317186cb6291f3e4))
- **addon**: Publish dev addon version 7.5.0.dev325 \[skip ci]
  ([`b580b45`](https://github.com/homeassistant-ai/ha-mcp/commit/b580b452e9007deb33acc49098238988aa768603))
- Sync tool docs after merge \[skip ci]
  ([`8567c3a`](https://github.com/homeassistant-ai/ha-mcp/commit/8567c3a6e66e7bebbbad8e96b94058f8456deb14))
- **addon**: Publish dev addon version 7.5.0.dev324 \[skip ci]
  ([`a65579d`](https://github.com/homeassistant-ai/ha-mcp/commit/a65579d0b6e4a8bb7f8c1ed97fd432cd770c47a4))
- **addon**: Publish dev addon version 7.5.0.dev323 \[skip ci]
  ([`c7667ba`](https://github.com/homeassistant-ai/ha-mcp/commit/c7667ba66538f1ba8a06b7616fb15896bf021744))
- **addon**: Publish dev addon version 7.5.0.dev322 \[skip ci]
  ([`44d15a8`](https://github.com/homeassistant-ai/ha-mcp/commit/44d15a89cbacc2c38ab39868b380414507a6708b))
- **addon**: Publish dev addon version 7.5.0.dev321 \[skip ci]
  ([`8739f6c`](https://github.com/homeassistant-ai/ha-mcp/commit/8739f6c09121c88a596470df293ac8e7e0f1050a))
- **addon**: Publish dev addon version 7.5.0.dev320 \[skip ci]
  ([`02b6e47`](https://github.com/homeassistant-ai/ha-mcp/commit/02b6e47f8eb6c778f709d7adca115638c2fe98a2))
- Sync tool docs after merge \[skip ci]
  ([`ab68c9a`](https://github.com/homeassistant-ai/ha-mcp/commit/ab68c9a9aa94ac6861af7b59997ec679f1849503))
- **addon**: Publish dev addon version 7.5.0.dev319 \[skip ci]
  ([`4472904`](https://github.com/homeassistant-ai/ha-mcp/commit/44729040c11af0bd97189080c1ec59995fc563b4))
- **addon**: Publish dev addon version 7.5.0.dev318 \[skip ci]
  ([`e030dbc`](https://github.com/homeassistant-ai/ha-mcp/commit/e030dbcc99e002751834274b1d53da161ab27759))
- **addon**: Publish dev addon version 7.5.0.dev317 \[skip ci]
  ([`d87855c`](https://github.com/homeassistant-ai/ha-mcp/commit/d87855cf07cef9d9d7babf0bbec74d228149327d))
- Sync tool docs after merge \[skip ci]
  ([`a72a4e8`](https://github.com/homeassistant-ai/ha-mcp/commit/a72a4e8c0de99a8516f3820545642c37a31c17e5))
- **addon**: Publish dev addon version 7.5.0.dev316 \[skip ci]
  ([`bd9397f`](https://github.com/homeassistant-ai/ha-mcp/commit/bd9397f3a088a24a14af66a97afcf1c97904ef61))
- **addon**: Publish dev addon version 7.5.0.dev315 \[skip ci]
  ([`264bfc2`](https://github.com/homeassistant-ai/ha-mcp/commit/264bfc2fcb5ef6fe3ee6f9e073b69e0469eeafdd))
- **addon**: Publish dev addon version 7.5.0.dev314 \[skip ci]
  ([`df62881`](https://github.com/homeassistant-ai/ha-mcp/commit/df6288194cdde8b625132f19b0dd3edb2142a2b3))
- **addon**: Publish dev addon version 7.5.0.dev313 \[skip ci]
  ([`f6c47ca`](https://github.com/homeassistant-ai/ha-mcp/commit/f6c47caa21b0d82799b2be9330f97aa5494aa3c8))
- **addon**: Publish dev addon version 7.5.0.dev312 \[skip ci]
  ([`2bb7a74`](https://github.com/homeassistant-ai/ha-mcp/commit/2bb7a74f06e0652a729a735b08fc7cdc20a034f6))
- Sync tool docs after merge \[skip ci]
  ([`137e279`](https://github.com/homeassistant-ai/ha-mcp/commit/137e27943b1b704fe1d3e3a5b525b4d82bce33eb))
- **addon**: Publish dev addon version 7.5.0.dev311 \[skip ci]
  ([`28324ea`](https://github.com/homeassistant-ai/ha-mcp/commit/28324ea4a92fbf61f5ee40c561286c466af2309a))
- Sync tool docs after merge \[skip ci]
  ([`9a753d4`](https://github.com/homeassistant-ai/ha-mcp/commit/9a753d49abb4ccd84e874451dbcc563260f9e19d))
- **addon**: Publish dev addon version 7.5.0.dev310 \[skip ci]
  ([`f893b2e`](https://github.com/homeassistant-ai/ha-mcp/commit/f893b2ebf91967d0e2548f9205a15bfe0e7d86c2))
- **addon**: Publish dev addon version 7.5.0.dev309 \[skip ci]
  ([`8cbdb7b`](https://github.com/homeassistant-ai/ha-mcp/commit/8cbdb7bf318707fed1a0b3e8cb9922e6c170521e))
- **addon**: Publish dev addon version 7.5.0.dev308 \[skip ci]
  ([`2d18016`](https://github.com/homeassistant-ai/ha-mcp/commit/2d18016de8eb26a18cfb471e7b5f755f1309bd36))
- **addon**: Publish dev addon version 7.5.0.dev307 \[skip ci]
  ([`3fc3b28`](https://github.com/homeassistant-ai/ha-mcp/commit/3fc3b28881f237df02da8b65467fba9a7d693009))
- Sync tool docs after merge \[skip ci]
  ([`9e6cff8`](https://github.com/homeassistant-ai/ha-mcp/commit/9e6cff8f641bcd8122e94fc8be9c30aa18456e80))
- **addon**: Publish dev addon version 7.5.0.dev306 \[skip ci]
  ([`8bdd0fc`](https://github.com/homeassistant-ai/ha-mcp/commit/8bdd0fca9c107f45e4c3719e7616984b68876a9e))
- **addon**: Publish dev addon version 7.5.0.dev305 \[skip ci]
  ([`83535b9`](https://github.com/homeassistant-ai/ha-mcp/commit/83535b99e190fb56b7ce227334331ebf2affb3e1))
- **addon**: Publish dev addon version 7.5.0.dev304 \[skip ci]
  ([`1435b3a`](https://github.com/homeassistant-ai/ha-mcp/commit/1435b3a24d73503e189b83f8ea5aaeea20d9ebf3))
- **addon**: Publish dev addon version 7.5.0.dev303 \[skip ci]
  ([`e2da659`](https://github.com/homeassistant-ai/ha-mcp/commit/e2da6591d6ad2def0b48a9be750cb8a41f40524d))
- Sync tool docs after merge \[skip ci]
  ([`23789fa`](https://github.com/homeassistant-ai/ha-mcp/commit/23789fa978591b7d3966894082a2683ca6a6ae3b))
- **addon**: Publish dev addon version 7.5.0.dev302 \[skip ci]
  ([`6c8e574`](https://github.com/homeassistant-ai/ha-mcp/commit/6c8e574e7e3d8d78b3a2e48f6a70531d7a95eed8))
- Sync tool docs after merge \[skip ci]
  ([`d2329cb`](https://github.com/homeassistant-ai/ha-mcp/commit/d2329cbff39891d209317528fd7b42759c3414a8))
- **addon**: Publish dev addon version 7.5.0.dev301 \[skip ci]
  ([`bb538f7`](https://github.com/homeassistant-ai/ha-mcp/commit/bb538f70d2fc57072f09cfc6202e9d3dc1a2d257))
- Sync tool docs after merge \[skip ci]
  ([`f70f0e1`](https://github.com/homeassistant-ai/ha-mcp/commit/f70f0e14222b29a8923e706f113d1fafb4a5c23e))
- **addon**: Publish version 7.5.0 \[skip ci]
  ([`9c5eb37`](https://github.com/homeassistant-ai/ha-mcp/commit/9c5eb37779236ef19366a2a59a667d3916458e5a))

##### Continuous Integration

- **deps**: Bump actions/upload-artifact in the github-actions group
  ([#&#8203;1437](https://github.com/homeassistant-ai/ha-mcp/pull/1437))
- Share qcow2 cache + GHCR fallback between HAOS lanes
  ([#&#8203;1407](https://github.com/homeassistant-ai/ha-mcp/pull/1407))
- Add ruff format --check on changed Python files
  ([#&#8203;1387](https://github.com/homeassistant-ai/ha-mcp/pull/1387))
- Exempt assigned issues from stale bot
  ([#&#8203;1368](https://github.com/homeassistant-ai/ha-mcp/pull/1368))
- **deps**: Bump the github-actions group with 3 updates
  ([#&#8203;1362](https://github.com/homeassistant-ai/ha-mcp/pull/1362))

##### Refactoring

- Consolidate lovelace/dashboards/list through shared helper
  ([#&#8203;1344](https://github.com/homeassistant-ai/ha-mcp/pull/1344))

##### Testing

- **haos-e2e**: Bake + install webhook-proxy addon and exercise its runtime
  ([#&#8203;1443](https://github.com/homeassistant-ai/ha-mcp/pull/1443))
- **config-subentry**: Mark forecast\_solar e2e as known flaky + relative-import sweep
  ([#&#8203;1430](https://github.com/homeassistant-ai/ha-mcp/pull/1430))
- **haos-e2e**: Trim cache-save race, compress GHCR qcow2, eval boot snapshot
  ([#&#8203;1428](https://github.com/homeassistant-ai/ha-mcp/pull/1428))
- JSDOM behaviour harness + auto-discovery parse coverage for every rendered <script>
  ([#&#8203;1425](https://github.com/homeassistant-ai/ha-mcp/pull/1425))
- **hacs**: Retry TestMcpToolsInstallation on flake
  ([#&#8203;1426](https://github.com/homeassistant-ai/ha-mcp/pull/1426))
- **e2e**: Drop redundant lifecycle roundtrips, keep only Matter Server ([#&#8203;1414](https://github.com/homeassistant-ai/ha-mcp/issues/1414))
  ([#&#8203;1419](https://github.com/homeassistant-ai/ha-mcp/pull/1419))
- **e2e**: Assert backend dispatch matches workflow env on every lane
  ([#&#8203;1409](https://github.com/homeassistant-ai/ha-mcp/pull/1409))
- Escape ideographic space and format file ([#&#8203;1237](https://github.com/homeassistant-ai/ha-mcp/issues/1237))
  ([#&#8203;1410](https://github.com/homeassistant-ai/ha-mcp/pull/1410))
- **e2e**: Measure \_POLL\_CADENCE p50/p99 to validate or retune (closes [#&#8203;1389](https://github.com/homeassistant-ai/ha-mcp/issues/1389))
  ([#&#8203;1398](https://github.com/homeassistant-ai/ha-mcp/pull/1398))
- **e2e**: Wait for addon state=started in haos proxy header test
  ([#&#8203;1402](https://github.com/homeassistant-ai/ha-mcp/pull/1402))
- Pin remaining \_classify\_by\_message branches
  ([#&#8203;1385](https://github.com/homeassistant-ai/ha-mcp/pull/1385))
- **haos-e2e**: Slim addon set + real-addon ha\_manage\_addon coverage (closes [#&#8203;1350](https://github.com/homeassistant-ai/ha-mcp/issues/1350))
  ([#&#8203;1379](https://github.com/homeassistant-ai/ha-mcp/pull/1379))
- **haos-e2e**: Close out [#&#8203;1349](https://github.com/homeassistant-ai/ha-mcp/issues/1349) — lifecycle, integrations, supervisor\_mock migration, no more skips
  ([#&#8203;1375](https://github.com/homeassistant-ai/ha-mcp/pull/1375))
- **e2e**: Consolidate readiness gates onto /api/core/state (refs [#&#8203;366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
  ([#&#8203;1372](https://github.com/homeassistant-ai/ha-mcp/pull/1372))
- **e2e**: Tighten 5 readiness-gate budgets with 2-63x headroom (refs [#&#8203;366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
  ([#&#8203;1369](https://github.com/homeassistant-ai/ha-mcp/pull/1369))
- Scaffold HAOS E2E tier image-build pipeline (refs [#&#8203;1281](https://github.com/homeassistant-ai/ha-mcp/issues/1281))
  ([#&#8203;1326](https://github.com/homeassistant-ai/ha-mcp/pull/1326))
- **e2e**: Instrument HA\_MCP\_TOOLS\_WAIT readiness gate (refs [#&#8203;366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
  ([#&#8203;1346](https://github.com/homeassistant-ai/ha-mcp/pull/1346))
- **e2e**: Centralize wait\_for\_entity\_registration helper (refs [#&#8203;366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
  ([#&#8203;1308](https://github.com/homeassistant-ai/ha-mcp/pull/1308))
- **e2e**: Unify dict-error message extraction across e2e tests (refs [#&#8203;366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
  ([#&#8203;1311](https://github.com/homeassistant-ai/ha-mcp/pull/1311))
- **e2e**: Surface readiness-gate elapsed times in CI logs (refs [#&#8203;366](https://github.com/homeassistant-ai/ha-mcp/issues/366))
  ([#&#8203;1310](https://github.com/homeassistant-ai/ha-mcp/pull/1310))

</details>

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/994
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] decide ha_delete_helpers_integrations idempotent dual-success contract

2 participants