"""全部领域枚举。 放在包根、不依赖任何东西 —— models / engine / schemas / api 都从这里取, 保证"状态"这个概念在全仓库只有一份定义。 """ from __future__ import annotations from enum import Enum class StrEnum(str, Enum): """Python 3.9 没有 enum.StrEnum,自己来一个。""" def __str__(self) -> str: # pragma: no cover - 只影响日志可读性 return self.value # ---------------------------------------------------------------- Run / Step class RunState(StrEnum): QUEUED = "QUEUED" # 等资源 PREFLIGHT = "PREFLIGHT" # 安全门禁 + 环境指纹冻结 RUNNING = "RUNNING" RECOVERING = "RECOVERING" # 恢复阶梯进行中 PAUSED = "PAUSED" # 人工暂停 FROZEN = "FROZEN" # 冻结现场,停止一切覆盖性动作(终态) COMPLETED = "COMPLETED" # 终态 ABORTED = "ABORTED" # 紧急停止(终态) REJECTED = "REJECTED" # 安全门禁拒绝(终态) class StepState(StrEnum): PENDING = "PENDING" DISPATCHED = "DISPATCHED" # 已租给 Agent,等确认接手 RUNNING = "RUNNING" SUCCEEDED = "SUCCEEDED" FAILED = "FAILED" TIMED_OUT = "TIMED_OUT" SKIPPED = "SKIPPED" CANCELLED = "CANCELLED" class Verdict(StrEnum): PASS = "PASS" FAIL = "FAIL" INCONCLUSIVE = "INCONCLUSIVE" # 非幂等步骤中断后不自动重跑 → 需人工确认 # ------------------------------------------------------------------ 恢复阶梯 class RecoveryLevel(StrEnum): """方案 §7.2 的五级阶梯。顺序即升级顺序。""" AGENT_SOFT = "L1_AGENT_SOFT" # Agent 优雅停止 / 软重启进程 OS_REBOOT = "L2_OS_REBOOT" # OS 远程通道重启 OOB_RESET = "L3_OOB_RESET" # 带外触发主板 Reset OOB_ATX_POWER = "L4_OOB_ATX_POWER" # 带外模拟 ATX 长按关机再开机 OOB_AC_CYCLE = "L5_OOB_AC_CYCLE" # 整机 AC 断电 → 安全间隔 → 上电 FREEZE = "FREEZE" # 冻结现场,不再自动恢复 @property def requires_oob(self) -> bool: return self in ( RecoveryLevel.OOB_RESET, RecoveryLevel.OOB_ATX_POWER, RecoveryLevel.OOB_AC_CYCLE, ) class RecoveryOutcome(StrEnum): RECOVERED = "RECOVERED" FAILED = "FAILED" ESCALATED = "ESCALATED" FROZEN = "FROZEN" class RecoveryTrigger(StrEnum): HEARTBEAT_LOST = "HEARTBEAT_LOST" STEP_TIMEOUT = "STEP_TIMEOUT" HOST_CRASH = "HOST_CRASH" # 蓝屏 / kernel panic DUT_NOT_ENUMERATED = "DUT_NOT_ENUMERATED" DATA_INTEGRITY = "DATA_INTEGRITY" # → 直接 FREEZE,不走阶梯 MANUAL = "MANUAL" # -------------------------------------------------------------------- 资产 class HostStatus(StrEnum): ONLINE = "ONLINE" DEGRADED = "DEGRADED" # 心跳迟到但未判失联 OFFLINE = "OFFLINE" UNKNOWN = "UNKNOWN" class DutStatus(StrEnum): IDLE = "IDLE" IN_USE = "IN_USE" QUARANTINED = "QUARANTINED" # 疑似坏盘,隔离待人工确认 MISSING = "MISSING" # 探针找不到 class PowerState(StrEnum): ON = "ON" OFF = "OFF" UNKNOWN = "UNKNOWN" class DangerLevel(StrEnum): NONE = "none" LOW = "low" HIGH = "high" # 需要审批记录 # -------------------------------------------------------------------- 失败 class FailureClass(StrEnum): """INFRA_FAILURE 必须与 DUT_DEFECT 分开统计 —— 见 domain-model.md。 把网络断了算成 SSD 缺陷,客户第一周就不信任这套系统。 """ DUT_DEFECT = "DUT_DEFECT" INFRA_FAILURE = "INFRA_FAILURE" SCRIPT_FAILURE = "SCRIPT_FAILURE" DATA_INTEGRITY = "DATA_INTEGRITY" UNKNOWN = "UNKNOWN" class IntegrityState(StrEnum): OK = "OK" MISMATCH = "MISMATCH" NOT_CHECKED = "NOT_CHECKED" # ------------------------------------------------------------- 事件(时间线) class EventSource(StrEnum): CONTROL_PLANE = "control_plane" AGENT = "agent" OOB = "oob" # 带外通道 —— 主机死后唯一还在说话的 HUMAN = "human" class Severity(StrEnum): DEBUG = "DEBUG" INFO = "INFO" WARNING = "WARNING" ERROR = "ERROR" CRITICAL = "CRITICAL" class EventKind(StrEnum): """统一时间线的事件种类。 新增事件种类是常事;删除/改名不是 —— 历史事件已经落库,改名会让旧 Run 的 时间线读不出来。只增不改。 """ # Run 生命周期 RUN_CREATED = "RUN_CREATED" RUN_QUEUED = "RUN_QUEUED" RUN_PREFLIGHT_STARTED = "RUN_PREFLIGHT_STARTED" RUN_PREFLIGHT_PASSED = "RUN_PREFLIGHT_PASSED" RUN_REJECTED = "RUN_REJECTED" RUN_STARTED = "RUN_STARTED" RUN_PAUSED = "RUN_PAUSED" RUN_RESUMED = "RUN_RESUMED" RUN_COMPLETED = "RUN_COMPLETED" RUN_ABORTED = "RUN_ABORTED" RUN_FROZEN = "RUN_FROZEN" # 循环与步骤 LOOP_STARTED = "LOOP_STARTED" LOOP_COMPLETED = "LOOP_COMPLETED" STEP_DISPATCHED = "STEP_DISPATCHED" STEP_LEASE_RENEWED = "STEP_LEASE_RENEWED" STEP_LEASE_EXPIRED = "STEP_LEASE_EXPIRED" STEP_STARTED = "STEP_STARTED" STEP_OUTPUT = "STEP_OUTPUT" STEP_SUCCEEDED = "STEP_SUCCEEDED" STEP_FAILED = "STEP_FAILED" STEP_TIMED_OUT = "STEP_TIMED_OUT" STEP_RETRYING = "STEP_RETRYING" STEP_CANCELLED = "STEP_CANCELLED" # 检查点 CHECKPOINT_SAVED = "CHECKPOINT_SAVED" CHECKPOINT_RESUMED = "CHECKPOINT_RESUMED" # 心跳与双通道观测 HEARTBEAT_DEGRADED = "HEARTBEAT_DEGRADED" HEARTBEAT_LOST = "HEARTBEAT_LOST" HEARTBEAT_RECOVERED = "HEARTBEAT_RECOVERED" OOB_OBSERVATION = "OOB_OBSERVATION" OOB_POWER_STATE = "OOB_POWER_STATE" # 恢复 RECOVERY_STARTED = "RECOVERY_STARTED" RECOVERY_ESCALATED = "RECOVERY_ESCALATED" RECOVERY_SUCCEEDED = "RECOVERY_SUCCEEDED" RECOVERY_FAILED = "RECOVERY_FAILED" # 设备与数据 DUT_ENUMERATION_LOST = "DUT_ENUMERATION_LOST" DUT_ENUMERATION_RESTORED = "DUT_ENUMERATION_RESTORED" INTEGRITY_MISMATCH = "INTEGRITY_MISMATCH" # 安全与资源 SAFETY_APPROVED = "SAFETY_APPROVED" SAFETY_REJECTED = "SAFETY_REJECTED" LOCK_ACQUIRED = "LOCK_ACQUIRED" LOCK_RELEASED = "LOCK_RELEASED" # 人与产物 HUMAN_TOUCH = "HUMAN_TOUCH" # 每一次人工介入都记 —— UCR 的分母来源 FAILURE_SIGNED = "FAILURE_SIGNED" EVIDENCE_BUNDLED = "EVIDENCE_BUNDLED" class StepType(StrEnum): COMMAND = "command" DEVICE_CHECK = "device_check" WAIT = "wait" LOOP = "loop" PRECHECK = "precheck" REPORT = "report" class OnFail(StrEnum): RETRY = "retry" FAIL_RUN = "fail_run" CONTINUE = "continue" FREEZE = "freeze" RECOVER = "recover"