名称: invariant-ace 描述: “通过定义拥有的归纳不变性并在解析/构造/API/数据库/锁/事务边界处强制执行它们,并附带验证信号,将‘不应发生’变为‘无法发生’。当提示提到不变性、不可能状态、验证蔓延、缓存/索引漂移、幂等性/版本控制、重试/重复/乱序事件、竞争/线性化错误、循环正确性或通过不变性检查首先强化另一个工作流(例如$fix)时使用。”
不变性王牌
使命
以最小化、高杠杆的更改将“不应发生”变为“无法发生”:选择拥有的归纳不变性;在最强的廉价边界处强制执行;通过具体反例追踪和验证信号证明。
使用时机(信号)
- 空值/形状意外、运行时验证蔓延或输入解码分散在代码库中。
- 冗余存储事实漂移(缓存/索引/非规范化列)或“修复”代码经常运行。
- 标志/状态爆炸;不可能组合出现;“不可达”变得可达。
- 竞争、重复/乱序事件、重试、部分失败或“恰好一次”假设。
- 幂等键、单调版本/纪元检查、陈旧写入或线性化问题是核心。
- 循环/算法正确性依赖于注释或直觉;棘手的索引/算术/终止。
- “不应发生”分支出现在日志或错误跟踪器中。
路由优先级
- 如果任务具有不变性/协议线索并要求广泛实现(
$tk,$fix,$work),首先运行此技能以锁定不变性,然后执行编辑。 - 如果无法命名状态所有者+过渡,在实现前切换到澄清/发现。
核心模型(快速定义)
- 不变性:谓词P(state) 旨在在作用域内对所有可达状态保持为真。
- 归纳的:初始时为真 AND 由该作用域内每个允许的过渡保持。
- 所有者:控制所有突变以保持P的单个模块/类型/事务/锁/参与者。
- 前置条件/后置条件:调用者义务 vs 操作保证;不要将这些误标为不变性。
- 派生属性:可重新计算的事实;除非集中更新,否则避免存储为“必须匹配”。
- 安全性与活性:不变性是安全性(“没有坏事”);保持进度(“最终”)分开。
即时扫描
- 状态所有者:真理在哪里(类型/模块/服务/表)?
- 状态边界:原始数据在哪里进入(API/数据库/文件/队列)?
- 允许的过渡:列出突变状态的操作/事件(包括重试和并发)。
- 当前失败:一个具体追踪(输入 + 过渡 + 时间表)达到坏状态。
- 保护级别:希望 -> 运行时 -> 构造时 -> 类型/编译时 -> 持久化/协议/原子性。
- 痛点标签:数据 | 并发/协议 | 算法/循环(通常多个)。
保护阶梯
选择最便宜的强层,使违反变得困难或不可能。
- 基于希望:注释、假设、“不可达”。
- 运行时:分散的守卫/验证器靠近使用点。
- 构造时:在边界处一次解析/验证;核心代码仅处理精炼值。
- 类型/编译时:非法状态无法表示(抽象数据类型、类型状态、不透明包装器)。
- 持久化:模式/约束/事务在静态时强制执行不变性。
- 并发边界:锁/参与者/CAS/事务定义不变性必须保持的位置(锁下、提交时、线性化点)。
协议(反例驱动)
-
声明作用域 + 所有者。
- 写“P在何时/何处保持”:始终 | 构造后 | 锁下 | 事务提交时 | 消息应用后。
- 如果无法命名所有者,不变性将漂移;首先选择一个扼制点。
-
列出过渡并尝试打破P。
- 对于每个过渡(及重试/乱序变体),尝试反例追踪。
- 如果P失败,决定:错误 vs 错误作用域 vs 缺失状态 vs 错误所有者。
-
使P归纳(或降级它)。
- 弱化P、将其移至前置/后置条件,或添加辅助状态(版本/纪元/状态/幂等键),直到它在过渡下闭合。
-
运行协调检查(并发/分布式)。
- 问:两个各自有效的并发过渡可以合并成违反P的状态吗?
- 如果是,需要协调(锁/事务/共识) OR 必须重新设计不变性/操作(分区、托管、单调合并、幂等性)。
-
在最强的廉价边界编码强制执行。
- 偏好:解析器/解码器 + 智能构造函数 + 狭窄/不透明类型 + 集中突变。
- 避免:N个分散验证器、没有单一写者的重复真理、每次读取的“修复”例程。
-
如果完整强制执行必须分阶段进行,则添加可观察性。
- 添加廉价触发器(断言/日志/指标)和隔离路径(拒绝/死信/补偿)。
- 记录可重放上下文(过渡名称、ID、版本),而非原始秘密。
-
用正确的测试验证。
- 数据:模糊/属性测试解析器/构造函数。
- 状态机:有状态/基于模型的测试(序列)。
- 并发:压力 + 时间表扰动;在静止点断言。
- 协议:小型模型检查/模拟丢弃/重复/重排序。
- 算法:循环中的不变性断言 + 与参考的差异测试。
紧凑模式(快速路径)
当任务小或时间有限时使用。
- 反例:一个具体失败追踪(<=5个过渡)。
- 不变性:1-2个谓词,具有明确所有者 + 作用域。
- 强制执行边界:一个选择的扼制点(解析/构造/API/数据库/锁/事务)。
- 验证:一个信号链接到一个谓词。
如果任何上述内容模糊或非归纳,则升级到完整协议。
不变性记录(使用此格式)
- 谓词:P(state)(精确,可检查)
- 所有者:模块/类型/服务/表/锁/事务
- 保持:始终 | 构造后 | 锁下 | 提交时 | 应用后
- 由维护:必须保持P的过渡
- 在处强制执行:解析/构造/API/数据库/锁/事务/协议
- 要避免的反例:今天打破它的最小追踪
- 验证:属性/有状态/压力/模型/差异
按痛点分类模式
数据建模和输入有效性
- 边界精炼:原始 -> 解析 -> 验证;仅验证进入核心。
- 规范化:尽早规范化(大小写/空格/时区/ID格式),以便相等性和缓存稳定。
- 显式缺失:显式建模可选性;避免核心中的“有时为空”。
- 跨字段耦合:将耦合字段合并为一个值,防止非法组合。
- 非规范化纪律:如果存储派生事实,集中写入或使其可重新计算。
并发和协议正确性
- 锁/事务不变性:P在锁下或提交时保持;定义线性化点。
- 单调元数据:版本/纪元/计数器只增加;拒绝陈旧写入。
- 幂等性:重试和重复是安全的(幂等键、去重表、“应用一次”)。
- 显式状态机:枚举状态 + 允许过渡;持久化足够元数据以拒绝乱序事件。
- 协调决策:如果P依赖于全局唯一性或并发借计下的非负性,选择协调或重新设计(分区/托管)。
算法和循环密集代码
- 循环不变性:断言每迭代保持什么(分区区域、排序前缀、守恒定律)。
- 变体/终止:命名递减度量;如果不能,预期非终止边。
- 表示不变性:在API后隐藏内部结构;为测试/调试添加表示检查。
- 差异测试:与简单、慢参考实现比较,捕捉角落情况。
之前/之后草图(语言无关)
边界精炼(数据)
之前:函数接受RawInput并临时验证
之后: parseRaw(...) -> ValidatedValue | 错误
核心函数仅接受ValidatedValue
幂等性 + 版本控制(并发/协议)
之前:handle(event) 直接突变状态(重试重复副作用)
之后: if seen(event.id) return
if event.version <= state.version return(或拒绝)
apply(event) 在单个原子边界(锁/事务/CAS)
循环不变性(算法)
之前:注释说“数组左侧是分区”
之后: assert(invariant(state)) 在循环内
测试:随机数组,缩小失败案例,与参考比较
验证
选择至少一个信号,并将其链接到特定不变性谓词。
- 属性/模糊:解析器、构造函数、规范化。
- 有状态/基于模型:操作序列;每一步后检查不变性。
- 并发压力:N线程 + 抖动;在静止点断言不变性。
- 协议模拟:重排序/重复/丢弃 + 崩溃/重启;断言安全不变性。
- 模型检查(可选):小状态 + 穷举探索协议。
- 差异/参考:算法输出等于随机输入的参考。
- 运行时触发器:分阶段推出的断言/日志记录/指标。
研究锚点(心智模型,非要求)
- Hoare/Floyd/Dijkstra:不变性作为证明对象;最弱前置条件。
- ADT/表示不变性(Liskov风格):抽象函数 + 局部推理。
- 抽象解释:过近似可达状态;推断不变性。
- 动态不变性挖掘(Daikon风格):候选生成;用反例证伪。
- 分离逻辑/框架:不变性链接到所有权;干扰感知推理。
- 依赖保证和线性化:时间表下的并发不变性。
- TLA+/Alloy思维方式:协议作为过渡 + 不变性;反例追踪。
- 协调避免 / CRDT法则:当不变性需要协调 vs 合并安全设计时。
输出契约(必要标题)
在最终响应中为此技能使用这些确切标题:
- 反例
- 不变性
- 所有者和作用域
- 强制执行边界
- 接缝(之前 -> 之后)
- 验证
- 可观察性(可选)
可交付清单
- 反例:最小破坏追踪(包括时间表/重试,如果相关)。
- 不变性:1-5个谓词,具有所有者 + 作用域(“在何时保持”)。
- 强制执行边界:边界/类型/API/数据库/锁/事务/协议选择 + 原因。
- 接缝(之前 -> 之后):使违反困难的最小结构更改。
- 验证:属性/有状态/压力/模型/差异链接到至少一个谓词。
- 可观察性(可选):如果推出必须分阶段,触发器/隔离/指标。
跨协调
- 如果出现更广泛的故障,依赖不健全性清单。
- 如果更强不变性影响人体工程学,参考枪伤防护措施。
测量(seq)
用seq跟踪采用和合规性:
uv run codex/skills/seq/scripts/seq.py skill-trend --skill invariant-ace --bucket week
uv run codex/skills/seq/scripts/seq.py skill-report --skill invariant-ace \
--sections "Counterexample,Invariants,Owner and Scope,Enforcement Boundary,Seam (Before -> After),Verification,Observability (optional)" \
--sample-missing 5