Files
yuanshuai c91a64fddb
CI / Python 3.12 (push) Waiting to run
CI / Python 3.9 (push) Waiting to run
chore(repo): initialize team collaboration repository
2026-07-27 20:40:12 +08:00

97 lines
4.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 领域模型:7 个核心对象 → 14 张表
方案 §5.3 列了 7 个核心领域对象。当前 SQLAlchemy 元数据包含 14 张表。
额外表用于事件溯源、恢复动作、资源锁、失败实例与审计;它们不是新的顶层产品概念,
而是核心对象的行为记录和读模型。
## 对象 → 表
| 方案对象 | 表 | 补充说明 |
|---|---|---|
| DUT | `duts` | 序列号是防错盘的第一信号 |
| Test Host | `test_hosts` + `oob_controllers` | 带外控制器独立成表:它必须能在主机死后独活 |
| Firmware Artifact | `firmware_artifacts` | 哈希 + 签名 + 适用型号,缺一不可审计 |
| Workflow | `workflows` | 存 spec 原文 + spec_hash,改一个字就是新版本 |
| Run | `runs` + `run_steps` + `run_events` + `recovery_actions` | 见下 |
| Failure Signature | `failure_signatures` + `run_failures` | 签名是聚类锚点,失败实例挂在它下面 |
| Evidence Bundle | `evidence_bundles` | manifest 记录完整率,缺字段要能查出来 |
| —(新增) | `resource_locks` | DUT/主机独占,防并发踩踏 |
| —(新增) | `audit_log` | 谁在什么时候用哪个模板做了什么 |
## Run 为什么拆成四张表
`runs` 只存**当前投影**(状态、进度、结论)。真相在 `run_events`
```
run_events (append-only, 唯一真相)
│ projection
runs / run_steps / recovery_actions (可重建的读模型)
```
任何时刻都能靠重放 `run_events` 重建 `runs` 的状态——这是"事件溯源"落地的含义,
也是统一时间线、审计、自动复现三个功能的共同地基。
**代价**:写路径必须走 `events/recorder.py`。仓储层故意**没有**
`update_run_state()` 这种 API。想改状态?记一条事件,投影自己会跟上。
## 关键字段的设计理由
### `duts.allow_destructive` + `duts.serial`
破坏性动作(Format / Sanitize / 刷写)的三重校验:序列号匹配、
`allow_destructive=True`、设备路径不是系统盘。三个信号缺一个就拒绝执行。
误盘一次 = PoC 判定失败(方案 §9.3),所以这个字段不给 API 直接改,
只能走带审批记录的资产管理接口。
### `runs.env_fingerprint`JSON,不可变快照)
任务开始时冻结:主板 / BIOS / OS / 内核 / 驱动 / Agent 版本 / 工具版本 / DUT 固件。
A/B 对比的前提是环境相同——固件之外任何一项变了,对比结论就不成立。
签名哈希也吃这个指纹,所以"换了台机器复现不出来"能被自动识别为不同签名。
### `runs.unattended_completion` + `runs.human_touches`
这两个字段是**销售武器**,不是技术指标。UCR(无人值守完成率)和人工触碰次数
是客户签字确认 ROI 的凭据(方案 §9.3、报告 Phase 2 现场指标)。
从第一行代码就记,不要等到要卖了才补。
### `run_events.seq`(每个 run 内单调递增)
时间戳会因为主机断电、时钟漂移、带外控制器与主机时钟不同步而乱序。
`seq` 由控制平面单点分配,保证时间线可重放。带外事件与 Agent 事件
进同一条序列——双通道观测的交叉校验靠它。
### `failure_signatures.hash`8 要素)
```
hash(workflow_step, normalized_error_codes, log_templates, host_state,
dut_enumeration_state, data_integrity_state, recovery_outcome,
environment_fingerprint)
```
只用错误码会把"掉盘"和"脚本超时"归成一类,聚类就废了。
`log_templates` 是日志模板化后的结果(数字/路径/时间被替换为占位符),
不是原始日志——否则每条日志都是新签名。
### `run_failures.failure_class`
`DUT_DEFECT` / `INFRA_FAILURE` / `SCRIPT_FAILURE` / `DATA_INTEGRITY` / `UNKNOWN`
**`INFRA_FAILURE` 必须与 `DUT_DEFECT` 分开统计**(方案 §4.3)。
把网络断了、磁盘满了算成 SSD 缺陷,客户第一周就不信任这个系统了。
基础设施误报率 <5% 是 MVP 硬指标。
## 状态字段一览
| 表 | 字段 | 取值 |
|---|---|---|
| `runs` | `state` | QUEUED / PREFLIGHT / RUNNING / RECOVERING / PAUSED / FROZEN / COMPLETED / ABORTED / REJECTED |
| `runs` | `verdict` | PASS / FAIL / INCONCLUSIVE / null |
| `run_steps` | `state` | PENDING / DISPATCHED / RUNNING / SUCCEEDED / FAILED / TIMED_OUT / SKIPPED / CANCELLED |
| `test_hosts` | `status` | ONLINE / DEGRADED / OFFLINE / UNKNOWN |
| `duts` | `status` | IDLE / IN_USE / QUARANTINED / MISSING |
| `recovery_actions` | `outcome` | RECOVERED / FAILED / ESCALATED / FROZEN |
详见 [state-machine.md](state-machine.md)。