# 实战：盲抽症状的桌面演练

LLMS 索引： [llms.txt](/llms.txt)

---

本节不对数据库制造故障。它先从 Pigsty `FULL/L3` 沙箱采集一份最小只读上下文，再从
八个场景中盲抽两个，把本章协议压缩进前十五分钟。这里有两个容易混淆的 “level”：

```text
Pigsty FULL/L3   监控接入层级：PG + node + pool + HA + logs
experiment L0   风险层级：read-only，在线 mutation 为零
```

参考 run 的响应由程序生成，用来证明合同和 validator 自洽；真正的人员训练必须由主持人
只发盲包、按请求提供证据卡并独立评分。

## 31.6.1 随机症状、误导性首发告警与缺失信息 {#item-31-6-1}

### 先读合同

完整边界见
[`lab-contract.md`](/labs/ch31/lab-contract.md)，环境与验收条件见
[`requirements.json`](/labs/ch31/requirements.json)，响应协议见
[`incident-contract.json`](/labs/ch31/incident-contract.json)，拓扑与路由见
[`topology.mmd`](/labs/ch31/topology.mmd)，参与者填写
[`response-template.json`](/labs/ch31/response-template.json)。

先做纯静态检查：

```bash
static/labs/ch31/task.sh lint
```

完整参考 run 需要连接已经确认的四节点开发沙箱，但在线阶段只有只读 SQL、Patroni REST
和 `pgBackRest info`：

```bash
export PG36_EVIDENCE_DIR="$(
  mktemp -d "${TMPDIR:-/tmp}/pg36-ch31.XXXXXX"
)"
export PG36_CH31_SEED=pg36-ch31-reference-v1

static/labs/ch31/task.sh all
```

也可以分步执行：

```bash
static/labs/ch31/task.sh capture
static/labs/ch31/task.sh exercise
static/labs/ch31/task.sh verify
static/labs/ch31/task.sh review
```

`capture` 显式使用 `BEGIN READ ONLY`、短 statement/lock timeout，只保存聚合会话、复制、
slot、archive、control identity 和缩减后的 HA/backup 上下文。它不读取业务行、不保存
query text 或原始日志。`exercise` 完全离线，不 pause Patroni、不 failover、不重启、不
terminate connection、不改路由、不恢复 backup。

### 八个场景让首发症状“不够用”

| 场景 | 首发误导 | 正确主路线 |
|---|---|---|
| 订单数下降、复制延迟为零 | 把同步副本误当历史副本 | PITR |
| 数据库健康、退款突然增长 | 把技术健康误当语义正确 | PITR |
| 写端点 503、primary up | 把接入故障误当 primary 故障 | HA |
| DCS timeout、节点自称 primary | 相信单节点自报角色 | HA |
| connection timeout、CPU 43% | 只看 CPU，忽略连接槽和 pool | OVERLOAD |
| 满盘且 replica lag | 把 lag 当根因，想手删 WAL | OVERLOAD |
| checksum mismatch、lag 为零 | 把同步状态当完整性证明 | INTEGRITY |
| seq/index 结果不同 | 把 `REFRESH VERSION` 当重建 | INTEGRITY |

每个 blind packet 只包含：

- initial signal 与已报告用户影响；
- 可以请求的证据卡 ID、问题、层次和时间成本；
- 十五分钟 deadline 与作答规则。

它不会包含 hidden truth、严重度答案、route、required card、safe/dangerous action 或
证据 observation。`facilitator-pack.json` 才保存这些内容。场景源文件本身是公开教材，
所以这种隔离是教学流程而非密码学保密；正式考核应由主持人控制文件访问或使用私有
派生场景。

### “没有证据”也要进入记录

参与者请求一张暂时不可得的证据卡时，主持人应回答：

```text
unavailable / permission denied / collector down / retention expired
```

而不是替换成“正常”。参与者要决定是换独立观察面、升级权限 owner、缩小动作，还是
因为关键事实缺失而保持 stop line。事故能力的一部分就是在证据不完整时拒绝不安全的
确定性。

## 31.6.2 分别按单人和团队模式完成前十五分钟 {#item-31-6-2}

### 主持方式

1. 主持人运行参考工具并单独保管 evidence directory；
2. 只把一个 blind packet 与空白 response template 发给参与者；
3. 参与者先声明五轴影响和当前 severity；
4. 参与者按 ID 请求证据卡，主持人从 facilitator pack 逐张返回 observation；
5. 每个有副作用的建议都要求 risk、owner、expected、stop、rollback；
6. 第 15 分钟停止，参与者发布状态更新并完成 handoff；
7. 最后才揭示 hidden truth、required cards、safe/dangerous actions。

参考 run 固定 seed 抽到：

```text
solo  integrity-collation-index  -> INTEGRITY
team  data-accidental-delete     -> PITR
```

随机 seed 可改变题目，但 runner 会保证两题属于不同路线。不要重复抽到熟题就假装完成
盲测；应记录 seed、场景使用历史和参与者是否见过答案。

### solo 与 team 使用同一张答卷

solo 模式四个 role 都由 `solo-oncall` 承担，但按时间串行切换；team 模式要求 IC、
operator、scribe、business liaison 是四个不同 actor。两者都必须做到：

