# 实战：复盘四类事故并完成全书结业

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

---

最后一次实验不再连接数据库。它把第 32～35 章公开证据作为不可改写的输入，验证我们
能否在不夸大结论的前提下形成跨事故控制路线，并把全书能力映射为可答辩的证据。

## 36.7.1 汇总 ch32–ch35 的证据、决策与用户影响 {#item-36-7-1}

### 实验合同

先读：

- [`requirements.json`](/labs/ch36/requirements.json)：输入、风险和验收；
- [`incident-catalog.json`](/labs/ch36/incident-catalog.json)：source pointer、影响、时间线与判断；
- [`control-backlog.json`](/labs/ch36/control-backlog.json)：十二项控制合同；
- [`capability-map.json`](/labs/ch36/capability-map.json)：ch01～ch36 结业证据；
- [`negative-cases.json`](/labs/ch36/negative-cases.json)：36 个必须拒绝的语义篡改；
- [`lab-contract.md`](/labs/ch36/lab-contract.md)：事实、行动与认证边界；
- [`topology.mmd`](/labs/ch36/topology.mmd)：离线数据流。

静态检查会创建临时输出，编译、验证后删除；它没有网络/SSH/数据库入口：

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

创建一份自己的 closure bundle：

```bash
evidence_dir="$(mktemp -d /tmp/pg36-ch36-evidence.XXXXXX)"

PG36_EVIDENCE_DIR="$evidence_dir" \
  static/labs/ch36/task.sh compile

PG36_EVIDENCE_DIR="$evidence_dir" \
  static/labs/ch36/task.sh all
```

`compile` 拒绝覆盖非空目录。`all` 只消费已有 bundle，重新验证 source hash、JSON
Pointer、控制合同、路线和 36 个 mutant。它不会执行 backlog。

### 输出结构

```text
closure-report.json
postmortem-portfolio.json
roadmap-90d.json
capability-assessment.json
input-manifest.json
source-manifest.json
validation-report.json
negative-report.json
public-summary.json
review.txt
```

四份输入分别绑定：

```text
../ch32/pitr-run.json
../ch33/failover-run.json
../ch34/overload-run.json
../ch35/rescue-run.json
```

每条 fact 保存：

```json
{
  "id": "F35-CHECKSUM",
  "source_pointer": "/physical_page/offline_bad_checksums",
  "expected": 1,
  "actual": 1,
  "matches_source": true,
  "knowledge_stage": "during-response"
}
```

编译器重新从源文件解析 `actual`。修改报告里的数字、pointer、source schema 或 hash
都会失败；事后解释也不能改写 `knowledge_stage`。

### 四份事故记录

| 记录 | 影响证据 | 决策 | 验收/边界 |
|---|---|---|---|
| ch32 误写 | fixture 1,000 victims、1,000 wrong outbox、外发 0 | exclusive PITR + audited delta | 恢复 1,000，保留 100 条合法后写，fixture loss 0 |
| ch33 主库失效 | 160 attempts、130 ack、最大 ack gap 6,211.692334 ms | fence → promote → reconcile → rejoin | ack missing 0、unknown unresolved 0；不是生产 RTO |
| ch34 资源压力 | flow 30/21 admitted/9 rejected；retained WAL 42,611,296 B | flow 与 retention 分开 route | exact fixture 清理；managed mutations 0 |
| ch35 完整性 | 1 byte、1 bad checksum、`XX001`；另一 case checksum 0 + version mismatch | trusted copy；REINDEX 后 REFRESH | checksum/amcheck/业务不变量通过，原件保留 |

`impact.kind` 只能是 `simulated` 或 `observed-sandbox`。报告中没有真实用户、生产数据或
生产影响。

### 事实与叙事分离

catalog 为每个 incident 保留：

```text
impact statement -> source fact IDs
decision route -> basis fact IDs
ordered timeline
control theme IDs
claims not made
```

这使读者可以质疑叙事而不改写证据。例如 ch33 的 observed gap 确实是
`6,211.692334 ms`，但 `claims_not_made` 明确拒绝“这就是生产 RTO”；ch35 确实翻转
一个 byte，但不声称模拟真实控制器或内存故障。

## 36.7.2 找出跨事故重复出现的控制缺口 {#item-36-7-2}

### 先找共同问题，不先宣布生产有缺陷

四次实验可以支持：

```text
these mechanisms repeatedly matter
```

不能直接支持：

```text
your production platform lacks them
```

所以七个结果都标为：

```text
status = production-assessment-required
basis  = exercise-exposed-risk-not-confirmed-production-deficiency
```

