# Ops Readiness Lab：把“我会运维”变成可审计证据

这个实验对应 Ch26–28。它只依赖 **Python 标准库**，可以在没有 GPU、Kubernetes 或遥测后端的个人电脑上运行。输入是固定的教材合成事件，输出是一份机器可读 JSON 和一份适合放进作品集附件的 Markdown。

> **证据边界：synthetic / CPU-only。** 本实验能证明你会定义指标、复算错误预算、关联发布与副本、编写安全负例并约束 claim；它不能证明真实 OTel、DCGM、GPU 或 K8s 能力。

## 一次运行

在本目录执行：

```bash
python3 ops_readiness_lab.py
python3 -m unittest -v
```

也可以把产物写到临时目录：

```bash
python3 ops_readiness_lab.py --output-dir /tmp/ops-readiness-evidence
```

默认生成：

- `artifacts/claim-evidence.json`：结构化 claim、evidence、scope 与 limitations；
- `artifacts/claim-evidence.md`：便于人工评审的证据摘要。

## 1. Composite SLI：交集，不是平均数

本实验的 eligible request 是每条 `request` 事件。单个请求只有同时满足三项才算 good：

```text
good = success AND latency_ms <= 800 AND result_valid
composite_SLI = good_requests / eligible_requests
```

这是为了让 CPU-only 教具保持通用而做的字段压缩。映射到本课程的 LLM 服务合同时，`latency_pass` 必须展开为 `TTFT_pass AND TPOT_request_pass`；`result_valid` 只代表协议/响应结构正确，不代表模型质量。模型质量与安全仍作为独立硬门，不能靠更快的低质量响应抵消。

合成数据中 8 个请求有 5 个 good，因此 composite SLI 是 `5 / 8 = 62.5%`。这个数故意很差，方便你逐条核对失败原因；它不是生产基线。

`trace` 的 linked/complete rate 单独报告，**不放进服务 SLI**。原因是 trace 采样或导出失败属于测量质量问题，不应在没有明确合同的情况下冒充用户请求失败。你仍应把 trace 缺口列为证据可信度风险。

## 2. 30d / 99.9% 的燃尽率

SLO 目标是 30 天滚动窗口 `99.9%`，所以错误预算比例为：

```text
error_budget_ratio = 1 - 0.999 = 0.001
burn_rate = observed_bad_ratio / 0.001
```

`burn_bucket` 是压缩后的加权合成请求桶，不是假装有 30 天逐请求历史。四个桶经过窗口聚合后，精确得到：

| 窗口 | bad / eligible | observed bad | burn rate |
|---|---:|---:|---:|
| 5m | 37 / 2,500 | 1.48% | 14.8x |
| 1h | 290 / 20,000 | 1.45% | 14.5x |
| 30m | 62 / 10,000 | 0.62% | 6.2x |
| 6h | 366 / 60,000 | 0.61% | 6.1x |

程序要求两个窗口同时严格越线：`1h + 5m` 都必须 `> 14.4x`，以及 `6h + 30m` 都必须 `> 6x`。合成数据刻意放在阈值之上，避免把“恰好等于”误判为触发。短窗口验证问题仍在发生，长窗口抑制瞬时噪声。阈值用于教学演算；真实告警还要结合流量下限、缺数策略、通知分级和团队响应成本。

## 3. 从 release 定位到 replica

`release`、`replica` 与 `queue` 事件共享身份字段。程序先比较各 release 的平均 queue depth，再在每个 release 内比较 replica：

```text
release-canary mean queue = 16.0
release-stable mean queue = 3.5

release-canary/canary-a mean queue = 29.0
release-canary/canary-b mean queue = 3.0
```

默认只有同时满足 `ratio >= 2` 且 `delta >= 5` 才报告 skew，避免只凭微小分母放大倍率。结果把范围从 `release-canary` 收窄到 `canary-a`；它是排障假设，不是根因证明。下一步仍需检查 admission、并发配置、依赖延迟、节点资源与实际 trace。

## 4. 安全负例，而不只是 happy path

`policy_cases.json` 包含一个允许用例和三个必须拒绝的负例：

1. 跨租户访问；
2. 未签名制品；
3. 日志中出现 `authorization` / `api_key` 等敏感字段。

本地策略采取 fail-closed：缺失签名也按未签名拒绝。单元测试验证实际 decision 与期望一致。这个函数只是一份可读的 policy-as-code 教具，不是 OPA、云 IAM、Kubernetes admission webhook 或运行时隔离边界。

## 5. Claim–Evidence 怎么写

报告中的每条 claim 都带：

- `claim`：数据真正支持的结论；
- `evidence`：可复算的计数、比例、异常或测试结果；
- `scope`：结论适用范围；
- 顶层 `limitations`：没有被本实验验证的真实系统能力。

作品集中可以说：

> 我用标准库实现了一个可重复的合成运维证据流水线，复算 composite SLI、30d/99.9% 多窗口燃尽率，定位 release/replica queue skew，并对跨租户、未签名制品与敏感日志执行负例测试。

不要说：

> 我已经验证生产集群的 OTel 链路、DCGM 指标、GPU 性能和 Kubernetes 高可用。

## 文件地图

- `ops_readiness_lab.py`：所有计算、诊断、策略与报告生成逻辑；
- `synthetic_events.jsonl`：request / trace / release / replica / queue / burn bucket；
- `policy_cases.json`：允许用例与安全负例；
- `test_ops_readiness_lab.py`：不依赖第三方库的回归测试；
- `artifacts/`：运行后生成的 claim-evidence JSON / Markdown。

## 本实验不能证明什么

- 不能证明 OpenTelemetry SDK、collector、采样、上下文传播或后端查询可靠；
- 不能证明 DCGM exporter 指标语义与标签质量；
- 不能证明任何 GPU kernel、显存、吞吐、延迟或功耗结论；
- 不能证明 Kubernetes scheduler、controller、rollout、PDB、HPA/KEDA 或故障恢复行为；
- 不能证明生产策略引擎、身份系统、网络隔离和审计存储真的拦截攻击；
- 不能替代 30 天真实流量、事故时间线、变更记录和 on-call 复盘。

把这个实验当成“分析方法与证据纪律”的起点。要升级成生产级求职证据，下一步应在经授权的测试集群中复现同一合同，并附上采集配置、原始证据、版本身份、失败注入和可重复命令。
