"""Event ingress — dual trigger (Plan | Event) v0.2.""" from __future__ import annotations from typing import Any from steering.kernel.binding import resolve_primary_method_key from steering.kernel.evaluate import evaluate_steering from steering.lifecycle.event_transitions import EventKind from steering.lifecycle.orchestrator import transition from steering.lifecycle.slot_providers import ( register_default_slot_providers, resolve_event_via_providers, ) from tenant_context import TenantContext register_default_slot_providers() def apply_steering_event( ctx: TenantContext, *, initiative_id: str, event_kind: EventKind, payload: dict[str, Any] | None = None, ) -> dict[str, Any]: """ Event-Schub in den Kernel. Plan-dominante Methoden: Event aktualisiert lifecycle_state entlang slot_map, danach Re-Evaluate über evaluate_steering (Plan-Zug bleibt führend für Next). """ payload = payload or {} primary_key = resolve_primary_method_key(ctx, initiative_id) chain = resolve_event_via_providers( primary_method_key=primary_key, event_kind=event_kind, payload=payload, ) transitions: list[dict[str, Any]] = [] handled = bool(chain) for slot_state in chain: result = transition( ctx, initiative_id, slot_state, reason=f"steering_event:{event_kind}", tenant_id=ctx.tenant_id, user_id=ctx.user_id or None, ) if not result.get("unchanged"): transitions.append(result) evaluation = evaluate_steering(ctx, initiative_id=initiative_id) return { "accepted": True, "event_kind": event_kind, "initiative_id": initiative_id, "handled": handled, "lifecycle_chain": list(chain), "transitions": transitions, "message": ( "Lifecycle aktualisiert — Re-Evaluate via Plan-Zug" if handled else "Event protokolliert — kein Lifecycle-Slot für diese Methode" ), "payload_keys": sorted(payload.keys()), "evaluation": evaluation.to_dict(), }