iteration-close — 提炼、清除、验证接管、演练引导、播种下一轮
一个不断迭代的产品会累积两种隐性债务,而该技能会在每次迭代边界安全(不丢失任何东西)但彻底(不保留任何无用之物)地清偿这两种债务:
- 废弃文件的存在会逐渐腐坏,成为两种真相的源头——一个弃用的目录可能存续数周;一份操作手册可能在功能发布很久后仍宣称某个组件“尚未构建”。
- 仅存在于聊天窗口中的知识会随窗口消失——完整的流水线曾在草稿区消亡;来之不易的决策会随会话结束而丢失。保留经验教训,而非制品。
该技能是通用的:它通过读取仓库自身的约定来工作,当缺少约定时,它会创建最小所需内容,而不会自行假定或报错。“新窗口或新机器可以继续”只有在经过测试后才是一个事实;保持最新(拉取)始终是安全的,但发布(推送)是一个深思熟虑的选择。使用用户当前使用的语言进行回应。
两种运行方式
- 完整关闭(默认):所有五个阶段按顺序执行。当一个迭代/切片完成且用户希望从头到尾关闭时使用。
- 仅清除(独立清理):当用户仅要求清理旧/废弃/过时的文件时,仅执行阶段2——不要强迫他们执行完整的五步关闭。前提条件仍然适用:执行步骤0(定位),以及关闭式拒绝对话检查,以及对删除清单进行范围限定的阶段1抽查——任何仅存在于聊天中的经验教训或决策,首先被提炼到一个跟踪文件中,否则不纳入清单。每个阶段2的规则均适用,包括明确的“是”确认门控和隔离规则。
步骤0——定位到此仓库(发现,否则计划创建)
读取存在的任何入口文档——CLAUDE.md/AGENTS.md/README/docs/索引——并发现六件事。使用找到的内容;如果某物缺失,则将其标记为本轮关闭将填补的空白(以下每个阶段都会说明如何填补),绝不发明不存在的路径。
- 经验教训/决策记录——此仓库在哪里记录决策?(
CHANGELOG、docs/adr/、DECISIONS.md或仓库特定的注册表。)如果没有,阶段1会创建一个单一的DECISIONS.md。 - 已确认的上传命令——一个经过深思熟虑的推送步骤(
bin/sync、make deploy、有文档记录的git push规范)?如果是,那它就是上传通道;绝不绕过它。如果没有,阶段3a使用普通的git push,但要先展示差异统计并确认。 - 引导命令——全新克隆如何能够启动?(
bin/bootstrap、bin/sync-setup、install.sh、make setup、包管理器安装。)如果没有,阶段4会创建一个。 - 测试命令——从CI配置、
package.json脚本、Makefile或语言默认(pytest/go test/cargo test/npm test)中获取。如果没有可发现的测试命令,则此仓库还没有可运行的测试套件:将其视为下面的明确状态——绝不将其读作“绿色”,也绝不拒绝一个按理不应有测试套件的仓库。 - 基础/门控技能——一个产品基础或构建前门控技能?如果有,其“构建后”检查清单就是你的关闭前门控。(产品特定的门控位于产品仓库内;此技能保持通用并遵循它们。)
- 声明的数据/恢复/隔离目录——入口文档中命名为保存真实数据、恢复材料或隔离文件的目录。这些目录免除以下所有“类归档目录不得存在”的规则,且绝不得出现在删除清单中。
拒绝运行(关闭式失败)
不要在迭代中间关闭——你会失去表皮和血肉。如果出现以下情况,则拒绝运行(在两种运行模式下):目录不是git仓库(停止并说明——运行git init是用户决定);存在测试套件且实际为失败状态(不存在的测试套件不是失败——参见步骤0.4);如果仓库有对抗性门控,其状态为待处理或需要更改;或者其他代理/通道在你将要触碰的路径中有未提交的中间切片工作。说明阻塞原因并停止。
在完整关闭中,按顺序运行各个阶段。每个阶段都有退出测试;绝不要在退出测试失败后继续。
阶段1——提炼(挽救门控:在经验教训被记录之前,什么都不删除)
- 将此迭代中聊天产生的决策扫入仓库的决策记录(步骤0.1),每个决策附带其状态和来源。如果仓库尚未记录任何决策,创建记录也属于此阶段——在仓库根目录创建一个单一的
DECISIONS.md就足够了。 仅存在于聊天窗口中的决策不存在;不要让经过提炼的决策无处安放。 - 此迭代中发现的新不变量/规则 → 放入仓库的合约文件,如果缺少合约文件则放入决策记录——理想情况下每个规则对应一个测试。如果两者都不存在,创建决策记录并将它们放入其中。删除制品,保留不变量。
- 仅会话能力检查:此迭代是否依赖于仅存在于提示、草稿区或某人记忆中的任何东西?将其提升到仓库中(代码/技能/文档),或记录其有意排除的原因。明确列出每个项目——这是流水线消亡的地方。
- 如果结构发生变化,则更新——或者,如果不存在且结构现在变得复杂,则创建一个简短的架构/系统说明,使其仍然描述现实。如果仓库有状态看板(例如进度文档),则将其更新至最新。
退出测试:在仓库内搜索此迭代的关键决策和不变量——每个都能在跟踪文件中找到。任何只能在聊天中找到的内容 = 阶段1未完成。
阶段2——清除(彻底删除;git历史是唯一的归档)
- 构建一个带有证据的删除清单,每行一个:
路径 | 为何废弃 | 被何物取代。涵盖被取代的模块/规范、废弃/空目录、开发残留(草稿文件、mktemp风格垃圾、真实形存储器中的测试行)、已完成的计划/TODO文档,以及过时的文档——运行文档与代码矛盾检查;一份断言与代码矛盾的内容的文档比没有更糟。将每行标记为TRACKED或UNTRACKED(git ls-files --error-unmatch <path>),因为两者命运不同(规则3和4)。 - 向用户展示完整的清单,并等待明确的“是”确认后才能删除任何内容。 部分批准是可以的——仅对批准的行执行操作。代理绝不会自行按下不可逆的按钮;“用户要求清理”只授权构建清单,而非执行删除。
- 已跟踪文件:仅使用
git rm。没有_archive/目录,没有.bak,没有old-/legacy-重命名,没有注释掉的尸体。恢复 = git历史,通过一次git revert即可恢复——那就是归档;删除前创建一个检查点提交可使其万无一失。 - 未跟踪或gitignored文件:绝不要直接使用
rm——git历史无法恢复从未提交的内容。这是数据安全线。 将它们移动到仓库声明的隔离目录(步骤0.6)中。如果没有声明,现在创建一个:在仓库根目录下创建.iteration-quarantine/,添加到.gitignore,在入口文档中用一行说明(“待删除的未跟踪文件隔离区——由用户手动清空”)。清空隔离区是用户的行为——在未来的关闭中提供此选项,并附带其自己的明确“是”;绝不静默执行。 - 切勿将产品的真实数据当作开发残留删除。 用户/客户状态、保存的会话、用户内容的真实归档看起来像杂乱数据,但却是产品的灵魂。当一个目录可能两种属性兼具时,将其视为数据并保留;在
git rm之前进行验证。 - 按主题分组提交删除;每个提交消息说明为什么删除 + 被何物取代。
- 删除后检查(所有适用项必须通过):如果仓库有测试套件,则测试通过;针对每个删除的模块/符号的悬空引用搜索为空(导入已删除文件会在启动时崩溃——真正的伤疤);入口文档和技能文档未引用任何已删除路径。
退出测试:git status干净,不存在类归档目录——除了入口文档声明为数据、恢复或隔离的目录(步骤0.6)——悬空引用搜索为空,如果存在测试套件则测试通过。
阶段3——双重就绪通道(不同需求;分别验证)
上传和可继续性不是同一个问题。将它们混为一谈会导致仓库被“推送到云端”,而其真实状态仍然存在于聊天日志中。分别验证每一个。
3a. 已确认的云上传(传输问题)
- 仅对已跟踪文件进行密钥扫描(sk-ant / ghp_ / gho_ / github_pat / AKIA / xox[baprs] / consumer_secret / access_token / Bearer / BEGIN PRIVATE KEY / .env形状)。任何命中 → 停止,清理,重新扫描。
- 检查
git remote。如果没有远程,上传需要用户提供一个——添加远程是一个配置更改,因此与用户确认,或记录“无远程——发布推迟”并跳转到3b,而不是在裸git命令上报错。 - 有远程时:显示
git log @{u}..HEAD --oneline+ 差异统计(当没有上游时回退到“所有本地提交”)——即将要离开此机器的确切内容。 - 通过仓库的已确认上传命令(步骤0.2)在用户确认后上传;如果仓库没有,则在展示差异统计并确认后使用
git push。绝不要自动推送。
3b. 零上下文接管(知识完整性问题)——冷启动探测
- 让一个真正无上下文的读者接触仓库——在Claude Code中:生成一个新的子代理(任务工具);在Codex中:运行一个全新的
codex exec或一个没有先前上下文的新会话;在任何裸的框架上:打开新会话并仅粘贴仓库路径加上问题,绝不粘贴本次对话。仅给它仓库路径和:“从这个仓库的入口文档冷启动阅读。然后回答:(1) 这个产品是什么,用一句话概括;(2) 工作进展如何(已完成/下一步);(3) 你接下来会做什么以及为什么;(4) 说出在这里你绝不能做的三件事。” - 根据仓库的规范文档评分其答案。如果仓库根本没有入口/规范文档,创建一份最小文档(用一句话描述产品、当前状态已完成/下一步、三个绝不要做的事)是本轮关闭的一部分——它是探测所评估的制品。不要针对空内容运行探测。
- 每个错误或缺失的答案都是接管文档的错误,而不是探测的问题。修复(或创建)文档,用新的全新读者重新运行。反复直到冷读者得分为4/4,最多3轮——如果3轮后仍然失败,列出剩余的差距并将决策交给用户。
退出测试:探测通过4/4。只有这样,“任何新窗口/机器都可以继续”才是一个经过测试的事实。
阶段4——单命令引导(经过演练,而非假设)
- 确保仓库的引导命令(步骤0.3)存在且是最新的——幂等,安全地重新运行:验证工具链版本;连接同步/配置;安装依赖;如果存在测试套件则运行测试;打印当前状态 + 任何缺失的本地密钥的名称(不显示值,例如“config.local.json缺失——仅用于实时发布时需要”);任何失败时以非零退出,并附带一行原因。如果引导命令尚不存在,则本轮迭代是创建它的时机。
- 演练它:将仓库克隆到一个临时目录(从原始URL,或当没有远程时从本地仓库路径),并在那里运行引导命令。它必须以绿色状态结束,且零手动步骤。演练完成后删除克隆。
- 新机器故事必须是一行,且在此演练后为真:
git clone <origin-url> <dir> && cd <dir> && <bootstrap command>。如果还没有远程,说明这一行在用户设置远程之前尚不为真——不要将其发布为可工作状态。
退出测试:演练克隆在未手动干预的情况下以绿色状态完成引导。
阶段5——关闭并播种(连续性)
- 为此迭代打标签:
git tag iter-<N>-<slug>(注释标签,一行摘要)。N = 1 + 现有iter-*标签的数量(git tag --list "iter-*");第一次关闭是iter-1。 - 如果仓库有状态看板/日志,用一行更新:提炼了什么,删除了多少文件,探测4/4,引导已演练。
- 将下一轮迭代的种子发送到聊天中:本轮迭代抛出的未解决问题 + 一个可粘贴的下一轮启动提示(目标、验收标准,以及如果存在则提醒在构建前运行仓库的接地门控)。
重大迭代——当结构本身被替换时(相同规则,更大范围)
结构性大修——新架构、新模块树,甚至“旧方法错了”——仍然是一个有机体的迭代,而不是重启。它保留其git历史、决策和经验教训;只有表面是新的。重启会失血:每次项目在一个全新仓库中重生时,经验级别的材料都会被落下。因此:
- 在此仓库中并行生长新结构,同时保留旧结构(绞杀者模式):新树首先赢得测试和所有权;旧树仅在没有任何内容引用它时,在阶段2中被删除。
- 打开一个新仓库是代价高昂的例外,而非默认——需要记录一个决策,说明为什么必须放弃此历史,并在任何文件移动之前获得批准。
- 相同的五个阶段;只是删除清单更大,冷启动探测更重要——新结构的文档从未见过陌生人。
- 如果产品的名称或入口命令发生变化,阶段4的单行故事在同一轮迭代中更新。两个活跃名称是一个两种真相的错误。
护栏(不可协商)
- 阶段顺序是安全机制:绝不要在阶段1退出前进行阶段2的清除——在仅清除模式下,对清单的阶段1抽查就是那个门控。
- 完整的删除清单展示给用户,未经其明确同意,不删除任何内容。代理绝不会自行按下不可逆的按钮。
- 未跟踪或gitignored文件被隔离,绝不使用
rm——git历史无法恢复它们。 - 删除需要替代证据,而非感觉。真正不确定?再保留一轮迭代,在决策记录中记录疑问。