正式报告中 `production_gaps_confirmed=0`。真实采用时，要用本地 inventory、policy、
runtime、访谈和演练逐项把 status 更新为 `present/effective`、`gap`、`exception`
或 `not-applicable`。

### 七个共同主题

| 主题 | 出现章节 | 生产评估问题 |
|---|---|---|
| observation contract | 32/33/34/35 | user impact、identity、数据库与业务证据是否可关联 |
| production claim gate | 32/33/34/35 | sandbox timing/route 是否会被误当目标或批准 |
| business validation | 32/33/35 | 恢复是否超越 process/topology 到业务事实 |
| reversible exact scope | 32/33/34/35 | mutation/cleanup 是否有目标、guard、rollback |
| unknown outcome | 32/33 | timeout/ack/commit 是否能按稳定 token 对账 |
| classifier stop route | 34/35 | 缺失/冲突证据是否阻止错误动作 |
| lineage and authority | 32/33/35 | source、timeline、writer authority 是否可证明 |

出现次数不等于优先级。用 production exposure、impact、现有控制强度、验证成本和多事故
覆盖率排序。

### 主题必须双向一致

每个 incident 列出 theme IDs，每个 theme 又列 incident IDs。validator 检查双向
membership，并要求至少两个 incident 才能称 cross-incident。删除一个主题、把主题
缩成单事故或引用不存在的 incident 都会被拒绝。

### 控制不是事故类型的一一映射

同一个 target-identity gate 可以保护：

- PITR 不恢复错 cluster；
- failover 不接纳错 lineage；
- overload mitigation 不取消无关会话/slot；
- rescue 不改写 managed/unique PGDATA。

同一事故也需要多类控制：

```text
prevent   exact target + safeguard
detect    user SLI + source-bound evidence
mitigate  admission / fence / stop route
recover   restore / rejoin / reconcile
```

平台 backlog 优先寻找这类多边覆盖，但仍保留专用控制，例如 collation dependency
重建或 outbox 对账。

### 识别“控制存在但无效”

生产评估不能只问“有没有”：

```text
implemented?
deployed to intended scope?
operating now?
tested against negative case?
effective at cutting the causal edge?
evidence still valid?
exceptions complete?
```

有 backup job 但从未 restore，不算已验证 recover control；有 runbook 但 current
version 无法执行，也不算；有 safeguard 但 generic token 可绕过 target identity，
只能算弱控制。

## 36.7.3 输出 90 天改进路线、平台 backlog 与复验计划 {#item-36-7-3}

### 路线是参考 proposal，不是自动变更

十二项 action 均为：

```text
status                        proposed
production_execution_approved false
```

每项包含 stable owner role、P0/P1、due day、source themes、control type、artifact、
verification procedure、pass condition、evidence to close、failure condition 与
revalidation days。采用者要把 role、scope、date 和 approval 映射到自己的组织。

### Day 0～30：先让风险可见、危险动作可停

| Action | 控制 |
|---|---|
| A36-01 | 版本化 incident observation/evidence schema，并让缺字段 packet 失败 |
| A36-02 | destructive workflow 强制 exact target、data/traffic/authority 与 approval |
| A36-03 | 定义 request idempotency token 与 unknown-outcome reconciliation |
| A36-04 | 分开 user-impact SLI 与 PostgreSQL/host 诊断 telemetry |

这一阶段不承诺完成所有架构改造，先建立 identity、证据和 stop line。没有这些基础，
后续演练可能只是在更好地记录错误动作。

### Day 31～60：证明四条恢复能力

| Action | 控制 |
|---|---|
| A36-05 | 多 PITR candidate + legitimate delta + business manifest |
| A36-06 | fence/failover/client reconciliation/rejoin |
| A36-07 | flow/retention blind classifier + ambiguous stop |
| A36-08 | checksum/amcheck/collation review + clone-only rescue |
| A36-09 | Pigsty inventory、release、safeguard 与 dangerous playbook review |

演练用隔离环境，生产不被当作故障注入场。失败产物被保留并转 action；不能为了按期
完成把 pass condition 改成“脚本退出 0”。

### Day 61～90：把局部改进变成持续系统

| Action | 控制 |
|---|---|
| A36-10 | 用生产测量/有边界演练修订 SLO、RPO、RTO、容量与安全 ADR |
| A36-11 | 每月聚合重复 theme、过期 evidence 与 exception |
| A36-12 | blind 90-day game day + 独立 effectiveness review |

第 90 天不是项目结束。control registry 根据 `revalidation_days` 继续检查 30/60/90/180
天周期；版本、拓扑、workload 或依赖变化会提前使证据失效。

### validator 如何对抗“纸面完成”

