"""Lifecycle orchestrator — persistierter Standard Lifecycle (AP1.0).""" from __future__ import annotations from typing import Any, Optional from services import steering_context as sc_service from steering.lifecycle.states import validate_lifecycle_state from tenant_context import TenantContext def get_lifecycle_state(ctx: TenantContext, initiative_id: str) -> str: row = sc_service.get_steering_context( tenant_id=ctx.tenant_id, initiative_id=initiative_id ) if row: return row["lifecycle_state"] created = sc_service.ensure_steering_context( tenant_id=ctx.tenant_id, initiative_id=initiative_id, initial_state="intake", ) return created["lifecycle_state"] def transition( ctx: TenantContext | None, initiative_id: str, to_state: str, *, reason: str = "", tenant_id: Optional[str] = None, user_id: Optional[str] = None, ) -> dict[str, Any]: """Lifecycle-Transition — AP1.0: freier Übergang (Guards in AP1.1).""" validate_lifecycle_state(to_state) tid = tenant_id or (ctx.tenant_id if ctx else None) if not tid: raise ValueError("tenant_id erforderlich") existing = sc_service.get_steering_context(tenant_id=tid, initiative_id=initiative_id) if not existing: existing = sc_service.ensure_steering_context( tenant_id=tid, initiative_id=initiative_id, initial_state=to_state, ) return { "initiative_id": initiative_id, "from_state": None, "to_state": to_state, "reason": reason, } from_state = existing["lifecycle_state"] if from_state == to_state: return { "initiative_id": initiative_id, "from_state": from_state, "to_state": to_state, "reason": reason, "unchanged": True, } updated = sc_service.update_lifecycle_state( tenant_id=tid, initiative_id=initiative_id, lifecycle_state=to_state, user_id=user_id, reason=reason, from_state=from_state, ) return { "initiative_id": initiative_id, "from_state": from_state, "to_state": updated["lifecycle_state"], "reason": reason, }