Files
workbuddy_skills/session-mechanism/references/rules.md
T

125 lines
13 KiB
Markdown
Raw Normal View History

# 会话机制 · 规矩与判据(照它做,⛔ 别自己另发明)
> ⚠️ 本文件是**作业规矩**;机制全貌 ⇒ `references/architecture.md`;坑 ⇒ `references/pitfalls.md`。
> 🔴 与项目层 `CODEBUDDY.md §1` 冲突时**以项目层为准**(那里有裁决顺序)。
## 1 提问判据(唯一一条)
> **只问「超过现有判断方法边界」的问题。**
- **边界内 ⇒ 自决策,不要问**:技术选型 / 实现路径 / 命名与数据结构 / 调参 / 部署与同步 / 排查方法 / 版本依赖 / 兼容降级 / 方案取舍 / 文档技术内容。 **「部署上线」属此项 ⇒ 做完即上线,不要问**;生产变更**直接做**,只需**动手前一句话说明**。
- **边界外 ⇒ 必须问**:① 业务目标与优先级 ② 花钱与资源承诺 ③ 对外承诺 ④ 需用户提供的凭据或审批 ⑤ 无客观优劣的偏好 ⑥ 影响面超出本平台 ⑦ 红线门禁 ⑧ 判不准。
- **判据**:有没有**客观可判的优劣**?有 ⇒ 自决策;没有 ⇒ 问。
- **提报用户标准 = 存在真取舍**:候选**只有优点或只有缺点 ⇒ 自己拍掉**;各有优劣才提报用户,且**逐项写优点 + 缺点**。
- ⛔ **不许捆包**:要问红线**只问那一句**;技术方案自己定好、当**已定项**陈述。
- ⛔ **禁用征询句收尾**(「要我…吗 / 请确认 / 你看怎么办」)⇒ 按三问重判,没命中就**删掉、自己做完**。
- 🔴 **提报用户内容必须自包含**:① 一句话说清要决定什么(⛔ 不用指代;🔴 **决定对象必须点名**)② 为什么要你定(影响谁 / 断多久 / 花多少钱)③ 每候选写优点 + 缺点,末行给倾向 ④ 一轮一问 ⑤ ⛔ **只服务实现**的内部细节(函数名 / 变量名 / 行号 / sha / 表名字段名 / 内部编号)下沉「技术附录」。
- 🔑 **⑤ 与 ① 的同一句判据**:**少了这个标识,用户还能不能决定?** 不能 ⇒ 必须写进正文;能 ⇒ 必须删。
⚠️ 旧措辞是「⛔ 不出现包名 / 路径 / 变量名 / 类名」——按**词性**一刀切 ⇒ 把"决定对象"也删了
(2026-10-09 实测:把要撤的两份文件写成「那两份」⇒ 用户回「不说具体 我怎么知道」)⇒ **已改成按功能判**。
## 2 回复排版(🔴 用户 2026-10-01 定稿,照抄即可)
- **骨架**:`# 大类`(**已完成** / **待处理任务**)→ `## 任务名` → 每件事两段:**当前状态** + **待处理事项**。
- 🔴 **大类标题必须比任务名大一号**(大类用 `#`、任务名用 `##`;⛔ 不许同号,否则层级压平)。
- **当前状态**:每条一个**圆点**,**一句陈述句说重点**;复杂情况放**句末圆括号**。
- **待处理事项**:用**序号**(`1、2、`,⛔ 不是 `1.`);每条写完整句子。
- **附件**:写在该板块**最末**一行(`附件:<路径>`)。
- **大类顺序**:**已完成的放最前**,`待处理任务`放**最后**。
- **三禁**:⛔ 表格(=省略讲理)|⛔ 长散文(不是写小说)|⛔ 碎标签堆叠。
- ⚠️ 本条只管**给人读的回复**;注释 / 日志 / 解析字段不受限。
## 3 锁
- **开工先抢锁**(是"抢"不是"看");**抢不到 ⇒ 停手 + 报告**(红线 R9:⛔ 不删锁、⛔ 不接管)。
- 🔴 **R9 的唯一例外(用户 2026-10-09 授权)**:「工作区项目机制对应的会话**异常**导致未解锁 ⇒ **检查会话**可自解除**孤儿锁**」。
判据**不靠猜**:`scripts/lock/orphan-lock.py` 去宿主库 `sessions` 表读持有者真身状态 —— **只有**
`terminated`/`error`/`archived`,或 `completed` 且静默 ≥30 分钟 ⇒ 可解除;`working` ⇒ **一律不动**。
⛔ 唯一执行面就是这支脚本(`--dry-run` 先看;⛔ 别自己写 `rm -rf` 删锁);⛔ 例外**只给检查会话**、**只覆盖这一种情形**。
- 🔴 **默认一律带域**(`--domains <本工作区域>/`);⛔ 别省略 —— 省略=**全局独占**,别人连域锁都抢不了。
- 🔴 **只有真正"全平台共用"的改动**(配置 / 加解密 / 隔离 / 锁与钩子**本身**、技能文件)才用**独占**。
- 🔴 **释放必须反序且带会话名**:`--release` → `--release-exec "<会话名>"`;⛔ 不带名 ⇒ 拒释放。
- 🔴 **锁的生命周期 = 任务的生命周期**:⛔ 禁抢锁做一半、不解锁就结束回合(带锁结束=把所有人挡在门外);中途要停 ⇒ 先释放。
- 🔴 **域键算法 shell/hook 必须逐字一致**,否则**静默失效**。
## 4 日志闸(会话"活多久"的物理边界)
- 本工作区闸值:文件**软 5 MiB / 硬 8 MiB**;工具调用**软 200 / 硬 250**。命中 ⇒ 开接续会话。
- 🔴 **宿主侧还有一个 10 MiB 硬上限**:撞顶即**拒写** ⇒ **界面静默哑掉、用户零感知**,而投递方仍记 `ok:true`(**假绿**)。
- 🔴 **病根是"调用次数多",不是"每次调用贵"**;增长只与"工具在跑"成正比(实测:活跃 ≈630 KB/分 ↔ 空闲 34 分钟 0 行)。
- **压增长三条硬纪律**:① 大输出先落盘、只读关键行 ② 命令层限流(`| head -30` / `grep -c` 代替裸 `grep`)③ 让脚本内部聚合、只 print 摘要。⛔ 禁 `cat` 大文件、无 `head` 的 `grep -r`。
- ⛔ **不要在会话里起常驻后台长跑任务**:它每次输出都把会话反复唤醒 ⇒ 永远回不到 idle ⇒ 用户看到"卡死"(已复现多次)。✅ 正确起法=**会话后台任务 + stdout 全重定向到文件**;或干脆做成**独立进程**(见 §6)。
## 5 钩子与脚本的写法约束
- 🔴 **hook 脚本必须走 `sys.stdout.buffer.write(bytes)`** 输出 —— 否则文案含非 ASCII 符号时抛 `UnicodeEncodeError` ⇒ stdout 为空 ⇒ **静默放行**。
- 🔴 **不要按位置推导根目录**:钩子脚本被搬一次就会**静默指错**(历史事故:台账写到别处、测试却全绿)⇒ 用外置的 `roots.env`(本包由 `install.py` 生成)。
- ⚠️ `settings.json` 的 hook 条目**没有 `env` 字段** ⇒ ⛔ 别指望用 env 给钩子传参。
- 🔴 **作用域⛔ 不许静默排除**:被跳过必须**留下痕迹**(写跳过清单 + stderr),否则"没动作"与"坏了"长得一模一样。
- ⚠️ **钩子脚本内容改动即时生效**;但 `settings.json` 的 hooks 条目是**应用启动时快照** ⇒ 改条目要**完全重启**(关窗 ≠ 退出)。
## 6 常驻的精确边界
- 🔴 **「协作与投递一直运行(常驻)」是已定案项**(09-29 定案,2026-10-01 用户再确认)⇒ ⛔ **不得拿"进程数=0"去否它**。
- 🔴 **⛔ 禁的是"在会干活的会话里起"**:会话自己的后台任务会**压制该会话的 idle 钩子**(实测被僵尸任务压 **6h20m**)
⇒ 载体应用**专用容器会话**;且**输出必须完全静默**(`stdout` 全重定向到文件,⛔ 否则反复唤醒宿主 ⇒ 看着像卡死)。
- ✅ **独立进程不在禁令内**(输出不接回任何会话 ⇒ 不唤醒宿主);但它**读不到网关口令 ⇒ 不能投递**,只能做只读判定 / 告警。
- **存活边界一句话**:「**后台任务跟着应用活,不跟着会话活**」⇒ 要"关了应用也还在"必须做成独立进程(⚠️ 但那就没口令了)。
## 7 其他硬约束
- 🔴 **技术讨论不谈法规**:⛔ 不引条文当论据、⛔ 不主动提合规、⛔ 不前置提报用户;只在你问起、或对象就是"对外承诺 / 资质 / 合同"时才谈。
- 🔴 **红线 R5 / R7 / R9 / R10 永远硬约束**(内容见项目层 `CODEBUDDY.md §3` 红线全表)。
- 🎯 **要解决问题,不将就妥协**:降级 / 延期 / 静默兜底**都不算解决**;🟢 **只做正向迭代**。
- 🔴 **接手前人结论先做最小取证**,⛔ 别拿旧结论当既成事实;**取现状一律按 mtime 取最新那份**。
## 8 🔴 验证通过的机制 ⇒ **必须写进技能**(2026-10-05 用户明令)
> 用户原话:「**这个也是会话规则,验证通过的机制要写进技能中**」。
- 🔴 **一条机制实测跑通之后,落点只能是技能**(`SKILL.md` 或 `references/`),⛔ **不许只留在工作区日志或当次对话里**。
- **判据**:换一个新会话、**不读任何历史**,只看技能能不能照着做出来。做不到 ⇒ 等于没立。
- **⚠️ 写的位置决定会不会被读到**:`SKILL.md` 第一屏/「必读三篇」/索引表 ⇒ **每次都会读到**;长文档正文底部 ⇒ 基本没人会翻到(等于没写)。
- ⛔ **反例(10-05,同一件事栽到第四次)**:常驻的起法只写在当天日志里 ⇒ 之后每一轮都重新折腾一遍、每一轮都得出同样的结论。
✅ 正解:结论**同时**落三处 —— `SKILL.md` 第一屏(会被读)+ `pitfalls.md` 一条(有来龙去脉)+ 本档一条规矩(约束以后怎么写)。
- 🔴 **配套**:凡"换会话容易忘、忘了就会重来"的结论,**优先放第一屏**,⛔ 不要塞进长文档。
## 9 🔴 一律用肯定表述("要什么"优先)(2026-10-07 + 2026-10-09 用户令)
**写或改技能与规则文件时,一律写"要什么、怎么做"** —— **新建、生成时同样适用**(⛔ 不只管"修改")。
落点(都是「自动匹配面 / 每轮注入面」):技能的 `description` 与首屏 · **每轮注入的排版块与钩子文案** ·
技能与文档的「用途/范围」段 · 其它规则正文。⛔ 不写「不要 A/B/C」这类负向描述。
- **为什么(机制性,不只"占地方")**:负向词进匹配面 = **把 X 这些词喂进去** ⇒ 反而更容易命中 X
(实测形态:`draw-ui` 描述里列「不用于普通插画/海报/故事板」⇒ 用户说"做个海报"时它更可能被选上);
进**注入面**是同一回事 —— 同样的反向拉高。
- **例外(按文档性质定,⛔ 不按句子定)**:**以「经验沉淀」或「红线/避坑」为目的**的技能与规则
(踩坑记录 · 红线清单 · 反例库 · `pitfalls.md` 这类)**可以写负向** ——
写法=「**正向目标 + 依据(曾栽过什么)**」,⛔ 不把禁令单独摆在那儿。
- 🔴 **落地(2026-10-09)**:这条口径已写进**每轮注入块**(工作区规则文件的 `REPLY-CORE` 段
+ 包内 `03-回复排版-核心块.md`,两份逐字一致),并在 `改包纪律.md` 立为第 5 条硬纪律。
此前它**只在本文里**、且只覆盖"用途/范围 段" ⇒ 注入面看不到 ⇒ 我又在注入块里写了一整段负向表述
(用户 2026-10-09 点破)。防漂移判据=`selftest.py::t_reply_core_same_source`。
- ⛔ **别与"事实陈述"混**:「配置里不含本工作区」「该目录不含 `board.py`」是在**描述事实**,
不在本条管辖内 —— 一刀切会把它们误删。
- ⚠️ **硬禁令(「三禁」这类)不在本条改写范围** —— 它们是约束本体,强度要留住;
本条管的是**描述性文字**与**可选的举例**。
## 10 🔴 遇阻碍 ⇒ 把目标状态改成「阻碍」⇒ 机制暂停 ⇒ 让用户决策(2026-10-09 用户令)
**口径**(用户原话:「**其他类型 阻碍 遇到阻碍修改目标状态 暂停机制 让用户决策**」):
阻碍**解不了**时,正确动作不是反复重试,而是**改目标状态把机制停住、交回用户**。
- **什么叫"阻碍"(三条全中)**:① 队列里那条 `blocked` **确认解不了**
(含跑过孤儿锁判定仍判「不动」的);② 它是在**等人**,不是等某个会话;③ 原因已写进台账与 `NEED-USER.md`。
- **谁去做**:🔴 **结果检查会话** —— 它是**唯一能看见 `blocked`** 的那条腿(靠"队列非空"触发);
「目标检查会话」虽有权改状态,却要**队列为空**才触发 ⇒ 队列里躺着 `blocked` 时它**永不触发**。
⇒ 不给结果检查这一个出口,两条腿会互相锁死、只剩空转(2026-10-09 `contentm_agent` 实测:
连开 **11 棒、约 5 小时、零派活**,每 30 分钟一棒)。
- **怎么做**:`collabd.py --set-life 阻碍 --by "<会话名>" --check-why "<一句现状>"`
⇒ 闸① 随即生效、**不再建检查棒**(这就是"暂停机制")。
⚠️ 「为什么」的旗标是 **`--check-why`**,⛔ 不是 `--why`(那是 `--retire` 的,写错会被**静默忽略**)。
⚠️ 写完**必须回读** `goal.json` 确认(本项目栽过「命令不存在却 rc=0 静默放行」)。
- **怎么恢复**:用户处置完 ⇒ **主会话**跑 `--set-life 进行中` ⇒ 机制自动复跑。
⛔ 阻碍时**不关**后台任务与协作程序(用户口径第②条),只是不派活、不建检查。
- ⛔ **别越界**:「已完成」不归结果检查 —— 那是「目标检查会话」的活(判据是完成度,不是队列)。