BEHAVIOR-004: trust HA automation actions
Some checks failed
quality / test (3.11) (push) Has been cancelled
quality / test (3.13) (push) Has been cancelled

This commit is contained in:
2026-06-14 15:58:05 +02:00
parent 1c5eab14b6
commit 7ad97320a2
8 changed files with 60 additions and 34 deletions

View File

@@ -161,8 +161,8 @@ def test_engine_trains_predicts_in_shadow_and_executes_only_after_approval(
shadow = engine.evaluate("light.office")
assert trained.behavior.status is BehaviorStatus.TRAINED
assert trained.behavior.sample_count == 3
assert trained.behavior.high_confidence_sample_count == 3
assert trained.behavior.sample_count == 6
assert trained.behavior.high_confidence_sample_count == 6
assert shadow.behavior.mode is BehaviorMode.SHADOW
assert shadow.behavior.prediction is not None
assert shadow.behavior.prediction.target_state == "on"
@@ -179,17 +179,27 @@ def test_engine_trains_predicts_in_shadow_and_executes_only_after_approval(
]
def test_engine_excludes_known_automation_actions(tmp_path: Path) -> None:
def test_engine_counts_known_automation_actions_like_manual_actions(
tmp_path: Path,
) -> None:
now = datetime.now(timezone.utc).replace(second=0, microsecond=0)
engine, _ = _engine(tmp_path, now)
trained = engine.train("light.office")
assert {pattern.target_state for pattern in trained.behavior.patterns} == {"on"}
assert {pattern.source for pattern in trained.behavior.patterns} == {"user"}
assert {pattern.target_state for pattern in trained.behavior.patterns} == {
"on",
"off",
}
assert {pattern.source for pattern in trained.behavior.patterns} == {
"user",
"automation",
}
assert trained.behavior.high_confidence_sample_count == 6
assert {pattern.weight for pattern in trained.behavior.patterns} == {1.0}
def test_engine_learns_causal_automation_for_shadow_without_user_credit(
def test_engine_learns_causal_automation_with_activation_credit(
tmp_path: Path,
) -> None:
now = datetime.now(timezone.utc).replace(second=0, microsecond=0)
@@ -270,7 +280,8 @@ def test_engine_learns_causal_automation_for_shadow_without_user_credit(
]
assert len(automation_patterns) == 3
assert trained.behavior.high_confidence_sample_count == 0
assert trained.behavior.high_confidence_sample_count == 3
assert {pattern.weight for pattern in automation_patterns} == {1.0}
assert {
(
pattern.trigger_entity_id,
@@ -280,6 +291,10 @@ def test_engine_learns_causal_automation_for_shadow_without_user_credit(
for pattern in automation_patterns
} == {("binary_sensor.storage_door", "off", "on")}
active = engine.set_active("light.storage", active=True)
assert active.behavior.mode is BehaviorMode.ACTIVE
def test_active_mode_rejects_unsafe_domains(tmp_path: Path) -> None:
settings = _settings(tmp_path)
@@ -301,7 +316,7 @@ def test_active_mode_rejects_unsafe_domains(tmp_path: Path) -> None:
engine.set_active("lock.front_door", active=True)
def test_active_mode_requires_user_attributed_actions(tmp_path: Path) -> None:
def test_active_mode_requires_trusted_manual_or_automation_actions(tmp_path: Path) -> None:
settings = _settings(tmp_path)
store = ActuatorStore(settings.actuator_store)
record = store.configure("light.office")
@@ -321,7 +336,7 @@ def test_active_mode_requires_user_attributed_actions(tmp_path: Path) -> None:
reader = FakeBehaviorReader(entities=[], history=[], logbook=[])
engine = BehaviorEngine(ha_reader=reader, store=store, settings=settings)
with pytest.raises(ValueError, match="eindeutig dir zugeordnete"):
with pytest.raises(ValueError, match="manuelle oder automatisierte"):
engine.set_active("light.office", active=True)