--- name: one-lesson-rule description: 交付期第 10 步,定期回看(一堂课法则):派一个便宜档的只读哨兵子代理常驻后台,持有 spec 与 plan,按一程预算定间隔,自己醒来取工作树事实,判偏离(含在圈外做功)、兜圈、腐化与子代理健康,写回看记录并给主代理发十行以内的消息;主代理在停顿点处置并写回 plan。进入自主交付期时加载并常驻,人说「定时回看」「起个哨兵」时也加载。人仍在逐步主导时不加载;回看后的汇报件归 progress-artifacts。 --- # 一堂课法则 一程自主交付很长,上下文会腐化而自己不觉。本法则不让主代理自己判自己:回看由一个独立的、新鲜上下文的便宜子代理做,按时间盒从顶层看。它是机制,不只是原则。本法则是思维模型 `think-closed-loop` 落在自主交付期的回路:间隔就是回路的延迟,哨兵就是独立的传感器。 ## 机制 主代理进入自主交付期、plan 写好之后,按 `delegate-brief` 的[哨兵简报](../delegate-brief/sentinel-brief-template.md)派哨兵子代理。哨兵持有 spec、plan 与整程上下文包,拿 [`scripts/sentinel.mjs`](scripts/sentinel.mjs) 取事实,自己计时,不改任何仓库文件。 | 环节 | 谁 | 做什么 | | --- | --- | --- | | 计时 | 哨兵自己 | 按[节拍](#节拍)定的间隔醒一次,两次之间阻塞等待,不消耗 token;宿主原生的定时机制只作备用,见[各宿主的接法](hosts.md) | | 取事实与增量 | 哨兵跑脚本 | 脚本读 plan 的进度行、当前行、切片表、子代理表、文档维护表、里程碑、处置记录与「圈外发现」,读 spec 的「责任分级」;读工作树的提交、改动统计、未提交改动,以及汇报目录里新出现的交回件;提交只看本分支的第一父链,合入算一条并单列次数,合进来的文件不算本程改动;子代理「在跑」只按状态格开头的状态词判;算信号,含文档陈旧、超出验收窗口、圈外改动、责任分级缺失(处置按入口[圈外的问题](../single-session-dev-flow/SKILL.md#圈外的问题)) | | 判与发 | 哨兵 | 对照 spec 与 plan 判六问,写一条[回看记录](review-record-template.md)到汇报目录,给主代理发不超过十行的消息 | | 处置 | 主代理 | 在下一个停顿点读消息,按常规出口动作,把处置写进 plan 的进度总览;「继续」也写一行 | 满 4 轮哨兵自己结束,最后一条消息写明;主代理续派一个新的,新哨兵先读上一个的记录。 ## 对齐层面 哨兵和主代理在契约层对齐,在事实层取证,不进实现层,不进会话层。没有 spec 与 plan,它只能报「有几个提交」,报不出「偏离了什么」。 | 层 | 内容 | 哨兵 | | --- | --- | --- | | 承诺层 | spec 的目标、验收标准、不变式、责任分级、范围外、待决事项、已定事项 | 派发时整份读,revision 变了再读 | | 分解层 | plan 的进度总览、切片表、预算、里程碑、收口记录、子代理表、历次回看与处置 | 每轮重读,与上一轮比差 | | 框架层 | 整程上下文包的不变式与系统地图;交付声明 | 派发时读一次 | | 事实层 | 脚本给的提交、改动统计、未提交改动、交回件路径与尾部 | 每轮读脚本输出,交回件只读尾部 | | 历史层 | 自己前几轮的记录;续派时上一个哨兵的记录 | 持有 | | 实现层 | 源码与测试;开工包的技术细节 | 源码与测试不读;技术细节只读进行中切片的那一节,只用来判不变式排除的路径 | | 会话层 | 主代理的对话与自述 | 不读 | ## 节拍 - 哨兵的间隔按一程预算算:取 plan「预算与回看」节的一程总预算,除以 6,不足 10 分钟取 10 分钟,超过 45 分钟取 45 分钟。例如总预算 2 小时得 20 分钟,30 分钟得 10 分钟,6 小时得 45 分钟。固定一个间隔不行:按 45 分钟,短于 45 分钟的一程一轮都醒不来。 - 4 轮一续派。间隔与轮数是简报参数,间隔的缺省值按上一条算。 - 子代理健康:哨兵从 plan 的子代理表读开始时间,运行到 30 分钟及其整倍数时查一次工作树事实。 - 主代理连续两轮没有写处置,脚本出信号,哨兵在下一条消息里把它当停滞升级。 - 宿主不能跑后台子代理时,退回 [各宿主的接法](hosts.md) 的备用做法,并把这个下限写进 plan 的「预算与回看」。 ## 回看什么 | 问 | 对齐在哪几层 | 看什么 | 不看什么 | | --- | --- | --- | --- | | 有没有偏离 spec 与 plan | 承诺、分解、事实 | 两类证据。(甲)偏离计划:提交碰了范围外的文件;切片表状态与提交历史不一致;收口记录有「未达到」却标已完成。(乙)在圈外做功:脚本的「圈外改动」信号;当前行、里程碑、处置或子代理交回在处理落在圈外的东西;主代理为不挡验收的圈外问题停下或问人;「圈外发现」里记成挡住验收的条目,其实不挡 spec 的任何一条验收。「圈外改动」只是事实:改的文件不在责任分级列出的路径里,可能是圈外做功,也可能是本程改动带出、还没补进 spec 的消费者,判法见入口[圈外的问题](../single-session-dev-flow/SKILL.md#圈外的问题) | 实现细节 | | 是不是在局部兜圈 | 分解、事实、历史 | 一直在改却没有进展:连续两轮都有提交,进度标记(当前行、勾上的里程碑数、切片状态)都没动,两轮改的又是同一处(脚本的「可能兜圈」信号);同一切片收口超过两轮;同一处测试或变异反复红 | 单轮的波动;顺着推进的连续提交,比如先实现、再补用例、再重构,同一文件连改几次是常态 | | 上下文有没有腐化的迹象 | 分解、事实 | plan 的裁定与 spec revision 不同步;同一决定两处写法不一致;收口记录越写越短;处置缺席 | 主代理的自述 | | 每个在跑的子代理是否健康 | 分解、事实 | 开始时间到了检查点;交回件有没有出现;工作树有没有动静 | 子代理的会话记录 | | 实现是不是比本质复杂 | 承诺、框架、分解、事实 | (甲)做久了:切片用时超过 plan 预算节给它的分钟数;同一切片提交多于三条;收口记录里新函数圈复杂度过线或变差多;改动统计远大于切片「交付」那一句的分量。(乙)为不变式排除的路径做功:从 spec 与整程包已经定义的不变式出发,plan、提交信息、子代理交回件或进行中切片的技术细节设计里,主代理或它派出的设计、开发子代理在给不变式写明不会出现的状态写处理、分支、用例或补变异用例;这类做得快,用时看不出 | 代码本身 | | 给人看的文档有没有过期 | 分解、事实 | 脚本的「文档陈旧」信号:进度行的 head 不是当前 HEAD;处置编号断号;汇报件早于最近一次提交;切片收口了而汇报件没有在那之后生成;预计收尾已过而 plan 没改;plan 连续两轮没改而这两轮都有新提交(主代理可能在写另一份 plan,例如换了工作树);plan 结构不合模板(`check-plan` 非零);文档维护表某行的「最近更新」落后于进度行而该文档在最近提交里被改过 | 文档内容的好坏,那归人读 | 结论四选一:继续;建议主代理介入(哪一处、为什么;第一问因(乙)为「是」时带固定提醒:提醒:<位置> 在圈外,不挡验收标准 <编号或无>,按入口[圈外的问题](../single-session-dev-flow/SKILL.md#圈外的问题)记一行,继续本程;证据是「圈外改动」时提醒里再写另一种可能:它是本程改动带出、还没补进 spec 的消费者,那就补进责任分级并升修订,由主代理判是哪一种;第二问「局部兜圈」为「是」时这一条带固定提醒:先答三问:应然、实然、差异。做法加载技能 `think-ought-vs-is`。「实现是不是比本质复杂」因(甲)为「是」时带固定提醒:各切片的实现本质上都简单,做久了是没找到本质解的信号,先问过度设计、不优雅、缺的数理建模、形式化建模、领域设计、OOP 建模(SOLID),再看是不是一边找正确一边打磨:先做对,再单独做好一轮。做法加载技能 `think-right-then-well`。因(乙)为「是」时带固定提醒:哪条不变式排除了这个状态,为它写处理与用例是过度设计,也从根上违背了对不变式的守护,按技能 `think-ought-vs-is` 的「不多做」删掉);建议停下问人(命中 spec 待决事项里只有人能定的一类);子代理健康问题(哪个、信号是什么)。信号带证据(提交号、文件、时刻、spec 编号或切片号),不带指令;什么算证据按思维模型 `think-evidence`,主代理与子代理的自述不算。 上下文已经腐化时,主代理先加载技能 `pstack:recall` 从 plan、整程包和提交历史重建现状,再继续。长程无人值守时,决策日志加载技能 `pstack:show-me-your-work`,哨兵记录与它互为索引。 ## 常规出口(主代理) | 出口 | 什么时候 | | --- | --- | | 继续 | 结论是继续,无信号 | | 升推理档位 | 子代理卡在同一失败一轮 | | 换更强模型 | 两轮不收敛,且判定本身没错 | | 主代理介入指导 | 方向偏、范围蔓延、在做测不出结果的工作;哨兵判局部兜圈时,先答三问:应然、实然、差异。做法加载技能 `think-ought-vs-is`。 | | 回到圈内 | 哨兵判在圈外做功。停下圈外的事,在 plan 的「圈外发现」记一行,回到当前切片。它其实是本程改动带出、还没列出的消费者时,补进 spec 的责任分级并升修订,照连带同步。判法见入口[圈外的问题](../single-session-dev-flow/SKILL.md#圈外的问题) | | 删掉不可能的路径 | 哨兵判在为不变式排除的路径做功。按技能 `think-ought-vs-is` 的「不多做」删掉处理与用例;派出去的写者在做,主代理介入指导并把那条不变式写进简报。哨兵看错了不变式时,在处置里写明哪条不变式允许这个状态 | | 回到建模 | 哨兵判实现比本质复杂且证据是做久了。这是[写代码的四条](../single-session-dev-flow/SKILL.md#写代码的四条)第四条的出口:停下实施,把这一片的问题重新建模:数理、形式化、领域、OOP(SOLID),找到本质解再写;一个切片本该简单,做久了多半是建模没到位,不是手慢 | | 主代理接手 | 子代理停下没交回,或接手比重派快 | | 停下问人 | 命中 spec 待决事项里只有人能定的那一类 | | 截程交付 | 脚本出「超出验收窗口」信号:预计收尾滑到人回来之后;或夜间一程两轮不收敛。停在当前切片的边界上,把已收口的切片整理成一次交付,剩下的切片标「跳过(截程交付)」,处置记一行「截程交付」,改预计收尾;跳过的切片写进交付声明,由设计会话在收回时定去处。不需要人在场。选「继续」时在处置里写明为什么 | 「超出验收窗口」是人这一侧的风险:一程大过人在验收窗口里验得完的量,人回来时拿到的是验不完的库存。人已经说过就按一程做时,脚本不再报。看到人这一侧的风险就说一次:提醒、依据、建议、选择。做法加载技能 `candid-friend`。 处置之后通常接一次向人汇报,加载技能 `progress-artifacts`。动作与理由记进[回看记录](review-record-template.md)的「主代理处置」。 ## 哨兵不做的 不改仓库文件(只写汇报目录)、不派子代理、不跑测试与构建、不给别的子代理下指令、不替主代理拍板。 ## 一程结束 让哨兵结束或等它满轮自结束,删掉备用的宿主定时任务;汇报目录按 `cleanup` 处理。