Add production safety controls
This commit is contained in:
@@ -76,6 +76,17 @@ class EventCore:
|
||||
learning=learning_profile,
|
||||
control=control_profile,
|
||||
)
|
||||
if not control.global_enabled and decision.allowed:
|
||||
decision = decision.model_copy(
|
||||
update={
|
||||
"allowed": False,
|
||||
"reason": "Globaler Not-Aus ist aktiv.",
|
||||
"blockers": [*decision.blockers, "Globaler Not-Aus ist aktiv."],
|
||||
}
|
||||
)
|
||||
if decision.dry_run:
|
||||
control_profile = _record_dry_run(control_profile, decision)
|
||||
control.profiles[actuator_id] = control_profile
|
||||
if callable(execute) and decision.allowed and not decision.dry_run:
|
||||
decision = _execute_decision(decision, execute)
|
||||
audit.append(
|
||||
@@ -110,3 +121,25 @@ def _execute_decision(decision: Decision, execute: Callable[[Decision], bool]) -
|
||||
}
|
||||
)
|
||||
return decision.model_copy(update={"executed": bool(result)})
|
||||
|
||||
|
||||
def _record_dry_run(profile: ControlProfile, decision: Decision) -> ControlProfile:
|
||||
events = profile.dry_run_events + 1
|
||||
successes = profile.dry_run_successes + int(decision.allowed and not decision.blockers)
|
||||
failures = profile.dry_run_failures + int(bool(decision.blockers))
|
||||
success_rate = successes / events if events else 0.0
|
||||
ready = events >= 5 and success_rate >= 0.8 and failures <= 1
|
||||
reason = (
|
||||
f"Dry-run {successes}/{events} erfolgreich."
|
||||
if ready
|
||||
else f"Dry-run braucht mindestens 5 Events und 80% Treffer; aktuell {successes}/{events}."
|
||||
)
|
||||
return profile.model_copy(
|
||||
update={
|
||||
"dry_run_events": events,
|
||||
"dry_run_successes": successes,
|
||||
"dry_run_failures": failures,
|
||||
"active_ready": ready,
|
||||
"active_readiness_reason": reason,
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user