```text
required evidence complete minute < route decision minute <= 15
all actions belong to declared safe action set
dangerous_actions_executed = []
decision log starts at minute 0 and ends at minute 15
at least one stakeholder update before or at minute 15
production_authorized = false
```

团队可以让多个 R0 track 并行，但仍只有一个 operator token；单人不能用“我自己复核过”
冒充独立 R2/R3 review。

### 一份可复用评分表

| 项目 | 分值 | 失分例 |
|---|---:|---|
| 五轴影响与 severity | 15 | 把 unknown 写成无影响 |
| 现场和恢复能力保护 | 20 | 未围住 writer；建议删除 WAL |
| 跨层证据选择 | 20 | 只看一张 dashboard |
| 技术 route 与目标 | 15 | severity 直接决定 failover |
| 决策日志与 stop line | 15 | 动作无预期、回退和结果 |
| 角色、升级与沟通 | 10 | 多人同时改；不报 unknown |
| 机密与生产边界 | 5 | 粘贴凭据；宣称已获生产授权 |

发生以下任一项应直接判定需要重练，不用总分掩盖：

- 在证明 writer 唯一前 promote；
- 删除现役 `pg_wal`；
- 在原始证据上执行覆盖式修复；
- 未经业务 owner 直接覆盖事后合法写入；
- 把 facilitator 未提供的信息自行当成事实。

程序生成的 `responses.json` 只是一份 schema-complete reference，不是答题者成绩。真人
评分要保存自己的 response、主持人发卡时间和讨论录音/记录权限，并由未参与执行的人
复核。

## 31.6.3 在 Pigsty L3 输出时间线、决策日志、证据包与路由选择 {#item-31-6-3}

### 正式参考现场

正式 run 在 `pg-test` 捕获：

```text
PostgreSQL version              18.6
system identifier              bound to pgBackRest stanza identity
timeline                       11
Patroni                         1 running primary + 2 running replicas
physical replication streams   2, max sent/replay gap 0 bytes
pgBackRest status / backups     0 / 6
SQL transaction                 READ ONLY
raw query / raw log             absent / absent
online mutation                 none
```

现场的 `pg_stat_archiver.failed_count` 为 21，但 last failure 在
`2026-07-29T18:57:58Z`，last archived success 在
`2026-07-30T01:36:16Z`。这正说明累计失败数不能直接解释成“当前归档故障”。本章不因
看到 21 就 reset 统计或修改 archive；它保留 reset 与时间，交给真实趋势和 backup
证据解释。

“repo 中有 6 份 backup”也不等于恢复通过。本次没有执行 restore，公开结论只写
`pgbackrest_status=0` 和 backup count；第 21、32 章的恢复证据才回答可恢复性。

### 私有证据与公开摘要分层

证据目录包含：

```text
preflight-evidence.json
blind-packets.json
facilitator-pack.json
responses.json
exercise-evidence.json
negative-report.json
validation-report.json
public-summary.json
review.txt
```

目录权限为 `0700`、文件为 `0600`。review 拒绝 credential URI、SCRAM verifier、
private key、clear password、raw SQL/log field，并检查 preflight、盲包、答案、
exercise 与 public summary 属于同一 run。

公开参考摘要见
[`incident-run.json`](/labs/ch31/incident-run.json)。它只保留环境轮廓、路线、安全
边界与验收计数，不公开 facilitator 答案和 live 细节。

### 反例验证防止“格式漂亮的伪响应”

正式 validator 要求：

```text
31 declared counterexamples rejected
18 live evidence mutants rejected
12 source files hash-bound
```

它会拒绝：

- severity 被允许直接选择 route；
- blind packet 泄露 hidden truth 或 expected route；
- required evidence 未齐就决策；
- solo/team role 语义不成立；
- action 属于 dangerous set 或晚于 minute 15；
- decision log 缺 expected/stop/rollback；
- live capture 不是 READ ONLY、cluster/timeline/topology 不匹配；
- backup system identifier 不同；
- source/upstream/evidence hash 被替换；
- 任何 production gate 被打开。

对同一份私有证据可以重复：

```bash
static/labs/ch31/task.sh verify
static/labs/ch31/task.sh review
```

但修改实验源文件、盲包或 response 后，不能继续复用旧 exercise hash；应开启新 run，
保留旧包作为历史。

### 本章交付物不是根因报告

合格的第 31 章 handoff 应包括：

```text
severity and five-axis basis
current user/data/recovery impact
authoritative or still-unknown writer/timeline
active fences and automation state
evidence manifest and decision timeline
chosen route and alternatives rejected
first safe action / stop line / owner
next update and escalation requests
```

参考 run 最终结论是：

```text
read-only-context-and-tabletop-protocol-demonstrated
human_competency_claimed = false
production_ch31_gate = pending
```

下一章从第一条路线开始：面对已经提交的误删误改，怎样选准恢复目标、在隔离实例完成
PITR，并把历史正确状态与事后合法写入重新合并。

---

[上一节：单人值守与团队响应](../05/) · [返回本章目录](../) · [下一章：PITR 与误操作恢复——妙手回春](/pitr/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
