payment/state_machine.py — Generated từ SPEC.md
from transitions import Machine
from enum import Enum
class PaymentState(str, Enum):
PENDING = "pending_payment"
PROCESSING = "processing"
CONFIRMING = "confirming"
PAID = "paid"
FAILED = "failed"
EXPIRED = "expired"
FULFILLED = "fulfilled"
REFUNDED = "refunded"
# EXACTLY mirrors valid transitions trong SPEC.md
# Adding a transition here WITHOUT updating spec = Constitution violation
VALID_TRANSITIONS = [
{"trigger": "initiate", "source": "pending_payment", "dest": "processing"},
{"trigger": "gateway_pending", "source": "processing", "dest": "confirming"},
{"trigger": "gateway_fail", "source": "processing", "dest": "failed"},
{"trigger": "webhook_success", "source": "confirming", "dest": "paid"},
{"trigger": "webhook_fail", "source": "confirming", "dest": "failed"},
{"trigger": "retry", "source": "failed", "dest": "processing",
"conditions": "within_retry_window"},
{"trigger": "fulfill", "source": "paid", "dest": "fulfilled"},
{"trigger": "refund", "source": ["paid","fulfilled"], "dest": "refunded",
"conditions": "within_refund_window"},
]
class PaymentOrder:
def log_transition(self):
# EARS[Ubiquitous]: every transition has audit_log
AuditLog.create(order_id=self.id, from_state=self.state, to_state=self.dest)
# → Invalid transition attempt raises MachineError automatically
# → Spec is enforced at runtime, not just documentation