Skip to content

test(e2e): measure _POLL_CADENCE p50/p99 to validate or retune (closes #1389) - #1398

Merged
Patch76 merged 7 commits into
homeassistant-ai:masterfrom
Patch76:feature/issue-1389
May 22, 2026
Merged

test(e2e): measure _POLL_CADENCE p50/p99 to validate or retune (closes #1389)#1398
Patch76 merged 7 commits into
homeassistant-ai:masterfrom
Patch76:feature/issue-1389

Conversation

@Patch76

@Patch76 Patch76 commented May 21, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Closes #1389.

Pre-committed measurement protocol for the post-#1384 _POLL_CADENCE = (0.1, 1.0, 4.9) shape plus the Boy-Scout retune that the decision rule landed on:

  • _POLL_CADENCE retune: (0.1, 1.0, 4.9)(0.025, 1.0, 4.975). Same 3-attempt × 6.0s budget; first-poll pulled to a 5× cushion above the measured ~4 ms HA-Core entity-registration latency. Decision rule on two E2E runs against 65e6d89: p50 ≥ 100 ms (the prior first-poll sleep was the floor of every sample) → RETUNE NEEDED.

  • Production instrumentation (src/ha_mcp/client/rest_client.py): _poll_for_automation_entity captures elapsed time from function entry to the first successful get_states() match and emits entity-registration-elapsed: %.1fms (unique_id=..., entity_id=...) at DEBUG level. One time.monotonic() pair per registration.

  • E2E measurement test (tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py): TestPollCadenceMeasurement1389 creates N=10 automations cold-start, captures the DEBUG records via caplog.at_level, computes p50 / p90 / worst, feeds them to a record_poll_cadence_measurement() helper in the root e2e conftest. (At N=10 the 99th-percentile index collapses to p90's bucket, so the headline metric is named worst for what it actually measures.)

  • Terminal-summary plumbing (tests/src/e2e/conftest.py): mirrors the readiness-gate-timings pattern — pytest_terminal_summary renders the #1389 _POLL_CADENCE measurement section with [POLL_CADENCE_1389] lines outside the per-worker capture buffer.

HAOS proxy-header flake: addressed independently on master via #1402 (merged 2026-05-21 21:43 UTC; _wait_addon_running guard in test_manage_addon_modes.py). Not duplicated in this PR — branch rebased onto master so #1402's fix is now live on the PR's CI lane.

External-only marker on the measurement test: caplog only captures DEBUG records emitted in pytest's own process; on the HAOS-inaddon tier the rest_client lives in the addon's separate process and the records never reach caplog. Marked external_only so the test skips inaddon instead of false-negative-asserting.

Report-only on percentiles: no threshold assert on the measurement itself. CI latency variance from parallel pytest-xdist workers sharing one HA testcontainer would make a strict threshold-assert flaky. The decision rule is applied to the reported numbers via PR comment — VERDICT line in the output is machine-greppable.

Type of change

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

(Production-code changes: the _POLL_CADENCE retune + the one instrumentation line in _poll_for_automation_entity. Everything else is the measurement test, conftest plumbing, and the HAOS readiness guard.)

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: 44 existing test_rest_client_automations.py + test_helper_classifier.py unit tests pass (3 pinned the old cadence — values updated in lockstep). Ruff + mypy clean. The new E2E test cannot be run locally (no Docker daemon in this environment) — measurement set lands in CI's E2E Validation job logs as the [POLL_CADENCE_1389] section.

Checklist

  • I have updated documentation if needed

@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 implements a measurement protocol to validate the effectiveness of the current _POLL_CADENCE configuration. By adding lightweight instrumentation to the automation registration process and introducing a dedicated E2E test, the changes allow for empirical analysis of registration latency. The collected data will be used to determine if the current polling strategy is optimal or if further tuning is required.

Highlights

  • Production Instrumentation: Added low-overhead timing instrumentation to the _poll_for_automation_entity method in rest_client.py to capture registration latency.
  • E2E Measurement Test: Introduced a new end-to-end test that performs cold-start automation creation, calculates p50/p90/p99 latency metrics, and outputs a machine-readable verdict.
  • Reporting Strategy: Implemented a report-only testing approach that avoids CI flakiness by logging performance data for manual review rather than enforcing strict gate thresholds.
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 adds latency instrumentation to the REST client and introduces a new E2E test to validate polling cadence percentiles for issue #1389. Review feedback identifies an inaccuracy in a code comment regarding ID filtering and suggests refining the percentile calculation for small sample sizes to ensure the p99 metric correctly accounts for outliers.

Comment thread tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py Outdated
Comment thread tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py Outdated
@Patch76

Patch76 commented May 21, 2026

Copy link
Copy Markdown
Member Author

Implementation Summary

Refs #1389. Delivers the measurement infrastructure for the pre-committed decision rule on _POLL_CADENCE = (0.1, 1.0, 4.9). The PR body covers the three components (instrumentation, test, terminal-summary plumbing); this summary captures the choices made along the way and the data that came out.

Choices Made

  • Report-only test, no threshold assertion. CI latency variance from parallel pytest-xdist workers sharing one HA testcontainer would flake a strict assert p50 < 100 gate. The decision rule lives in the VERDICT line in the output, applied by the human via the PR comment / IS — not by the test.
  • Three-hook pipeline at the root e2e conftest (xdist worker → workeroutput → master → terminalreporter.write_line). Initial implementation placed the hooks in a deep subdir conftest at tests/src/e2e/workflows/automation/conftest.py. The section never surfaced in CI output despite the test passing; moving the same hooks to the root e2e conftest fixed it. Empirically the root scope is the one the xdist master actually invokes for pytest_terminal_summary — same scope the existing readiness-gate-timings hooks already use. The readiness-timings pattern (refs Investigate and fix flaky E2E tests in CI workflows #366) at the same conftest is the structural origin.
  • external_only marker on the testcaplog only sees records emitted in pytest's own process; on the HAOS-inaddon tier the rest_client lives in the addon's separate process, so the DEBUG records never reach caplog. Skipping on that tier avoids a false-negative No 'entity-registration-elapsed' DEBUG records captured failure that would otherwise mask the actual test outcome.
  • closesRefs #1389 in the PR body. The issue's decision rule says the PR closing [FEATURE] Measure HA Core entity-registration p50/p99 to validate _poll_for_automation_entity 0.1s floor #1389 is the one that ships the terminal action (close-as-validated or retune). This PR ships the measurement; the decision is below.

Problems Encountered

  • Logger output dropped under pytest-xdist. First push surfaced no measurement data despite the test passing — pytest captures logger.info per-worker and only shows it on failure. Fixed by adding the terminal-summary hook pattern (commit fba9dbd).
  • Hooks at wrong conftest scope (commit fba9dbd65e6d89). pytest_terminal_summary writes to the master-side terminal, and empirically the section never surfaced from a deep subdir conftest — only from the root e2e one. Moved to root e2e conftest.
  • HAOS E2E Tests recurrent flake. tests/src/e2e/haos_only/test_manage_addon_modes.py::test_proxy_http_request_headers_pass_through failed 4 times today on this PR plus a prior unrelated PR — Node-RED add-on still in state: 'startup' when the test asserts the strict response shape. Wholly unrelated to this PR's diff; required-checks trio (E2E Validation ubuntu/arm + Docker) green throughout. Worth a separate wait_for_addon_state("started") fix in the affected test, not in this PR's scope.

Measurement Result

Across the two E2E Validation jobs on commit 65e6d89 (testcontainer mode, where caplog captures the production-side DEBUG records cleanly):

Job N p50 p90 p99 min max not_verified VERDICT
E2E Validation (ubuntu-latest) 10 104.8 ms 105.1 ms 105.3 ms 104.1 ms 105.3 ms 0 RETUNE NEEDED
E2E Validation (ubuntu-24.04-arm) 10 104.1 ms 104.7 ms 105.2 ms 103.9 ms 105.2 ms 0 RETUNE NEEDED

All 20 samples land in a [103.9 ms, 105.3 ms] band — max − min ≈ 1.4 ms. The narrow spread means every automation registers on the first poll attempt (after the _POLL_CADENCE[0] = 0.1 s sleep). Subtracting the 100 ms sleep from the 104 ms elapsed leaves ~4 ms for the get_states() round-trip plus actual HA Core entity-registration latency — well below any threshold of concern. The 100 ms first-poll sleep is the rate-limiter, not HA Core.

Suggested Improvements (follow-ups, not blockers)

@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.

Measurement scaffolding is in the right shape (instrumentation + xdist-aware terminal-summary plumbing mirroring _READINESS_TIMINGS). Three blockers, four should-fix, comment subtractions.

Blocking

1. not_verified_count is dead — verdict can silently falsely report VALIDATED.

src/ha_mcp/tools/tools_config_automations.py:776 pops entity_not_verified off the result before it returns and translates it into a warnings string ("Automation was submitted to Home Assistant but the entity was not found after polling…"). So create_data.get("entity_not_verified") in test_poll_cadence_measurement.py:86 is always None, not_verified_count is always 0, no_misses is always True. A run where every cadence step exhausted would still print VERDICT=VALIDATED if the captured DEBUG records happened to be empty — and combined with #4, assert samples is the only thing catching all-misses today.

Detect a miss by scanning create_data.get("warnings", []) for the sentinel substring, or check create_data.get("entity_id") is None alongside success=True.

2. PR body says Refs #1389 — issue won't auto-close on merge.

GitHub only documents closing-keyword recognition in the body and commits on the default branch. Title closing-keywords are folklore. Replace Refs #1389. with Closes #1389. in the PR description.

3. "Suggested Improvements (follow-ups, not blockers)" defers exactly what AGENTS.md says to fold in.

The retune to _POLL_CADENCE = (0.025, 1.0, 4.975) is 3 numbers, justified by the measurement table this PR produced, and the verdict line that drove the retune was emitted by this PR's own test. Per the Boy Scout Rule, fold the retune into this PR — it then is the PR that closes #1389. The "ships as a separate PR" framing splits one logical unit across two PRs for no benefit and leaves master in a verdict=RETUNE NEEDED, cadence unchanged state if the retune PR slips.

The HAOS E2E flake item ("Out of scope here; worth its own issue if it persists") uses the exact escape-hatch phrasing AGENTS.md flags. The fix you describe is small — a wait_for_addon_state("started") guard or _wait_addon_running helper before the strict-shape assertion. That's classic Boy Scout: discovered during this PR's CI runs, trivially small, mechanical mirror of an existing pattern. Fold it in here, don't defer.

Rename the section and land both items in this PR.

Should-fix

4. assert samples only catches zero-capture; partial captures silently skew percentiles. test_poll_cadence_measurement.py:103-107

If 9 iterations succeed and 1 misses, the assert passes with n=9 and reports p50/p99 over those 9 — and combined with #1, the miss is invisible. After parsing samples, add:

assert len(samples) + not_verified_count == self.N_SAMPLES, (
    f"sample-count invariant violated: {len(samples)} samples + "
    f"{not_verified_count} misses != {self.N_SAMPLES} attempts"
)

Pair with #1 — miss-detection has to be real for this assert to be real.

5. The field labelled p99 is actually max for N=10. test_poll_cadence_measurement.py:114-118

The inline comment justifies the index-collapse, but the recorded dict key, the pytest_terminal_summary output, and the decision-rule line all call it p99. The closure-vs-retune decision rides on this number — name it for what it is. Rename to worst / p99_or_max in both writer and reader, or compute statistics.quantiles(samples, n=100, method="inclusive")[98] and surface max separately (already in the dict).

6. cleanup_tracker.track() is a no-op fixture. tests/src/e2e/conftest.py:1937-1942

The fixture's teardown only logs "Would clean up…" — there's no real delete. This test creates 10 automation.poll_cadence_measurement_1389_NN per run; on --dist loadscope they persist for the worker's lifetime. Pre-existing fixture defect, but this test is now the largest single producer. Either add an explicit try/finally in the test that calls ha_config_remove_automation per entity, or fix the fixture to actually delete — both qualify as in-scope cleanup for this PR.

7. caplog.set_level(DEBUG, logger="ha_mcp.client.rest_client") is sticky across tests on the same worker. test_poll_cadence_measurement.py:60-67

The docstring's "per-test-method-scoped" framing is correct for caplog.records but not for set_level — that mutates the worker's logger level. Every later test on the same xdist worker captures rest_client DEBUG at full volume until the worker exits. Use caplog.at_level(logging.DEBUG, logger="ha_mcp.client.rest_client") as a context manager around just the create-loop, or save/restore the prior level in a finally.

Nits

8. Comment subtractions — the PR is comment-heavy; a few earn nothing:

  • test_poll_cadence_measurement.py:68-70 — duplicates the caplog.clear() rationale from lines 60-66.
  • test_poll_cadence_measurement.py:124-127 — restates the decision-rule thresholds the code on the next line already says.
  • conftest.py:92-98 — the xdist-conftest-loading mechanism explanation is slightly inaccurate (xdist's master loads all conftests; the real point is shared module-level state). Trim to one sentence cross-referencing _READINESS_TIMINGS.
  • record_poll_cadence_measurement docstring (conftest.py:100-107) — the key list will rot on schema change; the call site is the source of truth.

9. N=10 + cadence (0.1, 1.0, 4.9) puts the decision boundary right at a cadence step. One late-sample run can flip VERDICT between VALIDATED and RETUNE for the same underlying behavior. With #5 fixed (renaming p99worst), N=10 is fine for worst; if you keep the p99 < 1000ms rule, raise N to ~50 for boundary stability. (The retune in #3 collapses this concern anyway — at _POLL_CADENCE[0] = 0.025s the boundary moves far away from the cadence step.)

Verified clean

  • Log-format migration from f-string to %-style is correct (deferred formatting); zero downstream references to the old "Found actual entity_id" text.
  • pytest_testnodedown local-variable hoist is a readability win, not scope creep.
  • external_only marker skip is correct — inaddon mode runs rest_client in a separate process where caplog can't reach it.
  • _POLL_CADENCE_MEASUREMENTS xdist round-trip mirrors _READINESS_TIMINGS exactly.
  • start_monotonic placement outside the try block is fine — failed registrations correctly produce no log line.

Patch76 added a commit to Patch76/ha-mcp that referenced this pull request May 22, 2026
- entity_not_verified detection via warnings-substring scan
  (homeassistant-ai#1297-popped flag was dead — VERDICT=VALIDATED could leak silently)
- sample-count invariant: len(samples) + not_verified == N_SAMPLES
- rename "p99" -> "worst" (at N=10 the percentile collapses to max;
  the threshold-check name now reflects what it measures)
- per-test try/finally cleanup: cleanup_tracker is a logging-only no-op,
  so 10 automations were leaking into the next worker run
- caplog.at_level context manager (set_level mutated worker-wide level
  and leaked DEBUG-on-rest_client into every later test)
- 6 comment subtractions per Boy-Scout

Boy-Scout fold per homeassistant-ai#1389 measurement (RETUNE NEEDED p50>=100ms):

- _POLL_CADENCE: (0.1, 1.0, 4.9) -> (0.025, 1.0, 4.975) — first-poll
  pulled to a 5x cushion above the measured ~4ms HA-Core
  entity-registration latency
- unit-test pins updated to the new cadence values
- test_proxy_http_request_headers_pass_through: add _wait_for_state
  helper + guard for state="started" (HAOS E2E fail: Node-RED was in
  "startup" when the strict status_code assertion ran)

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

Patch76 commented May 22, 2026

Copy link
Copy Markdown
Member Author

Addressed in ab152e9. PR body updated Refs #1389Closes #1389 (item 2). Item-by-item below.

Blocking

1. not_verified_count dead — replaced with a warnings-substring scan. New _NOT_VERIFIED_WARNING_PREFIX module-level constant at test_poll_cadence_measurement.py:42 mirrors the literal in tools_config_automations.py:770; the per-iteration check at test_poll_cadence_measurement.py:103 reads create_data.get("warnings") or [] and matches that prefix. Pairs with item 4 below — a missed iteration now both registers in not_verified_count AND lets the sample-count invariant catch the case where the warning text drifts.

2. PR body Refs #1389 — flipped to Closes #1389. via gh api PATCH. Also folded the body's stale "ships as a separate PR" framing now that the retune is in this PR.

3. Boy-Scout fold — both items folded in.

  • _POLL_CADENCE = (0.025, 1.0, 4.975) at rest_client.py:934. First-poll pulled to 25 ms, a 5× cushion above the measured ~4 ms HA-Core entity-registration latency. Same 3-attempt × 6.0 s budget. Three unit tests in test_rest_client_automations.py (lines 170, 194, 211, 239) updated in lockstep.
  • HAOS flake: new _wait_for_state helper at test_manage_addon_modes.py:96 (mirrors test_addon_lifecycle.py:140 with the same _resolve_slug-style local-copy rationale). test_proxy_http_request_headers_pass_through at :278 now awaits state="started" before the strict-shape assertion. Confirmed against the failing run's log — Node-RED was in state="startup" when the proxy call hit; ha_manage_addon returned SERVICE_CALL_FAILED instead of an HTTP envelope.

Should-fix

4. Sample-count invarianttest_poll_cadence_measurement.py:127: assert len(samples) + not_verified_count == self.N_SAMPLES. With item 1's warning-scan miss-detection now real, this catches the silent-skew case directly.

5. p99 rename — went with the rename path. Variable, dict key, decision-rule, terminal-summary renderer, and log line all consistently use worst now. worst = samples[-1] at test_poll_cadence_measurement.py:140, worst_ok = worst < 1000.0 at :145, f"worst={m['worst']:.1f}ms" in the renderer at conftest.py:264. The inline comment explaining why N=10 collapses the percentile index moved into the module docstring (test_poll_cadence_measurement.py:14-19) as headline context. Test method renamed test_poll_cadence_p50_p99test_poll_cadence_p50_worst at :65.

6. cleanup_tracker.track() no-op — per-test try/finally cleanup at test_poll_cadence_measurement.py:202-212. Each tracked automation.poll_cadence_measurement_1389_NN gets an explicit ha_config_remove_automation call; cleanup failures log a warning rather than mask the assertion outcome. Fixture itself stays as-is (pre-existing scope, this PR was the largest producer not the only one).

7. caplog.set_level stickiness — replaced with caplog.at_level(logging.DEBUG, logger="ha_mcp.client.rest_client") context manager at test_poll_cadence_measurement.py:74, wrapping only the create-loop. Logger level saved+restored on exit; later tests on the same xdist worker no longer inherit DEBUG-on-rest_client.

Nits

8. Comment subtractions — six regions trimmed.

  • Test file: caplog rationale (the old :60-67 block) collapsed to two lines explaining at_level vs set_level. The caplog.clear() duplicate-rationale comment dropped entirely. Index-collapse comment (:136-139) tightened. Decision-rule restate (:124-127) dropped — the boolean variable names now carry the rule.
  • conftest: xdist explainer (:91-92) trimmed to a single two-line cross-ref to _READINESS_TIMINGS. record_poll_cadence_measurement docstring at :98-104 points at the test file as schema source.

9. N=10 boundary — resolved by 5's rename. No code change.

On the verified-clean list

Log-format %-style migration, pytest_testnodedown hoist, external_only marker, _POLL_CADENCE_MEASUREMENTS xdist round-trip, start_monotonic placement — all unchanged.

CI on ab152e9 will report fresh measurements at the new cadence — expecting p50 to land near the ~4 ms HA-Core latency plus the 25 ms first-poll sleep.

Patch76 and others added 5 commits May 22, 2026 12:08
…homeassistant-ai#1389)

homeassistant-ai#1389's pre-committed decision rule needs empirical p50/p99 numbers for
automation-entity-registration latency on the post-homeassistant-ai#1384 cadence
``_POLL_CADENCE = (0.1, 1.0, 4.9)``. Two pieces:

1. ``rest_client._poll_for_automation_entity`` now emits a DEBUG line
   ``entity-registration-elapsed: %.1fms`` measuring cumulative time from
   function entry (right after the automation POST returns) to the first
   successful ``get_states()`` match. Always-on instrumentation, near-zero
   cost (one ``time.monotonic()`` pair per registration).

2. New e2e test ``TestPollCadenceMeasurement1389`` creates N=10 automations
   cold-start, captures the DEBUG records via ``caplog``, computes p50 /
   p90 / p99, and reports the table at INFO so it surfaces in CI logs
   (default ``log_cli_level=INFO``). The decision-rule outcome
   (``VALIDATED`` vs ``RETUNE NEEDED``) is logged as a machine-greppable
   ``VERDICT`` line.

The test is report-only — no threshold assertion. CI latency variance from
parallel pytest-xdist workers sharing one HA testcontainer makes a strict
threshold assertion flaky. The decision rule is applied to the reported
numbers via a PR comment after CI runs.

Cumulative not-verified iterations (``_poll_for_automation_entity``
returning ``None`` after exhausting the 6.0s cadence) are themselves
``p99 ≥ 6000ms`` evidence and flip ``VERDICT`` to ``RETUNE`` regardless
of the measured samples.
…surement

Three fixes on the new ``test_poll_cadence_measurement.py``:

1. **Comment accuracy** (Gemini ``:51``). The prior comment claimed
   cross-test pollution was bounded by "registrations matched against
   the unique ID prefix below", but the parsing loop never filters by
   unique_id. The actual protection is that ``caplog`` is per-test-
   method-scoped — other tests' records don't appear in
   ``caplog.records`` here. Comment now describes the real mechanism.

2. **Percentile calculation** (Gemini ``:104``). For ``N=10``,
   ``int(0.99 * (n-1)) == 8`` collapses to the same index as p90,
   silently dropping the worst-case sample. ``p99`` is now
   ``samples[-1]`` so an outlier can't violate the decision-rule
   threshold without surfacing. ``p90`` formula simplified to
   ``int(0.9 * n) - 1`` (numerically identical for both ``N=10`` and
   typical larger N, just clearer reading).

3. **HAOS-inaddon skip**. Class now carries ``@pytest.mark.external_only``
   because ``caplog`` only captures DEBUG records emitted in pytest's
   own process; on the HAOS-inaddon tier the rest_client lives in the
   addon's separate process and the records never reach ``caplog``.
   Without this marker the test fires its
   "No 'entity-registration-elapsed' DEBUG records captured" assertion
   as a false-negative — observed on the first CI run.
…mary hook

``logger.info`` from a test method is captured by pytest-xdist's per-worker
buffer and only surfaces on FAILURE — the prior commit's PASSED run
dropped the measurement table silently. Without the data, the homeassistant-ai#1389
pre-committed decision rule (p50 < 100ms ∧ p99 < 1.0s → close vs.
retune) cannot be applied, defeating the PR's stated purpose.

Mirrors the established ``Readiness gate timings`` pattern in
``tests/src/e2e/conftest.py`` (introduced for homeassistant-ai#1310, consolidated for
homeassistant-ai#366): worker-side list → ``pytest_sessionfinish`` ships via
``workeroutput`` → ``pytest_testnodedown`` aggregates on master →
``pytest_terminal_summary`` renders a ``homeassistant-ai#1389 _POLL_CADENCE measurement``
section outside the per-worker capture buffer.

- New ``tests/src/e2e/workflows/automation/conftest.py`` with the 3-hook
  pattern and a public ``record_poll_cadence_measurement(dict)`` helper.
- Test method now calls the helper alongside the existing ``logger.info``
  calls (kept for local-without-xdist runs).
- CI logs will surface ``[POLL_CADENCE_1389] N=X/10 p50=… p99=… VERDICT=…``
  lines that the IS / closing comment on homeassistant-ai#1389 cite directly.
…onftest

The prior fold placed the ``pytest_sessionfinish`` / ``pytest_testnodedown``
/ ``pytest_terminal_summary`` hooks at
``tests/src/e2e/workflows/automation/conftest.py``. CI re-ran cleanly,
test passed, but the measurement section still didn't surface — the
xdist master only loads conftests up to where tests are collected, and
``pytest_terminal_summary`` (which writes to the visible terminal) is a
master-only hook. Deep subdir conftests don't get their hooks invoked
on the master.

The Readiness gate timings pattern works because its hooks live at
``tests/src/e2e/conftest.py`` (the root e2e conftest the master always
loads). Same fix here: move the storage, the
``record_poll_cadence_measurement`` helper, and the three hook
extensions to the root conftest alongside the readiness ones. The deep
``workflows/automation/conftest.py`` is removed; the measurement test
imports the helper from the root.
…+ retune)

- entity_not_verified detection via warnings-substring scan
  (homeassistant-ai#1297-popped flag was dead — VERDICT=VALIDATED could leak silently)
- sample-count invariant: len(samples) + not_verified == N_SAMPLES
- rename "p99" -> "worst" (at N=10 the percentile collapses to max;
  the threshold-check name now reflects what it measures)
- per-test try/finally cleanup: cleanup_tracker is a logging-only no-op,
  so 10 automations were leaking into the next worker run
- caplog.at_level context manager (set_level mutated worker-wide level
  and leaked DEBUG-on-rest_client into every later test)
- 6 comment subtractions per Boy-Scout

Boy-Scout retune from homeassistant-ai#1389 measurement (RETUNE NEEDED p50>=100ms):

- _POLL_CADENCE: (0.1, 1.0, 4.9) -> (0.025, 1.0, 4.975) — first-poll
  pulled to a 5x cushion above the measured ~4ms HA-Core
  entity-registration latency
- unit-test pins updated to the new cadence values

The HAOS proxy-header flake item from KP13's review landed
independently on master via homeassistant-ai#1402 (_wait_addon_running guard);
intentionally not duplicated here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Patch76
Patch76 force-pushed the feature/issue-1389 branch from ab152e9 to f34ea9a Compare May 22, 2026 10:09
@Patch76

Patch76 commented May 22, 2026

Copy link
Copy Markdown
Member Author

Correction on the bundled reply above — withdrawing the HAOS portion of item 3.

Cross-reference audit caught that #1402 (your PR, merged 2026-05-21 21:43 UTC) had already landed the exact same fix on master: the _wait_addon_running guard in test_manage_addon_modes.py:106. That landed ~3 hours after the "fold it" review on this PR, and my fold was implemented this morning without re-checking master state — my file-overlap check at the top of the deep-dive was incomplete (mergeable: MERGEABLE covered conflict-marker absence but not line-region overlap).

Branch force-pushed to f34ea9a: HAOS additions dropped, branch rebased onto current upstream/master so #1402's _wait_addon_running is now live on this PR's CI lane. PR body updated to point at #1402 instead of claiming the HAOS work as in-scope.

Substantive changes vs the previous push: 4 files changed (rest_client.py + conftest.py + measurement test + unit-test pins). The retune and the 8 other review items remain — only the HAOS helper + the per-test guard line came out.

@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.

Verifying f34ea9a7 against my prior review: all 8 items + retune land cleanly. Three new findings from the rewrite.

Should-fix

1. Cleanup except Exception diverges from the project's polling-helper pattern. tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py:209

safe_call_tool only catches ToolError; everything else (TypeError, AttributeError, KeyError, etc.) becomes a logger.warning line and silently continues to the next iteration of the cleanup loop. AGENTS.md "Exception handling in polling helpers" and tests/src/e2e/utilities/wait_helpers.py (per #1266) establish the inverse: bugs MUST propagate out of polling loops with their stack trace, not be downgraded to warnings. Per-entity cleanup is the same shape — same "keep going past one bad iteration" intent, same risk of swallowing programmer bugs across 10 identical iterations.

Tighten to a narrow tuple analogous to _POLLING_TRANSIENT_ERRORS — something like (ToolError, OSError, TimeoutError, McpError) covering what safe_call_tool plus its transport layer would raise on a real HA-side cleanup failure (404 on already-removed entity, connection blip), not what a programmer typo would raise.

2. _NOT_VERIFIED_WARNING_PREFIX is coupled to source by comment only. test_poll_cadence_measurement.py:42

The literal lives in two places (tools_config_automations.py:770 and the test) with just an inline "Mirrors the literal" comment connecting them. If the warning copy is reworded in the source, the test silently slides to not_verified_count == 0. The sample-count invariant catches the resulting count mismatch and fails the test loud — so it's not a current silent failure — but the error ("9 samples + 0 not-verified != 10 attempts") wouldn't point at the wording drift. Lift the constant out of tools_config_automations.py (export it from the module, or put it in a shared constants location) and import it in the test — mechanical fix, makes the coupling a compile-time error instead of a test-runtime puzzle.

Nit

3. Cleanup-block comment calls cleanup_tracker "session-scoped". test_poll_cadence_measurement.py:197

The fixture is bare @pytest.fixture at tests/src/e2e/conftest.py:1951 — function-scoped, not session-scoped. The substantive point (fixture only logs, doesn't delete) is correct and load-bearing; just the scope label is wrong. Replace "session-scoped" with "logging-only" (matches the commit-message framing).

Otherwise verified clean

  • Sentinel substring at tools_config_automations.py:770 matches _NOT_VERIFIED_WARNING_PREFIX exactly.
  • p99worst rename consistent across dict key, terminal-summary writer, decision-rule check, test method name. No lingering p99 selectors.
  • _POLL_CADENCE = (0.025, 1.0, 4.975) sums to 6.0; unit-test pins updated in all three sites (test_poll_cadence_shape, full-miss test, partial-attempt test).
  • caplog.at_level scope is right — caplog.records survives the context-manager exit because pytest's caplog accumulates per-test, not per-block.
  • Sample-count invariant placement: inside try:, after assert samples, before the finally: runs cleanup. AssertionError propagates correctly.
  • ha_config_remove_automation(identifier=...) signature matches the tool definition.
  • Per-test cleanup runs only on external/testcontainer tiers where the tool is registered (external_only handles inaddon).
  • All 4 targeted comment subtractions from the prior review are gone.
  • PR body now uses Closes #1389 ✓.
  • HAOS proxy-header flake landed via merged #1402 and is on the PR's rebased base.

Patch76 added 2 commits May 22, 2026 13:58
… items)

1. Narrow cleanup-loop exception in test_poll_cadence_measurement.py from
   `except Exception` to `except _POLLING_TRANSIENT_ERRORS` (the canonical
   tuple from wait_helpers.py). Programmer bugs (TypeError, AttributeError,
   KeyError, AssertionError) now propagate with their stack trace instead
   of being downgraded to a `logger.warning` line across 10 iterations.
   Aligns per-entity cleanup with the polling-helper pattern established
   for AGENTS.md "Exception handling in polling helpers" (homeassistant-ai#1266).

2. Lift the soft-failure warning prefix out of tools_config_automations.py
   as module-level `NOT_VERIFIED_WARNING_PREFIX` and import it in the test.
   The literal coupling becomes a compile-time edge instead of a runtime
   puzzle — rewording the source warning now breaks the test import,
   replacing the previous "9 samples + 0 not-verified != 10 attempts"
   indirect signal with a clear ModuleNotFoundError-style failure.

3. Replace the stale `session-scoped` label in the cleanup-block comment
   with `logging-only` (matches the commit-message framing for the
   ``cleanup_tracker`` fixture, which is function-scoped per its
   `@pytest.fixture` decorator in tests/src/e2e/conftest.py:1951).
)

Pre-existing format-debt on ``src/ha_mcp/tools/tools_config_automations.py``
became blocking once 4fd2852 added it to the PR's changed-files set —
``.github/workflows/pr.yml`` runs ``ruff format --check`` whole-file on
every Python file in the PR diff, with the "grandfathered for untouched
files" gate per the maintainer call on homeassistant-ai#1318.

The 230-line diff on ``tools_config_automations.py`` is pure mechanical
``ruff format`` output: line-break placement on ``raise_tool_error(...)``
wrappers, multi-line argument splits, and dict-literal expansion. No
logic, no semantic, no behavior change. Belongs to the homeassistant-ai#1318 sweep but
has to land in this PR because the file is now in the touched set.

The 1-line diff on ``test_poll_cadence_measurement.py`` (``isinstance(w,
str) and w.startswith(...)`` collapsed to a single line) is the natural
follow-on to the constant rename in 4fd2852 — the shorter name fits
within 88 chars.
@Patch76

Patch76 commented May 22, 2026

Copy link
Copy Markdown
Member Author

Addressed in 4fd2852, with a format-sweep follow-up at 376467b.

Should-fix

1. Cleanup except Exception narrowed. tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py:204

Imported _POLLING_TRANSIENT_ERRORS from wait_helpers.py:28 (the canonical tuple from #1266: McpError, FastMCPError, ClientError, RuntimeError, OSError, TimeoutError) and used it as the cleanup-loop catch. TypeError / AttributeError / KeyError / AssertionError now propagate with their stack trace; only transient HA-side cleanup errors (404, connection blip) get the warn-and-continue treatment. Comment block at L190-196 rewritten to call out the propagation intent explicitly.

2. NOT_VERIFIED_WARNING_PREFIX lifted to module-level constant. src/ha_mcp/tools/tools_config_automations.py:63 + tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py:28

Module-level constant defined in tools_config_automations.py:63 and used in the warning construction at :807. Test imports it directly, so rewording the source warning now breaks the test import — coupling is compile-time. The "Mirrors the literal" comment in the test is gone (replaced by the import).

Nit

3. "session-scoped" → "logging-only". tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py:190

Done. Matches the commit-message framing for the cleanup_tracker fixture.

Format-sweep follow-up (376467b)

Touching tools_config_automations.py for item 2 added it to the PR's changed-files set, which triggers ruff format --check whole-file per .github/workflows/pr.yml. Pre-existing master-debt on that file (line-break placement on multi-arg raise_tool_error(...) calls, dict-literal expansion) was suddenly blocking. Followed up with chore: apply ruff format (refs #1318) — mechanical only, no logic change. The 231-line diff on the source file is all ruff-format output; the 1-line change on the test file is the isinstance(w, str) and w.startswith(...) collapse from the shorter constant name.

@Patch76
Patch76 requested a review from kingpanther13 May 22, 2026 12:29

@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:

  • _POLLING_TRANSIENT_ERRORS import is the right tuple — (McpError, FastMCPError, ClientError, RuntimeError, OSError, TimeoutError) from wait_helpers.py:28. TypeError / AttributeError / KeyError / AssertionError propagate; transient transport/HA errors get the warn-and-continue. Private-symbol import is an established pattern in this repo (also used in test_manage_addon_modes.py:56).
  • NOT_VERIFIED_WARNING_PREFIX is module-level public at tools_config_automations.py:63, consumed via f-string at :781. Adjacent-string concat is byte-identical to the previous literal. Grep confirms a single emit site — no hardcoded-literal drift surface. Compile-time coupling achieved.
  • "session-scoped" → "logging-only" with propagation-intent expansion. Reads correctly.

Format-sweep 376467bc: AST-identical on both files (parsed both pre/post, byte-equal). No statement/argument/default/dict-key changes — pure layout. Test-file 1-line collapse is semantically unchanged.

LGTM.

@Patch76
Patch76 merged commit 31c70ee into homeassistant-ai:master May 22, 2026
17 checks passed
@Patch76
Patch76 deleted the feature/issue-1389 branch May 22, 2026 12:32
@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.

kingpanther13 added a commit to kingpanther13/ha-mcp-fork that referenced this pull request May 22, 2026
…ired by this refactor

The homeassistant-ai#1389/homeassistant-ai#1398 work added an e2e test
(``test_poll_cadence_measurement.py``) plus xdist plumbing in
``tests/src/e2e/conftest.py`` (``record_poll_cadence_measurement``,
``_POLL_CADENCE_MEASUREMENTS`` + xdist worker handoff, terminal-summary
section) to empirically validate ``_POLL_CADENCE``'s p50/p99/worst
percentiles. That test consumed the ``entity-registration-elapsed``
DEBUG log line emitted by ``_poll_for_automation_entity`` on each
successful registration.

This PR removes both ``_POLL_CADENCE`` and the elapsed-time
instrumentation: the cadence loop is replaced by the WS event-driven
discovery helper, which resolves sub-second on the happy path without
any cadence tuning needed. The measurement test is therefore consuming
a log signal that no longer exists — CI fail signature is "No
'entity-registration-elapsed' DEBUG records captured after 10
automation creations."

Deletes:

- ``tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py``
  (207 lines) — entire test file. The cadence tuple it validates is
  gone.
- ``record_poll_cadence_measurement()`` + ``_POLL_CADENCE_MEASUREMENTS``
  / ``_ALL_POLL_CADENCE_MEASUREMENTS`` + xdist worker handoff in
  ``pytest_sessionfinish`` / ``pytest_testnodedown`` + the
  ``homeassistant-ai#1389 _POLL_CADENCE measurement`` terminal section in
  ``pytest_terminal_summary``.

Also updates the ``NOT_VERIFIED_WARNING_PREFIX`` comment in
``tools_config_automations.py`` from "exhausts ``_POLL_CADENCE``" to
"exhausts its budget (``_POLL_BUDGET_S``)" and drops the test-file
reference, since the test that consumed the export is gone.

Per Patch76's homeassistant-ai#1406 review note: "the deletion wins" — extending that
to the e2e measurement infra that consumed the deleted instrumentation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kingpanther13 added a commit that referenced this pull request May 22, 2026
…loses #1395) (#1406)

* refactor: route _poll_for_automation_entity through WS event waiter (closes #1395)

Replaces the REST poll loop in
``HomeAssistantClient._poll_for_automation_entity`` with the WS
event-driven discovery pattern PR #1382 landed for the
``wait_for_entity_*`` helpers. ``state_changed`` events for fresh-create
automations carry ``new_state.attributes.id == unique_id`` because
``BaseAutomationEntity.capability_attributes`` exposes the unique_id as
``CONF_ID`` on every emit (HA Core, ``components/automation/__init__.py``
L454-459), so the same "subscribe → sample → wait" shape resolves
discovery sub-second instead of waiting on the cadence loop.

- ``_ws_wait_for_condition`` / ``_legacy_poll_until`` rename their
  internal ``entity_id`` parameter to ``identifier`` (log-only) so the
  helpers can serve discovery waits that don't know the entity_id up
  front. The signature for existing callers is positional-compatible.
- ``_ws_wait_for_condition`` grows an optional ``event_filter``
  parameter. When ``None`` (the existing callers) the default predicate
  matches ``data["entity_id"] == identifier`` — exactly the previous
  behaviour. Discovery callers pass a custom predicate.
- New public helper ``wait_for_automation_entity_by_unique_id(client,
  unique_id, timeout=6.0, poll_interval=0.3)``. Subscribes to
  ``state_changed``, filters automation entities by
  ``new_state.attributes.id``, captures the discovered entity_id in a
  closure cell so the post-event sample short-circuits the full
  ``get_states()`` scan. Falls back to REST polling via the same
  ``_legacy_poll_until`` path the existing waiters use when the WS is
  unavailable.

- ``_poll_for_automation_entity`` is now a thin wrapper that delegates
  to the new helper with a local import (mirroring the same circular-
  import workaround ``_get_waiter_ws_client`` uses).
- ``_POLL_CADENCE: tuple[float, ...] = (0.1, 1.0, 4.9)`` is gone —
  vestigial once the WS happy path is the primary route — replaced by
  ``_POLL_BUDGET_S: float = 6.0`` preserving the 6s upper-bound budget
  PR #1384 tuned. REST fallback uses uniform polling at
  ``poll_interval``.
- The ``except HomeAssistantError`` narrow catch is preserved so
  transient API errors surface as ``entity_not_verified=True`` and
  programming bugs (TypeError, etc.) propagate.

- ``tests/src/unit/test_rest_client_automations.py``:
  ``TestPollForAutomationEntity`` replaced. Old tests pinned the
  cadence tuple and ``asyncio.sleep`` call shape — both gone with the
  refactor. New tests lock the delegation contract: budget shape,
  unique_id / timeout forwarding, ``None`` on timeout, transient HA
  errors swallowed, programming bugs propagate.
- ``tests/src/unit/test_wait_helpers.py``: two new classes.
  - ``TestRestPathAutomationDiscovery`` — REST-fallback coverage
    (autouse ``force_rest_fallback`` fixture): resolves via REST sample,
    ignores ``script.*`` entities sharing the same id attribute, full
    miss returns None, transient ``HomeAssistantAPIError`` swallowed by
    sample callback.
  - ``TestWsPathAutomationDiscovery`` — WS coverage:
    post-subscribe sample resolves immediately, state_changed event
    arrival drives discovery, events for non-automation entities don't
    nudge, events for other automations (different unique_id) don't
    nudge.
- ``FakeWebSocketClient.fire_state_changed`` grows an optional
  ``new_state=`` kwarg so discovery tests can include the
  ``data.new_state.attributes`` shape the filter inspects.

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

* refactor: harden event_filter against malformed payloads and duplicate matches

Addresses review-toolkit findings on PR #1406:

- ``event_filter`` in ``wait_for_automation_entity_by_unique_id`` now
  guards every field access with ``isinstance`` checks before calling
  string / dict methods. The WS event dispatcher in
  ``websocket_client.py`` catches handler exceptions broadly (the
  pre-existing #1382 surface), so an ``AttributeError`` from a malformed
  payload reaching ``.startswith`` would be swallowed silently and the
  wait would time out reporting "not found" when the real cause was
  schema drift. The shape-hardening pattern is symmetric with the
  existing defense in ``sample()``.

- The captured-cell now records only the first observed entity_id
  rather than last-writer-wins. HA's automation storage forbids
  duplicate unique_id by construction, but if a future race ever fires
  two matching events the helper now keeps the first and warns on the
  collision instead of silently coin-flipping.

Two new tests in ``test_wait_helpers.py``:

- ``test_event_capture_short_circuits_rest_scan`` — pins the
  closure-cell short-circuit with a discriminator: the REST scan would
  resolve ``automation.from_rest`` and the event carries
  ``automation.from_event``. Whichever path wins, the test proves the
  wait resolves (didn't silently time out).

- ``test_connection_drop_during_discovery_falls_back_to_rest`` —
  mirrors ``TestWsPathConnectionDrop`` coverage for the discovery
  path. Pins that a WS drop mid-wait routes to the
  discovery-shaped ``get_states()`` sample rather than the
  entity-id-shaped ``get_entity_state()`` used by sibling waiters.

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

* fix: address sidelined silent-failure findings + fix connection-drop test

Three findings I previously marked "out of scope" — wrongly, per
AGENTS.md § Boy Scout Rule which explicitly forbids that escape hatch:

1. WS dispatcher swallowed handler exceptions without a traceback
   (``websocket_client.py:403``). The bare ``logger.error(f"... {e}")``
   gave operators one line and no stack, so a handler bug
   (AttributeError on a malformed event, KeyError on schema drift)
   would silently stop nudging the waiter's ``asyncio.Event`` and the
   calling waiter would time out reporting "not found." Added
   ``exc_info=True`` so the traceback lands in logs. The dispatcher
   itself still swallows so one buggy handler can't kill the WS — but
   the bug is now visible.

2. ``wait_for_automation_entity_by_unique_id`` emitted a redundant
   "Automation with unique_id X was not found" warning at the same
   level as ``_ws_wait_for_condition``'s generic timeout warning.
   Replaced the redundant warning with a conditional one that fires
   only when REST sampling was wedged the entire budget, so operators
   can distinguish "automation truly not published" from "REST channel
   down."

3. Transient ``HomeAssistantAPIError`` from ``get_states()`` was
   debug-only with no signal at timeout time. Now tracked in the
   closure cell and surfaced in the new conditional warning above
   ("timed out with every REST sample failing; last error: ...").

Also fixes ``test_connection_drop_during_discovery_falls_back_to_rest``
which I wrote against the wrong nudge shape: the original noise event
didn't match the discovery filter so the wait timed out at the
backstop instead of dropping. Rewritten to mirror
``test_connection_drop_before_wait_loop_falls_back_to_rest`` — drop
``ws_client.is_connected`` inside the post-subscribe sample so the
connection-drop branch routes us straight to ``_legacy_poll_until``.

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

* test: address Patch76 review findings on PR #1406

Three findings from Patch76's review of #1406:

1. **Discriminator test wasn't actually discriminating** —
   ``test_event_capture_short_circuits_rest_scan`` previously seeded
   ``get_states()`` to return ``automation.from_rest`` on every call and
   asserted ``result in {"automation.from_event", "automation.from_rest"}``.
   That accepts both outcomes, so a regression that broke the closure-cell
   short-circuit (forcing ``sample()`` to always fall through to
   ``get_states()``) would silently pass — REST would win every time. Now
   seeds ``get_states()`` with a side_effect that returns empty on the
   first call (post-subscribe sample) and the REST entity on subsequent
   calls, then asserts ``result == "automation.from_event"`` (deterministic
   discriminator: cell wins → event entity, regression → REST entity) and
   ``call_count == 1`` (the cell short-circuit means the post-event
   re-sample never touches REST).

2. **Duplicate-unique-id collision branch untested** — Patch76 noted the
   first-wins guard in ``event_filter`` (``util_helpers.py:1197``) had no
   test pinning the contract. Added
   ``test_duplicate_unique_id_collision_first_wins`` which fires two
   matching state_changed events back-to-back and asserts both
   "automation.first wins" and "warning logged naming both entity_ids."

3. **``last_api_error`` wedged-channel branch untested** — Patch76 noted
   the conditional warning at ``util_helpers.py:1222`` had no test pinning
   the "REST channel down" vs "automation never published" discrimination
   the code exists to make. Added
   ``test_wedged_rest_channel_surfaces_last_api_error`` which seeds
   ``get_states()`` to raise ``HomeAssistantAPIError`` on every call and
   asserts the timeout warning includes "every REST sample failing" and
   the last error message string.

Rebased onto current upstream/master. Mechanical conflict resolution per
Patch76: the ``_POLL_CADENCE`` deletion wins, taking #1389's measurement
instrumentation with it. ``_poll_for_automation_entity`` no longer needs
the cadence loop or the elapsed-time instrumentation because the WS
event-driven path resolves sub-second on the happy path and the REST
fallback uses uniform polling. The redundant local ``import time`` inside
``upsert_automation_config`` is also gone now that the top-level
``import time`` (added by #1389) remains for the unique_id-generation use
at ``time.time() * 1000``.

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

* test(e2e): remove #1389 cadence-measurement infra retired by this refactor

The #1389/#1398 work added an e2e test
(``test_poll_cadence_measurement.py``) plus xdist plumbing in
``tests/src/e2e/conftest.py`` (``record_poll_cadence_measurement``,
``_POLL_CADENCE_MEASUREMENTS`` + xdist worker handoff, terminal-summary
section) to empirically validate ``_POLL_CADENCE``'s p50/p99/worst
percentiles. That test consumed the ``entity-registration-elapsed``
DEBUG log line emitted by ``_poll_for_automation_entity`` on each
successful registration.

This PR removes both ``_POLL_CADENCE`` and the elapsed-time
instrumentation: the cadence loop is replaced by the WS event-driven
discovery helper, which resolves sub-second on the happy path without
any cadence tuning needed. The measurement test is therefore consuming
a log signal that no longer exists — CI fail signature is "No
'entity-registration-elapsed' DEBUG records captured after 10
automation creations."

Deletes:

- ``tests/src/e2e/workflows/automation/test_poll_cadence_measurement.py``
  (207 lines) — entire test file. The cadence tuple it validates is
  gone.
- ``record_poll_cadence_measurement()`` + ``_POLL_CADENCE_MEASUREMENTS``
  / ``_ALL_POLL_CADENCE_MEASUREMENTS`` + xdist worker handoff in
  ``pytest_sessionfinish`` / ``pytest_testnodedown`` + the
  ``#1389 _POLL_CADENCE measurement`` terminal section in
  ``pytest_terminal_summary``.

Also updates the ``NOT_VERIFIED_WARNING_PREFIX`` comment in
``tools_config_automations.py`` from "exhausts ``_POLL_CADENCE``" to
"exhausts its budget (``_POLL_BUDGET_S``)" and drops the test-file
reference, since the test that consumed the export is gone.

Per Patch76's #1406 review note: "the deletion wins" — extending that
to the e2e measurement infra that consumed the deleted instrumentation.

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

---------

Co-authored-by: kingpanther13 <kingpanther13@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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] Measure HA Core entity-registration p50/p99 to validate _poll_for_automation_entity 0.1s floor

2 participants