# Cybernetic Systems Engineering

> 用“系统工程 + 工程控制论 + 总体设计（GDA）”的方法做软件工程闭环控制。 适用：真实代码库中的 bugfix、feature、refactor、性能、迁移、事故复盘、测试设计、架构审计、门禁验证。 尤其适合：问题复杂、跨模块、需要最小可验证变更、需要离线/在线双层验证、需要防止“测试全绿但真实环境失败”的任务。 不适用：纯知识问答、翻译、创作、一次性聊天建议、无需验证的单句结论。

- Skill: `misonl/cybernetic-systems-engineering` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add misonl/cybernetic-systems-engineering`
- Raw SKILL.md: https://api.skillmd.com/api/skills/misonl/cybernetic-systems-engineering/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: misonl (https://skillmd.com/u/misonl)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/misonl/cybernetic-systems-engineering

---


# Cybernetic Systems Engineering（CSE）

把软件开发当作一个**闭环控制系统**来做：

- **被控对象（Plant）**：代码库 + 运行时环境 + 依赖 + 数据 + 测试系统
- **控制器（Controller）**：你（Agent）+ 你的计划、策略、节奏控制
- **传感器（Sensors）**：测试、构建日志、运行日志、指标、复现脚本、审计文档
- **执行器（Actuators）**：代码修改、配置变更、依赖升级、回滚、文档更新、测试补强
- **参考输入（Reference）**：需求、issue、验收标准、SLO/SLA、业务边界
- **输出（Output）**：实际行为（通过/失败测试、运行结果、性能数据、门禁结果）
- **误差（Error）**：参考输入与输出之间的差距
- **扰动（Disturbance）**：环境差异、并发、flake、脏状态、真实 schema 漂移
- **时滞（Delay）**：慢测试、CI 排队、真实环境依赖、发布窗口

本 skill 的目标不是“让你会用控制论术语”，而是让你在复杂工程任务中：

1. 先建立正确的观测与误差定义  
2. 再用最小控制输入减少误差  
3. 用分层验证防止振荡与假收敛  
4. 用总体设计视角控制复杂性

## 项目级控制拓扑

CSE 不只处理“当前这一条任务怎么修”，还要先回答“这个项目由谁控制、在哪一层控制、跨模块如何协调”。

从控制层级看，CSE 默认同时存在两套闭环：

- **任务级闭环**
  - 面向单个 issue、单次 patch、单轮验证
  - 关注最小控制输入、最小 failing case、分层验证
- **项目级控制拓扑**
  - 面向多模块、多团队、多阶段演化
  - 关注总体设计部、控制结构、跨模块协调、边界冻结与升级路径

如果只建立任务级闭环，而没有项目级控制拓扑，常见结果是：

- 单个 patch 看起来正确，但把复杂性偷偷转移到别的模块
- 局部验证通过，但共享接口、共享状态或共享基础设施被无意破坏
- 每个人都在改“自己眼前那一层”，但没有人对整体误差负责

因此在以下场景，必须先补项目级控制拓扑，再进入具体修复：

- 改动跨 2 个及以上模块、服务或语言边界
- 需要同时改代码、配置、schema、运行流程中的两类以上对象
- 任务会影响共享接口、共享状态、共享基础设施或统一门禁

项目级控制拓扑至少要回答四个问题：

1. **总体设计部在哪里**
   - 谁负责维护项目级参考输入、关键边界和最终裁决
2. **控制结构是什么**
   - 本次问题主要落在哪些层，哪些层只能观测，哪些层允许施加控制输入
3. **跨模块协调怎么发生**
   - 哪些模块存在强耦合，改动会沿什么路径外溢，谁需要被显式通知或升级
4. **哪些边界先冻结**
   - 哪些接口、schema、门禁口径在本轮不能被顺手改写

### 控制面 / 数据面 / 状态面

为了避免“看起来只是改一行代码，实际上改穿了整个系统”，复杂任务开始前必须先识别本次改动主要落在哪一面：

- **控制面**
  - 负责决定系统如何调节自己
  - 典型对象：限流、重试、熔断、路由、灰度、回滚、门禁、调度策略
- **数据面**
  - 负责承载真实业务流量和核心处理路径
  - 典型对象：请求处理、任务执行、核心计算、主链调用、用户可见结果
- **状态面**
  - 负责保存共享事实、恢复锚点与跨节点一致性
  - 典型对象：数据库、schema、缓存、队列、事件日志、检查点、幂等键

默认要求：

1. 先标出本次改动的**主落点**在哪一面
2. 再标出会被连带影响的次级面
3. 如果一次改动同时触碰两面以上，必须显式写出复杂性是如何转移的

一个典型例子：

- 把重试、限流从业务代码下沉到 mesh 或统一网关
  - 不是“复杂性消失了”
  - 而是复杂性从数据面转移到了控制面
- 把会话、任务进度或幂等信息从应用内存迁到 Redis / 数据库
  - 不是“状态更简单了”
  - 而是状态复杂性从节点内部转移到了状态面

如果主落点都判断不清，默认先不要改实现，而是先补控制结构说明。

### 复杂性转移账本

复杂性不会凭空消失，只会被下沉、上浮或转移到别处。

因此每次声称“系统更简单了”时，都应至少记一条复杂性转移账本：

| 字段 | 说明 |
| --- | --- |
| 复杂性原位置 | 复杂性原来压在哪一层、哪个模块、哪条链路 |
| 新位置 | 复杂性被转移到了哪里 |
| 收益 | 本次转移换来了什么 |
| 新成本 | 新增了什么依赖、运维成本或观测成本 |
| 失效模式 | 转移后最可能新增什么故障模式 |

典型例子：

- 把重试、限流、路由从应用代码下沉到 mesh
  - 复杂性原位置：数据面应用逻辑
  - 新位置：控制面基础设施
  - 收益：业务代码更薄、统一治理更强
  - 新成本：调试链变长、配置漂移风险上升
  - 失效模式：控制面误配导致全局放大
- 把会话、幂等键或任务恢复点外包到 Redis / 数据库
  - 复杂性原位置：节点内内存与本地状态
  - 新位置：状态面共享存储
  - 收益：重启恢复更稳定、横向扩展更容易
  - 新成本：一致性、超时、容量与运维复杂度上升
  - 失效模式：状态面抖动放大为全局故障
- 把同步调用改成异步补偿
  - 复杂性原位置：同步链路上的时延与阻塞
  - 新位置：队列、重试、补偿和对账流程
  - 收益：主链解耦、峰值承压更强
  - 新成本：最终一致性与对账成本上升
  - 失效模式：补偿堆积、重复消费、长尾未收敛

项目级控制拓扑的默认治理协议如下：

### 最小 owner matrix

| 角色 | 默认职责 | 有权决定什么 | 无权单独决定什么 |
| --- | --- | --- | --- |
| 总体设计部 | 维护项目级参考输入、关键边界、升级路径与最终裁决 | 跨模块优先级、冻结边界、变更窗口、最终 gate 口径 | 直接跳过模块 owner 的局部约束与证据 |
| 模块 owner | 维护本模块不变量、主链入口与回归边界 | 模块内部实现、局部回归、局部重构 | 擅自改共享接口、共享状态、共享门禁 |
| 共享边界 owner | 维护共享 API、schema、队列、缓存、统一门禁等共享事实源 | 共享契约演化节奏、兼容窗口、迁移前置条件 | 在未通知受影响模块时直接改共享契约 |

### 默认升级路径

按风险从低到高，默认这样升级：

1. **模块内局部改动**
   - 模块 owner 可在本模块边界内完成分析、修改与验证
2. **跨模块但不改共享契约**
   - 必须显式通知受影响模块 owner，并记录外溢路径
3. **触碰共享接口、共享状态、统一门禁**
   - 必须升级到总体设计部裁决，再进入实现
4. **触碰冻结边界或发布窗口**
   - 默认停止当前 patch，先拿到明确批准

### 接口冻结条件

以下任一对象在本轮默认视为冻结边界，不能顺手改写：

- 共享 API 输入输出结构
- 数据库 schema 与持久化字段语义
- 队列、缓存、事件格式等共享状态契约
- 统一门禁口径、核心指标口径、发布与回滚流程

要解冻这些边界，至少要同时满足：

1. 有明确变更理由，而不是“顺便改一下更优雅”
2. 有受影响模块清单与兼容路径
3. 有总体设计部或对应共享边界 owner 的显式裁决

### 跨模块裁决规则

凡是跨模块变更，最终裁决责任默认不属于“谁先改代码”，而属于总体设计部。

它至少要回答：

- 为什么这次改动值得跨模块扩散
- 哪些模块只需要被通知，哪些模块需要同步修改
- 哪些边界继续冻结，哪些边界被批准打开
- 如果跨模块协调失败，当前 patch 应该收缩到哪里

如果这些问题答不出来，默认结论不是“继续改”，而是：

- 先补控制拓扑
- 先画清边界
- 先确认谁对整体误差负责

后续章节中的 Control Contract、GDA 四步法、传感器工程与验证分层，都是建立在这层项目级控制拓扑之上执行的。

## 0. 何时触发

以下任一场景，优先使用本 skill：

- 需要修改代码并验证结果
- 任务跨多个模块/服务/语言边界
- 需要从 bugfix 推进到测试补强、门禁、handoff
- 用户要求做“严格 review”“系统性复盘”“架构与测试一起收口”
- 出现“离线通过，真实环境失败”“测试通过，业务不闭环”“修一个坏两个”的迹象

如果任务时间跨度长、步骤多、存在中断恢复需求，应**同时配合 `harness`** 使用。

## 1. 五维心智模型（执行时要内化）

执行任务时必须同时考虑以下五个维度：

1. **第一性原理**
   - 找系统不变量、硬约束、物理边界
   - 不先问“用什么框架”，先问“系统真正不能妥协的是什么”

2. **公理化思维**
   - 契约先于实现
   - 明确哪些接口、状态转换、schema、事件语义是不可破坏的公理

3. **多模型思维**
   - 至少用 3 个视角看问题：
     - 数据流
     - 状态机
     - 时序 / 并发 / 排队

4. **类比迁移**
   - 遇到拥堵、震荡、雪崩、阻塞时，主动寻找物理同构：
     - 队列 / 水库 / 缓冲
     - 熔断 / 断路器
     - PID / 弹性控制

5. **反馈与验证**
   - 没有可观测闭环的设计，不算完成
   - 特别注意：
     - 时滞
     - 非线性
     - 假阳性测试
     - 真实环境与离线环境的分层差异

详细方法论与例子见：

- `references/gda-framework.md`

## 2. 启动动作：先写 Control Contract

在真正改代码前，先产出一个极短的控制合同 v2（可在回复、计划或审计文档里）：

- **Primary Setpoint**
  - 本轮最主要的目标变量，必须是一句能判断成败的话
- **Acceptance**
  - 哪些测试、命令、日志或指标能证明主目标已达成
- **Guardrail Metrics**
  - 哪些护栏指标不能被顺手打坏，例如错误率、尾延迟、成本、吞吐
- **Sampling Plan**
  - 用什么频率、在哪些观察点采样，避免只看一次结果就下结论
- **Known Delays / Delay Budget**
  - 已知时滞在哪里，以及本轮允许消耗多少时滞预算，例如 CI 排队、异步队列、缓存刷新、灰度传播
- **Recovery Target**
  - 如果本轮控制失败，允许多快恢复到安全状态，例如 MTTR 预算或回滚时限
- **Rollback Trigger**
  - 一旦出现什么信号，默认停止推进并回滚，而不是继续硬顶
- **Constraints**
  - 不能破坏什么硬约束、不变量、合规边界或真实环境前提
- **Boundary**
  - 本次允许触碰的模块、文件、配置、schema 与运行流程范围
- **Coupling Notes**
  - 这次改动会和哪些模块、共享接口、共享状态发生耦合
- **Approximation Validity**
  - 本轮采用的近似、stub 或离线验证在哪些条件下才成立
- **Actuator Budget**
  - 本轮允许施加多少控制输入，例如允许改代码、配置、观测点中的哪几类
- **Risks**
  - 1~3 个主要风险与缓解方式

如果用户没给验收标准，先从：

- issue
- 失败日志
- 现有测试
- 文档契约

中提炼；仍缺失时，补最小合理验收。

## 3. GDA 四步执行骨架

### Step 1：Axiom & Boundary

开始前必须回答：

- 系统真正目标是什么
- 不能违反的硬约束是什么
- 现有实现的关键不变量是什么
- 物理/环境边界在哪里（网络、磁盘、数据库 schema、构建环境）

### Step 2：Multi-model Construction

至少同时建立以下三个模型中的两个，复杂任务必须三个都建：

- **静态契约域**
  - API / schema / 事件格式 / 配置项
- **动态状态域**
  - 状态机 / 生命周期 / 回调矩阵 / 状态收口
- **容量与排队域**
  - 队列、缓冲、吞吐、时滞、阻塞点

复杂任务还应显式补一个**黑盒输入-输出影响矩阵**：

- 把系统先当成黑盒，不急着解释内部实现
- 先列：
  - 当前准备调哪个 **control input / knob**
  - 希望影响哪个 **output**
  - 影响方向是增、减、延后还是收敛更快
  - 会不会外溢到相邻模块、共享状态或共享基础设施

如果系统是多变量耦合的，再补一个**解耦矩阵**：

- 哪些输入主要影响哪个输出
- 哪些输入会顺带打坏别的输出
- 哪些输入必须成组调整，不能单独动

一个典型例子：

- 调高重试次数
  - 目标 output：短期成功率可能上升
  - 连带 output：尾延迟、下游 QPS、队列积压、成本可能一起上升
- 调低限流阈值
  - 目标 output：下游压力下降
  - 连带 output：入口拒绝率、任务完成时间可能恶化

默认规则：

1. 复杂任务在改实现前，先列控制输入、目标输出、影响方向与外溢风险
2. 如果一个 knob 同时强影响多个 output，默认把它视为高耦合输入
3. 高耦合输入优先做小步试探，而不是一次拉满

### Step 3：Cybernetic Control

一次只施加一个最小控制输入：

- 一个最强假设
- 一个最小修改
- 一组最便宜的验证

如果出现振荡：

- 降低步长
- 回到最小 failing case
- 加观测点，而不是继续盲改

### Step 4：Closed-loop Verification

验证必须分层：

- **L0 快回路**
  - lint / typecheck / 单测子集 / 静态审计
- **L1 中回路**
  - 相关模块测试 / 小集成
- **L2 慢回路**
  - 全量回归 / 真实环境 / 性能 / gate

原则：

- L0/L1 不稳定，不进入 L2
- 离线通过不等于真实环境通过
- 必须显式标注哪些风险只在 L2 才能验证

## 4. 传感器工程（Harness Engineering）

### 4.1 基线建立

默认顺序：

1. `git status` / `git diff`
2. 读取 issue、相关代码、最近改动、已有 review
3. 跑最便宜的验证路径
4. 记录失败命令、失败用例、关键信号

### 4.2 传感器去噪

如果信号不稳定：

- 重跑 3~5 次
- 固定随机种子 / 时区 / 并发
- 隔离外部依赖
- 把偶现变成最小稳定复现

### 4.3 特别规则：schema-sensitive 路径

凡是涉及以下任一因素：

- 真实数据库列类型
- SQL cast
- 驱动参数序列化
- `PG_CH` / 真实 broker / 真实文件系统 / 真实扩展加载

都必须明确区分：

1. **语义测试**
   - fake fetcher / stub / resolver 白盒
2. **schema 契约测试**
   - 锁定关键 SQL / schema / 分支行为
3. **真实环境 gate**
   - Windows / VPN / 真实数据库 / 真实 broker

禁止把：

- “resolver 语义通过”
- “cargo test 全绿”

直接写成：

- “真实环境通过”

### 4.4 动态控制病：采样与观测新鲜度

性能和稳定性问题默认先审查观测质量，而不是先改实现。

必须显式检查：

- **采样周期**
  - 采样过慢会把瞬时尖峰、短时雪崩、短时队列积压平均掉
  - 采样过快但没有聚合窗口，会把瞬时噪声误判成系统趋势
- **观测新鲜度**
  - 延迟到达的 metrics、异步刷新的 trace、缓存后的 dashboard，可能让你基于旧世界做新决策
  - 任何观测结果都要先确认时间戳、刷新周期和传播时滞
- **采样别名**
  - 用粗粒度采样看周期性抖动时，容易把真实震荡看成稳定
  - 典型后果是把“周期性过载”误判成“偶发 flake”
- **陈旧指标**
  - 指标本身还在更新，但语义已经落后于当前发布版本、schema 或流量路径
  - 典型后果是优化了旧瓶颈，却把新主链打坏
- **观测盲区**
  - 只看入口成功率，不看下游队列、缓存击穿、回放链路，会把局部成功误判成整体稳定

默认规则：

1. 遇到性能或稳定性问题，先写清本轮采样周期、观测新鲜度和主要盲区
2. 任何“趋势判断”都必须说明观测窗口，而不是只引用单次结果
3. 如果怀疑存在采样别名或陈旧指标，先补观测点或换采样方式，再决定是否改代码

### 4.5 动态控制病：去抖、滞回、退避与冷却

很多系统不是“控制能力不足”，而是“控制动作太频繁”。

默认要检查四种抑振手段：

- **告警去抖**
  - 当同类告警在短时间内反复触发时启用
  - 目的不是隐藏故障，而是避免把瞬时尖峰误当成稳定故障模式
- **滞回区间**
  - 当扩缩容、限流、熔断或降级阈值存在边缘来回抖动时启用
  - 进入阈值和退出阈值不应完全相同，否则系统会反复横跳
- **退避策略**
  - 当重试、探测、轮询、恢复动作连续失败时启用
  - 失败后必须扩大间隔，而不是用固定频率继续打系统
- **控制冷却时间**
  - 当一次控制动作刚施加、系统尚未完成传播和收敛时启用
  - 在冷却窗口内默认禁止同类控制动作再次触发

执行规则：

1. 只要控制动作会修改阈值、流量、路由、重试或容量，就必须声明是否存在滞回和冷却窗口
2. 只要恢复动作依赖轮询、重试或探测，就必须声明退避策略
3. 默认禁止连续重复同类控制动作不带冷却窗口
4. 如果没有去抖或滞回设计，任何“阈值附近反复跳变”都应先视为控制病，而不是先怪业务逻辑

### 4.6 动态控制病：anti-chatter、anti-windup 与控制器冲突

当系统已经进入震荡区，继续叠加控制器通常只会把问题放大。

- **anti-chatter**
  - 指防止控制动作在相邻状态之间高速来回切换
  - 典型场景：熔断开关在半开与关闭之间反复横跳，或扩缩容在相邻副本数之间频繁切换
- **anti-windup**
  - 指防止控制器在执行器已经饱和时，仍然继续累积“应该再加一把力”的内部误差
  - 典型场景：下游已经限流或队列已经打满，但上游重试、补偿或扩容信号仍不断叠加，最终形成重试风暴或扩缩容超调
- **控制器冲突**
  - 指两个及以上控制器同时修改同一 knob，却没有统一仲裁
  - 典型场景：应用内重试、sidecar 重试、网关重试同时打开；HPA、队列消费调度器、人工扩容同时改副本数

默认规则：

1. 同一 knob 只能有一个主控制器，其他控制器要么只观测，要么通过明确仲裁接入
2. 只要执行器已经饱和，就必须显式考虑 anti-windup，而不是继续累积恢复动作
3. 只要系统出现高频开关、周期性回摆或阈值附近来回跳变，就必须先排查 anti-chatter
4. 遇到重试风暴、补偿堆积、扩缩容超调，默认先查控制器冲突，再查业务逻辑

### 4.7 无观测，不优化

任何性能或稳定性优化，默认都要先拿到观测基线。

最小入场券：

- **trace**
  - 先看跨服务链路到底卡在哪一跳
- **flame graph**
  - 先看 CPU / wall time 真正烧在什么调用栈
- **profiling baseline**
  - 先记录修改前的基线，不要只拿修改后的单次结果自嗨
- **golden signals**
  - 至少关注延迟、流量、错误、饱和度这类核心信号
- **对照实验**
  - 能做 A/B、shadow、canary 或前后对照时，优先做对照，而不是纯猜测

默认规则：

1. 无观测，不优化
2. 观测不足时，默认先补观测点、profiling 或链路追踪，再决定是否改代码
3. 任何“感觉这里慢”“猜这里有瓶颈”的说法，都不能直接升级成优化动作
4. 优化结果至少要和修改前的 profiling baseline 做一次对照

## 5. 决策准则

当多个方案都能修时，优先：

1. **最小风险**
2. **最强可验证**
3. **最可逆**
4. **最符合模块业务区位**

特别注意：

- 不为了通过测试而偏离原始语义
- 不为了抽象而扩大不该公开的 API 面
- 不把测试便利性凌驾于模块职责之上

### 5.1 机制优于策略

默认优先设计“生成策略的机制”，而不是把人的经验直接硬编码成静态策略。

默认禁止把以下对象直接写死成“经验常数”后就当作稳定设计：

- timeout
- retry 次数
- 熔断阈值
- 连接池大小
- 扩缩容阈值

优先选择的机制包括但不限于：

- **自适应控制**
  - 根据延迟、错误率、队列长度、资源利用率动态调整控制输入
- **反馈回路**
  - 让上一次控制结果影响下一次控制强度，而不是重复拍脑袋
- **搜索或在线学习**
  - 当最优点未知且环境持续漂移时，用搜索、探索或在线更新替代静态猜测

裁决规则：

1. 能用机制吸收环境变化时，默认不要把人的经验写成永久阈值
2. 静态策略只能作为启动值、护栏值或临时保守值，不能伪装成长期真理
3. 如果一个策略需要频繁人工调参，优先怀疑“缺机制”，而不是继续加参数

例外条件：

- 环境几乎不变、观测明确且失效成本极高时，可以短期采用静态策略
- 但必须同时写清监控条件、失效信号与后续替换计划

### 5.2 MTTR-first 与 crash-only

对现代复杂系统，默认优先级不是“尽量永不出错”，而是“出错后多快回到安全状态”。

默认裁决：

- **MTTR 优先于 MTBF**
  - 当两种方案不能同时兼得时，优先选择更快恢复而不是更长时间不出错
- **crash-only**
  - 遇到不可恢复、未定义或无法证明安全的状态，优先显式失败、退出或重启，而不是维持僵尸状态
- **自动回滚**
  - 只要风险可外溢到共享接口、共享状态或核心链路，就要优先设计自动回滚信号
- **故障注入**
  - 不能只验证“正常时能跑”，还要验证“坏了能多快恢复”

执行规则：

1. Control Contract 里的 `Recovery Target` 不是装饰项，必须给出恢复时间预算或安全回退时限
2. 只要系统进入不可恢复状态，默认先显式失败，而不是静默维持
3. 只要回滚条件可被机器识别，就优先设计自动回滚，而不是依赖人工盯盘
4. 任何声称“高可用”的路径，都应至少经过一次故障注入或等价恢复演练

特别注意：

- crash-only 不是吞错后假装恢复，而是让失败可见、可重启、可回退
- 快速恢复不等于快速掩盖，必须保留故障证据、恢复路径和恢复时间

### 5.3 抽象审查协议

抽象的默认目标不是“减少重复”，而是“减少错误耦合”。

默认原则：

- **允许 WET**
  - 如果两段逻辑当前相似，但未来不保证一起变化，允许先物理重复
- **优先物理解耦**
  - 宁可保留两份小实现，也不要为了复用把两个生命周期不同的模块绑死
- **按共变关系做抽象**
  - 决定是否抽象的依据，不是代码长得像，而是未来是否真的会同时变化

判定规则：

1. 只要两个调用点的发布节奏、故障域或 owner 不同，默认先不要抽象
2. 只要抽象会扩大共享 API 面、共享状态面或统一门禁面，先怀疑这是错误抽象
3. 代码相似但业务语义、失败模式或演化方向不同，不应因为“长得一样”就抽象
4. 在决定抽象前，至少回答一次：它们未来真的会同时变化吗

反过来说：

- DRY 不是被废除，而是要服从模块职责、故障隔离和长期演化
- 如果抽象让系统更难切分、更难回滚、更难定位责任，就不是好抽象

### 5.4 演进式架构与可逆决策

复杂系统默认不是被一次性设计出来的，而是从简单可用系统逐步长出来的。

默认原则：

- **先长出简单可用系统，再逐步演化**
  - 没有真实反馈前，不要预支未来 5 年的复杂性
- **two-way door 决策优先快试**
  - 可逆决策优先小步试、快反馈、保留回退路径
- **one-way door 决策优先控边界**
  - 不可逆决策必须先冻结契约、清点依赖、确认迁移窗口

执行规则：

1. 每个重要架构决策都应先判断它是 **two-way door** 还是 **one-way door**
2. two-way door 决策优先用小范围实验、最小实现、短反馈回路验证
3. one-way door 决策必须显式写出桥接期、回退条件和受影响模块
4. 契约默认先稳后扩，不要在桥接期一边迁移一边改口径

桥接期协议：

- 迁移默认存在一个**桥接期**
- 桥接期内优先使用：
  - **shadow**
    - 新链路跟跑、不接管主裁决
  - **canary**
    - 小流量、小范围、可快速回退
- 桥接期结束前，默认保留旧事实源或旧主链作为对照基线

如果一个方案：

- 无法定义桥接期
- 无法解释怎么回退
- 无法说明契约何时冻结

那它默认不是成熟的演进式架构方案

## 6. 高风险反模式（必须主动检查）

1. **假收敛**
   - 单测通过，但真实环境条件未覆盖

2. **双真相**
   - 文档一套、主链一套、备用路径一套

3. **影子实现**
   - callback_dispatcher 更完整，但主链不用
   - helper 存在，但主链不可达

4. **弱断言**
   - 只有 `is_ok()`，没有行为语义断言

5. **测试驱动代码偏离职责**
   - 为了测试方便扩大 `pub` 面
   - 暴露本不该公开的内部实现

6. **把离线测试当 gate**
   - 真实 schema / 真实扩展 / 真实网络问题无法由 stub 替代

## 7. 交付格式

最终交付优先按下面结构组织：

1. **Summary**
2. **State Estimate / Root Cause**
3. **Changes**
4. **Verification**
5. **Recovery Evidence**
6. **Observability Evidence**
7. **Residual Risks / Gate Boundary**

其中：

- **Recovery Evidence**
  - 说明怎么恢复、多久恢复、触发了什么回滚或重启语义、恢复预算是否满足
- **Observability Evidence**
  - 说明依据什么判断问题存在、优化有效或风险仍在
  - 至少给出本轮关键日志、指标、trace、profiling 或 gate 证据中的一类

如果是长任务，还应同步：

- 审计文档
- 回归矩阵
- handoff 文档

## 8. 实战剧本

### Bugfix / 回归

1. 最小复现
2. 最小 failing test
3. 根因假设
4. 最小修复
5. 相关回归
6. 全量相关回归

### 测试补强

1. 审计当前覆盖层次
2. 找“语义层 / schema 层 / 真实环境层”缺口
3. 先补最能拦截真实风险的离线测试
4. 再补回归矩阵
5. 最后明确 gate 边界

### 架构收口 / 清理

1. 先证明主链实际入口
2. 再证明影子实现是否仍被使用
3. 删除或收敛重复事实源
4. 用测试或调用链审计防止回归

### 性能退化

1. 先拿 profiling baseline 与 golden signals
2. 再定位是 CPU、IO、锁竞争、网络还是排队
3. 画输入-输出影响矩阵，避免错改高耦合 knob
4. 小步优化并做前后对照
5. 记录收益、代价与残余风险

### 异步队列背压

1. 先确认队列长度、消费速率、重试率、死信情况
2. 再区分是数据面过载、状态面卡死还是控制面误配
3. 检查 anti-windup、退避与扩容是否互相打架
4. 先止血，再恢复，再补治理
5. 明确消息堆积的恢复边界

### 迁移 cutover

1. 先定义桥接期与冻结边界
2. 再安排 shadow、canary 或双写对照
3. 明确切流条件、回退条件、终止旧链路条件
4. 分层验证 cutover 前、中、后状态
5. 最后关闭桥接并归档证据

### 部分故障 / 依赖 brownout

1. 先确认故障是全挂还是 brownout
2. 再查重试、熔断、降级是否放大故障
3. 识别依赖是否已进入不可恢复状态
4. 优先保主链和恢复预算
5. 记录恢复动作和隔离边界

### 配置回滚

1. 先确认问题是否由配置变更触发
2. 再识别配置属于控制面、数据面还是状态面
3. 检查是否满足自动回滚触发条件
4. 回滚后验证关键护栏指标是否恢复
5. 补配置审计与冻结规则

### Flake Triage

1. 先稳定复现，确认是否真 flake
2. 固定随机种子、时区、并发与外部依赖
3. 区分测试抖动、环境抖动、时序抖动、观测误判
4. 用最小观测点把偶发现象变成稳定信号
5. 再决定是修实现、修测试还是修环境

### 成本失控

1. 先确认成本是流量驱动、重试驱动还是闲置浪费
2. 再看哪个 control input 把成本推高
3. 检查是否存在过量重试、过量扩容、过量缓存或重复计算
4. 优先找可逆的小步降本动作
5. 明确降本对成功率、延迟与可靠性的护栏

### SLO 漂移

1. 先确认是瞬时波动还是长期漂移
2. 再看 setpoint、guardrail 与采样窗口是否仍有效
3. 检查控制器是否已经失调或环境是否变了
4. 优先调恢复与观测，再调业务逻辑
5. 明确是改 SLO、改实现，还是改治理策略

## 9. 引用导航

如果需要更完整的理论和场景化方法，请按需读取：

- `references/gda-framework.md`
  - 五维方法论
  - GDA 四步法
  - 软件总体设计视角
- `references/README.md`
  - 引用索引
- `assets/quickstart.md`
  - 快速用法与交付模板

