Coverage for src / lexigram / contracts / workflow / steps.py: 100%
20 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-19 05:41 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-19 05:41 +0800
1"""Pipeline step execution result types.
3Moved from ``lexigram.contracts.execution`` — step results are a workflow
4concern, not a generic execution or Result concern.
5"""
7from __future__ import annotations
9from dataclasses import dataclass, field
10from typing import TYPE_CHECKING, Any
12if TYPE_CHECKING:
13 from collections.abc import Awaitable, Callable
15 from lexigram.contracts.core.result import Result
17__all__ = [
18 "SagaStep",
19 "SagaStepError",
20]
23class SagaStepError(Exception):
24 """Represents a recoverable failure from a single saga step action.
26 SagaProtocol step actions must return ``Result[T, SagaStepError]`` so that the
27 orchestration layer can detect failures without catching exceptions.
29 Attributes:
30 step_name: Identifier of the failing step (set by the orchestrator).
31 detail: Human-readable description of what went wrong.
32 """
34 _code: str = "LEX_ERR_WF_002"
36 def __init__(self, detail: str, step_name: str = "") -> None:
37 super().__init__(detail)
38 self.detail = detail
39 self.step_name = step_name
41 def __repr__(self) -> str:
42 """Return developer-friendly repr."""
43 return f"{type(self).__name__}(step={self.step_name!r}, detail={self.detail!r})"
46@dataclass(frozen=True)
47class SagaStep:
48 """Descriptor for a single saga orchestration step.
50 Shared across ``lexigram-workflow`` and ``lexigram-events`` via contracts.
52 The ``action`` callable **must** return ``Result[Any, SagaStepError]``.
53 The ``compensation`` callable is called only when the saga is unwinding
54 and may raise exceptions freely (infrastructure failures in compensation
55 should propagate).
57 Attributes:
58 name: Unique step identifier within the saga.
59 action: Async callable returning ``Result[Any, SagaStepError]``.
60 compensation: Async callable to undo the step on failure.
61 max_retries: Maximum retry attempts if action returns ``Err``.
62 retry_delay: Seconds to wait between retry attempts.
63 idempotent: Whether the compensation is safe to call multiple times.
64 """
66 name: str
67 action: Callable[..., Awaitable[Result[Any, SagaStepError]]]
68 compensation: Callable[..., Awaitable[None]] | None = None
69 max_retries: int = 3
70 retry_delay: float = 1.0
71 idempotent: bool = field(default=False)