Files
admin 5004909267 提问规则审计 + 撤出本机生成的两份契约 + 「一律用肯定表述」落进注入面
用户 10-09 三条令:
①「那两份 不说具体 我怎么知道,看看会话提问的规则是否有缺陷」
②「A 方案」(撤出 session-mechanism/roots.env 与 references/manifest.md)
③「要用确定XXXX 这样的描述,避免 不要XXXXX 会导致上下文干扰的描述,除了经验沉淀和红线避坑外」
   +「不只是修改 创建生成时也需要遵守」

一、提问规则审计(三条缺陷,全部修掉)
1、判据用错了维度:旧措辞「⛔ 提问正文不许出现的:包名·环境变量·文件路径·commit/sha·表名/字段名·
   类名/函数名」是按**词性**一刀切,而同一段末尾又写「正文只留能决定下一步的内容」⇒ 两句自相矛盾。
   我按前半句执行、把要撤的文件名删成了「那两份」⇒ 待拍板项不可答。
   ✅ 改成按功能判:**少了这个标识,用户还能不能决定** —— 不能 ⇒ 写进正文;能 ⇒ 删、下沉技术附录。
2、同一判据散在 6 处、措辞各不同(违反本项目自己的「禁重复判定标准」):已收敛到同一句判据,
   并互相标注「改这里必须同批改」。
3、🔴 最隐蔽:**每轮注入的那份 ≠ 包内那份**。钩子 `_core()` 是三级回退,① **本工作区
   CODEBUDDY.md 的 `REPLY-CORE` 段**才是每轮注入的(包内那份只是换机器的兜底)。
   我先只改包内 ⇒ 注入的仍是旧条文,而"文件都改了、自测全绿",看不出来。
   ⇒ 两份都改 + 新增防漂移自测 `t_reply_core_same_source`(两份实质内容必须逐字一致)。

二、撤出两份「本机生成」的契约(用户选 A)
- `git rm --cached session-mechanism/roots.env` 与 `session-mechanism/references/manifest.md`
  —— **本地文件一律保留**(实测 624 B / 18 568 B 仍在)。
- 为什么必须撤:别的电脑取仓时「同名覆盖」会把它们换成**我们这台机器**的路径 ⇒ 那台机器的
  机制脚本去找不存在的目录。
- 新增入库样例 `session-mechanism/roots.env.example`(占位符,无本机路径)。
- `.gitignore`:加这两份的忽略行(⛔ 防 `git add -A` 捎回),并改掉原「刻意入库」那段注释。

三、「一律用肯定表述」写进注入面(原来只在 rules.md,注入面看不到)
- 口径:**写或改技能与规则文件时一律写"要什么、怎么做";新建、生成时同样适用**;
  例外=**以「经验沉淀」或「红线/避坑」为目的**的技能与规则(写法=正向目标 + 括号里的踩坑依据)。
- 落点:injected `REPLY-CORE` 段(工作区 + 包内,逐字一致)· `rules.md §9` ·
  `改包纪律.md` 新增第 5 条硬纪律(「二、四条」→「五条」)· `01-文档索引.md` 指针同步 ·
  把我在注入块里加的那段负向表述改成**正向主导**。

四、🔴 顺带抓到并修掉一个我自己造成的净变差
- 注入块有 **1400 字上限、且从开头截** ⇒ 我加条文把它顶过上限(1274 → 1414+)⇒
  尾部三条(变相征询禁止 / 不用征询句收尾 / 本工作区另有定稿)**静默消失**、不再注入。
- 修:上限 1400 → **2000**;并在 `t_reply_core_same_source` 里加断言 **块长 ≤ 上限** ——
  以后谁再顶破上限,自测直接报红,逼他"要么精简、要么显式抬上限"。
- 验证:`被截断=False`,尾部三条都回来了。

五、验证
- 全套自测 **PASS 109 / FAIL 0**;py 语法全绿;`install.py --manifest` 重算(78 份,语法失败 0)。
- 注入块实测:来源=工作区 CODEBUDDY.md,不截断,含「一律用肯定表述」「决定对象要点名到具体」
  「新建、生成时同样适用」。
2026-10-09 10:45:00 +08:00

126 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 会话机制 · 规矩与判据(照它做,⛔ 别自己另发明)
> ⚠️ 本文件是**作业规矩**;机制全貌 ⇒ `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 进行中` ⇒ 机制自动复跑。
⛔ 阻碍时**不关**后台任务与协作程序(用户口径第②条),只是不派活、不建检查。
- ⛔ **别越界**:「已完成」不归结果检查 —— 那是「目标检查会话」的活(判据是完成度,不是队列)。