chore(repo): initialize team collaboration repository
CI / Python 3.12 (push) Waiting to run
CI / Python 3.9 (push) Waiting to run

This commit is contained in:
2026-07-27 20:40:12 +08:00
commit c91a64fddb
109 changed files with 21121 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
# 领域模型: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)。