Cybernetic Systems Engineering(CSE)
把软件开发当作一个闭环控制系统来做:
- 被控对象(Plant):代码库 + 运行时环境 + 依赖 + 数据 + 测试系统
- 控制器(Controller):你(Agent)+ 你的计划、策略、节奏控制
- 传感器(Sensors):测试、构建日志、运行日志、指标、复现脚本、审计文档
- 执行器(Actuators):代码修改、配置变更、依赖升级、回滚、文档更新、测试补强
- 参考输入(Reference):需求、issue、验收标准、SLO/SLA、业务边界
- 输出(Output):实际行为(通过/失败测试、运行结果、性能数据、门禁结果)
- 误差(Error):参考输入与输出之间的差距
- 扰动(Disturbance):环境差异、并发、flake、脏状态、真实 schema 漂移
- 时滞(Delay):慢测试、CI 排队、真实环境依赖、发布窗口
本 skill 的目标不是“让你会用控制论术语”,而是让你在复杂工程任务中:
- 先建立正确的观测与误差定义
- 再用最小控制输入减少误差
- 用分层验证防止振荡与假收敛
- 用总体设计视角控制复杂性
项目级控制拓扑
CSE 不只处理“当前这一条任务怎么修”,还要先回答“这个项目由谁控制、在哪一层控制、跨模块如何协调”。
从控制层级看,CSE 默认同时存在两套闭环:
- 任务级闭环
- 面向单个 issue、单次 patch、单轮验证
- 关注最小控制输入、最小 failing case、分层验证
- 项目级控制拓扑
- 面向多模块、多团队、多阶段演化
- 关注总体设计部、控制结构、跨模块协调、边界冻结与升级路径
如果只建立任务级闭环,而没有项目级控制拓扑,常见结果是:
- 单个 patch 看起来正确,但把复杂性偷偷转移到别的模块
- 局部验证通过,但共享接口、共享状态或共享基础设施被无意破坏
- 每个人都在改“自己眼前那一层”,但没有人对整体误差负责
因此在以下场景,必须先补项目级控制拓扑,再进入具体修复:
- 改动跨 2 个及以上模块、服务或语言边界
- 需要同时改代码、配置、schema、运行流程中的两类以上对象
- 任务会影响共享接口、共享状态、共享基础设施或统一门禁
项目级控制拓扑至少要回答四个问题:
- 总体设计部在哪里
- 谁负责维护项目级参考输入、关键边界和最终裁决
- 控制结构是什么
- 本次问题主要落在哪些层,哪些层只能观测,哪些层允许施加控制输入
- 跨模块协调怎么发生
- 哪些模块存在强耦合,改动会沿什么路径外溢,谁需要被显式通知或升级
- 哪些边界先冻结
- 哪些接口、schema、门禁口径在本轮不能被顺手改写
控制面 / 数据面 / 状态面
为了避免“看起来只是改一行代码,实际上改穿了整个系统”,复杂任务开始前必须先识别本次改动主要落在哪一面:
- 控制面
- 负责决定系统如何调节自己
- 典型对象:限流、重试、熔断、路由、灰度、回滚、门禁、调度策略
- 数据面
- 负责承载真实业务流量和核心处理路径
- 典型对象:请求处理、任务执行、核心计算、主链调用、用户可见结果
- 状态面
- 负责保存共享事实、恢复锚点与跨节点一致性
- 典型对象:数据库、schema、缓存、队列、事件日志、检查点、幂等键
默认要求:
- 先标出本次改动的主落点在哪一面
- 再标出会被连带影响的次级面
- 如果一次改动同时触碰两面以上,必须显式写出复杂性是如何转移的
一个典型例子:
- 把重试、限流从业务代码下沉到 mesh 或统一网关
- 不是“复杂性消失了”
- 而是复杂性从数据面转移到了控制面
- 把会话、任务进度或幂等信息从应用内存迁到 Redis / 数据库
- 不是“状态更简单了”
- 而是状态复杂性从节点内部转移到了状态面
如果主落点都判断不清,默认先不要改实现,而是先补控制结构说明。
复杂性转移账本
复杂性不会凭空消失,只会被下沉、上浮或转移到别处。
因此每次声称“系统更简单了”时,都应至少记一条复杂性转移账本:
| 字段 | 说明 |
|---|---|
| 复杂性原位置 | 复杂性原来压在哪一层、哪个模块、哪条链路 |
| 新位置 | 复杂性被转移到了哪里 |
| 收益 | 本次转移换来了什么 |
| 新成本 | 新增了什么依赖、运维成本或观测成本 |
| 失效模式 | 转移后最可能新增什么故障模式 |
典型例子:
- 把重试、限流、路由从应用代码下沉到 mesh
- 复杂性原位置:数据面应用逻辑
- 新位置:控制面基础设施
- 收益:业务代码更薄、统一治理更强
- 新成本:调试链变长、配置漂移风险上升
- 失效模式:控制面误配导致全局放大
- 把会话、幂等键或任务恢复点外包到 Redis / 数据库
- 复杂性原位置:节点内内存与本地状态
- 新位置:状态面共享存储
- 收益:重启恢复更稳定、横向扩展更容易
- 新成本:一致性、超时、容量与运维复杂度上升
- 失效模式:状态面抖动放大为全局故障
- 把同步调用改成异步补偿
- 复杂性原位置:同步链路上的时延与阻塞
- 新位置:队列、重试、补偿和对账流程
- 收益:主链解耦、峰值承压更强
- 新成本:最终一致性与对账成本上升
- 失效模式:补偿堆积、重复消费、长尾未收敛
项目级控制拓扑的默认治理协议如下:
最小 owner matrix
| 角色 | 默认职责 | 有权决定什么 | 无权单独决定什么 |
|---|---|---|---|
| 总体设计部 | 维护项目级参考输入、关键边界、升级路径与最终裁决 | 跨模块优先级、冻结边界、变更窗口、最终 gate 口径 | 直接跳过模块 owner 的局部约束与证据 |
| 模块 owner | 维护本模块不变量、主链入口与回归边界 | 模块内部实现、局部回归、局部重构 | 擅自改共享接口、共享状态、共享门禁 |
| 共享边界 owner | 维护共享 API、schema、队列、缓存、统一门禁等共享事实源 | 共享契约演化节奏、兼容窗口、迁移前置条件 | 在未通知受影响模块时直接改共享契约 |
默认升级路径
按风险从低到高,默认这样升级:
- 模块内局部改动
- 模块 owner 可在本模块边界内完成分析、修改与验证
- 跨模块但不改共享契约
- 必须显式通知受影响模块 owner,并记录外溢路径
- 触碰共享接口、共享状态、统一门禁
- 必须升级到总体设计部裁决,再进入实现
- 触碰冻结边界或发布窗口
- 默认停止当前 patch,先拿到明确批准
接口冻结条件
以下任一对象在本轮默认视为冻结边界,不能顺手改写:
- 共享 API 输入输出结构
- 数据库 schema 与持久化字段语义
- 队列、缓存、事件格式等共享状态契约
- 统一门禁口径、核心指标口径、发布与回滚流程
要解冻这些边界,至少要同时满足:
- 有明确变更理由,而不是“顺便改一下更优雅”
- 有受影响模块清单与兼容路径
- 有总体设计部或对应共享边界 owner 的显式裁决
跨模块裁决规则
凡是跨模块变更,最终裁决责任默认不属于“谁先改代码”,而属于总体设计部。
它至少要回答:
- 为什么这次改动值得跨模块扩散
- 哪些模块只需要被通知,哪些模块需要同步修改
- 哪些边界继续冻结,哪些边界被批准打开
- 如果跨模块协调失败,当前 patch 应该收缩到哪里
如果这些问题答不出来,默认结论不是“继续改”,而是:
- 先补控制拓扑
- 先画清边界
- 先确认谁对整体误差负责
后续章节中的 Control Contract、GDA 四步法、传感器工程与验证分层,都是建立在这层项目级控制拓扑之上执行的。
0. 何时触发
以下任一场景,优先使用本 skill:
- 需要修改代码并验证结果
- 任务跨多个模块/服务/语言边界
- 需要从 bugfix 推进到测试补强、门禁、handoff
- 用户要求做“严格 review”“系统性复盘”“架构与测试一起收口”
- 出现“离线通过,真实环境失败”“测试通过,业务不闭环”“修一个坏两个”的迹象
如果任务时间跨度长、步骤多、存在中断恢复需求,应同时配合 harness 使用。
1. 五维心智模型(执行时要内化)
执行任务时必须同时考虑以下五个维度:
第一性原理
- 找系统不变量、硬约束、物理边界
- 不先问“用什么框架”,先问“系统真正不能妥协的是什么”
公理化思维
- 契约先于实现
- 明确哪些接口、状态转换、schema、事件语义是不可破坏的公理
多模型思维
- 至少用 3 个视角看问题:
- 数据流
- 状态机
- 时序 / 并发 / 排队
- 至少用 3 个视角看问题:
类比迁移
- 遇到拥堵、震荡、雪崩、阻塞时,主动寻找物理同构:
- 队列 / 水库 / 缓冲
- 熔断 / 断路器
- PID / 弹性控制
- 遇到拥堵、震荡、雪崩、阻塞时,主动寻找物理同构:
反馈与验证
- 没有可观测闭环的设计,不算完成
- 特别注意:
- 时滞
- 非线性
- 假阳性测试
- 真实环境与离线环境的分层差异
详细方法论与例子见:
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:入口拒绝率、任务完成时间可能恶化
默认规则:
- 复杂任务在改实现前,先列控制输入、目标输出、影响方向与外溢风险
- 如果一个 knob 同时强影响多个 output,默认把它视为高耦合输入
- 高耦合输入优先做小步试探,而不是一次拉满
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 基线建立
默认顺序:
git status/git diff- 读取 issue、相关代码、最近改动、已有 review
- 跑最便宜的验证路径
- 记录失败命令、失败用例、关键信号
4.2 传感器去噪
如果信号不稳定:
- 重跑 3~5 次
- 固定随机种子 / 时区 / 并发
- 隔离外部依赖
- 把偶现变成最小稳定复现
4.3 特别规则:schema-sensitive 路径
凡是涉及以下任一因素:
- 真实数据库列类型
- SQL cast
- 驱动参数序列化
PG_CH/ 真实 broker / 真实文件系统 / 真实扩展加载
都必须明确区分:
- 语义测试
- fake fetcher / stub / resolver 白盒
- schema 契约测试
- 锁定关键 SQL / schema / 分支行为
- 真实环境 gate
- Windows / VPN / 真实数据库 / 真实 broker
禁止把:
- “resolver 语义通过”
- “cargo test 全绿”
直接写成:
- “真实环境通过”
4.4 动态控制病:采样与观测新鲜度
性能和稳定性问题默认先审查观测质量,而不是先改实现。
必须显式检查:
- 采样周期
- 采样过慢会把瞬时尖峰、短时雪崩、短时队列积压平均掉
- 采样过快但没有聚合窗口,会把瞬时噪声误判成系统趋势
- 观测新鲜度
- 延迟到达的 metrics、异步刷新的 trace、缓存后的 dashboard,可能让你基于旧世界做新决策
- 任何观测结果都要先确认时间戳、刷新周期和传播时滞
- 采样别名
- 用粗粒度采样看周期性抖动时,容易把真实震荡看成稳定
- 典型后果是把“周期性过载”误判成“偶发 flake”
- 陈旧指标
- 指标本身还在更新,但语义已经落后于当前发布版本、schema 或流量路径
- 典型后果是优化了旧瓶颈,却把新主链打坏
- 观测盲区
- 只看入口成功率,不看下游队列、缓存击穿、回放链路,会把局部成功误判成整体稳定
默认规则:
- 遇到性能或稳定性问题,先写清本轮采样周期、观测新鲜度和主要盲区
- 任何“趋势判断”都必须说明观测窗口,而不是只引用单次结果
- 如果怀疑存在采样别名或陈旧指标,先补观测点或换采样方式,再决定是否改代码
4.5 动态控制病:去抖、滞回、退避与冷却
很多系统不是“控制能力不足”,而是“控制动作太频繁”。
默认要检查四种抑振手段:
- 告警去抖
- 当同类告警在短时间内反复触发时启用
- 目的不是隐藏故障,而是避免把瞬时尖峰误当成稳定故障模式
- 滞回区间
- 当扩缩容、限流、熔断或降级阈值存在边缘来回抖动时启用
- 进入阈值和退出阈值不应完全相同,否则系统会反复横跳
- 退避策略
- 当重试、探测、轮询、恢复动作连续失败时启用
- 失败后必须扩大间隔,而不是用固定频率继续打系统
- 控制冷却时间
- 当一次控制动作刚施加、系统尚未完成传播和收敛时启用
- 在冷却窗口内默认禁止同类控制动作再次触发
执行规则:
- 只要控制动作会修改阈值、流量、路由、重试或容量,就必须声明是否存在滞回和冷却窗口
- 只要恢复动作依赖轮询、重试或探测,就必须声明退避策略
- 默认禁止连续重复同类控制动作不带冷却窗口
- 如果没有去抖或滞回设计,任何“阈值附近反复跳变”都应先视为控制病,而不是先怪业务逻辑
4.6 动态控制病:anti-chatter、anti-windup 与控制器冲突
当系统已经进入震荡区,继续叠加控制器通常只会把问题放大。
- anti-chatter
- 指防止控制动作在相邻状态之间高速来回切换
- 典型场景:熔断开关在半开与关闭之间反复横跳,或扩缩容在相邻副本数之间频繁切换
- anti-windup
- 指防止控制器在执行器已经饱和时,仍然继续累积“应该再加一把力”的内部误差
- 典型场景:下游已经限流或队列已经打满,但上游重试、补偿或扩容信号仍不断叠加,最终形成重试风暴或扩缩容超调
- 控制器冲突
- 指两个及以上控制器同时修改同一 knob,却没有统一仲裁
- 典型场景:应用内重试、sidecar 重试、网关重试同时打开;HPA、队列消费调度器、人工扩容同时改副本数
默认规则:
- 同一 knob 只能有一个主控制器,其他控制器要么只观测,要么通过明确仲裁接入
- 只要执行器已经饱和,就必须显式考虑 anti-windup,而不是继续累积恢复动作
- 只要系统出现高频开关、周期性回摆或阈值附近来回跳变,就必须先排查 anti-chatter
- 遇到重试风暴、补偿堆积、扩缩容超调,默认先查控制器冲突,再查业务逻辑
4.7 无观测,不优化
任何性能或稳定性优化,默认都要先拿到观测基线。
最小入场券:
- trace
- 先看跨服务链路到底卡在哪一跳
- flame graph
- 先看 CPU / wall time 真正烧在什么调用栈
- profiling baseline
- 先记录修改前的基线,不要只拿修改后的单次结果自嗨
- golden signals
- 至少关注延迟、流量、错误、饱和度这类核心信号
- 对照实验
- 能做 A/B、shadow、canary 或前后对照时,优先做对照,而不是纯猜测
默认规则:
- 无观测,不优化
- 观测不足时,默认先补观测点、profiling 或链路追踪,再决定是否改代码
- 任何“感觉这里慢”“猜这里有瓶颈”的说法,都不能直接升级成优化动作
- 优化结果至少要和修改前的 profiling baseline 做一次对照
5. 决策准则
当多个方案都能修时,优先:
- 最小风险
- 最强可验证
- 最可逆
- 最符合模块业务区位
特别注意:
- 不为了通过测试而偏离原始语义
- 不为了抽象而扩大不该公开的 API 面
- 不把测试便利性凌驾于模块职责之上
5.1 机制优于策略
默认优先设计“生成策略的机制”,而不是把人的经验直接硬编码成静态策略。
默认禁止把以下对象直接写死成“经验常数”后就当作稳定设计:
- timeout
- retry 次数
- 熔断阈值
- 连接池大小
- 扩缩容阈值
优先选择的机制包括但不限于:
- 自适应控制
- 根据延迟、错误率、队列长度、资源利用率动态调整控制输入
- 反馈回路
- 让上一次控制结果影响下一次控制强度,而不是重复拍脑袋
- 搜索或在线学习
- 当最优点未知且环境持续漂移时,用搜索、探索或在线更新替代静态猜测
裁决规则:
- 能用机制吸收环境变化时,默认不要把人的经验写成永久阈值
- 静态策略只能作为启动值、护栏值或临时保守值,不能伪装成长期真理
- 如果一个策略需要频繁人工调参,优先怀疑“缺机制”,而不是继续加参数
例外条件:
- 环境几乎不变、观测明确且失效成本极高时,可以短期采用静态策略
- 但必须同时写清监控条件、失效信号与后续替换计划
5.2 MTTR-first 与 crash-only
对现代复杂系统,默认优先级不是“尽量永不出错”,而是“出错后多快回到安全状态”。
默认裁决:
- MTTR 优先于 MTBF
- 当两种方案不能同时兼得时,优先选择更快恢复而不是更长时间不出错
- crash-only
- 遇到不可恢复、未定义或无法证明安全的状态,优先显式失败、退出或重启,而不是维持僵尸状态
- 自动回滚
- 只要风险可外溢到共享接口、共享状态或核心链路,就要优先设计自动回滚信号
- 故障注入
- 不能只验证“正常时能跑”,还要验证“坏了能多快恢复”
执行规则:
- Control Contract 里的
Recovery Target不是装饰项,必须给出恢复时间预算或安全回退时限 - 只要系统进入不可恢复状态,默认先显式失败,而不是静默维持
- 只要回滚条件可被机器识别,就优先设计自动回滚,而不是依赖人工盯盘
- 任何声称“高可用”的路径,都应至少经过一次故障注入或等价恢复演练
特别注意:
- crash-only 不是吞错后假装恢复,而是让失败可见、可重启、可回退
- 快速恢复不等于快速掩盖,必须保留故障证据、恢复路径和恢复时间
5.3 抽象审查协议
抽象的默认目标不是“减少重复”,而是“减少错误耦合”。
默认原则:
- 允许 WET
- 如果两段逻辑当前相似,但未来不保证一起变化,允许先物理重复
- 优先物理解耦
- 宁可保留两份小实现,也不要为了复用把两个生命周期不同的模块绑死
- 按共变关系做抽象
- 决定是否抽象的依据,不是代码长得像,而是未来是否真的会同时变化
判定规则:
- 只要两个调用点的发布节奏、故障域或 owner 不同,默认先不要抽象
- 只要抽象会扩大共享 API 面、共享状态面或统一门禁面,先怀疑这是错误抽象
- 代码相似但业务语义、失败模式或演化方向不同,不应因为“长得一样”就抽象
- 在决定抽象前,至少回答一次:它们未来真的会同时变化吗
反过来说:
- DRY 不是被废除,而是要服从模块职责、故障隔离和长期演化
- 如果抽象让系统更难切分、更难回滚、更难定位责任,就不是好抽象
5.4 演进式架构与可逆决策
复杂系统默认不是被一次性设计出来的,而是从简单可用系统逐步长出来的。
默认原则:
- 先长出简单可用系统,再逐步演化
- 没有真实反馈前,不要预支未来 5 年的复杂性
- two-way door 决策优先快试
- 可逆决策优先小步试、快反馈、保留回退路径
- one-way door 决策优先控边界
- 不可逆决策必须先冻结契约、清点依赖、确认迁移窗口
执行规则:
- 每个重要架构决策都应先判断它是 two-way door 还是 one-way door
- two-way door 决策优先用小范围实验、最小实现、短反馈回路验证
- one-way door 决策必须显式写出桥接期、回退条件和受影响模块
- 契约默认先稳后扩,不要在桥接期一边迁移一边改口径
桥接期协议:
- 迁移默认存在一个桥接期
- 桥接期内优先使用:
- shadow
- 新链路跟跑、不接管主裁决
- canary
- 小流量、小范围、可快速回退
- shadow
- 桥接期结束前,默认保留旧事实源或旧主链作为对照基线
如果一个方案:
- 无法定义桥接期
- 无法解释怎么回退
- 无法说明契约何时冻结
那它默认不是成熟的演进式架构方案
6. 高风险反模式(必须主动检查)
假收敛
- 单测通过,但真实环境条件未覆盖
双真相
- 文档一套、主链一套、备用路径一套
影子实现
- callback_dispatcher 更完整,但主链不用
- helper 存在,但主链不可达
弱断言
- 只有
is_ok(),没有行为语义断言
- 只有
测试驱动代码偏离职责
- 为了测试方便扩大
pub面 - 暴露本不该公开的内部实现
- 为了测试方便扩大
把离线测试当 gate
- 真实 schema / 真实扩展 / 真实网络问题无法由 stub 替代
7. 交付格式
最终交付优先按下面结构组织:
- Summary
- State Estimate / Root Cause
- Changes
- Verification
- Recovery Evidence
- Observability Evidence
- Residual Risks / Gate Boundary
其中:
- Recovery Evidence
- 说明怎么恢复、多久恢复、触发了什么回滚或重启语义、恢复预算是否满足
- Observability Evidence
- 说明依据什么判断问题存在、优化有效或风险仍在
- 至少给出本轮关键日志、指标、trace、profiling 或 gate 证据中的一类
如果是长任务,还应同步:
- 审计文档
- 回归矩阵
- handoff 文档
8. 实战剧本
Bugfix / 回归
- 最小复现
- 最小 failing test
- 根因假设
- 最小修复
- 相关回归
- 全量相关回归
测试补强
- 审计当前覆盖层次
- 找“语义层 / schema 层 / 真实环境层”缺口
- 先补最能拦截真实风险的离线测试
- 再补回归矩阵
- 最后明确 gate 边界
架构收口 / 清理
- 先证明主链实际入口
- 再证明影子实现是否仍被使用
- 删除或收敛重复事实源
- 用测试或调用链审计防止回归
性能退化
- 先拿 profiling baseline 与 golden signals
- 再定位是 CPU、IO、锁竞争、网络还是排队
- 画输入-输出影响矩阵,避免错改高耦合 knob
- 小步优化并做前后对照
- 记录收益、代价与残余风险
异步队列背压
- 先确认队列长度、消费速率、重试率、死信情况
- 再区分是数据面过载、状态面卡死还是控制面误配
- 检查 anti-windup、退避与扩容是否互相打架
- 先止血,再恢复,再补治理
- 明确消息堆积的恢复边界
迁移 cutover
- 先定义桥接期与冻结边界
- 再安排 shadow、canary 或双写对照
- 明确切流条件、回退条件、终止旧链路条件
- 分层验证 cutover 前、中、后状态
- 最后关闭桥接并归档证据
部分故障 / 依赖 brownout
- 先确认故障是全挂还是 brownout
- 再查重试、熔断、降级是否放大故障
- 识别依赖是否已进入不可恢复状态
- 优先保主链和恢复预算
- 记录恢复动作和隔离边界
配置回滚
- 先确认问题是否由配置变更触发
- 再识别配置属于控制面、数据面还是状态面
- 检查是否满足自动回滚触发条件
- 回滚后验证关键护栏指标是否恢复
- 补配置审计与冻结规则
Flake Triage
- 先稳定复现,确认是否真 flake
- 固定随机种子、时区、并发与外部依赖
- 区分测试抖动、环境抖动、时序抖动、观测误判
- 用最小观测点把偶发现象变成稳定信号
- 再决定是修实现、修测试还是修环境
成本失控
- 先确认成本是流量驱动、重试驱动还是闲置浪费
- 再看哪个 control input 把成本推高
- 检查是否存在过量重试、过量扩容、过量缓存或重复计算
- 优先找可逆的小步降本动作
- 明确降本对成功率、延迟与可靠性的护栏
SLO 漂移
- 先确认是瞬时波动还是长期漂移
- 再看 setpoint、guardrail 与采样窗口是否仍有效
- 检查控制器是否已经失调或环境是否变了
- 优先调恢复与观测,再调业务逻辑
- 明确是改 SLO、改实现,还是改治理策略
9. 引用导航
如果需要更完整的理论和场景化方法,请按需读取:
references/gda-framework.md- 五维方法论
- GDA 四步法
- 软件总体设计视角
references/README.md- 引用索引
assets/quickstart.md- 快速用法与交付模板