Skip to content

Commit e49a7b6

Browse files
sergeykadSergey
andauthored
feat(search): use Home Assistant's reference graph for entity dependency discovery (#2277)
* test: scope the supply-chain Dockerfile scan to repository content - rglob picked up Dockerfiles inside gitignored worktree checkouts - Renovate only sees tracked content, so the assertion should too - unblocked committing for anyone following the worktree workflow * feat(search): add Home Assistant reference-graph lookups - query-shape gate, search/related frame, response parsing and merge - distinguishes an unreadable answer from 'no references found' - suppresses repeat frames only after a second unknown_command rejection * refactor(search): drop the phantom bulk config tier and use the reference graph - the keyless bulk GET matched no HA route and 404'd on every version - per-id fetch now orders by what the graph already confirmed - renamed scenes resolve through the registry storage key * test(search): update suites for per-id fetching and renamed-scene resolution - drop mocks and assertions that simulated the removed bulk endpoint - delete two tests whose hand-built input the real path cannot produce - rename the bulk-fetch e2e file to what it actually covers * docs: record unit-test invocation and e2e component routing - AGENTS.md documented only the E2E command; add the parallel unit one - note that ha_search routes to the component on every e2e lane * fix(search): address review findings on the reference-graph merge - disclose unmodelled consumers as a count, never ids: enforce mode refuses any response carrying a hidden entity_id, which failed the whole search - treat a populated but unreadable bucket as not consulted - bound the optional graph lookup with its own 5s timeout - emit match_in_references on dashboard records too - fix the documented unit-test command to run from tests/ * fix(search): let scene incompleteness reach the scope-sentence gate - a scene-only search whose configs failed lost the scope sentence entirely - tighten a scene assertion that could pass on unrelated wording - drop a docstring reference to state that was consolidated away * fix(search): correct the budget-exhausted guidance - raising config_time_budget does complete the scan when Home Assistant's serialized reads finish inside the higher limit - state the latency tradeoff and the throughput ceiling instead of claiming the limit is irrelevant, which steered users to the component needlessly * refactor(internal): isolate the reference-graph clock behind a seam - _graph.time is the stdlib module object, so patching monotonic through it faked the clock for every module in the process - mirrors the existing component_api._monotonic pattern * test: address review findings on e2e conventions and the Dockerfile scan - use call_tool_success inside MCPAssertions, and safe_call_tool for cleanup so a cleanup failure cannot mask the real assertion - enumerate Dockerfiles via git ls-files: the .claude name filter also excluded the tracked .claude/skills tree - refresh a fixture comment that still described the removed bulk tier * fix(test): let the Dockerfile scan read the index inside CI's container - the unit-test job runs in a container with the workspace bind-mounted, so the checkout is owned by another uid and git refused with exit 128 - scope safe.directory to the one invocation; no git config is written - carry git's stderr into the assertion so the next failure explains itself --------- Co-authored-by: Sergey <sergey@example.com>
1 parent 3bc9d1e commit e49a7b6

17 files changed

Lines changed: 2315 additions & 449 deletions

AGENTS.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,16 @@ uv run hamcp-test-env --no-interactive # For automation
417417

418418
Test token centralized in `tests/test_constants.py`.
419419

420+
**Unit tests** (`tests/src/unit/`, no Docker) — run them in parallel, as CI does
421+
(`pr.yml`); serial takes 25+ minutes for ~11k tests:
422+
423+
```bash
424+
cd tests && uv run pytest src/unit/ -n auto --tb=short
425+
```
426+
427+
`tests/pytest.ini` sets `--maxfail=3`, so a run reporting "3 failed" has stopped
428+
early rather than finished — pass `--maxfail=0` when you need the full picture.
429+
420430
### Code Quality
421431

422432
C901 (mccabe complexity ≤10) is enforced repo-wide with zero per-file exemptions (issue #925 cleared the grandfathered list) — never reintroduce a `["C901"]` per-file-ignore; extract helpers instead.
@@ -896,7 +906,10 @@ empty, so the English a `tools` entry translates is read from the tool
896906
definition in `src/ha_mcp/tools/` — the `title=` kwarg and the summary
897907
paragraph of the docstring, or the `FEATURE_GATED_TOOLS` stub where a gated
898908
tool shows one instead. Editing that summary moves the English out from under
899-
six catalogs; the pipeline retranslates them. One deliberate exception: a
909+
six catalogs; the pipeline retranslates them. A parameter's
910+
`Field(description=...)` is NOT in the baseline — only the title and the
911+
docstring summary are — so editing one owes no translation work. One
912+
deliberate exception: a
900913
change to a feature-gated tool's PARSED docstring (its stub unchanged) is
901914
stub-review work, not translation work — the pipeline holds that baseline key
902915
stale, and the locale-sync run stays red until a human confirms the stub

src/ha_mcp/tools/smart_search/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020
# keep resolving.
2121
from ._config import (
2222
AUTOMATION_CONFIG_TIME_BUDGET,
23-
BULK_REST_TIMEOUT,
24-
BULK_WEBSOCKET_TIMEOUT,
2523
DEFAULT_CONCURRENCY_LIMIT,
24+
ENTITY_REGISTRY_TIMEOUT,
2625
INDIVIDUAL_CONFIG_TIMEOUT,
2726
INDIVIDUAL_FETCH_BATCH_SIZE,
2827
SCENE_CONFIG_TIME_BUDGET,

src/ha_mcp/tools/smart_search/_config.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
# Default concurrency limit for parallel operations
1111
DEFAULT_CONCURRENCY_LIMIT = 20
1212

13-
# Bulk fetch timeouts (in seconds)
14-
BULK_REST_TIMEOUT = 5.0 # Timeout for bulk REST endpoint calls
15-
BULK_WEBSOCKET_TIMEOUT = 3.0 # Timeout for bulk WebSocket calls
13+
# Timeout for the entity-registry WebSocket list used by the scene walk.
14+
ENTITY_REGISTRY_TIMEOUT = 3.0
1615

1716

18-
# Attempt-C (per-id fallback; the letter predates the removal of the phantom
19-
# WS bulk tier in #1889 and is kept as a proper name) tuning knobs. Sourced from the resolved
17+
# Per-id config-fetch tuning knobs. The code calls this pass "Attempt C":
18+
# a proper name left from when two earlier bulk tiers were tried first,
19+
# both since removed as phantoms (#1889, #2258). It is now the only pass. Sourced from the resolved
2020
# Settings (issues #1538 / #1784) so the env var, the web Settings UI
2121
# override file, and the field defaults all flow through one precedence path
2222
# — and so add-on users (who cannot set raw env vars) can tune them from the
@@ -25,7 +25,7 @@
2525
# carry a restart-required notice in the UI).
2626
_settings = get_global_settings()
2727

28-
# Time budgets for fallback individual fetching (in seconds).
28+
# Wall-clock budgets for the per-id config fetch (in seconds).
2929
AUTOMATION_CONFIG_TIME_BUDGET = _settings.automation_config_time_budget
3030
SCRIPT_CONFIG_TIME_BUDGET = _settings.script_config_time_budget
3131
SCENE_CONFIG_TIME_BUDGET = _settings.scene_config_time_budget

0 commit comments

Comments
 (0)