36 个 live mutant 覆盖六组失败：

```text
source integrity
  drop incident, change fact/pointer/schema/hash

epistemic boundary
  claim production impact, rewrite knowledge stage, remove claims-not-made

cross-incident reasoning
  single-incident theme, unknown membership, missing theme

action quality
  no owner/due/verification/failure/revalidation, vague result

governance
  mark closed, auto-approve production, incomplete roadmap

graduation
  duplicate chapter coverage, auto-certify learner
```

正式结果：

```text
run_id                         91c4464b-89f7-4145-9708-f07256d747ce
input files hash-bound        4
compiler source files bound  12
live mutants rejected        36 / 36
database connections          0
SSH connections               0
external dispatch             0
production mutation           0
production_ch36_gate          pending
```

公开摘要 SHA-256：

```text
c00463cfedbd4d880d60d6af2f3401d568ef7549948f4cbd062c9b500e53117b
```

摘要见 [`closure-run.json`](/labs/ch36/closure-run.json)。raw formal bundle 不发布，
因为公开教材只需要去敏结论和可重跑 source。

## 36.7.4 回看从 SQL 到生产的能力地图 {#item-36-7-4}

### 十二个可答辩能力域

[`capability-map.json`](/labs/ch36/capability-map.json) 将 36 章恰好覆盖一次：

| 能力域 | 章节 | 读者应能交付 |
|---|---:|---|
| context/workflow | 1–2 | 精确身份、对象地图和可重跑任务 |
| model/integrity | 3–4 | 用 schema/type/constraint 编码业务不变量 |
| transaction/programming | 5–6 | 解释 MVCC、事务与服务端副作用 |
| query engineering | 7–9 | 从 plan/stats/workload 证明优化 |
| concurrency/release | 10–12 | 兼容发布、锁边界、rollback 与 contract test |
| extension workloads | 13–18 | 按语义、生命周期、风险和退出选择扩展 |
| service baseline | 19–22 | 用 Pigsty 交付 route/HA/backup/recovery |
| security/governance | 23–25 | least privilege、SLO/SOP 与 observation contract |
| capacity/maintenance | 26–28 | 可复现 envelope、调优、vacuum/freeze/bloat |
| evolution | 29–30 | migration/upgrade candidate、cutover 与 rollback |
| incident/recovery | 31–35 | blind classify、保护权威与证据、正确恢复 |
| platform learning | 36 | 将证据转成控制并独立验证效果 |

地图完整只证明教材没有漏章，不证明具体读者掌握。因此正式结果必须保持：

```text
learner_assessment.status        not-assessed
automatic_certification          false
assessment_required              true
```

### 结业不是记忆命令

对每个域，读者完成四层答辩：

```text
explain
  用自己的话说明机制、边界与反例

execute
  在授权环境完成实验并保留机器证据

diagnose
  面对隐藏场景从 evidence 选择 route，而不是背答案

design
  把一次结果转成适合本地 service 的控制、验证和复位
```

只会复制 `psql`、playbook 或恢复命令，不构成专家能力；只会讲原理、不能从 runtime
证明状态，也不构成。PostgreSQL 原生证据、Pigsty 平台状态和业务事实要互相校验。

### 建个人结业 portfolio

```text
portfolio/
  environment-and-version-contract/
  schema-and-transaction-design/
  query-and-concurrency-cases/
  release-and-service-baseline/
  backup-ha-security-observability/
  capacity-maintenance-evolution/
  incident-recovery/
  postmortem-and-control/
```

每份 evidence 标注：

```yaml
produced_by:
environment_authority:
version_and_topology:
source_hashes:
claim:
what_it_does_not_prove:
reviewer:
verified_at:
valid_until:
```

真正的结业由你所在环境的 owner/reviewer 根据证据决定，而不是本书脚本替组织签字。

### 从哪里继续

读完全书不是把 PostgreSQL 变成“学完的知识”，而是获得一套持续更新的方法：

```text
先确认身份与目标
再从原生证据理解 PostgreSQL
用 Pigsty 把能力组合成服务
用业务不变量决定是否真的正确
用隔离演练证明恢复
用复盘和平台默认值防止同类路径重演
```

下一步选择一个真实但低风险的 service，把本节 12 项参考 backlog 做本地
`present/gap/not-applicable/exception` 评估，只批准一项最小、可验证改进。完成它、
保存效果证据、安排重验，然后再进入下一项。这比一次性宣布“数据库平台建设完成”
更接近长期可靠性。

---

[上一节：将控制固化到平台](../06/) · [返回本章目录](../) · [返回全书导读](/guide/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
