- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次) - .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…), 目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪 - .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/) - .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*) - .gitignore 补:备份件(*.bak-*) - 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
7.6 KiB
唤醒 · 「上报给主会话」到底是不是唤醒 + 门控该归谁(2026-09-30)
起因(用户原话):「会话协作项目中有任何会话在执行时,唤醒定时任务跳过处理(应该是通过 hook),无任何协作队列无任务,且无任何会话执行时,检查目标状态(完成:同时暂停,阻碍:反馈给协作程序 同时暂停,未完成:反馈给协作程序),这样等队列信息上报给主会话时 是不是就唤醒了」 判据:文中每条都标了源码位置(
~/.workbuddy/skills/multi-session-collab/scripts/collabd.py)。
0. 结论(三行)
- 是 —— 但前提是主会话此刻活着。因为在这套机制里,「上报」不是写文件,是投递;投递落地 ⇒ 主会话多跑一轮 ⇒ 这就是唤醒。
- 主会话已退出 ⇒ 投不出去 ⇒ 不会唤醒。那一格只能由唤醒轮(自动任务起新会话)覆盖。
- 你这条规则里,"有会话在执行就跳过""无队列才查目标""目标三态判定"大半已经是现成实现(协作程序
supervise()/_deliver_str);真正缺的是两格:「完成/阻碍 ⇒ 自动暂停」 与 「有队列但无会话执行 ⇒ 派棒」。
1. 把「上报」拆成三段 —— 只有第二段会唤醒
| # | 段 | 具体动作 | 会不会唤醒谁 |
|---|---|---|---|
| ① | 内容 | 写 tasks.json(队列本体)、TO_MAIN.md(投影)、blocked.json、NEED-USER.md |
❌ 一个人都叫不起来(纯落盘) |
| ② | 投递 | 钩子 → POST /api/v1/sessions/<主会话>/reply {text}(collabd.py:1058) |
✅ 这才是唤醒:主会话多跑一轮 |
| ③ | 起会话 | 自动任务(唤醒轮) | ✅ 主会话不在时的唯一通道 |
判据:
supervise()先写TO_MAIN.md(collabd.py:1770),紧接着才_deliver_str(txt, "上报·单条", st)(collabd.py:1777)。 ⇒ 只做了 ① 没做 ②,等于没上报。 你问的"上报时是不是就唤醒了",答案取决于走没走 ②。
2. 你的表述 vs 现有实现(逐格对照)
| 你的表述 | 现有实现(位置) | 状态 |
|---|---|---|
| 有会话在执行 ⇒ 跳过 | _session_status(目标)=="working" ⇒ target-busy 延后(collabd.py:1050) |
✅ 已有 |
| 队列无任务 | tasks.json 四态 pending/running/done/blocked,唯一权威(collabd.py:852) |
✅ 已有 |
| 无任何会话执行 | 宿主库 sessions.status='working'(_main_state collabd.py:1616;reconcile collabd.py:1644) |
✅ 已有 |
| 检查目标状态 | goals_open():台账非 done ∪ 任务图非 done ∪ goal.json.acceptance_state 任一非 pass(collabd.py:1403,三路取并集) |
✅ 判据已有 |
| 完成 ⇒ 同时暂停 A、B | 现有只有「任务图全 done ⇒ skipped=all-done 不再投递」(collabd.py:754)——它⛔不会去暂停自动任务 |
🔴 缺 |
| 阻碍 ⇒ 反馈协作程序 + 暂停 | task_report(state="blocked", reason=…)/need_user()(collabd.py:878/728) |
⚠️ 接口有;⛔ 见 §3-② |
| 未完成 ⇒ 反馈协作程序 | goals_open()==True ⇒ 写差距;现有只在"有活可派/僵住"时才报(collabd.py:786-798) |
⚠️ 部分 |
| 有队列任务 且 无会话执行 | —— | 🔴 你的规则没定义这一格 —— 而这正是最该动的那一格(有活没人干) |
3. 落地必须先知道的三个硬约束(源码级)
reply只认 live ⇒ 主会话退出后投不出去;程序此时拒绝盲投(不投给任意会话),只按工作区解析,解析不出就need_user("找不到主会话…")(collabd.py:1038-1049)。 ⇒ "上报即唤醒"对已退出的主会话结构性不成立,且程序的处置是喊人,不是自己想办法。- 队列只有「投递方」才配改(
mutate,collabd.py:1690-1696):--tick(宿主钩子)是唯一推进方;--once/常驻只做投影。⛔ 唤醒轮不许手改tasks.json,要用task_report口径上报,否则会重演「把待反馈项消费掉却不投递」的静默丢件。 - "跳过"是零 token 的:投递前的否决(
same-item内容哈希去重 /too-soon最小间隔 300s /target-busy)都在钩子进程内完成,不碰会话、不烧 token(collabd.py:960-967)。⚠️ 但钩子拦不住自动任务起会话——automation 无条件触发,所以唤醒轮"起来后发现有人在跑就立刻退"仍靠域锁。
4. 完整闭环:两半合起来才闭合
| 主会话此刻 | 谁把它叫起来 | 延迟 | 成本 |
|---|---|---|---|
| 活着 · 空闲 | 钩子投递(reply) |
秒级~分钟 | 到投递前零 token |
| 活着 · 执行中 | 不打扰(target-busy 延后,等它空闲) |
等它空 | — |
| 已退出(worker 已回收) | 唤醒轮(自动任务起新会话) | ≤30 分钟 | 一个新会话 |
⇒ 所以「等队列信息上报给主会话时就醒了」——对"活着"那行成立,对"已退出"那行不成立;后者靠唤醒轮。
⚠️ 代价(源码里写着的一句话,必须知道):collabd.py:857-860 注释——
「每次投递都会唤起主会话跑一轮 ⇒ 用户发消息撞 busy ⇒ 体感"卡"」 ⇒ "上报即唤醒"=会占用主会话 ⇒ 必须节流。现有的四道节流:单条+握手(一次只反馈一条,等它执行完才发下一条)/内容哈希去重/最小间隔 300s/真停滞门槛 15 分钟(
HEARTBEAT_MIN_IDLE,有进展一条都不发)。⛔ 落地时不许把这四道拆掉。
5. 落地:要补的两格(其余照抄现成)
唤醒轮起来 → ① 抢域锁(抢不到 = 有人在推进 ⇒ 立即结束,零成本跳过)
→ ② 读队列 tmp/supervise-inbox/tasks.json
→ ③ 读会话:宿主库 sessions.status='working'(cwd=本工作区,排除自己)
→ ④ 读目标:tasks.json 非 done ∪ taskgraph.json 非 done ∪ goal.json.acceptance_state 任一非 pass
| 格 | 条件 | 动作 |
|---|---|---|
| A | 有队列任务(pending/running)且 无会话执行 | 派一棒(起一个会话去干)← 🔴 你原规则缺的这格 |
| B | 无队列 且 无会话执行 · 目标未完成 | 把差距写进 tmp/supervise-inbox/(⛔ 不手改 tasks.json) |
| C | 无队列 且 无会话执行 · 目标有阻碍 | 写清"要用户做什么" + A、B 两条排期一起置 PAUSED |
| D | 无队列 且 无会话执行 · 目标已完成 | A、B 两条排期一起置 PAUSED ← 🔴 现成实现没有这一格 |
| E | 判不准 | 按 B 处理(宁可空转一轮,⛔ 不许造活) |
A/B 排期 id(自我暂停时用;⛔ 只改 status,不动 rrule):
- 唤醒轮 A
caca9a89-fa82-48e1-a55c-7e0f3a06bd48| 唤醒轮 B16bec5ce-98c0-470c-afa9-6f5a06218068
6. 一句话速记
上报(写文件)≠ 唤醒;投递(钩子把文字推进活着的会话)才=唤醒。 主会话活着 ⇒ 秒级唤醒(但要节流,否则把它顶"卡");主会话退出 ⇒ 钩子也没了,只剩唤醒轮起新会话(≤30 分钟)。 判据一句:"有会话在执行就跳过"=
sessions.status=='working'或 域锁被占。
附:图
见同目录 唤醒-上报即唤醒与门控归属-20260930-图.html(① 三段拆解图:标出哪一段才唤醒;② 门控矩阵图:标红两格缺失)。