dsh-find-simplifications
把一句「找找能简化的地方」变成有证据支撑的 Agent Note:死代码、重复、投机性抽象、本可用现成依赖却手搓。
这是 .agents/skills/dsh-find-simplifications/SKILL.md 的中文精读。它把一句宽泛的「找找有什么能简化的」变成有证据支撑的 Agent Note——删掉或折拢 harness 里真实存在的表面积。
什么时候触发
在仓库里找非显而易见的简化候选、写 proposed Agent Note 或行内 TODO/FIXME/XXX、审计或合并过时的 Agent Note、或把另一个 PR 里有价值的简化想法折进来时使用。它是引导,不是清单:跟着代码走,保持判断在线,宁要几个证据扎实的候选,不要一堆轻飘飘的猜测。
先建立仓库上下文
- 读 AGENTS.md——尤其是 pre-release 立场、约定(含「测试不是金标准」「Agent Note 也不是金标准」两条教义),以及 docs/defensive-patterns.md、docs/testing.md。
- 评判
packages/下任何东西之前先过一遍 docs/architecture.md;与服务地图或事件分类法对着干的简化,需要额外证据。 - 用 Agent Note 树理解「刻意设计」:双 LLM 适配器、双持久化后端这类设计默认是刻意的。除非用户明确推翻,不要提议以「低成本」为由删掉其中任何一个孪生体——但删掉受保护 seam 内部一个没人用的方法或 hook,只要不塌掉被保护的设计,仍然可以成立。
什么算强候选
强简化删掉、折拢或降格某个真实存在的东西,且有清晰证据证明当前设计的成本大于收益:
- 某个公开方法、事件、配置项、注册表通知、helper、包、耐久事件或测试产物没有生产消费者;
- 测试或文档是唯一消费者,且它们钉住的行为并不承重;
- 两种表示镜像同一个事实——尤其是耐久 session 事件与瞬态
agent/*事件之间; - 某个 seam 有「每个实现都必须支持、但没有消费者使用」的方法;
- 某个独立包只装测试/demo/support 代码,却增加发布或依赖开销;
- 某个特性实现的是投机性的产品通用性:多 session/session 加载、后台任务花名册、注册表实时失效、turn 中 steering、工具自有 UI 渲染等没有产品属主的设计;
- 某个不变量、回滚路径、期望输出集或特判测试,只为保护一个没人用的 API 而存在;
- 手搓代码重新实现了维护良好的外部包或引擎底线内的 Node 内建——且替换能连实现带专属测试一起删掉(见依赖政策决策记录);
- 简化后行为可能略有差异,但新行为仍然合理且更好解释。
单薄候选通常撑不起一篇 Agent Note:删一个笔误、跑一次 knip、删掉一个刻意记录在案的后端/适配器、或者没有调用点证据就说「这看起来复杂」。
广度扫描
用户要广度或多候选时,用并行 subagent,给每个 agent 一个领域并要求证据而非猜测。常用领域:agent loop 与 session 日志(turn/step 边界、steering、abort、耐久事件、回放、加载/恢复);ACP 自动化与人类 UI API;LLM/工具/系统 prompt;bash 与工具执行;包/示例/脚本/测试。
没有 subagent 就自己模拟同样的广度。别让第一个好候选终止扫描。从生产代码体量最大的差集开始——只停在「明显没人用的符号」上的审计,会错过那些重复的生命周期与防御性机器最烧钱的文件。
审计信任与生命周期边界
对每个防御性拷贝、freeze、校验器、回调捕获,说清值从哪来、下一步归谁。同进程的带类型 service/plugin 调用通常借用只读值;解析器、配置加载器、队列、模型/工具 JSON、耐久文件、worker、进程、线上解码器拥有或校验自己的数据。围绕敌意 getter、伪造类型对象、回调替换、同进程交接后变异来构建的测试,是「契约可能投机」的证据,而不是自动保留它的理由。
复杂的异步代码:画出所有权图,把每个哨兵、ready promise、取消路径、disposer、状态标志映射到唯一的属主或迁移。多个机制镜像同一个活性/结算事实时,提议一个事务或生命周期控制器。但保护同步发布与回滚、回调围堵、终态仲裁、worker/进程所有权、dispose-to-quiescence 的机制要保留。
手搓代码 vs 引入依赖
引入依赖是合法的简化动作,不是政策例外——门槛由依赖政策决策记录定。扫描时问:协议解析器、帧器、重试/退避循环、glob 匹配器、diff 引擎这类基础设施,是否已有维护良好的 npm 包或引擎底线内的 Node 内建?
- 读手搓实现,点名那个包覆盖的精确范围;包覆盖不了的残余语义算在替换头上,写进 Agent Note;
- 诚实检查包的健康度(维护、采用、传递依赖体积),引擎底线有内建就优先内建;
- 先查 Agent Note 树:schemastery、vendored Cordis、孪生适配器等已记录在案的 seam 是已定局的——一个会塌掉它们的替换,必须打赢记录里的理由,而不只是引用政策;
- 掂量净删除量:实现 + 专属测试 + 文档,减去剩下的胶水。把同样复杂度挪个地方的包装器不算赢。
证实或否决每个候选
写之前先给消费者分类:生产语料(packages/*/src、examples、运行时脚本、loader/配置路径);非生产语料(测试、README/docs、Agent Note、快照、生成的期望输出、注释);含糊语料(可能是产品冒烟路径的 examples 和 scripts——先查用法再分类)。
先上 rg:精确符号、事件名、包名、配置 key、带不带点的两种方法名写法、线上字符串。然后读调用点。knip 可以帮忙,但替代不了对公共接口、动态事件名、测试、文档和 Cordis loader 路径的理解。
出现以下情况就否决或降级候选:
- 存在生产调用方——那这是功能决策,不是清理;
- API 被某篇 implemented Agent Note 或来之不易的防御性模式明确论证过,而新证据打不赢那个理由;
- 移除会逼出无关的连锁改动,却没有真正缩小公共 API 或必需行为;
- 想法对但太小——改用带紧迫度语义的定点 TODO/FIXME/XXX(见 docs/development.md)。
合并过时的 Agent Note
仅当用户要求削减/合并 note 树,或正在落地的简化让某篇属主 note 过时时,才审计 Agent Note 树;不要把每次代码简化扫描都扩大成全仓 note 审计。保留判断与归档机械操作走 dsh-archive-agent-notes。
对每个候选链:
- 从 shipped 代码、配置、生成目录、包文档、更新的 note、入站链接中确认当前属主——日期和标题只是线索,不是证据;
- 把旧 note 分类为完全或部分被取代。任何残存行为、当前契约、耐久格式、兼容义务、或仍成立的被否方案,都算部分;
- 完全取代:把每个独有理由、备选、后果、shipped 验证证据、具名覆盖空洞搬进当前属主。只描述已删实现机制的清单不算决策事实;
- 修好每个入站链接,然后把英文 note、中文对应、一致性记录一起删掉;
- 改完搜精确文件名、符号、配置 key、事件名、线上字符串。部分取代的保持交叉链接且保持时效。
让「删除 note」接管历史的前提是:该特性已从生产代码、配置、schema、耐久/线上格式、迁移、兼容行为中彻底消失;没有当前文档说它可用;没有测试当它受支持。删除理由与强制其缺席的测试可以留下。要保留:它当初为什么存在、为什么动机不再成立、完整删除之外的备选、放弃的能力、重新引入条件、删除已完成的证据。
写那篇 Agent Note
每个耐久的提案一篇文件:.agents/notes/<lifecycle>/<class>/yyyy-mm-dd-topic.md,遵守 README 的生命周期与分类规则。散文段落一物理行一段,用相对 Markdown 链接。推荐结构:
# Agent Note: <动作导向的标题>,Status: proposed;## Problem:点名当前 API、引用相关文件、给出消费者证据,生产调用方与测试/文档分开列;## Proposal:说清到底删什么、折什么、降什么、搬去哪——含测试、文档、README、JSDoc、事件分类、快照、生成文件的清理;## Why not keep it?/## What we give up:把最强的反对意见写到可读;## Acceptance criteria:可观察的终态与门禁;## Risks:公开 API 变化、行为变化、未来产品需求,以及为什么这个交换仍然合理。
具体到「一个实施中的 PR 能照着走」的程度。避免「简化这个包」式的空泛 note。与已有 note 重叠时,把有用的细节并进已有的那篇,不要另起重复。
行内 TODO 与收尾
行内 TODO/FIXME/XXX 只用于小而局部、明显有用、但不构成耐久设计决策的清理:用稳定 tag 命名病灶(如 TODO(double-default)),说清为什么回头再看是安全的、什么动作能简化它。
纯文档的 note 工作至少跑 pnpm run doc-sync、pnpm run lint、git diff --check;动到代码注释或 skill 时,有对应验证器就跑。开 PR 时汇报:新增/合并/保留为部分取代/删除的 note 各多少、扫了哪些领域、刻意排除了什么、哪些检查通过。扫描还在扩大时用 draft PR,候选集、review 回应、验证都落定后再标 ready。