From b0f5a9b16df003f11266ae5afa144ed811369d6a Mon Sep 17 00:00:00 2001 From: Graham Hosking <142685548+ITSpecialist111@users.noreply.github.com> Date: Tue, 28 Jul 2026 07:04:24 +0100 Subject: [PATCH 1/2] Avoid phantom unloaded duplicate automations --- automation_inspector/app/dependency_map.py | 4 +++ tests/test_dependency_map.py | 31 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/automation_inspector/app/dependency_map.py b/automation_inspector/app/dependency_map.py index e97fa9e..a7e6b24 100644 --- a/automation_inspector/app/dependency_map.py +++ b/automation_inspector/app/dependency_map.py @@ -497,6 +497,10 @@ def build_inspection(snapshot: SourceSnapshot, settings: Settings) -> dict[str, ) if file_automation: matched_file_keys.add(file_automation.key) + if runtime_config is not None and config_id: + for candidate in file_by_id.get(config_id, []): + if candidate.config == runtime_config: + matched_file_keys.add(candidate.key) if not settings.include_disabled and state.get("state") != "on": continue diff --git a/tests/test_dependency_map.py b/tests/test_dependency_map.py index bb75aa1..9deb473 100644 --- a/tests/test_dependency_map.py +++ b/tests/test_dependency_map.py @@ -236,6 +236,37 @@ def test_duplicate_file_id_and_registry_only_helper_remain_visible() -> None: ] +def test_identical_file_duplicates_matching_loaded_automation_do_not_create_unloaded_rows() -> None: + config = { + "id": "duplicate", + "alias": "Loaded copy", + "triggers": [], + "actions": [], + } + snapshot = SourceSnapshot( + states=[ + { + "entity_id": "automation.loaded_copy", + "state": "on", + "attributes": {"id": "duplicate"}, + } + ], + home_assistant_config={"version": "2026.7.2"}, + automation_configs={"automation.loaded_copy": config}, + file_automations=[ + FileAutomation(0, "duplicate", config), + FileAutomation(1, "duplicate", dict(config)), + FileAutomation(2, "duplicate", dict(config)), + ], + ) + + report = build_inspection(snapshot, Settings()) + + assert report["summary"]["automations"] == 1 + assert report["summary"]["unloaded"] == 0 + assert list(report["automations"]) == ["automation.loaded_copy"] + + def test_excluding_disabled_automation_does_not_report_its_file_as_unloaded() -> None: config = {"id": "off-id", "alias": "Off", "triggers": [], "actions": []} snapshot = SourceSnapshot( From 25cb289639eb79dcd890377df04e8a70736426b6 Mon Sep 17 00:00:00 2001 From: Graham Hosking <142685548+ITSpecialist111@users.noreply.github.com> Date: Tue, 28 Jul 2026 07:27:33 +0100 Subject: [PATCH 2/2] Collapse duplicate file automations reliably --- automation_inspector/app/dependency_map.py | 4 +-- tests/test_dependency_map.py | 32 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/automation_inspector/app/dependency_map.py b/automation_inspector/app/dependency_map.py index a7e6b24..9526a60 100644 --- a/automation_inspector/app/dependency_map.py +++ b/automation_inspector/app/dependency_map.py @@ -497,9 +497,9 @@ def build_inspection(snapshot: SourceSnapshot, settings: Settings) -> dict[str, ) if file_automation: matched_file_keys.add(file_automation.key) - if runtime_config is not None and config_id: + if config_id: for candidate in file_by_id.get(config_id, []): - if candidate.config == runtime_config: + if candidate.config == file_automation.config: matched_file_keys.add(candidate.key) if not settings.include_disabled and state.get("state") != "on": continue diff --git a/tests/test_dependency_map.py b/tests/test_dependency_map.py index 9deb473..7b4224d 100644 --- a/tests/test_dependency_map.py +++ b/tests/test_dependency_map.py @@ -267,6 +267,38 @@ def test_identical_file_duplicates_matching_loaded_automation_do_not_create_unlo assert list(report["automations"]) == ["automation.loaded_copy"] +def test_duplicate_file_entries_collapse_even_when_runtime_config_differs() -> None: + file_config = { + "id": "duplicate", + "alias": "Loaded copy", + "triggers": [], + "actions": [], + } + runtime_config = dict(file_config) | {"mode": "single"} + snapshot = SourceSnapshot( + states=[ + { + "entity_id": "automation.loaded_copy", + "state": "on", + "attributes": {"id": "duplicate"}, + } + ], + home_assistant_config={"version": "2026.7.2"}, + automation_configs={"automation.loaded_copy": runtime_config}, + file_automations=[ + FileAutomation(0, "duplicate", dict(file_config)), + FileAutomation(1, "duplicate", dict(file_config)), + FileAutomation(2, "duplicate", dict(file_config)), + ], + ) + + report = build_inspection(snapshot, Settings()) + + assert report["summary"]["automations"] == 1 + assert report["summary"]["unloaded"] == 0 + assert list(report["automations"]) == ["automation.loaded_copy"] + + def test_excluding_disabled_automation_does_not_report_its_file_as_unloaded() -> None: config = {"id": "off-id", "alias": "Off", "triggers": [], "actions": []} snapshot = SourceSnapshot(