发布:常驻文档按现行形态重写 + 作业规矩/01 先并后删
一、常驻机制文档 references/supervise-persistence.md(整份重写 410→469 行)
- 照抄段由废弃的 start-supervise.ps1 形态,改为现行形态:
计划任务 collabd-keepalive-<区>(每 5 分钟)→ pythonw.exe → supervise-launch.py → collabd.py --supervise
- 旧 ps1 形态整体降级为「§四 旧形态留痕」(逐条标 🟠,内容一字未删,供读老日志/老进程用)
- 判据订正:LastTaskResult 在长驻运行中是 267009(旧口径「必须 0」属"跑一次就退"时代,已作废);
BOM 那条随 ps1 形态一并降为历史;另两条仍有效(CODEBUDDY_CONFIG_DIR 空库 / WorkingDirectory 必须是工作区根)
- 删除 assets/start-supervise.ps1.tpl —— SKILL.md、manifest.md、collabd.py、selftest.py 四处早已按「该模板已删除」口径,本次把磁盘与文档对齐
二、references/作业规矩/01 先并后删(用户选定 A 方案:不丢内容 + 只剩一处)
- 判据类并入 references/02-功能优先协作协议.md:
§3.2 补「规则冲突裁决顺序」「冲突 ≠ 门禁」;§3.3 补回完整语言转换表(原处"已收敛到通用技能"在并包后成了悬空指针);
§5.3 铁律由五条补到六条 + 接上配套硬红线「只做正向迭代」;新增 §5.5「提报前必答三问 + 回话前自检」
- 排版类并入 references/03-回复排版-核心块.md 的「完整版」段(十四条反模式 / 骨架路由表 / 文案点名主体 / 文档直入主题)
该段放在 REPLY-CORE 标记之外 ⇒ 每轮注入块逐字未变(实测仍 1172 字符)
- 删除 references/作业规矩/01-协作与提报用户判据.md,并跟改 6 处引用(SKILL.md 第一屏表、作业规矩/00 索引表与两处指针、
作业规矩/03-多棒接力编排、00 的 frontmatter 变更记录)——含一处二级指针「见 §6 第 0 条」,已改指 03 完整版段
三、判据与卫生
- pitfalls.md:P0-74 去冗余(7107 → 5982 B,重复叙述合并),「沉淀纪律」由 FAIL 1 转绿
- install.py:manifest_files() 补排 logs/ —— 与它自己「运行日志不入表」的口径一致,否则跑一次钩子表就过期
- .gitignore:补 logs/;撤跟踪 logs/_dr_probe.json(钩子输出转储,全包零引用)
- references/manifest.md 用生成器重算:66 份文件,语法失败 0
验收读数:selftest.py rc=0 PASS 99 / FAIL 0(另 1 条报告型不计入);
session-rules-check.py fail 0 / warn 1("此刻无活会话",正常态)/ ok 13;改动文件行尾全 LF。
This commit is contained in:
1 parent
9fd120f40b
commit
e5dfb6e4ef
14 files changed
+456
-721
No files matched your search
@@ -13,6 +13,9 @@ __pycache__/
|
||||
Thumbs.db
|
||||
*.swp
|
||||
*~
|
||||
# 钩子/探针的运行期输出(2026-10-07 补:与 references/manifest.md 的「运行日志不入表」同一口径;
|
||||
# 撤跟踪 logs/_dr_probe.json —— 它是钩子输出转储,全包零引用)
|
||||
logs/
|
||||
|
||||
# 本机凭据(⛔ 一律不入库)
|
||||
.neodata_token
|
||||
|
||||
@@ -51,7 +51,7 @@ agent_created: true
|
||||
| 1 | **`references/00-动手前必过.md`** | 六条动作红线(⛔ 开工前只读这一篇就够) |
|
||||
| 2 | **`references/rules.md`** | 现行规则本体(⛔ 历史在 `pitfalls.md`) |
|
||||
| 3 | **`references/manifest.md`** | 清单:哪个文件是**权威**(改之前先确认) |
|
||||
| 4 | **`references/作业规矩/`** | **会话必须遵守的作业规矩**(原 `agent-operating-rules`,2026-10-06 按用户令整包搬入):`00-作业总规矩` · `01-协作与提报用户判据` · `02-工作区纪律` · `03-多棒接力编排` · `04-去AI味与说话方式` |
|
||||
| 4 | **`references/作业规矩/`** | **会话必须遵守的作业规矩**(原 `agent-operating-rules`,2026-10-06 按用户令整包搬入):`00-作业总规矩` · `02-工作区纪律` · `03-多棒接力编排` · `04-去AI味与说话方式`。⚠️ 原 `01-协作与提报用户判据` 与包内正文**同题** ⇒ **2026-10-07 已并入**「判据 → `references/02-功能优先协作协议.md`(§3.2 冲突裁决 / §3.3 语言转换表 / §5.3 铁律 6 + 只做正向迭代 / §5.5 提报前三问)」「排版 → `references/03-回复排版-核心块.md` 完整版段」 |
|
||||
|
||||
**📇 完整索引(干什么事 → 看哪篇):`references/01-文档索引.md`**
|
||||
⚠️ 那篇里还有**文档四条规则**(分类索引/结论在最前/历史倒排·新的在前/单条 ≤6 KB)——
|
||||
@@ -403,7 +403,7 @@ python .workbuddy/collab/collabd.py --set-life 进行中 --by "主会话"
|
||||
**④ 我要复盘某个历史会话** ⇒ 读 `references/forensics.md`,取证脚本 `scripts/forensics/proc-parent.py`。
|
||||
|
||||
**⑤ 踩过坑 / 要避坑** ⇒ `references/pitfalls.md`;**包内文件清单与来源** ⇒ `references/manifest.md`(逐文件 md5 + provenance)。
|
||||
**⑥ 我要让常驻长期在线(⛔ 会话/工具调用起的活活不过当轮)** ⇒ 读 **`references/supervise-persistence.md`**(唯一权威:Windows 计划任务 + 守护循环 · 三条封死路 · 三个秒退坑 · `LastTaskResult` 验收)。
|
||||
**⑥ 我要让常驻长期在线(⛔ 会话/工具调用起的活活不过当轮)** ⇒ 读 **`references/supervise-persistence.md`**(唯一权威:计划任务 `collabd-keepalive-<区>` → `pythonw.exe` → `supervise-launch.py` · 三条封死路 · 两个秒退坑 · 心跳三判据验收)。
|
||||
🔴 **先分场景再动手**(该文档 §〇 有对照表):**用户手动创建主会话** / **定时任务创建主会话** —— 两者都要**同一个载体**(计划任务 + 永不返回的守护循环);⛔ **排期代替不了载体**(跑完即 `completed`,下一跳之前是空窗);⚠️ `status=ACTIVE` **≠ 在跑**(`once` 排期过期即哑:`next_run_at=None`)。
|
||||
|
||||
**⑦ 我要判断「这件事该自己定,还是该问用户」/ 要给用户一个「待拍板」清单** ⇒ 读 **`references/02-功能优先协作协议.md`**(2026-10-04 由 `dsh-decision` 搬入本包,**内容守恒**)。
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
# collabd supervisor keeper -- NEVER returns on purpose.
|
||||
#
|
||||
# 🔴🔴 2026-10-04 修:首行原本多打了三个双引号(即「三连双引号 + #」开头,
|
||||
# 把整份 `.ps1` 变成了「Python 看着合法、PowerShell 看着语法错」的畸形文件
|
||||
# ⇒ 生成物被 PowerShell 判定 9 处语法错、**一秒内秒退** ⇒ 常驻彻底没人续命。
|
||||
# ⛔ 这个文件是 **PowerShell**(不是 Python)⇒ 注释一律用 `#`,⛔ 不要三引号。
|
||||
#
|
||||
# ⚙️ 本文件由 `init_workspace.py` **按工作区变量自动生成**(⛔ 请勿手改:要改改模板 + 重跑脚本)。
|
||||
# 生成时间:__STAMP__
|
||||
# 适用工作区:__WS__
|
||||
#
|
||||
# Why this file exists(⛔ 下面几条是踩出来的,⛔ 别"简化"掉):
|
||||
# ① 计划任务**只在任务失败(非零退出)时重启**。早前版本末尾直接前台调 pythonw,
|
||||
# pythonw 死掉后脚本返回 0 ⇒ 任务被判"成功"⇒ RestartCount=999 永不触发
|
||||
# ⇒ **常驻死了就永远死着**。⇒ **重启逻辑必须住在脚本里**。
|
||||
# ② ⛔ **绝不能用 `& $pyw ...`** 起常驻:pythonw 是 GUI 子系统程序,PowerShell 的
|
||||
# 调用运算符**不阻塞**它 ⇒ 立刻返回 ⇒ 脚本以为"collabd 退出了"⇒ 每几秒就重拉
|
||||
# ⇒ **叠出一堆重复常驻**。⇒ 用 `Start-Process -Wait`(真阻塞)。
|
||||
# ③ **存活判据=心跳,不是退出码**:collabd 发现有活的常驻时会**故意 exit 0**(幂等),
|
||||
# 那个 0 退出**绝不能**触发重拉风暴。
|
||||
# ④ UTF-8 **带 BOM**(⛔ 不带 ⇒ PowerShell 5.1 按 ANSI/GBK 解码 ⇒ CJK 路径被毁
|
||||
# ⇒ 任务一秒内 Result=1 退出)。
|
||||
|
||||
$ErrorActionPreference = "Continue"
|
||||
|
||||
$env:CODEBUDDY_CONFIG_DIR = "__CFGDIR__"
|
||||
$env:COLLABD_CONFIG = "__COLLABDCFG__"
|
||||
$env:PYTHONIOENCODING = "utf-8"
|
||||
$env:PYTHONUNBUFFERED = "1" # stdout 重定向到文件,Python 会块缓冲 ⇒ 不设它诊断全压在 4KB 之后
|
||||
|
||||
$root = "__WS__"
|
||||
$pyw = "__PYW__"
|
||||
$script = "__SCRIPT__"
|
||||
$hbPath = "__HBPATH__"
|
||||
$logPath = "__LOG__"
|
||||
$stampPath = "__STAMP__"
|
||||
# 🔴 停止标志:机制侧 `--set-life 已完成` ⇒ 写它 ⇒ 常驻优雅退出。
|
||||
# ⚠️ 改前缺陷:keeper 不知道它 ⇒ 目标收口后**每 60 秒重拉一次、每次秒退**
|
||||
# (实测**空转 370 次/6 小时**)⇒ "完成即收工"只做到"停掉常驻",
|
||||
# ⛔ **没做到"别再拉它起来"** —— 那是同一件事的两半。
|
||||
$stopFlag = "__STOPFLAG__"
|
||||
|
||||
$staleSec = 90 # 与 collabd.supervise_alive() 同一陈旧阈值
|
||||
Set-Location $root
|
||||
|
||||
function Say([string]$m) {
|
||||
$ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
|
||||
Add-Content -LiteralPath $logPath -Value ("[" + $ts + "] " + $m) -Encoding UTF8
|
||||
}
|
||||
|
||||
function Get-HbAge {
|
||||
try {
|
||||
if (-not (Test-Path -LiteralPath $hbPath)) { return -1 }
|
||||
$raw = Get-Content -LiteralPath $hbPath -Raw -Encoding UTF8
|
||||
if (-not $raw) { return -1 }
|
||||
$ts = [double](($raw | ConvertFrom-Json).ts)
|
||||
if ($ts -le 0) { return -1 }
|
||||
return [int]((Get-Date).ToString("U") - $ts)
|
||||
} catch { return -1 }
|
||||
}
|
||||
|
||||
function Wait-HeartbeatFresh([int]$maxWait) {
|
||||
$waited = 0
|
||||
while ($waited -lt $maxWait) {
|
||||
$age = Get-HbAge
|
||||
if ($age -ge 0 -and $age -lt $staleSec) {
|
||||
Say ("another supervisor is alive (heartbeat " + $age + "s old) => standing down")
|
||||
return $true
|
||||
}
|
||||
Start-Sleep -Seconds 5
|
||||
$waited += 5
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
Say ("keeper up. keeper_pid=" + $PID + " script=" + $script)
|
||||
|
||||
$backoff = 5
|
||||
while ($true) {
|
||||
# ① 循环开头:目标已完成 ⇒ 收工,不再重拉
|
||||
if (Test-Path -LiteralPath $stopFlag) {
|
||||
Say "guard.stop present => target finished; keeper stands down (no more respawn)"
|
||||
exit 0
|
||||
}
|
||||
$ageBefore = Get-HbAge
|
||||
if ($ageBefore -ge 0 -and $ageBefore -lt $staleSec) {
|
||||
if (Wait-HeartbeatFresh 300) { continue }
|
||||
}
|
||||
|
||||
Say ("spawn collabd --supervise (backoff=" + $backoff + "s)")
|
||||
$outLog = "__OUTLOG__"
|
||||
$errLog = "__ERRLOG__"
|
||||
try {
|
||||
# -Wait 给的是**真阻塞**(`&` 给不了 GUI 子系统程序);-Redirect* 让证据落盘
|
||||
$proc = Start-Process -FilePath $pyw `
|
||||
-ArgumentList @("-u", $script, "--supervise") `
|
||||
-WorkingDirectory $root `
|
||||
-WindowStyle Hidden `
|
||||
-RedirectStandardOutput $outLog `
|
||||
-RedirectStandardError $errLog `
|
||||
-PassThru -Wait
|
||||
$code = $proc.ExitCode
|
||||
} catch {
|
||||
Say ("spawn threw: " + $_.Exception.Message + " => retry in " + $backoff + "s")
|
||||
Start-Sleep -Seconds $backoff
|
||||
if ($backoff -lt 60) { $backoff = [Math]::Min(60, $backoff * 2) }
|
||||
continue
|
||||
}
|
||||
|
||||
$ageAfter = Get-HbAge
|
||||
if ($ageAfter -ge 0 -and $ageAfter -lt $staleSec) {
|
||||
$verdict = "heartbeat still fresh (" + $ageAfter + "s) => idle exit, no respawn yet"
|
||||
} elseif ($ageAfter -ge 0) {
|
||||
$verdict = "heartbeat stale (" + $ageAfter + "s) => supervisor really died"
|
||||
} else {
|
||||
$verdict = "heartbeat unreadable"
|
||||
}
|
||||
Say ("collabd exited (exit=" + $code + ", " + $verdict + ")")
|
||||
Set-Content -LiteralPath $stampPath -Value ((Get-Date).ToString("yyyy-MM-dd HH:mm:ss")) -Encoding UTF8
|
||||
|
||||
# ② 退避**期间**标志可能出现 ⇒ 别再睡满一轮(⛔ 漏这里 ⇒ 收工后还会多拉一次)
|
||||
$waitLeft = $backoff
|
||||
while ($waitLeft -gt 0) {
|
||||
if (Test-Path -LiteralPath $stopFlag) {
|
||||
Say "guard.stop appeared during backoff => keeper stands down early"
|
||||
exit 0
|
||||
}
|
||||
Start-Sleep -Seconds 5
|
||||
$waitLeft -= 5
|
||||
}
|
||||
if ($backoff -lt 60) { $backoff = [Math]::Min(60, $backoff * 2) }
|
||||
}
|
||||
@@ -609,6 +609,8 @@ def manifest_files() -> list[Path]:
|
||||
continue
|
||||
if p.suffix in (".pyc", ".pyo") or rel.startswith("tmp/") or "/tmp/" in rel:
|
||||
continue
|
||||
if rel.startswith("logs/"): # 🔴 2026-10-06 补:运行日志(钩子/探针自己写的)⛔ 不入表 ——
|
||||
continue # 否则跑一次钩子 md5 就变 ⇒ 表立刻"过期"(同 MANIFEST_SKIP 的口径)
|
||||
keep.append(p)
|
||||
return sorted(keep, key=lambda q: q.relative_to(PKG).as_posix())
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"hookSpecificOutput": {"hookEventName": "SessionStart", "additionalContext": "【决策判据 · 常驻(违反即事故;正本 references/04-决策方法论.md)】\n遇到“要不要做/怎么做/能不能先凑合”这类判断,先过下面这几条:\n\n🔴 **目标不打折,路径取最小代价**(U27 + A6)\n 发现问题默认目标是**解决**。下面三种**都不算解决**,⛔ 不许当成交付:\n ① **降级目标**(把“要做到 A”悄悄改成“做到 A′ 也行”)\n ② **延期**(“下次顺手再说 / 等窗口再补”)\n ③ **静默兜底**(“先这样也能跑”,而风险与触发条件一个字没写)\n ⚠️ 唯一允许“暂时接受”=**客观不可逾越**,且必须写清三项:\n 卡在哪(证据)/当前已做到哪一步/什么条件一出现就必须回头解决。\n ⚠️ A6 的“最小代价”只约束**路径**,⛔ 不许读成“可以降低目标”。\n\n🔴 **先取证,再结论**(A1)\n ⛔ 不许拿文档/记忆/推断当既成事实。层级:`L1 文档说` < `L2 文件在` < `L3 本机实测`\n < `L4 真机/生产` < `L5 用户原话`;**冲突以高层级为准**,⛔ 不许用低层级否定高层级。\n ⛔ **不许把“我猜的”写成“事实”** —— 尤其“疑似是我刚才改坏的”:先 diff 备份再说。\n\n🔴 **不懂就问,但先自己查到位**(A2/A3 + 功能优先协议)\n · **技术实现**(框架/库/文件组织/命名/测试/性能/部署/目录结构/错误处理)\n ⇒ **自己定**,作为陈述句写进回复(“我选了什么,可推翻”),⛔ 不做成选项让用户选。\n · **只准提报用户三类**:① 功能语义分叉(用户能感知的差别)② 红线门禁\n ③ 超出决策方法边界。**必须问** ≠ 把技术方案捆进去问。\n · 提报时把技术话翻成**功能话**(“影响谁、断多久、花多少钱”),\n ⛔ 不写包名/环境变量/文件路径/代码标识符。一轮只问一个问题。\n\n🔴 **删/改/迁移先判代价对称性**(A8/A14/A16/A22)\n 删除收益 < 潜在破坏 ⇒ **标注废弃保留**,⛔ 不删。改名/迁移先列**伴随物清单**\n (只改主体必留隐患)。替换/退役:**先补位,再退役**。\n ⛔ 删任何东西之前先扫引用(“看起来像资料” ≠ “没被引用”)。\n\n🔴 **本机改完 ≠ 交付**(A25/A19/A18)\n 宣布完成前先画出**改动层 → 生效链路**:改了哪个文件、谁读它、什么时候生效。\n ⛔ **静默失败会伪造结论**(工具静默 + 降级静默,两头都要防)。\n ⛔ **只看回显不算验收** —— 落到**进程级/文件级证据**(pid / argv0 / 心跳 / 增量字节)。\n\n🔴 **不确定就说不确定**(A11/A15/A10)\n 未验证的能力显式抛 `unsupported`,⛔ 不假装支持;写状态必须带**三态 + 级别**,\n ⛔ 不用“支持/可用”描述没验过的项;失败面**必须留证据**,⛔ 不吞错误。\n\n📂 完整判据(U1–U28 用户决策 · A1–A25 AI 推理 · X1–X13 反例)\n ⇒ 本技能包内 `references/04-决策方法论.md`(+ `dsh-decision-method/` 三份素材库);\n 决策与“问不问”的完整裁决 ⇒ 本包 `references/02-功能优先协作协议.md`。\n"}}
|
||||
@@ -115,12 +115,34 @@
|
||||
**不中断在线用户的上线**(传产物 / 换 profile 包 / 改静态页 / 候选池投放)**属边界内的执行细节 ⇒ 做完即上线,自决策**。详见本包 `references/04-决策方法论.md` **U20 / X9**。
|
||||
- 🔑 **"平台级" ≠ "别人的"**(2026-09-16 收口):`dshs*`·`dsh-*` systemd 单元、`/var/lib/dshs/**`、nginx·nft、端口,**在我们自己的 47 / 106 / 本工作区上 ⇒ 本平台自己的资源 ⇒ 直接做**。只有**别人的 / 归属不明**的才"只报告不动手"。**判据看"归属",不看"是不是平台组件"。**
|
||||
|
||||
### 3.3 提报用户格式(**强制**) → **本档 §3.3 即权威**(下方即全表)
|
||||
**🔀 规则冲突裁决顺序**(同一对象被多条规则给出相反结论时,取**首个命中项**,⛔ 不"自行取保守侧"):
|
||||
① **开发 / 自用环境的放开条款** → ② **边界内自决策清单**(§2)→ ③ **其余红线**(扩大权限 / 批量写入 / 锁 / uid —— 这几条**永远是硬约束**,不参与裁决)。
|
||||
|
||||
> **完整对照表已收敛到通用技能**。**最小摘要**(3 条铁律):
|
||||
> ① **提报给用户时不出现**包名 / 环境变量 / 文件路径 / commit / API 路径 / 代码标识符 —— 出现即是没转换。
|
||||
> ② 翻译方向 = **从"技术选项"翻成"用户能感知的差别"**。例:不问「要不要启用 `enablePatch`」,而问「要让用户**自己装插件**,还是只由管理员统一装?」
|
||||
> ③ **一轮最多一个问题**,且**同类不连问两次**。
|
||||
⛔ **冲突 ≠ 门禁**:两条规则打架**不构成**提报用户理由;真门禁**只有** §3.2 那三类 + §3.4 八类。
|
||||
|
||||
> 📌 上面这段 2026-10-07 由原 `references/作业规矩/01-协作与提报用户判据.md §2` 并入(该档已删 ⇒ 判据只此一处)。
|
||||
|
||||
### 3.3 提报用户格式(**强制**) → **本档 §3.3 即权威**(下方含完整对照表)
|
||||
|
||||
**三条铁律**:
|
||||
|
||||
① **提报给用户时不出现**包名 / 环境变量 / 文件路径 / commit / API 路径 / 代码标识符 —— 出现即是没转换。
|
||||
② 翻译方向 = **从"技术选项"翻成"用户能感知的差别"** —— 完整对照表见下。
|
||||
③ **一轮最多一个问题**,且**同类不连问两次**。
|
||||
|
||||
**完整对照表**:
|
||||
|
||||
| ❌ 技术语言(禁止) | ✅ 用户能感知的语言(必须) |
|
||||
|---|---|
|
||||
| 「要不要启用 `enablePatch`?」 | 「要不要让用户**自己装插件**,还是只由管理员统一装?」 |
|
||||
| 「某环境变量设成哪个档位?」 | 「AI 在你的会话里**能不能直接执行命令**,还是每次都问你一遍?」 |
|
||||
| 「新会话 vs 改写存量会话事件」 | 「**新开一个会话**就好,还是要我去改你**已有的**会话设置(改完你正在用的会话会变)」 |
|
||||
| 「限堆 / 内存上限降到 X」 | 「每个用户能用的内存**小一点更安全**,但用户跑大任务时余地也小一点」 |
|
||||
| 「插件走内投技能还是平台共享技能层」 | 「技能**跟着插件一起装**,还是**单独管理**?」 |
|
||||
|
||||
> **规则**:提报用户时**不允许出现**包名、环境变量、文件路径、commit、API 路径、代码标识符。出现即是没转换。
|
||||
> 📌 本表 2026-10-07 由原 `references/作业规矩/01 §3` 并入(原处写着"完整对照表已收敛到通用技能",
|
||||
> 而那个技能已并包删除 ⇒ 该指针**曾悬空**;现已把表放回本档,⛔ 不再外指)。
|
||||
|
||||
### 3.4 (c) 超出决策方法边界的事 —— **必须问**(用户 2026-09-12 明确)
|
||||
|
||||
@@ -266,7 +288,7 @@ AI 交付时**先说功能,技术细节折叠在后**:
|
||||
> 第 3 段是这条协议的关键:**把"事前请示"改成"事后可推翻"** —— 用户获得了知情权与推翻权,但不需要在读之前做判断。
|
||||
---
|
||||
|
||||
### 5.3 五条铁律(都来自本工作区的真实失手)
|
||||
### 5.3 六条铁律(都来自本工作区的真实失手)
|
||||
|
||||
| # | 铁律 | 反例(实证) |
|
||||
|---|---|---|
|
||||
@@ -276,6 +298,19 @@ AI 交付时**先说功能,技术细节折叠在后**:
|
||||
| 4 | **能自决策的继续做;不能自决策的收到最后一节** —— 能按决策方法自决策 ⇒ **自决策 + 继续处理**(不为"要不要继续"而停);不能自决策(真门禁 / 需凭据·窗口)⇒ **收进整条回复的最后一节,按有序段落逐条编号**(每条 = 问题 + 选项**优缺点** + 我的倾向),⛔ 不许夹在中间,也不许散在正文里问 | 2026-09-15 用户原话:「**能根据决策方法 自行决策的就自决策继续处理,不能决策的问题和需确认内容放在回复的最后,按照有序段落展示**」—— 待拍板项夹在「进度 + 下一步」之间 ⇒ 用户扫不到、漏答 |
|
||||
| 5 | **提报给用户前先过「取舍筛」**:把候选各写 **优点 + 缺点** —— ① 某个**只有优点**(明显更优)或**只有缺点** ⇒ **不需要用户判断**,自己拍掉再陈述;② 只有**各有优有劣、客观标准分不出高下**(真取舍)才提报用户;③ 提报给用户时**必须逐项列出优点与缺点**(只写"差别在哪"不算);④ 候选**竖排成段**(A / B / C 各占一行),⛔ 不横排、不做成表格的列 | 2026-09-15 用户原话两段:「**需要我确认的方案需要说明优点和缺点,现在没法判断,假如只有优点或只有缺点那不需要我判断**」+「**每个需要我决策的问题的潜在解决方案 A B C 也按照段落式排版,别横着排列**」—— 此前只写"可感知差别"且**横排**,用户**没法判断** |
|
||||
|
||||
| 6 | **要解决问题,不是将就妥协** —— 面对风险 / 缺陷**默认目标是解决**;**降级目标 / 延期 / 静默兜底**三种**都不算解决**。只有**客观不可逾越**(技术不可行 / 上游未支持 / 需用户给凭据或窗口)才允许"暂时接受",且必须写明 ① 卡在哪(证据)② 已做到哪一步 ③ **什么条件一出现必须回头解决**。⚠️ 与"最小代价路径"不矛盾:**目标不打折,路径取最小代价** | 用户原话:「**要的是解决问题,不是将就妥协 / 我不要得过且过**」—— 「先这样吧 / 后续再优化 / 我加个兜底」三种都是把目标打折(同族:P0-93「拿兜底当修复」) |
|
||||
|
||||
> 📌 第 6 条 2026-10-07 由原 `references/作业规矩/01 §8`(六条铁律)并入(该档已删)。
|
||||
|
||||
**铁律 6 的配套硬红线 —— 只做正向迭代**(原 `01 §8.1`):**判据=这个改动是否让项目「任一维度」净变差** —— 目标 / 方向 / 架构 / 功能 / 性能 / 安全 / 交互 / UI / 便利性 / 扩展性?
|
||||
|
||||
命中 ⇒ **立即停下复盘**(⛔ 不许"先做着看"、不许将就):
|
||||
1、写清**劣化在哪一维、代价多大**(证据 / 量级);
|
||||
2、找出**能保住正向收益的做法**(改小范围 / 换实现 / 分阶段);
|
||||
3、**拿不出正向做法 ⇒ 立即停止、不再执行,只报告**。
|
||||
|
||||
⛔ **三种伪装禁止**:把劣化说成"必要代价"/用"后续再优化"掩盖已知劣化/把劣化项藏进交付不写。
|
||||
|
||||
> **自己失误的交代**:只在两种情况下写 —— ① 它**改变了结论**(例:某次改动引入了新问题);② 用户**问根因**。否则放最后一节一行,或先不提。
|
||||
|
||||
---
|
||||
@@ -302,6 +337,27 @@ AI 交付时**先说功能,技术细节折叠在后**:
|
||||
**待用户拍板项**:位置 = **最后一节**|形态 = **逐条编号**|语气 = **陈述句**。
|
||||
**去 AI 味**(说话像人):**本档 §5.3** —— 删填充词、破公式、变节奏、信任读者、删金句。
|
||||
|
||||
### 5.5 提报前必答三问 + 回话前自检(2026-10-07 由原 `references/作业规矩/01 §4.1/§5` 并入)
|
||||
|
||||
**提报给用户前必答三问**(任一条足以自决策,**全答"否"才允许提报用户**):
|
||||
|
||||
1、对象是**我们自己的资源**吗?→ 是 ⇒ 自决策。
|
||||
2、我**查证过**关键不确定点了吗(如"还有谁在用")?→ 没查 ⇒ **先查**,⛔ 不许把"不确定"当提报用户理由。
|
||||
3、候选排完序,**第一名是否明显更优**?→ 是 ⇒ 自决策。
|
||||
|
||||
> ⛔ **禁止把"我有倾向"降级成"建议 + 待你拍板"**:候选能排出优劣 ⇒ **直接做完**,并写一句「我选了什么(可推翻)」。
|
||||
|
||||
**发出任何回复前,先查有没有征询句收尾**:「要我…吗 / 是否要我 / 需要我…吗 / 要不要我 / 请确认 / 你看怎么办」。
|
||||
|
||||
🔴 **这条自检不能省,钩子替不了它**:拦截类钩子通常只能拦「提问工具」调用,而**真实的提报用户大多发生在正文里**
|
||||
(实测某工作区日志的提问工具调用数 `43 → 3 → 0 → 0`,因为大家改用正文提问了)⇒ **钩子拦不到正文里的征询句**。
|
||||
|
||||
命中征询句 ⇒ **重判三问**:
|
||||
|
||||
1、命中**真门禁**吗(不可逆破坏性操作 / §3.4 八类)?**没命中 ⇒ 删掉这句,自己做完,改成陈述句**。
|
||||
2、我是不是在**把已经定下来的事再问一遍**?是 ⇒ 删。
|
||||
3、要问的这件事,**候选之间是「真取舍」吗**?**只有优点 / 只有缺点 ⇒ 自己拍掉**;真取舍 ⇒ 才允许问,且**一轮只问这一句**、**逐项写优缺点**。
|
||||
|
||||
## 6. AI 自检清单(每次动手前 / 交付前)
|
||||
|
||||
**动手前**
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
> **两个消费者(都在本包内)**:
|
||||
> ① 钩子 `scripts/hooks/reply-style-guard.py` —— **每轮现读本块**注入会话(包内优先,②级回退);
|
||||
> ② 注入器 `scripts/apply-reply-rules.py` —— 把它写进**各环境的规则文件**(`CODEBUDDY.md` / `AGENTS.md`)。
|
||||
> 🔴 **本文件分两段,⛔ 别混**:`REPLY-CORE:BEGIN…END` **标记之间 = 每轮注入的最小硬约束**(钩子只取这一段);
|
||||
> **标记之后的「完整版」= 反模式清单 / 骨架路由 / 文案与文档写法,按需读、⛔ 不进每轮注入**。
|
||||
> ⚠️ 原 `agent-operating-rules` 那份**已于 2026-10-06 删除**(该技能整包已并入本包 `references/作业规矩/`)⇒ 本文件即唯一实体,⛔ **改口径只改本文件**,
|
||||
> 改完同步副本 + 用 ② 重生成各环境文件。
|
||||
> ⛔ **不要在本文件之外再抄一份规则文本** —— 抄了就成第二真相源,两边必然漂。
|
||||
@@ -31,3 +33,48 @@
|
||||
- ⛔ **不用征询句收尾**(「要我…吗/请确认/你看怎么办」);能自决策的直接做完,只留一句"我选了什么(可推翻)"。
|
||||
- ⚠️ 若**本工作区另有更新的定稿**(环境文件里有更细的排版节)⇒ **以那份为准**,本块是通用形态。
|
||||
<!-- REPLY-CORE:END -->
|
||||
|
||||
---
|
||||
|
||||
## 完整版(⛔ 不在每轮注入里 · 按需读)
|
||||
|
||||
> 📌 **2026-10-07 由原 `references/作业规矩/01-协作与提报用户判据.md §6` 并入**(该档已删 ⇒ **排版只此一处**,⛔ 不再有第二份)。
|
||||
> 本节是上面那块**每轮硬约束**的展开:块里是"必须满足什么",这里是"常见怎么违反 + 骨架怎么套"。
|
||||
|
||||
### 按回答类型套现成骨架(**不新造**)
|
||||
|
||||
| 回答类型 | 用哪个骨架 |
|
||||
|---|---|
|
||||
| 执行信息(做了什么 / 结果如何) | 本包 `references/02-功能优先协作协议.md` **§5.2 交付回执** |
|
||||
| 是否已实现 / 能不能 / 为什么不行 | 同上 **§5.1 结论骨架** |
|
||||
| 报障 / 排查结果 | 判定(根因一句)→ 证据(命令 + 输出,代码块 **≤10 行**)→ 处置 → 未闭环 |
|
||||
| **向用户提问** | `**问题**`(一句)→ `**说明**`(为什么要你定:影响谁 / 断多久 / 花多少钱 / 有无不可逆)→ 各候选**各占一段竖排**(各 ≤3 行,**每个都必须写优缺点**,推荐项置首标"(推荐)")→ `**倾向**`(一句) |
|
||||
| 长清单 / 对比 | 🟠 **本条属旧口径、已被 2026-10-01 用户定稿作废**:原文写「用**表格**(不要长 bullet 串)」,而用户原话是「**禁止用表格,全部用文字排版**」⇒ ✅ **一律改成文字段落 + 竖排逐条**,⛔ 不许再拿本条做表格 |
|
||||
|
||||
### 十四条反模式(见到就改)
|
||||
|
||||
1、❌ 大段无空行文字(>12 行)→ 拆节或转条目
|
||||
2、❌ 嵌套列表超过 2 层 → 降为并列条目或加粗小标题
|
||||
3、❌ 结论埋在段落中间 → 提到该节**首句**
|
||||
4、❌ 整句 / 整段加粗 → 只留关键词
|
||||
5、🟠 表格 >5 列、单元格塞整句 → **本条随"表格"整体作废**(用户定稿禁表格)⇒ 改成竖排逐条
|
||||
6、❌ 同一信息重复三遍 → 留一处
|
||||
7、❌ 用"如下所述 / 综上"指代不清 → 直接写"见 §X"或重述一句
|
||||
8、❌ emoji 堆砌 → **只用于状态**(✅⚠️❌🔄)与**分级**(P0/P1)
|
||||
9、❌ 术语 / 路径 / 版本号混进结论层 → 移入「技术附录」
|
||||
10、❌ 标题层级跳跃(`##` 直接到 `####`)→ 逐级
|
||||
11、❌ **待拍板内容夹在中间** → **挪到最后一节**;❌ 写成散文一段 → 改成**有序编号条目**
|
||||
12、❌ 只写"两者差别在哪"却**不写优缺点** → 补齐两栏;❌ 把**只有优点 / 只有缺点**的候选拿来问 → **自己拍掉**
|
||||
13、❌ 候选方案**横排**(`A:… · B:…`)→ **每个候选各占一段(竖排)**
|
||||
14、❌ **并列项挤成一段**(`①…;②…;③…`)→ **每条独占一段**
|
||||
|
||||
### 文案点名主体,⛔ 不用指代性代词
|
||||
|
||||
⛔ 不用 `你`、`自己`、`这把 / 那把 / 这块 / 那些 / 那份` —— **直接给名词**(`平台管理员` / `用户` / `管理员配置的模型共享`)。
|
||||
**判据** = **这一个分句单独摘出来,能不能答出"谁做的、说的是什么"**。
|
||||
⚠️ 例外:命令行占位符(`--email [email protected]`)是字面值,不动。
|
||||
|
||||
### 说明文档要「直入主题」
|
||||
|
||||
⛔ 不写「重点不在 X,而在 Y」这类**先否定再转折**的绕弯开场。
|
||||
**判据**:**第一句能不能单独看懂"这是什么、解决什么"**;凡是需要靠对比才读得懂的写法,一律改写成陈述句。
|
||||
@@ -1,13 +1,13 @@
|
||||
# manifest · 包内文件清单
|
||||
|
||||
> 生成方式:逐文件 `compile()` / `json.loads` + md5 | **最近一次全量重算:2026-10-06 22:35 (P0-74 二次收口:任务名统一 + `init_workspace.py` 旁路清除 + 删 `assets/start-supervise.ps1.tpl`)**
|
||||
> 生成方式:逐文件 `compile()` / `json.loads` + md5 | **最近一次全量重算:2026-10-07 00:32 (P0-74 二次收口:任务名统一 collabd-keepalive-* / init_workspace 旁路清除 / 删 assets/start-supervise.ps1.tpl / 守形态探针扩到全族)**
|
||||
> ⚠️ **2026-10-05 局部增量**:`references/pitfalls.md`(P0-77 拆条 + P0-73/P0-77 压缩)与
|
||||
> `scripts/goalctl.py`(`--switch-goal` 确认闸 + 旧目标归档)两行的 md5/大小已按当天实测值更新;**其余行仍是 10-04 基线**。
|
||||
> ⛔ 本表**不含** `install.log`(运行日志)与 `references/manifest.md`(自引用,写完即失真)。
|
||||
> ⚠️ **provenance 列里的 `skills/multi-session-collab/…`、`skills/workbuddy-session-forensics/…` 已是历史路径**
|
||||
> —— 那两个目录 2026-10-01 已移到 `<工作区>/归档/技能-退役-20261001/`(⛔ 不在技能根了)。
|
||||
|
||||
文件总数:**55** | 语法 / 结构检查失败:**0**
|
||||
文件总数:**66** | 语法 / 结构检查失败:**0**
|
||||
|
||||
## ✅ 已完成 · 2026-10-05 「目标唯一性 + 换目标需确认」(用户口径落地)
|
||||
|
||||
@@ -113,27 +113,36 @@
|
||||
|
||||
| 包内路径 | 字节 | md5 | 语法检查 |
|
||||
|---|---|---|---|
|
||||
| `SKILL.md` | 110832 | `25aefce4ad7402c216ad7784ebed7b92` | — |
|
||||
| `SKILL.md` | 113195 | `bceb71f9bcc3c3443754642767c5ab62` | — |
|
||||
| `assets/board-launch.py.tpl` | 4355 | `7e9dfe1c4845f20dbb89f599d80e167b` | — |
|
||||
| `assets/board-render-probe.js` | 14398 | `a21bd1905b34537436ce778c6bfbc288` | — |
|
||||
| `assets/board.html` | 151811 | `c597cd7f21543542e9cdbe486c5ccd79` | — |
|
||||
| `assets/design-tokens.css` | 6364 | `0668feb3a4729f1022e579ac0c5d2569` | — |
|
||||
| `install.py` | 33311 | `ee11283cbcdbb4f821f021e86cff4498` | ok |
|
||||
| `install.py` | 37297 | `55603c2e739e7b531998f5563f15f789` | ok |
|
||||
| `references/00-动手前必过.md` | 7181 | `33bc86e442ccd4fcbb930c79c4ad0641` | — |
|
||||
| `references/01-文档索引.md` | 3604 | `825999a411e2a4f6b740063f81c01b03` | — |
|
||||
| `references/02-功能优先协作协议.md` | 30502 | `e241742b41cb25ff7d1b6447b9ee623e` | — |
|
||||
| `references/03-回复排版-核心块.md` | 2187 | `201e7f112ee432b89e38f82f49301966` | — |
|
||||
| `references/02-功能优先协作协议.md` | 35529 | `9122a6715bde02ab549805d69866d1cf` | — |
|
||||
| `references/03-回复排版-核心块.md` | 7538 | `1b34438e21db640d17b97a4a2522a249` | — |
|
||||
| `references/04-决策方法论.md` | 35566 | `eb5bdf8f100beb8eacb9f20b042df86c` | — |
|
||||
| `references/99-速查清单.md` | 9832 | `5c97728af7cb67e9be9a3e491bdc5fd9` | — |
|
||||
| `references/architecture.md` | 119622 | `d7f0990daeb4cd7d2d262646f67b8ffd` | — |
|
||||
| `references/collab-detail.md` | 98760 | `7b843b0072d8da8abe0a162a44a96eb7` | — |
|
||||
| `references/architecture.md` | 119631 | `5fc3b103bb846b6dd903df0b7e736d22` | — |
|
||||
| `references/collab-detail.md` | 98805 | `24bd0cfd10da66831f5d12f1716b7ebc` | — |
|
||||
| `references/collab.md` | 16560 | `97aa751f86d9b4ba8db401b5ec592695` | — |
|
||||
| `references/deploy.md` | 16754 | `4e382f7876f31754ec9629925340c2d8` | — |
|
||||
| `references/dsh-decision-method/素材库-A-AI推理.md` | 19914 | `89fc178e671c989d9079c1def20591da` | — |
|
||||
| `references/dsh-decision-method/素材库-U-用户决策.md` | 24597 | `94c9e860148f4265f1e21e5322346f94` | — |
|
||||
| `references/dsh-decision-method/素材库-反例-X.md` | 5712 | `8bce93e8c1ce71d17e6d33aa9a2d7724` | — |
|
||||
| `references/forensics.md` | 6067 | `1fb6deca9bb05bebe950d4f4e3adf043` | — |
|
||||
| `references/pitfalls.md` | 281757 | `8e3c654a8ea824da2a066726305accde` | — |
|
||||
| `references/pitfalls.md` | 311254 | `d321a71e38dd246b8014b4c9100b12c7` | — |
|
||||
| `references/rules.md` | 8106 | `95af3566066d27c3c224ce681a82efc1` | — |
|
||||
| `references/supervise-persistence.md` | 27698 | `2e7ba3d89146881eb9a7ec5d2ada891b` | — |
|
||||
| `references/supervise-persistence.md` | 34394 | `95c5c7b75acf8c2240eec7d267a51ded` | — |
|
||||
| `references/taskgraph.md` | 3521 | `be6c6540be86475bb3430688c2987afc` | — |
|
||||
| `references/作业规矩/00-作业总规矩(原 agent-operating-rules).md` | 70243 | `80fc5471015b237ee7aacd6976eda6fe` | — |
|
||||
| `references/作业规矩/02-工作区纪律.md` | 21351 | `1a679fdeb9cca0883a47f619d1aec85d` | — |
|
||||
| `references/作业规矩/03-多棒接力编排.md` | 13048 | `f2452499a8fbaf0a25b3ccba1ef85f5b` | — |
|
||||
| `references/作业规矩/04-去AI味与说话方式.md` | 12179 | `bbae6c68fa1cd9f01f3045b1c6b2cb42` | — |
|
||||
| `roots.env` | 624 | `ec38f15f9a4101d69c815aa2cdd7b477` | — |
|
||||
| `scripts/apply-reply-rules.py` | 7172 | `551b0ee5bf6c7a9f6b64c1b1d53bd343` | ok |
|
||||
| `scripts/board-launch.py` | 2794 | `998a66b9d335ab1863b5b871a527bf4f` | ok |
|
||||
| `scripts/board.py` | 146111 | `d90395d1f1a7c3f94419a33cdf444384` | ok |
|
||||
| `scripts/board_ext.py` | 45655 | `2319fb9d2d21bf961e03a42da9a1ad4b` | ok |
|
||||
@@ -143,15 +152,17 @@
|
||||
| `scripts/deliver-gateway-token.py` | 5685 | `cbba9648d404ecd2683061e19dbdb24a` | ok |
|
||||
| `scripts/deploy_code.py` | 5325 | `a79cf5e5ffb3e8c60a31b4d0d8845f40` | ok |
|
||||
| `scripts/forensics/proc-parent.py` | 2347 | `8cdfff2dbb88303298752c3777da7b20` | ok |
|
||||
| `scripts/goalctl.py` | 47839 | `0e8b1d05003342a9ab474cfbfde5d704` | ok |
|
||||
| `scripts/goalctl.py` | 53820 | `c4eb6c020ac102ca3ae7f0463c5d8051` | ok |
|
||||
| `scripts/guard.py` | 13653 | `43f4e279896090c6c6c3fcbdb4fa95d6` | ok |
|
||||
| `scripts/hooks/_env.py` | 17767 | `7177d04805c607fa155831340267c49b` | ok |
|
||||
| `scripts/hooks/_env.py` | 17743 | `e08f33d97adb640dc1657c21ae59a2ad` | ok |
|
||||
| `scripts/hooks/bash-output-guard.py` | 17741 | `3f2fdfa17f66f7fcac42e06853433a26` | ok |
|
||||
| `scripts/hooks/decision-rules-hook.py` | 12399 | `c521237bada7487aecf5e54ad4d19ace` | ok |
|
||||
| `scripts/hooks/lock-guard-hook.py` | 20363 | `641457de0297ee7a812ccde57f67dc2b` | ok |
|
||||
| `scripts/hooks/reply-style-guard.py` | 10779 | `a05ca0d6ebef2be55a3d6f96a4c712da` | ok |
|
||||
| `scripts/hooks/prompt-guards.py` | 9332 | `0aa1d1fdd2bf5a40cda2e60d7a785534` | ok |
|
||||
| `scripts/hooks/reply-style-guard.py` | 11040 | `7e271b342f91e2e98cbc03631b7e68f3` | ok |
|
||||
| `scripts/hooks/session-log-guard.py` | 24636 | `4dd13b24d541d1afc7b4874dba6bb1eb` | ok |
|
||||
| `scripts/hooks/skill-load-guard.py` | 24261 | `21c3a3f8732698ef3a6f1a5c61aae343` | ok |
|
||||
| `scripts/hooks/stop-dialog-guard.py` | 40247 | `4e5f9889717d4ed37a6384c643b4d05e` | ok |
|
||||
| `scripts/hooks/skill-load-guard.py` | 24390 | `942bf35a6b58a3634d1baa6717a06a5c` | ok |
|
||||
| `scripts/hooks/stop-dialog-guard.py` | 41513 | `50374b192b6eba2bdb257846f06fde90` | ok |
|
||||
| `scripts/hooks/supervise-ensure-hook.py` | 14308 | `dc6f62584a8384baba0a1f2460828013` | ok |
|
||||
| `scripts/hooks/wb-result-hook.py` | 37199 | `2d4f694acd031222bf03b98a859b6e90` | ok |
|
||||
| `scripts/init_workspace.py` | 24042 | `dda53acd24bcc66d509bbdab3ebc0488` | ok |
|
||||
@@ -162,8 +173,8 @@
|
||||
| `scripts/lock/op-lock.sh` | 4690 | `1a31eda3642e23693a65e1519860c744` | — |
|
||||
| `scripts/lock/preflight-lock.sh` | 8673 | `e985ec1cb853fae4c351cd03b171355d` | — |
|
||||
| `scripts/mut_run.py` | 13323 | `3bffc12e1e57d5efc743bac55e584b62` | ok |
|
||||
| `scripts/selftest.py` | 481254 | `eb86a9165b77b63714ce948553088d72` | ok |
|
||||
| `scripts/session-rules-check.py` | 37640 | `552c90b93a051d775299170d5ff49b56` | ok |
|
||||
| `scripts/selftest.py` | 481274 | `995f1ec20fb14bacb10a2c38f114d9e2` | ok |
|
||||
| `scripts/session-rules-check.py` | 44412 | `b2b468992d80421106316eaf451e2477` | ok |
|
||||
| `scripts/stop-collab.py` | 10462 | `d8043bedd23b52b6642aaf7ec8b8c980` | ok |
|
||||
| `scripts/supervise-launch.py` | 2503 | `f416a2f197e5524a8859c1d227ba1d05` | ok |
|
||||
| `scripts/wake-session.py` | 11011 | `32c6038b541249730f322f933ee287c1` | ok |
|
||||
|
||||
@@ -1131,7 +1131,7 @@ os.environ["DSH_COLLAB_WS"] = <TEST_WS>
|
||||
⇒ **一次都没触发过**,界面却显示 ACTIVE。**判"真会触发"要看
|
||||
`schedule_type='recurring'` ∧ `next_run_at` 非空**。
|
||||
|
||||
**三个秒退坑**(详 ⇒ `supervise-persistence.md`):
|
||||
**三个秒退坑**(详 ⇒ `supervise-persistence.md`;⚠️ ③ 随 `.ps1` 形态 2026-10-06 整套废弃,⛔ 仅存历史):
|
||||
① 不设 `CODEBUDDY_CONFIG_DIR` ⇒ 退回读 **0 字节空库** ⇒ `no such table: sessions`
|
||||
⇒ 闸二永久失效 ⇒ **检查会话永远建不出来**(**看着在跑,其实在瞎报**)
|
||||
⇒ ✅ 正解用机制自带配置项 **`host_db`**(它本就优先于环境变量);
|
||||
@@ -1818,8 +1818,10 @@ PID 72088 in_job=True 在作业对象内 ← 🔴 决定性:还在作
|
||||
|
||||
**口径边界(⛔ 别搞反)**:本现象**不是故障**。`supervise-persistence.md` 口径明写:
|
||||
常态=「调用技能完成目标时起后台任务 + 检查程序」,**会话一收工就断,断了自己会补**
|
||||
(实测补起延迟 1~2 分钟)。⭐ **只有「目标做完还要继续跑」才需要计划任务那一层** ——
|
||||
且那层**是可选,⛔ 不许当欠项摊**(用户 2026-10-04 当场订正过)。
|
||||
(实测补起延迟 1~2 分钟)。⭐ **只有「目标做完还要继续跑」才需要计划任务那一层**。
|
||||
🟠 本行原写「那层**是可选,⛔ 不许当欠项摊**」(2026-10-04 订正)——**已被 2026-10-05 用户拍板推翻**:
|
||||
计划任务现在是**既定形态**(`collabd-keepalive-<区>` 每 5 分钟兜底,开关 `collabctl.py on|off`)。
|
||||
⚠️ 两句话不矛盾:**日常不必操心**(机制自己装),但它**是既定形态**,⛔ 不是"可有可无的选项"。
|
||||
|
||||
---
|
||||
|
||||
@@ -2469,8 +2471,8 @@ INBOX = '…\ai1net-dsh-server\tmp\supervise-inbox'
|
||||
PowerShell 是**控制台程序** ⇒ 每次触发都分配 `conhost.exe` ⇒ **闪一下**。
|
||||
- 🔴 **为什么"反复"闪**:该任务触发器 `-AtLogOn` + `RestartCount 999 / RestartInterval 1min`
|
||||
⇒ **起来就不会安静**。
|
||||
- 🔴 **触发链**:宿主钩子 `supervise-ensure-hook.py`(每次 `UserPromptSubmit`)→
|
||||
`collabd.py --ensure` → **就地起失败** → `_escalate_to_keeper()` → 建/启旧任务 → 闪窗。
|
||||
- 🔴 **触发链**:钩子 `supervise-ensure-hook.py`(每次 `UserPromptSubmit`)→ `collabd.py --ensure`
|
||||
→ **就地起失败** → `_escalate_to_keeper()` → 建/启旧任务 → 闪窗。
|
||||
实测日志逐字:`常驻自我供给(计划任务):✅ 已建本区计划任务 collabd-supervise-ai1net-dsh-server`。
|
||||
|
||||
### 三、✅ 修法(收敛成**同一个形态**,⛔ 不留第二套)
|
||||
@@ -2493,50 +2495,38 @@ INBOX = '…\ai1net-dsh-server\tmp\supervise-inbox'
|
||||
|
||||
### 三·补、🔴 2026-10-06 二次收口(第一次只改了动作,没改名字、也没扫旁路)
|
||||
|
||||
**三个漏网**(本轮实测抓到,`selftest` 探针一度只扫 `collabd.py` ⇒ 全都没报警):
|
||||
**三个漏网**(本轮实测抓到;探针当时只扫 `collabd.py` ⇒ 全没报警):
|
||||
|
||||
1、**任务名两套并存** —— 见上面第 3 条的订正。现已统一 `collabd-keepalive-<区>`;
|
||||
触发形态也对齐(`-AtLogOn` → **每 5 分钟重复触发**;去掉 `RestartCount 999/1min` ——
|
||||
每 5 分钟重复本身就提供重拉,每分钟重启是多余抖动)。本区遗留的旧名任务已 `Disable`。
|
||||
2、**`init_workspace.py` 是第二个建任务者** —— 自带 `_register_keeper_task()` + `_keeper_task_state()`,
|
||||
动作写 `powershell.exe -File start-supervise.ps1`、还要铺 `assets/start-supervise.ps1.tpl`、
|
||||
自检里有 `_ps_check()`(验 ps1 语法)。**整份删掉**(含 `--with-keeper` / `--no-task` 两个开关),
|
||||
改为只检查 `supervise-launch.py` 在位并指向唯一入口 `collabctl.py`。
|
||||
⛔ **建任务只许有一处实现** = `collabctl.py`(受 `supervise.switch` 总电闸管辖);
|
||||
自己建就绕过开关,是"第二条起法"。模板文件一并删除。
|
||||
3、**守形态的探针打偏** —— `t_keeper_legacy_ps1_form_gone` 原来只 `read_text("collabd.py")`。
|
||||
✅ 已扩成扫**全族**(`collabd.py` / `init_workspace.py` / `collabctl.py`),并新增两条判据:
|
||||
「**任务名口径唯一**」、「`init_workspace.py` 旧形态死代码已清」。
|
||||
1、**任务名两套并存**(见上条第 3 项订正)⇒ 已统一 `collabd-keepalive-<区>`,
|
||||
触发形态同步对齐(`-AtLogOn` → **每 5 分钟重复触发**;去掉 `RestartCount 999/1min`)。
|
||||
2、**`init_workspace.py` 是第二个建任务者** —— 自带 `_register_keeper_task()`/`_keeper_task_state()`/
|
||||
`_ps_check()`(验 ps1 语法),还铺 `assets/start-supervise.ps1.tpl`。**整份删掉**
|
||||
(含 `--with-keeper`/`--no-task` 开关),改为只检查 `supervise-launch.py` 在位。
|
||||
⛔ **建任务只许有一处实现** = `collabctl.py`(受总电闸 `supervise.switch` 管辖);
|
||||
自己建就绕过开关,就是"第二条起法"。
|
||||
3、**守形态的探针打偏** —— `t_keeper_legacy_ps1_form_gone` 原来只读 `collabd.py`。
|
||||
✅ 已扩成扫**全族**(`collabd.py`/`init_workspace.py`/`collabctl.py`),并新增两条判据:
|
||||
「**任务名口径唯一**」「旧形态死代码已清」。
|
||||
|
||||
⚠️ **探针本身的坑**:新增的"任务名唯一"判据**扫文本**,第一版**误红** ——
|
||||
它命中了 `collabctl.py` 里 `SCHED_TASKS = [...]` 那段(那是**故意**列旧名去禁用的)。
|
||||
⇒ 必须先 `re.sub` 剥掉该块再扫。**这是本项目第三次踩"判据扫到自己的否定句"**
|
||||
(前两次:查"PRD 有没有视觉词"命中免责声明、查"有没有六份旧产出"命中 PRD 里的禁令文本)。
|
||||
|
||||
⚠️ **另一条我自己的操作坑**:用 python 脚本读写 `init_workspace.py` / `collabd.py` 后,
|
||||
行尾从**纯 LF 被转成纯 CRLF**(技能包其余 7 个同族文件都是 LF)—— 已用 `write_bytes` 还原为 LF。
|
||||
⇒ **凡用脚本改技能源码,改完要核行尾**(否则 diff 里整个文件显示为"全改",审不出真改动)。
|
||||
⚠️ **探针自己的坑**:新判据"任务名唯一"**扫文本** ⇒ 第一版**误红**,命中了 `collabctl.py` 里
|
||||
`SCHED_TASKS = [...]`(那是**故意**列旧名去禁用的)⇒ 必修 `re.sub` 剥掉该块再扫。
|
||||
**本项目第三次踩"判据扫到自己的否定句"**(前两次:查 PRD 视觉词命中免责声明、查六份旧产出命中禁令文本)。
|
||||
⚠️ **另一个操作坑**:脚本读写这两个 `.py` 后行尾由**纯 LF 变纯 CRLF**(同族其余 7 个都是 LF)⇒ 已还原。
|
||||
**凡用脚本改技能源码,改完必核行尾**(否则整个文件显示为"全改",审不出真改动)。
|
||||
|
||||
|
||||
### 四、✅ 验收(2026-10-05 12:42 实测)
|
||||
|
||||
- 跑一次 `_escalate_to_keeper()` ⇒ 回读任务动作:
|
||||
```
|
||||
EXE=E:\ProgramData\.workbuddy\binaries\python\versions\3.13.12\pythonw.exe
|
||||
ARG="E:\ProgramData\AIProject\ai1net-dsh-server\.workbuddy\collab\supervise-launch.py"
|
||||
WD=E:\ProgramData\AIProject\ai1net-dsh-server
|
||||
```
|
||||
⇒ **不再是 `powershell.exe`**(grep `New-ScheduledTaskAction -Execute 'powershell.exe'` ⇒ **0 命中**)。
|
||||
- 回读任务动作:`EXE=…\pythonw.exe`/`ARG=…/.workbuddy/collab/supervise-launch.py`/`WD=<工作区根>`
|
||||
⇒ **不再是 `powershell.exe`**(`grep "New-ScheduledTaskAction -Execute 'powershell.exe'"` ⇒ **0 命中**)。
|
||||
- **零 PowerShell 看守残留**:`Get-CimInstance` 筛 `powershell.exe` 且命令行含 `start-superv` ⇒ **空**。
|
||||
- **三常驻全部 `ppid=3924`(调度器)**,且**三个都是启动器形态**:
|
||||
· `48372` `<ai1net>/…/supervise-launch.py`|· `61956` `<vibe>/…/supervise-launch.py`|· `63684` `<技能>/…/board-launch.py`
|
||||
- **三常驻全部 `ppid=3924`(调度器)且都是启动器形态**:`48372` ai1net/`61956` vibe/`63684` 看板
|
||||
⇒ 父链断在调度器 ⟹ **真常驻**;形态统一 ⟹ **不会再长出第二套起法**。
|
||||
|
||||
### 五、⛔ 教训(一句话)
|
||||
### 五、⛔ 教训
|
||||
|
||||
**"改了主路径" ≠ "把旁路也改了"** —— 上一轮把常驻主体收敛成"启动器形态",却漏了这个**自我供给旁路**;
|
||||
它平时不吭声,**只在你最不希望的时候闪你一下**(还带着 `RestartCount 999`)。
|
||||
⇒ **凡"同一种东西有第二条起法",收口时必须 `grep` 全文找一遍**(本次判据 = 全文搜 `New-ScheduledTaskAction` 与 `.ps1`)。
|
||||
**"改了主路径" ≠ "把旁路也改了"** —— 漏掉的那条**自我供给旁路**平时不吭声,专挑你在用时闪一下。
|
||||
⇒ **凡"同一种东西有第二条起法",收口时必须全文搜一遍**(判据=`grep New-ScheduledTaskAction` 与 `\.ps1`)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
# 常驻程序长期在线(Windows)
|
||||
|
||||
> 🔴🔴 **2026-10-06 过期警告 · 读之前必看**
|
||||
> 本档 §一(包装脚本)、§三(铺脚本步骤)等节描述的 **`start-supervise.ps1` 形态已整套废弃**。
|
||||
> 现行形态见 `SKILL.md`「两个启动器」表 + `pitfalls.md` **P0-74**:
|
||||
> **计划任务 → `pythonw.exe` → `supervise-launch.py`**(GUI 子系统 ⇒ 零控制台 ⇒ **不闪窗**)。
|
||||
> ⛔ 凡本档出现 `start-supervise.ps1`、`assets/start-supervise.ps1.tpl`(**该模板已删除**)、
|
||||
> 或 `New-ScheduledTaskAction ... -File` 的段落,**一律按历史留痕读,⛔ 不许照着做**。
|
||||
> ⚠️ 另:本档所说"载体是可选需求、常态用不着计划任务"的**2026-10-04 口径已被推翻** ——
|
||||
> 2026-10-05 用户拍板「**常驻崩了,拉起来这个事儿,你不能也用计划任务起个程序吗?**」
|
||||
> ⇒ 计划任务现在是**既定形态**(每 5 分钟兜底),开关是 `supervise.switch`(`collabctl.py on|off`)。
|
||||
> 📌 **整份重写待办**(本轮只加了本警告块,未重写正文)。
|
||||
|
||||
> 📌 **本档=「想让目标检查程序长期在线」时的可选做法**(2026-10-03 夜里整理)。
|
||||
> 🔴 **注意:常态用不着它** —— 常态是「调用技能完成目标时起后台任务 + 检查程序」,
|
||||
> 那套一直好好在跑(见下面那段口径)。
|
||||
> 证据源=测试3 的复盘 `目标-会话协作测试3-7cd276/S3_常驻启动成功复盘_20261003.md`
|
||||
> + `S4_常驻自愈闭环复盘_20261003.md` + `S5_A6自指修复与目标收口_20261004.md`。
|
||||
> 🔴🔴 **口径(2026-10-04 用户定案,当场订正)**
|
||||
> ✅ **2026-10-06 已按收口后的形态重写完毕**(本档头部原先挂的「📌 整份重写待办」已完成,过期警告块已撤)。
|
||||
>
|
||||
> 用户原话:「**从来没说过什么开机自启,只有调用技能完成目标时启动 后台任务和检查程序**」。
|
||||
> 🔴🔴 **现行形态(照这个做,⛔ 别自己发明)**:
|
||||
> **计划任务 `collabd-keepalive-<区>`(每 5 分钟触发)→ `pythonw.exe` → `supervise-launch.py` → `collabd.py --supervise`**
|
||||
>
|
||||
> ⇒ **常态就是:调用技能完成目标时,起后台任务 + 检查程序。** 这套**一直好好在跑**
|
||||
> (实测本区 pid 19424 从 10-03 17:05 活到现在 **24.7 h**)。
|
||||
> ⇒ ⛔ **「开机自启 / 计划任务 / 载体脚本」不是需求,是本文件后半段自己推演出来的可选项**。
|
||||
> ⛔ **不许**把它当"欠项 / 待办 / 风险"往用户面前摊(本轮就是这么摊错的)。
|
||||
> ⛔ 现行形态里**没有 `.ps1`**,也**没有"守护循环脚本"** —— 复活由「计划任务每 5 分钟重触发」
|
||||
> +「常驻本体幂等(发现已有活常驻就 `exit 0`)」两件一起承担。
|
||||
> 📌 权威同源:`SKILL.md`「常驻机制的真实形态」+ `pitfalls.md` **P0-73**(启动器为什么必须有)
|
||||
> /**P0-74**("两条起法"收口)。
|
||||
> 📌 旧 `.ps1` 形态(2026-10-03 ~ 10-05)的完整留痕在**第四、五节**,⛔ **只当历史读,别照着做**。
|
||||
>
|
||||
> 📌 **本文档怎么读**:
|
||||
> · 只想**把技能用起来** ⇒ **读到「〇」就够了**,后面的装法与本场景无关。
|
||||
> · 只在**明确要"目标做完了程序还得继续跑"**时 ⇒ 才看后面那几节。
|
||||
> · 只想**把技能用起来** ⇒ 读到「〇」就够了(**常态用不着计划任务**)。
|
||||
> · 明确要"**目标做完了程序还得继续跑 / 崩了自己爬起来**" ⇒ 从「一」往下照着做。
|
||||
> · 只想**查历史**("以前那套 ps1 是怎么回事")⇒ 直接跳**第四节**。
|
||||
|
||||
> 📌 **本档来源**(2026-10-03 夜里整理,2026-10-06 重写)。
|
||||
> 证据源=测试3 的复盘 `目标-会话协作测试3-7cd276/S3_常驻启动成功复盘_20261003.md`
|
||||
> + `S4_常驻自愈闭环复盘_20261003.md` + `S5_A6自指修复与目标收口_20261004.md`
|
||||
> + 2026-10-05/06 的 P0-72/P0-73/P0-74 实测。
|
||||
|
||||
|
||||
## 〇、🔴🔴 先分场景:两种"长期"不是一回事
|
||||
@@ -40,9 +32,22 @@
|
||||
| 典型形态 | 用户在 WorkBuddy 里自己开一条 `[主]-…` 会话,盯着它推进 | 排期按点拉起 `[主]-…`(`recurring`,如 `FREQ=HOURLY;INTERVAL=1`) |
|
||||
| 会话寿命 | **随用户何时收工**(可能几分钟,也可能几小时) | 跑完即 `completed`,**与下一跳之间有静默窗** |
|
||||
| 🔴 **对"常驻"的硬要求** | ⛔ **不能靠会话活着** —— 一收工就没人拉 ⇒ **必须脱离会话** | ✅ 会话自己周期性回来 ⇒ 但**每跳之间仍有空窗** ⇒ **同样要脱离会话** |
|
||||
| 唯一合格载体 | **计划任务 + 守护循环**(本文档第三~五节) | 同左(⛔ **排期代替不了载体** —— 排期只是"谁按点喊一次",喊完会话就结束) |
|
||||
| 唯一合格载体 | **计划任务**(第一~三节) | 同左(⛔ **排期代替不了载体** —— 排期只是"谁按点喊一次",喊完会话就结束) |
|
||||
| 怎么验它真活着 | 心跳 `pid` 活 ∧ `ts` 距今 < 90 s + `round` 递增 | 同左,⚠️ **且要静置 ≥ 12 分钟**(⛔ 短观察证明不了事) |
|
||||
| 谁负责"目标完成后关它" | 守护循环见 `guard.stop` 即 `exit 0`(第五节之二) | 同左 —— ⛔ **排期不会帮你关** |
|
||||
| 谁负责"目标完成后关它" | 常驻主循环见 `guard.stop` 即收工(第七节) | 同左 —— ⛔ **排期不会帮你关** |
|
||||
|
||||
### 🔴 常态口径(2026-10-04 用户定案,当场订正)
|
||||
|
||||
> 用户原话:「**从来没说过什么开机自启,只有调用技能完成目标时启动 后台任务和检查程序**」。
|
||||
|
||||
⇒ **常态是:调用技能完成目标时,起后台任务 + 检查程序。** 这套一直好好在跑。
|
||||
⇒ ⛔ **不许**把"没装计划任务"当"欠项 / 待办 / 风险"往用户面前摊(2026-10-03 夜里就是这么摊错的)。
|
||||
|
||||
> 🟠 **本档 2026-10-04 曾据此写过一句「计划任务 / 载体脚本不是需求,是本文档自己推演出来的可选项」**
|
||||
> —— **这句已被 2026-10-05 用户拍板推翻**。
|
||||
> 用户原话:「**常驻崩了,拉起来这个事儿,你不能也用计划任务起个程序吗?**」
|
||||
> ⇒ 计划任务现在是**既定形态**(每 5 分钟兜底),开关是 `supervise.switch`(`collabctl.py on|off`)。
|
||||
> ⚠️ 两句话不矛盾:**日常不必操心**(机制自己装),但它**是既定形态**,⛔ 不是"可有可无的选项"。
|
||||
|
||||
### 🔴 两个都踩过的坑(**与场景无关**,因为根子在载体)
|
||||
|
||||
@@ -50,8 +55,8 @@
|
||||
实测测试3 开工时 pid 69080 已死;本区两个后台任务(`collabd --supervise` 活 842 分钟、
|
||||
`board.py --serve` 活 634 分钟)父链都是
|
||||
`bash → bash → bash → sandbox-cli → WorkBuddy.exe`(**会话树内**),
|
||||
⛔ `.workbuddy/collab/` 里**既无 `.ps1` 也无 keeper** ⇒ **没走本文档这套**。
|
||||
⚠️ **它们现在活着,只因为发起它们的那条会话进程树至今没被回收**
|
||||
⛔ `.workbuddy/collab/` 里**既无载体脚本也无 keeper** ⇒ **没走本档这套**。
|
||||
⚠️ **它们当时活着,只因为发起它们的那条会话进程树至今没被回收**
|
||||
⇒ 「**存活时长 = 发起会话的存活时长**」(测试3 `S4` 第六节原话),
|
||||
**⛔ 不能用它论证"这种起法也能长期"**(该文明确写「这条『反例』**不成立**」)。
|
||||
2. **"排期是 `once` 且已过期"=哑排期** —— 实测 `[主]-会话协作测试3-主会话` 是
|
||||
@@ -59,12 +64,15 @@
|
||||
`last_run_at=None` ⇒ **它一次都没被触发过**,而界面上 `status=ACTIVE` **看起来像在跑**。
|
||||
⚠️ **`status=ACTIVE` ≠ "在跑"**;判"真会触发"要看 `schedule_type='recurring'` ∧ `next_run_at` 非空。
|
||||
|
||||
## 一、为什么必须换载体(⛔ 别再自己发明)
|
||||
|
||||
> 🔴 **「载体」= 那个"负责把常驻程序拉起来、并盯着它别死"的启动脚本。**
|
||||
> 说白了就一件事:**谁来开机就把它叫起来。**
|
||||
> 本文档里它指两样:① 批处理 `start-supervise.ps1` ② 把它挂上开机自启的**计划任务**。
|
||||
> (⚠️ 这个词是内部简写,不在别处用;本节表格用列名「**启动方式**」更直白。)
|
||||
## 一、🔴 现行载体:`pythonw.exe` + 启动器(⛔ 别再自己发明)
|
||||
|
||||
> 🔴 **「载体」= 那个"负责把常驻程序拉起来、并盯着它别死"的东西。**
|
||||
> 说白了就一件事:**谁来把它叫起来。**
|
||||
> 现行答案=**计划任务**;它**每 5 分钟**触发一次,动作是
|
||||
> `pythonw.exe "<区>/.workbuddy/collab/supervise-launch.py"`。
|
||||
|
||||
### 1.1 为什么"计划任务"是唯一合格答案(判据=父链根在谁)
|
||||
|
||||
| 启动方式 | 能不能长期 | 实证 |
|
||||
|---|---|---|
|
||||
@@ -73,18 +81,18 @@
|
||||
| `CREATE_BREAKAWAY_FROM_JOB` | ❌ | **`PermissionError(13,'拒绝访问。')`** —— 本机被作业对象拒绝,**这条路封死** |
|
||||
| `cmd /c start /B` | ❌ | 本机沙箱拦截 |
|
||||
| 排期到点起一次会话 | ❌ | **跑完即退** ⇒ 静默窗内无人(`once` 更糟:可能**永不触发**) |
|
||||
| **计划任务 + 守护循环** | ✅ | **实测 23:16:37 起活到 23:29 仍在跑**,`round` 1→74;死亡后 **5–6 秒**自动恢复 |
|
||||
| **计划任务 + 启动器** | ✅ | 进程根在 `svchost -s Schedule`(任务计划服务)⇒ 与会话树无关;实测 23:16:37 起活到 23:29 仍在跑,`round` 1→74;死亡后 **5–6 秒**自动恢复 |
|
||||
|
||||
⚠️ **本表判据是"父链根在谁",⛔ 不是 `in_job` 标志**(见下方 2026-10-04 深夜实测更正:
|
||||
本机**所有**被起的进程 `in_job` 都是 `Y`,含计划任务起的那个 ⇒ 标志位判不出死活)。
|
||||
⚠️ **本表判据是"父链根在谁",⛔ 不是 `in_job` 标志**:本机**所有**被起的进程 `in_job` 都是 `Y`,
|
||||
含计划任务起的那个 ⇒ **标志位判不出死活**。
|
||||
|
||||
**关键差别=父链根在谁**:计划任务创建的进程**根在 `svchost -s Schedule`(任务计划服务)**
|
||||
⇒ 与 WorkBuddy 会话树**无关** ⇒ 不会被会话回收。
|
||||
**关键差别=父链根在谁**:计划任务创建的进程**根在 `svchost -s Schedule`** ⇒ 与 WorkBuddy
|
||||
会话树**无关** ⇒ 不会被会话回收。
|
||||
|
||||
> 🔴🔴 **2026-10-04 深夜实测更正:⛔ 别再用 `IsProcessInJob` 判死活 —— 本机它对所有进程都返回 `Y`。**
|
||||
>
|
||||
> 起因:vibe 会话用 `proc_chain.py` 看到常驻 `in_job=True` ⇒ 判"它在会话的作业对象里、所以会被回收"。
|
||||
> **结论(「会话树内的会死」)是对的,但引用的判据是错的** —— 我做了三组对照:
|
||||
> **结论(「会话树内的会死」)是对的,但引用的判据是错的** —— 三组对照:
|
||||
>
|
||||
> | 进程 | `in_job` | 实际命运 |
|
||||
> |---|---|---|
|
||||
@@ -103,21 +111,140 @@
|
||||
> 实测:看板 62992 父链 `pythonw→cmd.exe→svchost(3924)→services.exe→wininit.exe` ⇒ 活;
|
||||
> 常驻 63628 父链 `pythonw→71800(已退出)→父已退出` ⇒ 会话回收即死。
|
||||
|
||||
> 🔴🔴 **2026-10-04 补一条实测更正(⛔ 我自己违反过,判据已落 `t_supervise_lifespan_not_invented`)**
|
||||
> 🔴🔴 **2026-10-04 再补一条(判据已落 `t_supervise_lifespan_not_invented`)**
|
||||
> ⛔ **别把「现在活着」当成"这种起法也能长期"**。实测:pid 19424 从 10-03 17:05 活到 10-04 17:15
|
||||
> = **24.2 h / 8695 轮**,而它的**父进程早已退出** ⇒ 它是**孤儿进程**,孤儿化后**不受会话结束影响**。
|
||||
> ⇒ ⚠️ **「会话/工具调用起的活一定活不过当轮」是错的说法**:能不能活取决于**父链还在不在**,
|
||||
> ⛔ **不许凭这个推断编造后果**。要判"还能活多久"=**先验父链 + 读心跳 `started_ts`**。
|
||||
> ✅ 但**开机自启这一层仍然缺**:本机 5 个区都**没有** `start-supervise.ps1`,
|
||||
> 全机只有 1 条计划任务(`collabd-supervise-ws3`)而它指向**不存在的文件** ⇒ 每次触发都失败。
|
||||
|
||||
## 二、装法(照抄,⛔ 别自创参数)
|
||||
### 1.2 🔴🔴 为什么必须夹一个"启动器"(2026-10-05 血的教训 · P0-73)
|
||||
|
||||
### ① 包装脚本 `<工作区>\.workbuddy\collab\start-supervise.ps1`
|
||||
**计划任务的"动作"里没有 env 字段** ⇒ 一切环境变量**只能由启动器在进程内设**。
|
||||
⇒ 动作**⛔ 不许直起 `collabd.py`**,必须经 `<区>/.workbuddy/collab/supervise-launch.py`。
|
||||
直起的后果(实测踩到):任务环境**没有 `CODEBUDDY_CONFIG_DIR`** ⇒ `_wb_db()` 落到
|
||||
`~/.workbuddy/workbuddy.db`(**0 字节空库**)⇒ `_all_sessions_idle()` 每轮报 **`no such table: sessions`**
|
||||
⇒ 闸② 恒判"有会话在跑" ⇒ **检查会话再也不建**(实测日志 36 次读库失败)。
|
||||
⚠️ 为什么有的区没炸:那区 `collabd.config.json` 里 `host_db` **写死了绝对路径**(兜住了)。
|
||||
|
||||
⚠️ **必须是「永不返回的守护循环」版**。⛔ **别写成"跑一次就退"** —— 那样常驻死掉时脚本
|
||||
**两个启动器对称存在,缺一个就静默半瘫**(`scripts/` 下,由 `deploy_code.py` 分发到各区):
|
||||
|
||||
| 启动器 | 服务的程序 | 进程内必须设 | ⛔ 缺了会怎样 |
|
||||
|---|---|---|---|
|
||||
| `supervise-launch.py` | 协作程序(`collabd.py --supervise`) | **`CODEBUDDY_CONFIG_DIR`** + `COLLABD_CONFIG` + `PYTHONIOENCODING` + `PYTHONUNBUFFERED` + 兜 `stdout/stderr` | **检查程序静默失效**(读 0 字节空库 ⇒ `no such table: sessions` ⇒ fail-safe 恒判"有会话"⇒ 再也不建检查会话) |
|
||||
| `board-launch.py` | 看板(`board.py --serve 20099`) | `COLLABD_CONFIG` + `PYTHONIOENCODING` + 兜 `stdout/stderr` | **看板崩溃重启循环**(`已拒跑`)、**20099 从没绑上** |
|
||||
|
||||
**`supervise-launch.py` 的四条实现要点**(见该文件头注,⛔ 别自己另写一份):
|
||||
|
||||
1. **它所在目录即本区 `.workbuddy/collab`** —— `collabd.py`/`collabd.config.json` 都在同目录,**用相对自身定位**(⛔ 别写死 `E:\`);
|
||||
2. `CODEBUDDY_CONFIG_DIR` 用 `setdefault`(宿主 env 优先,兜底才写死);`COLLABD_CONFIG` **必须指向本区**那份配置;
|
||||
3. `pythonw.exe` 下 `sys.stdout/stderr` 可能是 `None` ⇒ **任何 `print` 都会 `AttributeError` 秒退** ⇒ 启动器自己兜到 `logs/_supervise-launch.log`;
|
||||
4. 用 `runpy.run_path(CB, run_name="__main__")`(⛔ **不用 `exec`**)—— `runpy` 会把 `__name__`/`__file__`/`sys.path[0]` 按"真在跑那个脚本"设好;
|
||||
且 `sys.argv` **由启动器自己补 `--supervise`** ⇒ **任务参数里 ⛔ 不要再写**。
|
||||
|
||||
> 🔴 **重构"起法"时,旧起法里的 env 必须逐条搬**(P0-73 就是改成两层形态时**丢了 `CODEBUDDY_CONFIG_DIR` 这一句**)。
|
||||
> 🔴 **启动器里写死最稳**(⛔ 别指望 `roots.env` 兜住各区 —— 它只在技能目录,而各区副本在
|
||||
> `<ws>/.workbuddy/collab/`,`_sm_load_roots()` 向上 4 层**找不到**)。
|
||||
> ⚠️ **变量名坑**:`roots.env` 给的是 **`COLLABD_PROD_CONFIG`**,而 `board.py`/`collabd.py` 读的是
|
||||
> **`COLLABD_CONFIG`** ⇒ 名字对不上 ⇒ `roots.env` **兜不住**。
|
||||
|
||||
|
||||
## 二、装法(⛔ 别自己写 `Register-ScheduledTask`)
|
||||
|
||||
### 2.1 🔴 建任务**只许有一处实现**
|
||||
|
||||
| 处 | 谁 | 说明 |
|
||||
|---|---|---|
|
||||
| ✅ **唯一正门** | `scripts/collabctl.py::ensure_keepalive_tasks()` | 受 `supervise.switch` **总电闸**管辖;`on` / `ensure` 都走它 |
|
||||
| ✅ 自愈旁路(**同形态、同任务名**) | `scripts/collabd.py::_escalate_to_keeper()` | 常驻发现本区没任务时自己补一条 |
|
||||
| ⛔ 已删 | `scripts/init_workspace.py::_register_keeper_task()` | 2026-10-06 整份去掉(含 `--with-keeper`/`--no-task` 开关与 `_ps_check()`)—— 建任务**只许有一处实现**,自己建就绕过了总电闸 |
|
||||
|
||||
⚠️ **两处必须同形态同名** —— 否则自愈起的常驻会被下一次 `off` 当"旧形态"顺手干掉(2026-10-06 实测踩到)。
|
||||
|
||||
### 2.2 🔴 推荐做法:一句话让机制自己装
|
||||
|
||||
```powershell
|
||||
# 开关/盘点一律走这个入口(pythonw 没有 stdout ⇒ 必须 --out 落盘再读)
|
||||
& "<pythonw.exe>" "<技能目录>\scripts\collabctl.py" on --out "E:\tmp\collabctl-on.txt"
|
||||
```
|
||||
|
||||
- `on` ⇒ 建齐保活任务 + 立刻触发 + 开关 `on`;
|
||||
- `off` ⇒ **一键全关**(开关 `off` + 禁用任务 + 杀进程,幂等);
|
||||
- `ensure` ⇒ **幂等收敛**:`on` 就补齐缺失的、`off` 就全停;
|
||||
- 用户可见入口(双击):`会话机制-一键开关.bat`(工作区根 + 桌面各一份)。
|
||||
|
||||
⚠️ **本机一律 `pythonw.exe` 跑**(`python.exe` 是控制台程序 ⇒ **闪黑窗**,用户 2026-10-01 投诉过);
|
||||
而 `pythonw` **没有 stdout** ⇒ **不落盘就完全看不到结果**(判据不可信=没章法)。
|
||||
|
||||
### 2.3 动作/触发器/设置(照抄 `collabctl.py::ensure_keepalive_tasks()`)
|
||||
|
||||
```powershell
|
||||
$a=New-ScheduledTaskAction -Execute '<pythonw.exe>' -Argument '"<区>/.workbuddy/collab/supervise-launch.py"' -WorkingDirectory '<区>'
|
||||
$t=New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5)
|
||||
$s=New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries `
|
||||
-StartWhenAvailable -MultipleInstances IgnoreNew `
|
||||
-ExecutionTimeLimit (New-TimeSpan -Seconds 0) -Hidden
|
||||
$pr=New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive -RunLevel Highest
|
||||
Register-ScheduledTask -TaskName 'collabd-keepalive-<区名>' -Action $a -Trigger $t -Settings $s -Principal $pr -Force
|
||||
```
|
||||
|
||||
| 设置 | 值 | 漏了/写错会怎样 |
|
||||
|---|---|---|
|
||||
| `-Execute` | **`pythonw.exe`** | ⛔ `powershell.exe`/`cmd.exe` 是**控制台程序** ⇒ 每次触发分配 `conhost.exe` ⇒ **闪黑窗**(10-05 事故真因);⛔ `python.exe` 同病 |
|
||||
| `-Argument` | 启动器路径 | ⛔ **不许直起 `collabd.py`**(见 1.2);⚠️ 参数里 ⛔ 别再写 `--supervise`(启动器自己补) |
|
||||
| `-WorkingDirectory` | 🔴 **工作区根**(反斜杠形态) | ⛔ 写成脚本所在目录 ⇒ `load_cfg()` 去找 `<ws>/.workbuddy/collab/.workbuddy/collab/…` ⇒ **找不到** ⇒ `CFG_MISSING` ⇒ `--supervise` 拒跑(实测 `rc=2`、任务侧 `LastTaskResult=1`) |
|
||||
| `-RepetitionInterval` | **5 分钟** | 这就是"复活"的全部来源;⛔ 别改成每分钟 |
|
||||
| `-ExecutionTimeLimit` | `0`(无时限) | `--supervise` 是**长驻**进程,默认 72 h ⇒ 到点被掐死;设 2 分钟 ⇒ 每 2 分钟重建一次=另一种抖动 |
|
||||
| `-MultipleInstances` | `IgnoreNew` | 重复起 ⇒ 双写台账 |
|
||||
| `-Hidden` + `Interactive` + `Highest` | — | 缺 ⇒ 开机/登录后不启动;权限不足 |
|
||||
| 🟠 `-RestartCount 999`/`-RestartInterval 1min` | **已去掉** | 旧写法。**每 5 分钟重复触发本身就提供重拉**;每分钟重启是多余的抖动(P0-74 记过"反复"的成因) |
|
||||
|
||||
### 2.4 ⚠️ 本机两条操作纪律
|
||||
|
||||
1. **⛔ `schtasks.exe` 在本机沙箱被黑名单拦截**(Security Center → Command Security)
|
||||
⇒ **建/查/改/停计划任务全部走 PowerShell 的 `ScheduledTasks` 模块**
|
||||
(`Get-/New-/Set-/Start-/Unregister-ScheduledTask`)+ `Out-File` 落盘再读,
|
||||
⛔ **别指望命令回显**。
|
||||
2. **改"起法"必须两边都改** —— 判据 = `grep -n "New-ScheduledTaskAction"` + `grep -n "\.ps1"`。
|
||||
⚠️ **"改了主路径" ≠ "把旁路也改了"**(2026-10-05 只换动作、没换名字与旁路 ⇒ 2026-10-06 二次收口)。
|
||||
|
||||
|
||||
## 三、🔴 两个仍然有效的坑(现行形态下照样会踩)
|
||||
|
||||
### 坑① 🔴 不设 `CODEBUDDY_CONFIG_DIR` ⇒ 读到 **0 字节空库**
|
||||
|
||||
- 计划任务**不继承**会话的环境变量 ⇒ `_wb_db()` 退回 `Path.home()/.workbuddy/workbuddy.db`
|
||||
(本机那个是 **0 字节、无 `sessions` 表**)。
|
||||
- 症状:每 20 秒刷一次 `all_sessions_idle 读库失败 no such table: sessions`
|
||||
⇒ 闸二(所有会话都结束)**永久失效** ⇒ fail-safe 判"有会话在跑" ⇒ **检查会话永远建不出来**。
|
||||
- ✅ **两道兜底都要有**:
|
||||
· **启动器进程内设**(通用,见 1.2);
|
||||
· **本区 `collabd.config.json` 写死 `host_db`**(指真库 `E:/ProgramData/.workbuddy/workbuddy.db`,单区保险)。
|
||||
⚠️ 实测只有 `ai1net` 炸、`vibe` 没事 —— 差别就在 `vibe` 那份配置里 `host_db` 写了绝对路径。
|
||||
|
||||
### 坑② 🔴 配置查找靠 `cwd` ⇒ 传错 cwd 当场拒跑
|
||||
|
||||
`_cfg_candidates()` = `COLLABD_CONFIG` → `<cwd>/.workbuddy/collab/collabd.config.json`。
|
||||
⛔ **不要把 `cwd` 设成 `collab/` 目录** —— 那会拼出多一级 `.workbuddy` ⇒ 当场拒跑。
|
||||
✅ 设成**工作区根** + 同时显式给 `COLLABD_CONFIG`(双保险)。
|
||||
(对应到任务侧就是 `-WorkingDirectory` **必须是工作区根**,见 2.3。)
|
||||
|
||||
> 🟠 **原坑③「PowerShell 5.1 读无 BOM 的 UTF-8 `.ps1` ⇒ 中文路径全毁 ⇒ 秒退」**
|
||||
> —— **随 `.ps1` 形态整套废弃而失效**,⛔ 现行形态已无 `.ps1` 可读。
|
||||
> 留痕见第四节 5.1 条(本机所有含中文路径的 `.ps1` 仍应带 BOM,是通用经验)。
|
||||
> ⚠️ 判据口径也跟着变了:旧形态 `LastTaskResult` **必须 0**;
|
||||
> **现行形态是长驻进程 ⇒ 正在跑时 `LastTaskResult=267009`(`0x41301`="任务正在运行")**,
|
||||
> ⛔ **别再拿"必须 0"当判据**(见第五节的正确判据)。
|
||||
|
||||
|
||||
## 四、🟠 旧形态留痕(2026-10-03 ~ 10-05 · ⛔ 只当历史读)
|
||||
|
||||
> ⛔ **本节所有写法都已废弃,⛔ 不许照着做。** 保留只为两件事:
|
||||
> ① 出问题时能读懂老日志/老进程;② 里面有若干**通用教训**(下面标了 📌)。
|
||||
|
||||
### 4.1 旧载体=`<区>\.workbuddy\collab\start-supervise.ps1`(永不返回的守护循环)
|
||||
|
||||
⚠️ 旧版要求"必须是永不返回的守护循环版",⛔ 别写成"跑一次就退" —— 那样常驻死掉时脚本
|
||||
**正常返回 0** ⇒ 任务被判「成功」⇒ `Restart*` 永不触发(测试3 实测:活 12 分钟后再不复活)。
|
||||
完整可用版见第五节(含 `-Wait`/心跳判据/退避/**停止标志**四项要点)。
|
||||
|
||||
```powershell
|
||||
$ErrorActionPreference = "Continue"
|
||||
@@ -129,7 +256,7 @@ $env:PYTHONUNBUFFERED = "1" # ⛔ 否则重定向到文件时 Python
|
||||
$root = "<工作区>"; Set-Location $root
|
||||
|
||||
$hbPath = "<工作区>\.workbuddy\collab\logs\supervise-heartbeat.json"
|
||||
$stopFlag = "<工作区>\tmp\supervise-inbox\guard.stop" # 🔴 目标完成信号(第五节之二)
|
||||
$stopFlag = "<工作区>\tmp\supervise-inbox\guard.stop"
|
||||
$logPath = "<工作区>\tmp\keeper.log"
|
||||
$staleSec = 90 # 与 collabd.supervise_alive() 同口径
|
||||
|
||||
@@ -159,147 +286,91 @@ while ($true) {
|
||||
if ($backoff -lt 60) { $backoff = [Math]::Min(60, $backoff * 2) }
|
||||
}
|
||||
```
|
||||
⚠️ **落盘必须带 BOM**(坑③):`[System.IO.File]::WriteAllText($p,$text,[System.Text.UTF8Encoding]::new($true))`。
|
||||
|
||||
### ② 建任务(⚠️ 一律 PowerShell 的 `ScheduledTasks` 模块)
|
||||
|
||||
⛔ **`schtasks.exe` 在本机沙箱被黑名单拦截**(Security Center → Command Security)
|
||||
⇒ **建/查/改/停计划任务全部走 `Get-/New-/Set-/Start-ScheduledTask` + `Out-File` 落盘再读**
|
||||
(⛔ 别指望命令回显)。
|
||||
⚠️ 旧形态落盘**必须带 BOM**:`[System.IO.File]::WriteAllText($p,$text,[System.Text.UTF8Encoding]::new($true))`。
|
||||
|
||||
**旧形态的建任务**(⛔ 与 2.3 的区别就是 `-Execute` 与 `-Argument`):
|
||||
```powershell
|
||||
$a = New-ScheduledTaskAction -Execute "C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe" `
|
||||
-Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File "<工作区>\.workbuddy\collab\start-supervise.ps1"'
|
||||
$t = New-ScheduledTaskTrigger -AtLogOn -User "Administrator"
|
||||
# 🔴 三个设置缺一不可(少一个就前功尽弃):
|
||||
$s = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) `
|
||||
-MultipleInstances IgnoreNew -RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1)
|
||||
New-ScheduledTask -TaskName "collabd-supervise-<区名>" -Action $a -Trigger $t -Settings $s -Principal $p
|
||||
# 改动作不影响已配的触发器 ⇒ 更新时只传 -Action
|
||||
Set-ScheduledTask -TaskName "..." -Action $a
|
||||
```
|
||||
⚠️ 旧文档曾写「动作一律用 `powershell.exe`(不是 `pythonw.exe`)—— 动作里直接跑解释器没有'设环境变量'这一步」
|
||||
—— 🔴 **这句是 P0-72/P0-73 的病根**:env 应该由**启动器**在进程内设,⛔ 不该靠 `powershell.exe` 去设;
|
||||
而 `powershell.exe` 是控制台程序 ⇒ **闪黑窗**。
|
||||
|
||||
| 设置 | 值 | 漏了会怎样 |
|
||||
|---|---|---|
|
||||
| `ExecutionTimeLimit` | `0`(无时限) | 默认 72 h ⇒ 到点被杀 |
|
||||
| `MultipleInstances` | `IgnoreNew` | 重复起 ⇒ 双写台账 |
|
||||
| `RestartCount`/`RestartInterval` | `999`/`1 min` | 死了不重拉 |
|
||||
| Trigger | `AtLogOn`(Interactive・最高权限) | 开机不启动 |
|
||||
### 4.2 旧形态的三个坑(5.1 是通用经验,另两条随 `.ps1` 一并废弃)
|
||||
|
||||
⚠️ **动作一律用 `powershell.exe`(不是 `pythonw.exe`)** —— 动作里直接跑解释器没有"设环境变量"这一步。
|
||||
(用户长期记忆里那条"`python.exe` 会闪黑窗"针对的是**交互式起进程**;计划任务走 `Hidden`+无控制台,不闪。)
|
||||
|
||||
## 三、🔴 三个坑(都可复现,逐个都是"秒退"或"看着在其实没跑")
|
||||
|
||||
### 坑① 🔴 不设 `CODEBUDDY_CONFIG_DIR` ⇒ 读到 **0 字节空库**
|
||||
|
||||
- 计划任务**不继承**会话的环境变量 ⇒ `_wb_db()` 退回 `Path.home()/.workbuddy/workbuddy.db`
|
||||
(本机那个是 **0 字节、无 `sessions` 表**)。
|
||||
- 症状:每 20 秒刷一次 `all_sessions_idle 读库失败 no such table: sessions`
|
||||
⇒ 闸二(所有会话都结束)**永久失效** ⇒ fail-safe 判"有会话在跑" ⇒ **检查会话永远建不出来**。
|
||||
- ✅ **正解=用机制自带的配置项 `host_db`**(`collabd.py` 里它本就**优先于**环境变量),
|
||||
指向真库 `E:/ProgramData/.workbuddy/workbuddy.db`。
|
||||
⇒ **这比设环境变量更可靠**(配置跟着工作区走,不依赖谁起的它)。
|
||||
|
||||
### 坑② 🔴 配置查找靠 `cwd` ⇒ 传错 cwd 当场拒跑
|
||||
|
||||
`_cfg_candidates()` = `COLLABD_CONFIG` → `<cwd>/.workbuddy/collab/collabd.config.json`。
|
||||
⛔ **不要把 `cwd` 设成 `collab/` 目录** —— 那会拼出多一级 `.workbuddy` ⇒ 当场拒跑。
|
||||
✅ 设成**工作区根** + 同时显式给 `COLLABD_CONFIG`(双保险)。
|
||||
(`ensure_supervise()` 内部原先传 `cwd=脚本所在目录` —— 已由测试3 主会话修成 `cwd=str(WS)`。)
|
||||
|
||||
### 坑③ 🔴 PowerShell 5.1 读**无 BOM** 的 UTF-8 `.ps1` ⇒ 中文路径全毁 ⇒ **秒退**
|
||||
|
||||
- 症状:计划任务 `LastTaskResult=1` **秒退**,心跳毫无动静。
|
||||
**5.1 🔴 PowerShell 5.1 读无 BOM 的 UTF-8 `.ps1` ⇒ 中文路径全毁 ⇒ 秒退**
|
||||
- 症状:任务 `LastTaskResult=1` **秒退**,心跳毫无动静。
|
||||
- 定位:`Get-Content -Encoding Byte -TotalCount 3` ⇒ `36 69 114`(ASCII 的 `$Er`)⇒ **无 BOM**。
|
||||
PowerShell 5.1 对无 BOM 文件按 **ANSI(GBK)** 解码 ⇒ 脚本里 `会话协作测试3` 变乱码 ⇒ 路径不存在。
|
||||
- ✅ 落盘**必须带 BOM**:
|
||||
`[System.IO.File]::WriteAllText($p,$text,[System.Text.UTF8Encoding]::new($true))`(`$true` = 带 BOM)。
|
||||
- 📌 **本机所有含中文路径的 `.ps1` 一律带 BOM**,否则一律秒退。
|
||||
- ⚠️ 判据:**`LastTaskResult`** —— `0` = 成功;`1` = 秒退(八成是 BOM)。
|
||||
- 📌 **通用经验(仍然有效)**:本机所有含中文路径的 `.ps1` 一律带 BOM,否则一律秒退。
|
||||
⚠️ 现行形态不用 `.ps1` 了,所以这条只在"你自己还要写 .ps1"时才相关。
|
||||
|
||||
## 四、验收(三样都齐才算成,⛔ 打印"已启动"不算)
|
||||
**5.2 🟠 keeper 是 `powershell.exe -File <ps1>` ⇒ `Stop/Start-ScheduledTask` 不足以让它生效**
|
||||
PowerShell **启动时把脚本读进内存** ⇒ 磁盘上改了、任务重启了,**旧 keeper 进程可能仍在跑老脚本**。
|
||||
实测:同时存在两个 keeper(57680 旧的 + 20180 新的),**旧的按老路径拉常驻** ⇒ "我明明改好了,起来还是老样子"。
|
||||
✅ 旧做法:重铺后**显式杀 keeper 进程**(`taskkill /F /T /PID <keeper_pid>`)再 `Start-ScheduledTask`。
|
||||
📌 **通用教训(仍有效)**:**改完副本必须重启常驻**,判据是**心跳里的 `argv0`**,⛔ 不是文件 `md5`
|
||||
(md5 一致只证明文件换了,⛔ 不证明进程换了。P0-17/P0-74 同族)。
|
||||
|
||||
**5.3 🟠 从工作区副本发起时,找载体模板不能写死包根**
|
||||
旧 `_escalate_to_keeper()` 写死 `Path(__file__).resolve().parent.parent / "assets"`:
|
||||
- 技能目录里对(`<pkg>/scripts/collabd.py` ⇒ `.parent.parent` = `<pkg>`);
|
||||
- **工作区副本里错**(`.workbuddy/collab/collabd.py` ⇒ `.parent.parent` = `<WS>/.workbuddy`
|
||||
⇒ 去找 `<WS>/.workbuddy/assets/`,**不存在**)。
|
||||
⇒ 症状**极具误导性**:返回值写着「⛔ 缺模板 `assets/start-supervise.ps1.tpl`」,
|
||||
看着像仓库少了个文件,其实只是**算错了包根**;而模板好好躺在
|
||||
`<WS>/.workbuddy/skills/session-mechanism/assets/`。
|
||||
📌 **通用教训(仍有效)**:**凡"从 `__file__` 往上推包根"的代码,副本换布局后都会错** ——
|
||||
副本是 `<WS>/.workbuddy/collab/`(**不是**包树里的 `scripts/`),别套用同一套相对层数。
|
||||
🔴 2026-10-05 起 **`_find_keeper_tpl()` 与 `assets/start-supervise.ps1.tpl` 依赖已整套删除**。
|
||||
|
||||
### 4.3 🔴 为什么被换掉(两个事故,都在用户眼前犯的)
|
||||
|
||||
1. **闪黑窗**:任务动作写死 `powershell.exe -WindowStyle Hidden -File start-supervise.ps1`,
|
||||
而 PowerShell 是**控制台程序** ⇒ 每 5 分钟触发一次就**闪一个黑窗**。用户 2026-10-05 报
|
||||
「**又弹了窗口**」/2026-10-01 「**程序在界面一会弹出一会弹出的,影响我操作**」,
|
||||
实测抓到 `powershell.exe` + `conhost.exe` 这对进程。
|
||||
✅ 修法:动作改 `pythonw.exe`(GUI 子系统 ⇒ Windows **永不为它分配控制台窗口**)+ 启动器。
|
||||
2. **两条起法并存**:`collabd.py::_escalate_to_keeper()` 这条**自我供给旁路**还在建旧形态任务
|
||||
⇒ "改了主路径没改旁路"。2026-10-06 二次收口:**任务名**统一 `collabd-keepalive-<区>`、
|
||||
**旁路清除**(`init_workspace.py`)、**探针扩成扫全族**。
|
||||
⚠️ **教训**:凡"这一族文件都不许有 X",必须**枚举整族**,⛔ 不许只挑一个代表 —— 挑一个就等于没扫。
|
||||
|
||||
|
||||
## 五、验收(⛔ "打印已启动"不算,三样都要机读)
|
||||
|
||||
```powershell
|
||||
Get-ScheduledTask -TaskName "collabd-supervise-<区名>" | Select-Object TaskName,State
|
||||
Get-ScheduledTaskInfo -TaskName "collabd-supervise-<区名>" | Select-Object LastRunTime,LastTaskResult
|
||||
# ⚠️ schtasks 被拦;一律 PowerShell 模块 + 落盘看结果
|
||||
Get-ScheduledTask -TaskName "collabd-keepalive-<区名>" > E:\tmp\t1.txt
|
||||
Get-ScheduledTaskInfo -TaskName "collabd-keepalive-<区名>" > E:\tmp\t2.txt
|
||||
```
|
||||
🔴 `LastTaskResult` **必须 0**。
|
||||
|
||||
| # | 判据 | 现值应该是 | ⚠️ 别搞错 |
|
||||
|---|---|---|---|
|
||||
| 1 | `State` | **`Running`** | `Ready` 只说明"此刻没在跑",⛔ **不代表机制坏**(5 分钟触发窗内常是 Ready);要配合 ③ 才算稳 |
|
||||
| 2 | `LastRunTime` | 近 5 分钟内 | — |
|
||||
| 3 | `LastTaskResult` | **`267009`**(`0x41301`="任务正在运行") | ⛔ **别再拿"必须 0"当判据**(那是"跑一次就退"时代的);`1` = 秒退(旧形态八成是 BOM) |
|
||||
|
||||
**存活唯一机读判据**(=机制里那条,⛔ 别用"日志在更新"代替):
|
||||
`.workbuddy/collab/logs/supervise-heartbeat.json` 里 **`pid` 活着 ∧ `ts` 距今 < 90 秒**。
|
||||
`.workbuddy/collab/logs/supervise-heartbeat.json` 里 **`pid` 活着 ∧ `ts` 距今 < 90 秒 ∧ `round` 递增**。
|
||||
|
||||
```powershell
|
||||
# pid 是否真在进程表(⛔ tasklist 走 bash 会被当路径;用 PowerShell)
|
||||
$p = Get-Process -Id <pid> -ErrorAction SilentlyContinue # $null = 已死
|
||||
# ⛔ tasklist 走 bash 会被当路径;一律用 PowerShell
|
||||
```
|
||||
|
||||
**静置观察**(≥ 4 分钟):`round` 持续递增、`argv0` 逐字等于本区 `collabd.py`、
|
||||
`已有活的常驻 ⇒ 本实例退出(幂等)` 出现一次(证明没双写)。
|
||||
**静置观察(≥ 12 分钟,⛔ 短于 10 分钟证明不了任何事 —— 常驻就死在第 12 分钟)**:
|
||||
`round` 持续递增、心跳里 `argv0` **逐字等于本区** `.workbuddy/collab/collabd.py`、
|
||||
并且 `已有活的常驻 ⇒ 本实例退出(幂等)` 出现一次(证明没双写)。
|
||||
|
||||
## 五、🔴 载体是**一个**永不返回的守护循环(⛔ 不是"两层")
|
||||
**判"改的代码真生效了"**:心跳里 `started_h`(或 `started_ts`)**晚于**你改完/分发完的时刻
|
||||
(⛔ 只看文件 md5 不算 —— 见 4.2 的 5.2 条)。
|
||||
|
||||
⚠️ **旧版这里写的是"必须两层=计划任务 + 周期性复活排期",🔴 已被实测推翻** ——
|
||||
真正常态兜底**就在这个计划的守护循环里**,⛔ 不需要另一条排期。
|
||||
|
||||
**实测 2026-10-03**:单纯"计划任务跑一次脚本"**救不了"被外部收走"** ——
|
||||
测试3 常驻 `23:16:37` 起、`23:28:47` 停(活 12 分钟),而计划任务
|
||||
`LastRunTime` 仍 `23:17:03`、`LastTaskResult=0`、`State=Ready` ⇒ **它没重拉**。
|
||||
|
||||
**根因**:`RestartCount/RestartInterval` **只在本任务自己非零退出时生效**。
|
||||
而脚本里若是**前台阻塞**调用常驻,常驻死掉 ⇒ 脚本**正常返回 0** ⇒
|
||||
任务调度器判定「成功」⇒ **`Restart*` 永不触发**(测试3 复盘原话:「自愈机制被**成功退出**这三个字废掉了」)。
|
||||
|
||||
⇒ ✅ **正解=守护循环版脚本**(⛔ 别用"跑一次就退"):
|
||||
```
|
||||
while ($true) {
|
||||
if (Test-Path $stopFlag) { Say "…stands down"; exit 0 } # 🔴 见第五节之二
|
||||
if (心跳新鲜(<90s)) { 让位等待; continue } # 活性判据=心跳,⛔ 不是退出码
|
||||
Start-Process -Wait -PassThru pythonw collabd.py --supervise # 🔴 -Wait 必须
|
||||
# 退避 5→10→20→40→60s 封顶;每轮开头都再查一次 $stopFlag
|
||||
}
|
||||
```
|
||||
| 要点 | 为什么 |
|
||||
|---|---|
|
||||
| `while ($true)` 包住 | 任务永远 `Running` ⇒ 调度器**不介入**、自己管复活 |
|
||||
| 🔴 **`Start-Process -Wait`** | ⛔ **`&` 对 `pythonw.exe`(GUI 子系统)不阻塞**、立即返回 ⇒ 循环误判"刚起的已退出"⇒ **叠出多个常驻**(测试3 实测 5/10/20/40s 连续重拉) |
|
||||
| 活性判据=**心跳新鲜度**(`<90s`),⛔ 不是退出码 | `collabd` 发现已有活常驻会**幂等 exit 0** ⇒ 按退出码重拉会造出风暴 |
|
||||
| 退避封顶 60s | 真崩时别刷屏 |
|
||||
| `.NET Process` + `add_OutputDataReceived` | ⚠️ PowerShell 5.1 **无消息泵 ⇒ 回调不触发**、日志被静默吞掉 ⇒ 用 `Start-Process -RedirectStandardOutput` |
|
||||
|
||||
**实测效果**:23:40 第一次死亡 **5 秒恢复**;23:47 单变量 kill 演练 **6 秒恢复**、新 pid、`pythonw` 实例数 `count=1`(无叠加)。
|
||||
|
||||
### 之二 🔴🔴 守护循环**必须看停止标志**(2026-10-04 补,本文档初版漏了)
|
||||
|
||||
**症状**:目标已完成(`--set-life 已完成` ⇒ `supervise_stop()` 写下 `guard.stop`、常驻已优雅退出),
|
||||
**但守护循环仍在每 60 秒重拉一次、每次秒退** ⇒ 实测**空转 370 次/6 小时**
|
||||
(`keeper.log` 连续 `exited (exit=0, heartbeat unreadable)`)。
|
||||
|
||||
**根因**:守卫只问「心跳新鲜吗」,**⛔ 不问「目标还活着吗」** ⇒
|
||||
**"完成即收工"只做到"停掉常驻",没做到"别再拉它"** —— 那是同一件事的两半。
|
||||
|
||||
✅ **正解=循环开头(+退避等待中)都先查停止标志**,在则**退出循环**:
|
||||
|
||||
```powershell
|
||||
$stopFlag = "<工作区>\tmp\supervise-inbox\guard.stop"
|
||||
while ($true) {
|
||||
if (Test-Path -LiteralPath $stopFlag) { Say "guard.stop present => stands down"; exit 0 }
|
||||
... # 起常驻
|
||||
$waitLeft = $backoff
|
||||
while ($waitLeft -gt 0) { # 🔴 退避期间也可能出现标志
|
||||
if (Test-Path -LiteralPath $stopFlag) { Say "…stands down early"; exit 0 }
|
||||
Start-Sleep -Seconds 5; $waitLeft -= 5
|
||||
}
|
||||
}
|
||||
```
|
||||
📌 退出前**必须 `Say` 一行**(⛔ 否则又变成"静默消失",同族红线:读到了就要说)。
|
||||
|
||||
**实测(2026-10-04 07:03,单变量:只换脚本、没动任务)**:
|
||||
新 keeper 起来 **0 秒**识别标志 ⇒ `keeper stands down` ⇒ 任务 `State=Ready`(⛔ 不是 `Running`)
|
||||
⇒ 重拉次数 **372 → 372**(一没涨)⇒ **空转彻底止住**。
|
||||
⚠️ 验「是否被回收」必须**只做单一变量**(⛔ 不许同时停/起任务)—— 否则因果会搞错。
|
||||
|
||||
⚠️ **验收要静置 ≥ 12 分钟**(⛔ 短于 10 分钟证明不了任何事 —— 常驻就死在第 12 分钟)。
|
||||
|
||||
## 六、⚠️ 还没有它就不算长期(两条,别自欺)
|
||||
|
||||
@@ -309,57 +380,71 @@ while ($true) {
|
||||
而**发起这一切的那条会话自己也在里面** ⇒ 只要它活着,检查会话就建不出来。
|
||||
⇒ **要让检查会话跑起来,必须先结束发起会话**(fail-safe 方向=宁可不建,不误建)。
|
||||
|
||||
|
||||
## 七、还有一条(已由机制收口,⛔ 别再自己写)
|
||||
|
||||
- **目标完成 ⇒ 关后台+常驻程序**:`collabd.py --set-life 已完成` 现在**真的会停常驻**
|
||||
(`supervise_stop()`:先写 `guard.stop` 走优雅退出 → 等 45 s → 不死才 `taskkill /T /F`)。
|
||||
(`supervise_stop()`:先写 `guard.stop` 走优雅退出 → 等 `STOP_GRACE`(45 s)→ 不死才 `taskkill /T /F`)。
|
||||
⛔ **受阻 / 已暂停不关**(口径如此)。
|
||||
- 🔴 **停止标志由常驻本体自己看**(`collabd.py::_guard_says_stop()`,**对所有实例生效**)——
|
||||
⛔ 现行形态**不再有"守护循环/ps1 去看标志"这一层**。
|
||||
⚠️ 于是"任务每 5 分钟还在触发"≠"还在徒劳重拉":常驻起来见 `guard.stop` 即**优雅退出**,
|
||||
不会空转(旧 ps1 时代那 6 小时空转 370 次的毛病,结构上已不存在)。
|
||||
- **"完成"可逆**:`ensure_supervise()` 续命前**清掉 `guard.stop`** ⇒ 新目标/目标调整后能再起来。
|
||||
⛔ 不清就永远起不来。
|
||||
- **跨区自愈**:本区常驻每 6 轮顺带扫一遍 `peer_workspaces`,**只补"目标进行中"的区**
|
||||
(已完成/受阻/有停止标志的 ⛔ 一律不拉)⇒ 但**计划任务是更靠前的第一道**。
|
||||
(已完成/受阻/有停止标志的 ⛔ 一律不拉)⇒ 但**计划任务是更靠前的第一道**
|
||||
(⛔ 别把跨区自愈当载体的替代品:它要求本区常驻先活着)。
|
||||
|
||||
|
||||
## 八、按场景对照(选哪条 / 怎么验 / 常见坑)
|
||||
|
||||
| 场景 | 主会话怎么来 | 常驻载体 | 目标完成后谁关 | 常见坑 |
|
||||
|---|---|---|---|---|
|
||||
| **A · 用户手动创建主会话** | 用户自己开 `[主]-…`,盯着推进 | 计划任务 + 守护循环 | keeper 见 `guard.stop` → `exit 0` | 🔴 用户一收工就没人拉 ⇒ 若没装载体,常驻会在会话结束时**静默死掉**(看板还显示"在线") |
|
||||
| **A · 用户手动创建主会话** | 用户自己开 `[主]-…`,盯着推进 | 计划任务 → `pythonw` → `supervise-launch.py` | 常驻见 `guard.stop` → 优雅退出 | 🔴 用户一收工就没人拉 ⇒ 若没装载体,常驻会在会话结束时**静默死掉**(看板还显示"在线") |
|
||||
| **B · 定时任务创建主会话** | 排期 `recurring` 到点拉 `[主]-…` | 同上(⛔ **排期代替不了载体**) | 同上 | 🔴 **`once` 排期过期即哑**(`next_run_at=None`、界面仍显示 ACTIVE)⇒ **静默窗内无人**;🔴 排期跑完即 `completed`,**下一跳之前是空窗** |
|
||||
|
||||
**共同判据(两种场景都一样,⛔ 每次改完都验)**:
|
||||
1. `LastTaskResult` = `0`(`1` ⇒ 秒退,八成是 BOM);
|
||||
2. 任务 `State` = **`Running`**(⛔ `Ready` 只说明"此刻没在跑",**不代表机制坏**,
|
||||
但要配合 ③ 才算稳);
|
||||
1. `State` = **`Running`**(或 5 分钟窗内 `Ready`);
|
||||
2. `LastTaskResult` = **`267009`**(长驻中);⛔ `1` 也是信号(秒退);
|
||||
3. 心跳 `pid` 活 ∧ `ts` 距今 **< 90 s** ∧ `round` 递增;
|
||||
4. **静置 ≥ 12 分钟**再看 ③(⛔ 短观察证明不了事 —— 常驻常死在第 12 分钟);
|
||||
5. 目标完成后:keeper 日志出现 `stands down` + **重拉计数不再增长**(验"真的停了",
|
||||
⛔ 不许只看"心跳停了"—— 那可能是死了而不是收工)。
|
||||
5. 目标完成后:常驻日志出现收工行 + **心跳不再更新但进程已退**(验"真的停了",
|
||||
⛔ 不许只看"心跳停了" —— 那也可能是死了而不是收工;旧形态的判据是 keeper 日志出现
|
||||
`stands down` + **重拉计数不再增长**)。
|
||||
|
||||
## 九、四个区各自的任务名(⛔ 名字别撞)
|
||||
|
||||
`collabd-supervise-<工作区名>`,例:`collabd-supervise-ws3`。
|
||||
## 九、任务名(⛔ 名字别撞,也别再改名)
|
||||
|
||||
| 对象 | 任务名 | 备注 |
|
||||
|---|---|---|
|
||||
| 常驻(协作程序) | `collabd-keepalive-<工作区名>` | 例:`collabd-keepalive-vibe-product` |
|
||||
| 看板 | `dsh-board-keepalive` | 动作 = `pythonw.exe` + `board-launch.py` |
|
||||
| 🟠 旧名 | `collabd-supervise-<区>` | **已废弃**;`collabctl.py::SCHED_TASKS` 把它列进**禁用名单**,见一条禁一条 |
|
||||
|
||||
⚠️ 一个区一个任务;⛔ 多个区**共用一个**任务名会被 `IgnoreNew` 挡掉第二个。
|
||||
🔴 **⛔ 别再改任务名** —— 它同时是 `collabctl.py` 的"启用名单"和"禁用名单"的键;
|
||||
改名必须**同时**改两边,否则自愈起的常驻会被 `off` 顺手干掉(2026-10-06 实测踩到)。
|
||||
|
||||
|
||||
## 十、🔴🔴 「各区都能常驻」怎么一次做齐(2026-10-04 用户点问)
|
||||
|
||||
> 用户原话:「看看是否有**各工作区都能启动常驻程序**的最好办法,
|
||||
> 而不是现在这种**只能某个工作区才能常驻**的办法」
|
||||
|
||||
✅ **答案:能,而且就是第八节那套 —— 每区各建一条任务,同一条命令换个区名即可。**
|
||||
✅ **答案:能,而且就是本节那套 —— 每区各建一条任务,同一条命令换个区名/换条路径即可。**
|
||||
⛔ **不存在"一个载体管所有区"的写法**,⛔ 也**不需要**:任务天然可以并存,
|
||||
`IgnoreNew` 只在**同一个任务名**上生效(⛔ 撞名才挡)。
|
||||
|
||||
### 一区一条,四步(把 `<区>` 换成工作区绝对路径、`<名>` 换成区名)
|
||||
### 一区四步(把 `<区>` 换成工作区绝对路径)
|
||||
|
||||
1. **铺包装脚本** `<区>\.workbuddy\collab\start-supervise.ps1`
|
||||
—— 用第二节①的守护循环版,**落盘必须带 BOM**(坑③,否则秒退)。
|
||||
`collabd.config.json` 里补两项:`host_db`(指真库,⛔ 别依赖环境变量,见坑①)
|
||||
+ 本区 `workspace`。
|
||||
2. **建任务**:`collabd-supervise-<名>`,动作=`powershell.exe -File <该区 ps1>`,
|
||||
触发器 `AtLogOn`,四个设置按第二节②的表配齐(`ExecutionTimeLimit=0`/
|
||||
`MultipleInstances=IgnoreNew`/`RestartCount=999`+`RestartInterval=1min`)。
|
||||
3. **立即 `Start-ScheduledTask`**(⛔ 别等下次登录)。
|
||||
4. **验收**:`LastTaskResult=0` ∧ 心跳 `pid` 活 ∧ `ts<90s` ∧ `round` 递增 ⇒ **静置 ≥ 12 分钟**再看一次。
|
||||
1. **确认启动器在位**:`<区>\.workbuddy\collab\supervise-launch.py`
|
||||
(⛔ 别自己铺 —— 缺就跑 `deploy_code.py --ws <区>` 分发)。
|
||||
`collabd.config.json` 里补两项:`host_db`(指真库,⛔ 别依赖环境变量,见坑①)+ 本区 `workspace`。
|
||||
2. **建任务**:走 `collabctl.py on`(正门)或等 `_escalate_to_keeper()` 自愈;
|
||||
任务名 `collabd-keepalive-<名>`,动作/触发器/设置按 2.3 那四条。
|
||||
3. **立即 `Start-ScheduledTask`**(⛔ 别等下次登录/别等 5 分钟)。
|
||||
4. **验收**:按第五节的 5 条 ⇒ **静置 ≥ 12 分钟**再看一次。
|
||||
|
||||
### 各区之间的隔离(为什么"能各建各的")
|
||||
|
||||
@@ -371,40 +456,14 @@ while ($true) {
|
||||
|
||||
### ⛔ 别犯的三个错
|
||||
|
||||
1. **⛔ 用一条任务带多个区**(一个动作只能跑一个区的脚本);
|
||||
1. **⛔ 用一条任务带多个区**(一个动作只能跑一个区的启动器);
|
||||
2. **⛔ 一区多条任务**(会双写台账);
|
||||
3. **⛔ 以为"某区现在活着"就不用建任务** —— 那是孤儿化幸存,
|
||||
父链一断就没了(第一节末尾那条实测更正)。
|
||||
3. **⛔ 以为"某区现在活着"就不用建任务** —— 那是孤儿化幸存,父链一断就没了(第一节末尾那条实测更正)。
|
||||
|
||||
### 🔴🔴 两个"看着做好了、其实没生效"的坑(2026-10-04 实测踩到)
|
||||
|
||||
**坑 A:从副本发起时,找载体模板不能写死包根。**
|
||||
`_escalate_to_keeper()` 原来写死 `Path(__file__).resolve().parent.parent / "assets"`:
|
||||
- 技能目录里对(`<pkg>/scripts/collabd.py` ⇒ `.parent.parent` = `<pkg>`);
|
||||
- **工作区副本里错**(`.workbuddy/collab/collabd.py` ⇒ `.parent.parent` = `<WS>/.workbuddy`
|
||||
⇒ 去找 `<WS>/.workbuddy/assets/`,**不存在**)。
|
||||
⇒ 症状**极具误导性**:返回值写着「⛔ 缺模板 assets/start-supervise.ps1.tpl」,
|
||||
看着像仓库少了个文件,其实只是**算错了包根**;而模板好好躺在
|
||||
`<WS>/.workbuddy/skills/session-mechanism/assets/`。
|
||||
✅ 修法=`_find_keeper_tpl()` 认三处(按优先级):
|
||||
① `<pkg>/assets/` ② `<WS>/.workbuddy/skills/session-mechanism/assets/`(**副本正解**)
|
||||
③ `<CFGDIR>/skills/session-mechanism/assets/`(兜底)。
|
||||
⚠️ **凡"从 `__file__` 往上推包根"的代码,副本换布局后都会错** —— 副本是
|
||||
`<WS>/.workbuddy/collab/`(**不是** 包树里的 `scripts/`),别套用同一套相对层数。
|
||||
|
||||
**坑 B:重铺 `.ps1` 后,`Stop/Start-ScheduledTask` 不足以让它生效。**
|
||||
keeper 是 `powershell.exe -File <ps1>`:PowerShell **启动时把脚本读进内存**,
|
||||
之后磁盘上改了、任务重启了,**旧 keeper 进程可能仍在跑老脚本**。
|
||||
实测:同时存在两个 keeper(57680 旧的 + 20180 新的),**旧的按老路径拉常驻**
|
||||
⇒ 现象是"我明明改好了,起来还是老样子"。
|
||||
✅ 做法:重铺后**显式杀 keeper 进程**(`taskkill /F /T /PID <keeper_pid>`)再 `Start-ScheduledTask`;
|
||||
复核判据=**新常驻的父链根**(`svchost -s Schedule`)+ 心跳 `argv0` 指向**本区副本**。
|
||||
|
||||
**坑 C:改完副本必须重启常驻,判据是 `argv0` 而不是文件 md5。**
|
||||
`deploy_code.py` 覆盖的只是**磁盘上的副本** —— 正在跑的进程仍持有旧代码
|
||||
(P0-17 同族)。✅ 判据=心跳里的 `argv0` 是否指向本区副本路径,
|
||||
⛔ 不是"`md5` 一致"(那只证明文件换了,⛔ 不证明进程换了)。
|
||||
|
||||
---
|
||||
📌 **本文档的事实全部来自实测**(计划任务状态/`LastTaskResult=0`/心跳 13 分钟/BOM 字节
|
||||
`239 187 191`/三条封死路的原始错误)。⛔ 任何"应该行得通但没实测"的写法都别往里加。
|
||||
📌 **本文档的事实在哪**:
|
||||
· 2026-10-03/04 部分(判据表、`in_job` 更正、静置 12 分钟、自锁)= 三份复盘 + 当晚实测;
|
||||
· 2026-10-05/06 部分(启动器、任务名统一、旁路清除、探针扩族)= **P0-72/P0-73/P0-74** 实测,
|
||||
权威源在 `SKILL.md`「常驻机制的真实形态」与本技能 `scripts/`。
|
||||
⛔ **任何"应该行得通但没实测"的写法都别往里加。**
|
||||
@@ -2,7 +2,7 @@
|
||||
name: agent-operating-rules
|
||||
description: 「AI 会话作业总规矩」—— 在任何工作区开工都适用的统一规则集:什么时候必须自己拍板、什么时候才允许问用户、回复怎么排版、**怎么说话才像人(去 AI 味)**、怎么不越界(归属 / 锁 / 目录 / 提交 / 批量)、长任务怎么多棒接力。当你在任何一个工作区开始任务、做技术决策、要问用户问题、**要写任何给用户看的回复或文档**、准备写文件或提交、要建接续任务 / 自动化,或发现自己正在读别的工作区的东西时使用。**也用于这些高频点名场景**(用户原话):说「**只做我明确要求的 / 别顺手改 / 别擅自扩大范围**」(历史原话高频出现)· 说「**先抢锁再动手 / 执行锁 / 并发**」· 说「**技术讨论不谈法规 / 别提合规**」· 说「**要的是解决问题,不是将就妥协 / 我不要得过且过**」· 说「**默认放 E 盘,别放 D 盘**」· 说「**文档直入主题 / 别绕弯子**」· 说「**点名主体、别用代词**」· 说「**成本 / token 消耗 / 上下文膨胀 / 积分**」· 说「**派活 / 派出去 / 分配给别的会话 / 让某条线做**」· 说「**持续监管 / 跟进执行情况 / 别的会话动了没 / 各会话干什么了**」· 说「**会话卡住 / 又卡住了 / 发消息没反应 / 一直转圈 / 不回话**」· 说「**监控 / 监管 / 后台任务 / 常驻任务**」。核心 = 提报用户唯一判据 + 归属三律 + 一把锁 + 交付门禁 + 多棒接力(含**一棒一线** + **派活必建监管棒** + **§7.7 监控别把自己监控死**)+ 去 AI 味 5 条原则。细节按需读 `references/`。
|
||||
version: 1.0.0
|
||||
last_change: 【2026-10-02 · 七补】🔴 **补 §1.1「排版自检」+ 给 `references/01` §6 加覆盖第 0 条** —— 起因:用户报「**我发现你又忘记如何回复 执行结果了,是不是技能规则失效了**」,查下去发现的是**规范冲突**(不是文件丢了):本技能 §6 的「表格 ≤5 列」「长清单 / 对比 ⇒ **表格**」是**旧口径**,而用户 2026-10-01 已定稿**⛔ 禁用表格**(原话「为什么回复的内容 那么人机 把我都看抑郁了,禁止用表格,全部用文字排版」)、骨架改成 **`#` 大类 → `##` 任务名 → 圆点陈述句 + `1、2、3、` 序号** ⇒ **照旧口径做就等于违反定稿**,而且**没有任何地方标注过它被覆盖**(同族问题:规则写了 ≠ 会被取用;这次更坏 —— 取到的还是**反向**的)。落点两处:① `SKILL.md §1.1` 增「排版自检」(发出前对一眼本工作区规则文件的排版节;以**最新用户定稿**为准);② `references/01-协作与提报用户判据.md §6` 头部加 **第 0 条(优先于本节全部条目)**,写明"本节只是通用形态、本工作区另有定稿则让位",并把 DSH 的冲突案例**逐字登记**(含用户原话),避免下一次又被"表格优先"拉回去。⚠️ **未动** §6 正文的十条约束(保留其"可扫读"的通用价值,只由第 0 条划出边界)。此前 【2026-10-01 · 六补】§1.8 增 **第 4 条「分清『定案原话』与『由它推出的结论』—— 只有前者不可动」** —— 起因:核对用户复述的方案时发现,某架构文件的「需求内闭环(**用户定案**)」节里,**规则**(一个需求只依赖自己需求内的东西)**至今有效**,但它推出的**结论**("需求内注定没有时钟 ⇒ 只有自建周期自动化/不建两条路")**已被当天更晚的一次用户定案推翻**(定案="协作与投递一直运行(常驻)"⇒ 本需求内**就有**时钟)。⇒ 只有第 1~3 条时,人会因节标题写着"用户定案"而**整节不敢动** ⇒ 矛盾长期留在权威文件里;没有这条边界,又会连**定案原话**一起改(= §1.8 上半段那次伪造署名的事故)。**可动的三条硬条件**:① 必须引用**更新的用户定案原话+日期**推翻它引用的前提(⛔ 不许只说"我觉得不对");② **只标注作废、原文一字不删**;③ 写清**"作废的是结论、哪条规则仍有效"**。此前 【2026-09-28 · 五补】§7.7 增 **第 5 条禁令「监管/钩子的作用域必须把监管者自己排除在外」** —— 用户点破「**你卡住是因为钩子把你自己也涵盖进去了**」:给几条线挂监控钩子时,作用域写成**整个大项目根**,而监管者自己的工作区也在里面 ⇒ **监控到自己头上**;叠加上禁令 1(常驻轮询)=**自己把自己顶住**。正确形态三件都要:① **显式白名单**列被监管线(⛔ 不用整根目录那种宽口径)② 监管者自己标 **`scope=home`**(记账但⛔不当被监管线)③ **被丢弃的必写 `skipped.jsonl` + stderr**(⛔ 不静默排除)。配套:线名按**相对大项目根第一段**取(⛔ 别用 `basename(cwd)`);**自检必须四类各跑一遍**(home/line/other/outside),⛔ 别只跑"应该通过"那一类。此前 【2026-09-28 · 四补】**新增 §7.7「监控别把自己监控死」**(起因:用户报「怎么又卡住了 发消息都没有恢复」⇒ 查明那个会话**自己起了常驻后台轮询任务**(`--interval 20 --max-hours 6`),输出每 20 秒当通知灌回会话 ⇒ **永不回 idle**;且它是**自动化会话**(`hostComposesUserContext=true`)⇒ 宿主按"持续干活"语义驱动、**不会按一问一答回话** ⇒ 用户三条消息全无回复、三次点停止只掐掉那一轮)。四条禁令:⛔ 会话内禁起常驻后台长跑任务(监管一律走一次性定时自动化)|⛔ 不在自动化会话里手动续聊(要接就新建会话)|⛔ 别凭"没新 node 进程 / 转录 mtime 冻结"断定"没派发"(agent 是宿主进程内的会话级运行 ⇒ **唯一权威判据 = 工作区日志的状态机**)|🔴 分清「没收到」与「收到但没干完」(后者 ⇒ **消息已作废,必须让用户重新给一次**)。配套:长会话主动换新(上下文 180K + `preMessageCompactPct=0` ⇒ 单次响应可达 1.9 MB/20 s)。【2026-09-28 · 三补】**用户追问「如何避免再次发生」⇒ §7.6 增第 5、6 条**(这是本轮最有价值的两条):**⑤ 监管必须闭环 —— 只报告的监管 = 没监管**(实测:某条棒"抢不到锁 ⇒ 未开工"但 `result_success=1` ⇒ 被判成"疑未产出",而该类处置是"只报告不重排" ⇒ **连续两轮发现了却没动手 ⇒ 活躺着死**;对策:把结论自述未执行的词当机器Line truncated
|
||||
last_change: 【2026-10-07】🔴 **`references/01-协作与提报用户判据.md` 已并入会话技能正文并从本包删除** —— 判据类(冲突裁决顺序 / 语言转换表 / 提报前三问 / 铁律 6 + 只做正向迭代)→ `session-mechanism/references/02-功能优先协作协议.md`;排版全文(十四条反模式 / 骨架路由 / 点名主体 / 直入主题)→ `session-mechanism/references/03-回复排版-核心块.md` 的「完整版」段。⚠️ 下面历史记录里出现的 `references/01`(及 `references/01-… §6`)**都是当时的路径**,现按新落点读。此前 【2026-10-02 · 七补】🔴 **补 §1.1「排版自检」+ 给 `references/01` §6 加覆盖第 0 条** —— 起因:用户报「**我发现你又忘记如何回复 执行结果了,是不是技能规则失效了**」,查下去发现的是**规范冲突**(不是文件丢了):本技能 §6 的「表格 ≤5 列」「长清单 / 对比 ⇒ **表格**」是**旧口径**,而用户 2026-10-01 已定稿**⛔ 禁用表格**(原话「为什么回复的内容 那么人机 把我都看抑郁了,禁止用表格,全部用文字排版」)、骨架改成 **`#` 大类 → `##` 任务名 → 圆点陈述句 + `1、2、3、` 序号** ⇒ **照旧口径做就等于违反定稿**,而且**没有任何地方标注过它被覆盖**(同族问题:规则写了 ≠ 会被取用;这次更坏 —— 取到的还是**反向**的)。落点两处:① `SKILL.md §1.1` 增「排版自检」(发出前对一眼本工作区规则文件的排版节;以**最新用户定稿**为准);② `references/01-协作与提报用户判据.md §6` 头部加 **第 0 条(优先于本节全部条目)**,写明"本节只是通用形态、本工作区另有定稿则让位",并把 DSH 的冲突案例**逐字登记**(含用户原话),避免下一次又被"表格优先"拉回去。⚠️ **未动** §6 正文的十条约束(保留其"可扫读"的通用价值,只由第 0 条划出边界)。此前 【2026-10-01 · 六补】§1.8 增 **第 4 条「分清『定案原话』与『由它推出的结论』—— 只有前者不可动」** —— 起因:核对用户复述的方案时发现,某架构文件的「需求内闭环(**用户定案**)」节里,**规则**(一个需求只依赖自己需求内的东西)**至今有效**,但它推出的**结论**("需求内注定没有时钟 ⇒ 只有自建周期自动化/不建两条路")**已被当天更晚的一次用户定案推翻**(定案="协作与投递一直运行(常驻)"⇒ 本需求内**就有**时钟)。⇒ 只有第 1~3 条时,人会因节标题写着"用户定案"而**整节不敢动** ⇒ 矛盾长期留在权威文件里;没有这条边界,又会连**定案原话**一起改(= §1.8 上半段那次伪造署名的事故)。**可动的三条硬条件**:① 必须引用**更新的用户定案原话+日期**推翻它引用的前提(⛔ 不许只说"我觉得不对");② **只标注作废、原文一字不删**;③ 写清**"作废的是结论、哪条规则仍有效"**。此前 【2026-09-28 · 五补】§7.7 增 **第 5 条禁令「监管/钩子的作用域必须把监管者自己排除在外」** —— 用户点破「**你卡住是因为钩子把你自己也涵盖进去了**」:给几条线挂监控钩子时,作用域写成**整个大项目根**,而监管者自己的工作区也在里面 ⇒ **监控到自己头上**;叠加上禁令 1(常驻轮询)=**自己把自己顶住**。正确形态三件都要:① **显式白名单**列被监管线(⛔ 不用整根目录那种宽口径)② 监管者自己标 **`scope=home`**(记账但⛔不当被监管线)③ **被丢弃的必写 `skipped.jsonl` + stderr**(⛔ 不静默排除)。配套:线名按**相对大项目根第一段**取(⛔ 别用 `basename(cwd)`);**自检必须四类各跑一遍**(home/line/other/outside),⛔ 别只跑"应该通过"那一类。此前 【2026-09-28 · 四补】**新增 §7.7「监控别把自己监控死」**(起因:用户报「怎么又卡住了 发消息都没有恢复」⇒ 查明那个会话**自己起了常驻后台轮询任务**(`--interval 20 --max-hours 6`),输出每 20 秒当通知灌回会话 ⇒ **永不回 idle**;且它是**自动化会话**(`hostComposesUserContext=true`)⇒ 宿主按"持续干活"语义驱动、**不会按一问一答回话** ⇒ 用户三条消息全无回复、三次点停止只掐掉那一轮)。四条禁令:⛔ 会话内禁起常驻后台长跑任务(监管一律走一次性定时自动化)|⛔ 不在自动化会话里手动续聊(要接就新建会话)|⛔ 别凭"没新 node 进程 / 转录 mtime 冻结"断定"没派发"(agent 是宿主进程内的会话级运行 ⇒ **唯一权威判据 = 工作区日志的状态机**)|🔴 分清「没收到」与「收到但没干完」(后者 ⇒ **消息已作废,Line truncated
|
||||
updated_at: 2026-10-01
|
||||
agent_created: true
|
||||
---
|
||||
@@ -20,7 +20,8 @@ agent_created: true
|
||||
|
||||
| 要什么 | 读哪个 |
|
||||
|---|---|
|
||||
| 完整的提报用户判据 / 语言转换表 / 排版十四条反模式 / 结论骨架全文 | `references/01-协作与提报用户判据.md` |
|
||||
| 完整的提报用户判据 / 语言转换表 / 结论骨架全文 | `session-mechanism/references/02-功能优先协作协议.md` |
|
||||
| 排版十四条反模式 / 骨架路由 / 文案与文档写法全文 | `session-mechanism/references/03-回复排版-核心块.md`(**「完整版」段**,⛔ 不在每轮注入里) |
|
||||
| 完整的归属律 / 锁 / 目录 / 提交 / 环境陷阱全文 | `references/02-工作区纪律.md` |
|
||||
| 完整的六件套 prompt / 七条防护 / 成本纪律全文 | `references/03-多棒接力编排.md` |
|
||||
| **去 AI 味的完整模式表(24 类)/ 中文场景加固 / 自查评分** | `references/04-去AI味与说话方式.md` |
|
||||
@@ -50,8 +51,8 @@ agent_created: true
|
||||
③ 候选之间是**真取舍**吗?—— **只有优点或只有缺点 ⇒ 自己拍掉**;是真取舍 → 才允许问,**一轮只问这一句**。
|
||||
|
||||
🔴 **排版自检(同一遍过)**:发出前先对一眼**本工作区规则文件的排版节** —— 排版以**最新用户定稿**为准,
|
||||
本技能 `references/01-协作与提报用户判据.md §6` 只是**通用形态**(⚠️ 它「表格 ≤5 列 / 长清单用表格」两条
|
||||
已被部分工作区的定稿**明确废除**,见 §6 第 0 条)。**示例(DSH 项目现行骨架,可直接照这个形态写)**:
|
||||
本包 `references/03-回复排版-核心块.md` 的**「完整版」段**只是**通用形态**(⚠️ 它「表格 ≤5 列 / 长清单用表格」两条
|
||||
已被部分工作区的定稿**明确废除**,见该档完整版段的**「十四条反模式」第 5 条**与**「按回答类型套现成骨架」表末行**——那两处已就地标 🟠 作废)。**示例(DSH 项目现行骨架,可直接照这个形态写)**:
|
||||
`# 大类`(**已完成** / **待处理任务**)→ `## 任务名` → 每条「`- ` 圆点 + **一句陈述句**(依据 / 细节入**句末圆括号**)」
|
||||
+ 待处理事项用序号 **`1、2、3、`**;🔴 **大类标题必须比任务名大一号**(`#` vs `##`);**三禁** =
|
||||
⛔ **表格** / ⛔ **长散文** / ⛔ **碎标签堆叠**;附件写在该板块**最末**一行;**已完成的大类放最前**。
|
||||
@@ -286,7 +287,7 @@ grep -n "已作废\|已被取代\|已退役" <文件> # 被取代的东西有
|
||||
| **向用户提问** | **问题**(一句)→ **说明**(为什么要你定:影响谁 / 断多久 / 花多少钱 / 有无不可逆)→ **A 案** / **B 案**(**各占一段**,各 ≤3 行,**必写优缺点**,推荐项置首)→ **倾向**(一句) |
|
||||
|
||||
**十四条反模式**(见到就改):文字墙 · 嵌套 >2 层 · 结论埋中间 · 整句加粗 · 表格(⛔ **已全禁**,见第 5 行) · 信息重复三遍 · "综上"指代不清 · emoji 堆砌 · 术语混进结论层 · 标题跳级 · **待拍板夹在中间 / 写成散文** · **只写差别不写优缺点** · **候选横排** · **并列项挤成一段**。
|
||||
详见 `references/01-协作与提报用户判据.md §6`。
|
||||
详见 `session-mechanism/references/03-回复排版-核心块.md`(**「完整版」段**)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
<!-- 🔴🔴 2026-10-06 权威归属(用户令:规则全部整合进会话技能)
|
||||
本档已从 `agent-operating-rules` 迁入 `session-mechanism`。
|
||||
⚠️ 其中「提报用户判据 / 边界内自决策 / 边界外八类 / 红线门禁 / 提报格式 / 拆包 / 取舍三问」
|
||||
与 **本包 `references/02-功能优先协作协议.md`** 同题 ⇒ **判据以 02 为准**,
|
||||
本档保留作**完整版(含全文与语言转换表)**参考;两者冲突时以 02 为准。
|
||||
本档独有、02 没有的:排版十四条反模式、结论骨架全文、语言转换表。 -->
|
||||
# 参考 01 — 协作与提报用户判据(全文)
|
||||
|
||||
> 本文件是 `agent-operating-rules` 的**细节层**。入口文件已给**每次都要生效**的硬规则;
|
||||
> 本文件给**完整依据、出处、语言转换表与排版全套**。**按需读**,别全塞进上下文。
|
||||
|
||||
---
|
||||
|
||||
## 1. 提报用户唯一判据(完整)
|
||||
|
||||
> **只问「超过现有判断方法边界」的问题。**(用户原话)
|
||||
|
||||
### 1.1 边界内 → 一律自决策
|
||||
|
||||
技术选型 / 实现路径 / 命名与数据结构 / 性能与资源调参 / 部署与同步 / 排查方法 / 版本与依赖 / 兼容与降级 / 方法内的方案取舍 / 文档与档案的技术内容。
|
||||
|
||||
- ⚠️ **「部署 / 上线」明确属于边界内**:**不中断用户**的上线动作(传产物、换包、改静态页、投放)**做完即上线,不要问** —— 用户要先看线上效果才能判断需求是否被满足。
|
||||
- **开发 / 自用环境**:重启、停任务、改配额或配置、改网关 **直接做**,只需**动手前一句话说明**。
|
||||
- **仍未放开**:不可逆的破坏性操作(删数据 / 迁库 / 清目录)⇒ **仍先出清单**。
|
||||
|
||||
### 1.2 边界外 → 必须问(八类)
|
||||
|
||||
| # | 类别 | 为什么方法判不了 |
|
||||
|---|---|---|
|
||||
| 1 | **业务目标与优先级** | 方法只能判"**怎么做得最优**",判不了"**该不该做**"。<br>⚠️ **出口**:方向已定(用户已说要做什么)时,"**先做哪个**"若候选有**客观排序** ⇒ **属边界内,自决策**。只有"几个都该做、用户对**节奏 / 取舍**有偏好"才提报用户。 |
|
||||
| 2 | **成本与资源承诺** | 涉及用户的钱,不是技术优劣问题 |
|
||||
| 3 | **对外承诺** | 对外 SLA / 合同 / 品牌文案 —— 商业后果超出工程判断 |
|
||||
| 4 | **需要用户提供的凭据 / 审批** | API Key、DNS 权限、账号授权 —— 只有用户有 |
|
||||
| 5 | **体验偏好(无客观优劣)** | 审美与文案语气、默认值取向、措辞 |
|
||||
| 6 | **影响面超出本平台** | 会波及其他系统 / 他人数据 / 不可逆的对外影响 |
|
||||
| 7 | **红线门禁** | 安全与影响面变更必须用户知情同意(见 §2) |
|
||||
| 8 | **方法确实判不准** | 两边都无依据、事实不足以判断 ⇒ **宁可问,不要卡死** |
|
||||
|
||||
**提报用户方式**:这八类**照实说人话**说明「为什么要你定」,⛔ 不要包装成技术选项。
|
||||
|
||||
### 1.3 判断口诀
|
||||
|
||||
**「用户能不能从可感知的视角判断这个选项的好坏?」**
|
||||
- 能 → 可以提报给用户(§1.2)
|
||||
- 不能 → **这就是 AI 的工作,不要问**
|
||||
|
||||
---
|
||||
|
||||
## 2. 红线门禁(通用形态)
|
||||
|
||||
> ⚠️ **具体编号与例外以本工作区规则文件为准**;下面只给**判据**。
|
||||
|
||||
| 门禁 | 判据 |
|
||||
|---|---|
|
||||
| **扩大权限 / 可见面** | 新挂载、放开遮蔽、暴露平台目录或环境变量、放宽网络规则、提升档位 ⇒ 先出「影响评估」并取得确认 |
|
||||
| **批量 / 全仓写入** | 可能影响 **>10 文件** ⇒ 先出受影响清单 + 确认;先**单点验证** |
|
||||
| **不可逆的破坏性操作** | 删数据 / 迁数据库 / 清目录 ⇒ **先出清单** |
|
||||
| ⛔ **「会中断在线用户」通常不是门禁** | 开发 / 自用环境 ⇒ 重启、停任务、改配置**直接做**,动手前一句话说明。⚠️ 生产环境相反,按本工作区规则判 |
|
||||
|
||||
**🔀 规则冲突裁决顺序**(同一对象被多条规则给出相反结论时,取**首个命中项**,⛔ 不"自行取保守侧"):
|
||||
|
||||
① **开发 / 自用环境的放开条款** → ② **边界内自决策清单** → ③ **其余红线**(权限扩大 / 批量写入 / 锁 / uid —— 这几条**永远是硬约束**,不参与裁决)。
|
||||
|
||||
⛔ **冲突 ≠ 门禁**:两条规则打架**不构成**提报用户理由;真门禁**只有**上面三类 + §1.2 八类。
|
||||
🔑 **"平台级" ≠ "别人的"**:**我们自己的**资源(自己的服务器单元、自己的数据目录、自己的网关配置、自己的端口)⇒ 按规则**直接做**;「只报告不动手」**只针对"别人的 / 归属不明"**的对象。
|
||||
|
||||
---
|
||||
|
||||
## 3. 提报用户格式(**强制**)
|
||||
|
||||
| ❌ 技术语言(禁止) | ✅ 用户能感知的语言(必须) |
|
||||
|---|---|
|
||||
| 「要不要启用 `enablePatch`?」 | 「要不要让用户**自己装插件**,还是只由管理员统一装?」 |
|
||||
| 「某环境变量设成哪个档位?」 | 「AI 在你的会话里**能不能直接执行命令**,还是每次都问你一遍?」 |
|
||||
| 「新会话 vs 改写存量会话事件」 | 「**新开一个会话**就好,还是要我去改你**已有的**会话设置(改完你正在用的会话会变)」 |
|
||||
| 「限堆 / 内存上限降到 X」 | 「每个用户能用的内存**小一点更安全**,但用户跑大任务时余地也小一点」 |
|
||||
| 「插件走内投技能还是平台共享技能层」 | 「技能**跟着插件一起装**,还是**单独管理**?」 |
|
||||
|
||||
> **规则**:提报用户时**不允许出现**包名、环境变量、文件路径、commit、API 路径、代码标识符。出现即是没转换。
|
||||
|
||||
### 3.1 拆包提报用户(**实证**)
|
||||
|
||||
**实证**:把「要不要现在重启服务(该问)」和「用 A 还是 B 实现(不该问)」**捆成一个提问** ⇒ 用户被迫先读懂两套技术方案才能回答那个红线问题 ⇒ 体感依然是"又在让我确认技术问题"。
|
||||
**这才是"设了规则却没用"的真正形态**:不是问得太多,而是**把该问的和不该问的混在一次提问里**。
|
||||
|
||||
**三条规则**:
|
||||
|
||||
1. **剥出红线问题单独问**,且只问用户能判断的维度:**要不要现在动 / 影响谁 / 断多久 / 能否避开**。
|
||||
2. **技术形态自己定**,作为**已定项**写进回复("我按 B 做,因为…;可推翻"),⛔ 不要做成选项让用户选。
|
||||
3. **一轮最多一个问题**;同一个问题**不要连问两次**(第二次只是细化 ⇒ 本可合并,或直接自定)。
|
||||
|
||||
**正确写法(照这个格式 · 已定项在前,提问按五栏竖排)**:
|
||||
|
||||
```text
|
||||
我先按 B 做(平台侧自动摘除坏插件,覆盖所有装法)——**已定**。
|
||||
|
||||
1、**问题**:什么时候可以重启服务。
|
||||
**说明**:重启会让正在用平台的用户断线数秒(实例"访问即拉起",会话数据不丢),不重启这一批改动就验不完。
|
||||
**A 案**:约一个空闲窗口(优点:影响最小;缺点:要等)。
|
||||
**B 案**:现在重启(优点:立刻能验完;缺点:在线用户被打断数秒)。
|
||||
**倾向**:A 案。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 取舍筛与三问(完整)
|
||||
|
||||
> **用户原话**:「**需要我确认的方案需要说明优点和缺点,现在没法判断,假如只有优点或只有缺点那不需要我判断**」
|
||||
|
||||
**提报用户标准 = 存在「真取舍」**:
|
||||
|
||||
1. 把候选各写 **优点 + 缺点**;
|
||||
2. 某个候选**只有优点**(明显更优)或**只有缺点** ⇒ **自己拍掉、直接做完、陈述结果**;
|
||||
3. 只有**各有优有劣、客观标准分不出高下**才算真取舍,才允许提报用户;
|
||||
4. 提报给用户时**必须逐项列出优点与缺点**(只写"差别在哪"**不算**);
|
||||
5. 候选**竖排成段**(A / B / C **各占一行**)—— ⛔ 不横排(`A:… · B:…`),⛔ 不做成表格的列。
|
||||
|
||||
### 4.1 提报给用户前必答三问(任一条足以自决策,全答"否"才允许提报用户)
|
||||
|
||||
① 对象是**我们自己的资源**吗?→ 是 ⇒ 自决策。
|
||||
② 我**查证过**关键不确定点了吗(如"还有谁在用")?→ 没查 ⇒ **先查**,⛔ 不许把"不确定"当提报用户理由。
|
||||
③ 候选排完序,**第一名是否明显更优**?→ 是 ⇒ 自决策。
|
||||
|
||||
> ⛔ **禁止把"我有倾向"降级成"建议 + 待你拍板"**:候选能排出优劣 ⇒ **直接做完**并写一句「我选了什么(可推翻)」。
|
||||
|
||||
### 4.2 方法本身的演进 —— 改为自决策
|
||||
|
||||
- **方法的日常应用不问**:边界内的一切判断自己定。
|
||||
- **方法本身的修订也不问**:发现缺口 / 反例 / 需加规则时**直接改、直接记录**(改完说一句"我更新了方法:因为 X")。
|
||||
- **唯一例外**:方法修订若**扩大**了 AI 的自主权或**收窄**了用户的门禁 ⇒ 属边界外第 1 / 7 类,**必须问**。
|
||||
|
||||
---
|
||||
|
||||
## 5. 回话前自检(**发出任何回复前过一遍**)
|
||||
|
||||
> ⚠️ **起因**:拦截类钩子通常只能拦「提问工具」调用,而**真实的提报用户大多发生在正文里**(实测某工作区日志:提问工具调用数 43 → 3 → 0 → 0,因为大家改用正文提问了)。
|
||||
> ⇒ **钩子拦不到正文里的征询句,只能靠这条自检。**
|
||||
|
||||
⛔ **禁止用征询句收尾**:出现「**要我…吗 / 是否要我 / 需要我…吗 / 要不要我 / 请确认 / 你看怎么办**」时,**重判三问**:
|
||||
|
||||
① 命中**真门禁**吗(不可逆破坏性操作 / 边界外八类)?**没命中 → 删掉这句,自己做完,改成陈述句**("我接着做 X");
|
||||
② 我是不是在**把已经定下来的事再问一遍**?是 → 删;
|
||||
③ 我要问的这件事,**候选之间是「真取舍」吗**?—— 某个只有优点 / 只有缺点 ⇒ **自己拍掉**;是真取舍 → 才允许问,且**一轮只问这一句**、**逐项写优缺点**。
|
||||
|
||||
---
|
||||
|
||||
## 6. 排版规范(让长回答**可扫读**)全文
|
||||
|
||||
> 🔴 **第 0 条(优先于本节全部条目):以「本工作区规则文件」的排版节为准。**
|
||||
> 本节写的是**通用形态**;某个工作区若对排版另有**更新定稿** ⇒ **本节让位**,⛔ 不许拿本节去覆盖它。
|
||||
> ⚠️ **已实测的冲突(2026-10-02 登记,务必先看)**:DSH 项目 2026-10-01 用户定稿**明确 ⛔ 禁用表格** ——
|
||||
> 原话「**为什么回复的内容 那么人机 把我都看抑郁了,禁止用表格,全部用文字排版**」,并把骨架定为
|
||||
> **`#` 大类(已完成 / 待处理任务)→ `##` 任务名 → 每条「`- ` 圆点陈述句 + `1、2、3、` 序号」**。
|
||||
> 而本节的**约束 5「表格 ≤5 列」**与 **§6.3「长清单 / 对比 ⇒ 表格」**仍是旧口径 ⇒ **照本节做就会违反定稿**
|
||||
> (实测症状:用户当场纠正「我发现你又忘记如何回复 执行结果了,是不是技能规则失效了」)。
|
||||
> ⇒ 在那类工作区里:**表格一律换成文字段落**、「首屏 3 行给判定」等**形态**可留,**"表格优先"必须废**。
|
||||
|
||||
> 目标:**30 秒扫到结论,2 分钟看全细节**。适用范围 = **每一轮回复**(执行信息 / 报障答复 / 提问 / 交付回执都算)。
|
||||
> 判据:排版不是为了好看,是为了**能不能被扫** —— 所以下面每条都**可自检**(数得出来)。
|
||||
|
||||
### 6.1 十条硬约束
|
||||
|
||||
| # | 约束 | 自检怎么数 |
|
||||
|---|---|---|
|
||||
| 1 | **首屏 3 行内给判定**(✅/⚠️/❌ + 一句) | 前 3 行有没有判定 |
|
||||
| 2 | **层级 ≤ 3 级**(`##` → `###` → 列表),**不出 `####`** | 有没有第 4 级 |
|
||||
| 3 | **每节 ≤ 7 行**;连续 **>12 行无结构** = 文字墙 | 有没有墙 |
|
||||
| 4 | **加粗只留跳读关键词**:每节 ≤2 处、**不整句加粗** | 数加粗处数 |
|
||||
| 5 | **表格 ≤ 5 列**;单元格不塞整句 | 数列宽 |
|
||||
| 6 | **一条信息只出现一次**(别标题 / 正文 / 表格各写一遍) | 抽查重复 |
|
||||
| 7 | **能自决策的继续做;不能自决策的收进最后一节、逐条编号** | 翻到最后一节看是不是拍板项;数它有没有编号 |
|
||||
| 8 | **提报给用户的项必须带「优点 / 缺点」两栏** | 每个候选是否优缺点各至少一条 |
|
||||
| 9 | **候选竖排成段**(各占一行)—— ⛔ 不横排、⛔ 不做成表格的列 | 有没有一行塞多个候选 |
|
||||
| 10 | **并列内容逐条分段** —— 凡 `①②③` / `1) 2) 3)` / `首先·其次·最后` 式的并列项,**每条独占一段**;⛔ 不许用分号或顿号挤在同一段 | 有没有 `①…;②…;③…` 串成一段 |
|
||||
|
||||
### 6.2 待用户拍板项的**位置与形态**(三条一起用)
|
||||
|
||||
- **位置 = 整条回复的最后一节**(⛔ 不许埋在中间,后面不许再有任何节);
|
||||
- **形态 = 有序段落、逐条编号**(⛔ 不写成散文一段);
|
||||
- **语气 = 陈述句**(问题 + 说明 + 各候选优缺点 + 倾向),⛔ **不是**征询句。
|
||||
|
||||
### 6.3 按回答类型套现成骨架(**不新造**)
|
||||
|
||||
| 回答类型 | 用哪个骨架 |
|
||||
|---|---|
|
||||
| 执行信息(做了什么 / 结果如何) | **§7.2 交付回执** |
|
||||
| 是否已实现 / 能不能 / 为什么不行 | **§7.1 结论骨架** |
|
||||
| 报障 / 排查结果 | 判定(根因一句)→ 证据(命令 + 输出,代码块 **≤10 行**)→ 处置 → 未闭环 |
|
||||
| **向用户提问** | `**问题**`(一句)→ `**说明**`(为什么要你定:影响谁 / 断多久 / 花多少钱 / 有无不可逆)→ `**A 案**` / `**B 案**`(**每个候选各占一段、竖排**,各 ≤3 行,**每个都必须写「优点 / 缺点」**,推荐项置首标"(推荐)")→ `**倾向**`(一句) |
|
||||
| 长清单 / 对比 | **表格**(不要长 bullet 串) |
|
||||
|
||||
### 6.4 十四条反模式(见到就改)
|
||||
|
||||
1. ❌ 大段无空行文字(>12 行)→ 拆节或转表
|
||||
2. ❌ 嵌套列表超过 2 层 → 降为表格或加粗小标题
|
||||
3. ❌ 结论埋在段落中间 → 提到该节**首句**
|
||||
4. ❌ 整句 / 整段加粗 → 只留关键词
|
||||
5. ❌ 表格 >5 列、单元格里塞整句 → 拆表 / 缩短
|
||||
6. ❌ 同一信息重复三遍 → 留一处
|
||||
7. ❌ 用"如下所述 / 综上"指代不清 → 直接写"见 §X"或重述一句
|
||||
8. ❌ emoji 堆砌 → **只用于状态**(✅⚠️❌🔄)与**分级**(P0/P1)
|
||||
9. ❌ 术语 / 路径 / 版本号混进结论层 → 移入「技术附录」
|
||||
10. ❌ 标题层级跳跃(`##` 直接到 `####`)→ 逐级
|
||||
11. ❌ **待拍板内容夹在中间** → **挪到最后一节**;❌ 写成散文一段 → 改成**有序编号条目**
|
||||
12. ❌ 只写"两者差别在哪"却**不写优缺点** → 补齐两栏;❌ 把**只有优点 / 只有缺点**的候选拿来问 → **自己拍掉**
|
||||
13. ❌ 候选方案**横排**或做成表格的列 → **每个候选各占一段(竖排)**
|
||||
14. ❌ **并列项挤成一段** → **每条独占一段**
|
||||
|
||||
### 6.5 文案点名主体,⛔ 不用指代性代词
|
||||
|
||||
⛔ 不用 `你`、`自己`、`这把 / 那把 / 这块 / 那些 / 那份` —— **直接给名词**(`平台管理员` / `用户` / `管理员配置的模型共享`)。
|
||||
**判据** = **这一个分句单独摘出来,能不能答出"谁做的、说的是什么"**。
|
||||
⚠️ 例外:命令行占位符(`--email [email protected]`)是字面值,不动。
|
||||
|
||||
### 6.6 说明文档要「直入主题」
|
||||
|
||||
⛔ 不写「重点不在 X,而在 Y」这类**先否定再转折**的绕弯开场。
|
||||
**判据**:**第一句能不能单独看懂"这是什么、解决什么"**;凡是需要靠对比才读得懂的写法,一律改写成陈述句。
|
||||
|
||||
---
|
||||
|
||||
## 7. 现成骨架(照抄)
|
||||
|
||||
### 7.1 结论骨架(回答「是否已实现 / 能不能 / 为什么不行」)
|
||||
|
||||
> **用户原话**:「**需要告诉我的是 是否已实现,如果未实现:为什么不能,需要我拍板可以问我**」
|
||||
> 触发场景:用户问「是否已实现」,AI 却用「我自己的失误 + 探针怎么被污染 + 版本流水 + 下一步三步计划」作答 ⇒ **要的结论被埋在第 5 段之后**。
|
||||
|
||||
**固定四节,顺序不许换;没有的节整节删掉,不要留空标题:**
|
||||
|
||||
```markdown
|
||||
## 判定
|
||||
❌ 未实现 / ⚠️ 部分可用 / ✅ 已实现 —— <一句话>
|
||||
|
||||
| 目标 | 状态 |
|
||||
|---|---|
|
||||
| <用户列的第 1 项> | ✅/❌ + 半句依据 |
|
||||
|
||||
## 为什么不行(只在有 ❌ 时写;最多 3 层,结论层零技术标识)
|
||||
- 已经排除的:<已修完、不再是原因的> —— 一句话带过
|
||||
- 当前唯一卡点:<一句人话>
|
||||
- 为什么难(可选):<1–2 句;不确定性要写进结论句,例:「还不能说做不到,只能说这一步还没试」>
|
||||
|
||||
## 我接着做
|
||||
- 下一步 <X> —— **陈述句,不是征询句**
|
||||
|
||||
## 需要你拍板(**最后一节**;真需要才写,不需要 → 整节删掉;**逐条编号**)
|
||||
|
||||
**1、问题**:<一句话>。
|
||||
**说明**:<影响谁 / 断多久 / 花多少钱 / 会不会丢数据>。
|
||||
**A 案**:<做法>(优点:…;缺点:…)。
|
||||
**B 案**:<做法>(优点:…;缺点:…)。
|
||||
**倾向**:<A 案 或 B 案>。
|
||||
```
|
||||
|
||||
### 7.2 交付回执(已完成工作的交付)
|
||||
|
||||
> AI 交付时**先说成果,技术细节折叠在后**。
|
||||
|
||||
```markdown
|
||||
## 做了什么
|
||||
<2-3 句:现在多了一个什么能力,在哪儿>
|
||||
|
||||
## 你现在能看到
|
||||
- <具体位置> 出现了 <什么>;点它会发生 <什么>
|
||||
- 验证方式:<用户亲手可做的一步>
|
||||
|
||||
## 不用你决策的技术选择(已定,可随时推翻)
|
||||
- <易感知的一条,一句话>(若你希望反过来,说一声即可)
|
||||
|
||||
## 技术附录(可选读)
|
||||
<文件 / commit / md5 / 端点 / 记录编号>
|
||||
```
|
||||
|
||||
> 第 3 段是关键:**把"事前请示"改成"事后可推翻"** —— 用户获得了知情权与推翻权,但不需要在读之前做判断。
|
||||
|
||||
---
|
||||
|
||||
## 8. 六条铁律
|
||||
|
||||
| # | 铁律 | 说明 |
|
||||
|---|---|---|
|
||||
| 1 | **回答主位 = 用户问的那件事** | AI 的进度 / 失误 / 计划**不得占前两节** |
|
||||
| 2 | **结论层零技术标识** | 版本号 / commit / 包名 / 内部函数名 / 路径 / 探针名 —— 最多放「技术附录」 |
|
||||
| 3 | **禁止征询式收尾** | 「要我接着做吗 / 说一声即可 / 你看怎么弄」—— 下一步**已定**且不命中门禁 ⇒ **直接做**,用陈述句交代。⚠️ 本条禁的是**形态**;**位置**见铁律 4 |
|
||||
| 4 | **能自决策的继续做;不能自决策的收到最后一节** | 能自决策 ⇒ **自决策 + 继续处理**(不为"要不要继续"而停);不能自决策 ⇒ **收进最后一节、逐条编号**,⛔ 不许夹在中间,也不许散在正文里问 |
|
||||
| 5 | **提报给用户前先过取舍筛**(§4) | 只有优点 / 只有缺点 ⇒ 自己拍掉;真取舍才提报用户,且**必须写优缺点、候选竖排** |
|
||||
| 6 | **要解决问题,不是将就妥协** | 面对风险 / 缺陷**默认目标是解决**;**降级目标 / 延期 / 静默兜底**三种**都不算解决**。只有**客观不可逾越**(技术不可行 / 上游未支持 / 需用户给凭据或窗口)才允许"暂时接受",且必须写明 ① 卡在哪(证据)② 已做到哪一步 ③ **什么条件一出现必须回头解决**。⚠️ 与"最小代价路径"不矛盾:**目标不打折,路径取最小代价**。 |
|
||||
|
||||
### 8.1 只做正向迭代(硬红线)
|
||||
|
||||
**判据**:这个改动是否让项目**任一维度净变差** —— **目标 / 方向 / 架构 / 功能 / 性能 / 安全 / 交互 / UI / 便利性 / 扩展性**?
|
||||
|
||||
**命中 ⇒ 立即停下复盘**(⛔ 不许"先做着看"、不许将就):
|
||||
① 写清**劣化在哪一维、代价多大**(证据 / 量级);
|
||||
② 找出**能保住正向收益的做法**(改小范围 / 换实现 / 分阶段);
|
||||
③ **拿不出正向做法 ⇒ 立即停止、不再执行,只报告**。
|
||||
|
||||
⛔ **三种伪装禁止**:把劣化说成"必要代价"/用"后续再优化"掩盖已知劣化/把劣化项藏进交付不写。
|
||||
|
||||
> **自己失误的交代**:只在两种情况下写 —— ① 它**改变了结论**;② 用户**问根因**。否则放最后一节一行,或先不提。
|
||||
@@ -127,7 +127,7 @@
|
||||
> ⛔ 顺序颠倒 = **自我扩权**(实测:因为"A 明显更优"就自己登记了下一棒 ⇒ 而拍板其实还没定 ⇒ 接续已开跑)。
|
||||
|
||||
**判据**:下一棒若含**边界外事项**(业务优先级 / 花钱 / 凭据 / 偏好 / 影响面 / 不可逆)⇒ **不登记下一棒**,停下等拍板;**拍板到手后再建**。
|
||||
边界外八类见 `references/01-协作与提报用户判据.md §1.2`。
|
||||
边界外八类见 `session-mechanism/references/02-功能优先协作协议.md §3.4`。
|
||||
|
||||
### 3.4 七条实测防护
|
||||
|
||||
|
||||
@@ -6362,7 +6362,7 @@ def t_supervise_lifespan_not_invented():
|
||||
· 它的 **父进程 pid 57216 早已不在进程表** ⇒ 它是**孤儿进程**
|
||||
· 孤儿化之后**独立存活,⛔ 不受会话结束影响** ⇒ 我说的"会被带走"是**编造的后果**
|
||||
|
||||
⚠️ 讽刺的是**正确答案早就写在权威文档里**(`supervise-persistence.md` 第 30 行):
|
||||
⚠️ 讽刺的是**正确答案早就写在权威文档里**(`supervise-persistence.md` §〇 那条「实测更正」):
|
||||
「⚠️ **它们现在活着,只因为发起它们的那条会话进程树至今没被回收**
|
||||
⇒ 「**存活时长 = 发起会话的存活时长**」
|
||||
⛔ 不能用它论证「这种起法也能长期」」
|
||||
|
||||
Reference in new issue
Block a user