"""分阶段 ACK DTO。 定义分阶段 ACK(FR-24)的枚举与不可变值对象,包括 ACK 策略、ACK 阶段 与 ACK 决策。所有枚举继承 ``str, Enum`` 以支持 JSON 序列化,DTO 均为 ``dataclass(frozen=True)``,仅依赖标准库,用于入站消息的分阶段 ACK 决策与幂等控制。 """ from __future__ import annotations from dataclasses import dataclass from enum import StrEnum from typing import Literal from yuxi.channels.contract.errors import ValidationError class AckPolicy(StrEnum): """ACK 策略。 标识入站消息的 ACK 时机,用于控制 ACK 与消息处理流程的耦合关系。 继承 ``str, Enum`` 以支持 JSON 序列化与字符串比较。 取值: AFTER_RECORD: 消息记录后 ACK。 AFTER_AGENT_DISPATCH: Agent 分发后 ACK。 AFTER_PERSIST: 持久化投递后 ACK。 MANUAL: 手动 ACK。 """ AFTER_RECORD = "after_record" AFTER_AGENT_DISPATCH = "after_agent_dispatch" AFTER_PERSIST = "after_persist" MANUAL = "manual" class AckStage(StrEnum): """ACK 阶段。 标识 ACK 决策所属的处理阶段,用于分阶段 ACK 的状态机推进。继承 ``str, Enum`` 以支持 JSON 序列化与字符串比较。 取值: RECORD: 记录阶段。 DISPATCH: 分发阶段。 PERSIST: 持久化阶段。 MANUAL: 手动阶段。 """ RECORD = "record" DISPATCH = "dispatch" PERSIST = "persist" MANUAL = "manual" @dataclass(frozen=True) class AckDecision: """ACK 决策(FR-24)。 描述一次 ACK 决策的结果,包括决策动作、所属阶段与幂等键,用于 分阶段 ACK 的决策传递与幂等控制。 字段: decision: 决策动作(ack | nack | retry | pending)。 stage: ACK 阶段。 idempotency_key: 幂等键(可选)。 """ decision: Literal["ack", "nack", "retry", "pending"] stage: AckStage idempotency_key: str | None = None def __post_init__(self) -> None: """校验 decision 取值合法。 ``decision`` 必须为 ``ack`` / ``nack`` / ``retry`` / ``pending`` 之一,在构造时 即抛出 ``ValidationError``,避免非法决策动作导致 ACK 状态机推进 异常(INV-8)。 """ if self.decision not in ("ack", "nack", "retry", "pending"): raise ValidationError("decision", "must be one of ack, nack, retry, pending")